为了在VR手柄上做按钮所做的一个研究, 假设图片分为上下两部分, 一个是射线移入的状态(正指向本按钮的状态) 一个是射线移开的初始的状态.
上次切换图片, 会出现内存出错, 这次用改变帖图坐标的方式. 本例用的贴图是OSG data文件夹带有的.
运行结果是:
隔5帧替换一次帖图帧:
代码:
#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();
}