爲了在VR手柄上作按鈕所作的一個研究, 假設圖片分爲上下兩部分, 一個是射線移入的狀態(正指向本按鈕的狀態) 一個是射線移開的初始的狀態.node
上次切換圖片, 會出現內存出錯, 此次用改變帖圖座標的方式. 本例用的貼圖是OSG data文件夾帶有的.數組
運行結果是: 測試
隔5幀替換一次帖圖幀:code
代碼:orm
#include <osgViewer/Viewer> // 加載 USE_GRAPHICSWINDOW() 所需 #include<osg/Texture2D> #include<osg/BlendFunc> #include<osg/AlphaFunc> #include<osg/TexEnv> /** * 生成一個面片 */ osg::Node* CreateQuad() { osg::Geode *g1 = new osg::Geode;// 白 g1->setName("Quad1_爲了按鈕"); osg::Geometry *gPlane1 = new osg::Geometry; g1->addDrawable(gPlane1); // 1.頂點: osg::Vec3Array *arrVertex1 = new osg::Vec3Array; arrVertex1->push_back(osg::Vec3(-1.0f,0.0f,-1.0f));// 頂點的順序, 會影響貼圖方向 arrVertex1->push_back(osg::Vec3(-1.0f,0.0f,1.0f)); arrVertex1->push_back(osg::Vec3(1.0f,0.0f,1.0f)); arrVertex1->push_back(osg::Vec3(1.0f,0.0f,-1.0f)); gPlane1->setVertexArray(arrVertex1); // 2.顏色: osg::Vec4Array *arrColor1 = new osg::Vec4Array; arrColor1->push_back(osg::Vec4(.5,.5,.5,1)); gPlane1->setColorArray(arrColor1,osg::Array::BIND_OVERALL); // 3.法線: osg::Vec3Array *arrNormal = new osg::Vec3Array; arrNormal->push_back(osg::Vec3(0,1,1)); gPlane1->setNormalArray(arrNormal,osg::Array::BIND_OVERALL); // 4.頂點關聯方式 gPlane1->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,arrVertex1->size()) ); //爲紋理建立數組 osg::ref_ptr<osg::Vec2Array> tArr0 = new osg::Vec2Array;//建立一個 Vec2Array對象以保存紋理單元 0 的紋理座標 tArr0->push_back(osg::Vec2(0,0)); tArr0->push_back(osg::Vec2(0,1)); tArr0->push_back(osg::Vec2(1,1)); tArr0->push_back(osg::Vec2(1,0)); gPlane1->setTexCoordArray(0,tArr0.get()); return g1; } osg::Node* CreateImageQuad() { osg::Node *node1 = CreateQuad(); // 爲Quad貼圖: osg::StateSet *state = node1->getOrCreateStateSet(); //打開混合 osg::BlendFunc* bf = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA ); state->setAttributeAndModes( bf ); // 設不受光照影響: state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); //讀圖: osg::Image *img = osgDB::readImageFile("Images/osg256.png");// Images/lz.rgb osg::Texture2D *texture1 = new osg::Texture2D(img); state->setTextureAttributeAndModes( 0, texture1 , osg::StateAttribute::ON ); return node1; } /* 測試按鈕幀的替換 */ class FrameCallback:public osg::NodeCallback { public: FrameCallback(osg::ref_ptr<osg::Vec2Array> v1, osg::Geometry *_geometry): tArr1(v1),geometry(_geometry) { } void operator()(osg::Node* node , osg::NodeVisitor* nv) { static int i=0; ++i; osg::notify(osg::NOTICE)<<node->getName()<<";"<<std::endl; if(0==i%5) { if(i%2) { (*tArr1)[3] = osg::Vec2(1,0); (*tArr1)[2] = osg::Vec2(1,0.5); // 這裏改變順序,並不會改變貼圖順序 (*tArr1)[0] = osg::Vec2(0,0); (*tArr1)[1] = osg::Vec2(0,0.5); } else { (*tArr1)[3] = osg::Vec2(1,0.5); (*tArr1)[2] = osg::Vec2(1,1); // 這裏改變順序,並不會改變貼圖順序 (*tArr1)[0] = osg::Vec2(0,0.5); (*tArr1)[1] = osg::Vec2(0,1); } geometry->setTexCoordArray(0,tArr1.get()); } traverse(node,nv); } private: osg::ref_ptr<osg::Vec2Array> tArr1; osg::Geometry *geometry; }; int main() { osgViewer::Viewer viewer1 ; osg::Group *gInteractiveScene = new osg::Group; osg::Node *node1 = CreateImageQuad(); // 取得貼圖數據: osg::Geode *draw1= node1->asGeode(); if(!draw1) { osg::notify(osg::FATAL) << "沒取到draw1" << std::endl; } osg::Drawable *draw2 = draw1->getDrawable(0); if(!draw2) { osg::notify(osg::FATAL) << "沒取到draw2" << std::endl; } osg::Geometry *draw3 = draw2->asGeometry(); if(!draw3) { osg::notify(osg::FATAL) << "沒取到draw3" << std::endl; } draw3->getTexCoordArray(0); osg::ref_ptr<osg::Vec2Array> tArr1 = (osg::Vec2Array*)draw3->getTexCoordArray(0); (*tArr1)[0] = osg::Vec2(0,0.5); (*tArr1)[1] = osg::Vec2(0,1); (*tArr1)[2] = osg::Vec2(1,1); (*tArr1)[3] = osg::Vec2(1,0.5);// 在此,單單修改帖圖座標是有效的, 可是在刷幀回調中, 還要加一句: geometry->setTexCoordArray(0,tArr1.get()); // 刷幀回調: gInteractiveScene->addUpdateCallback( new FrameCallback( tArr1 , draw3 ) ); gInteractiveScene->addChild(node1); viewer1.setSceneData(gInteractiveScene); return viewer1.run(); }