Learning OSG programing---osgAnimation(2)
1 osg::Node* createBase(const osg::Vec3& center,float radius) 2 { 3 4 5 6 int numTilesX = 10; 7 int numTilesY = 10; 8 9 float width = 2*radius; 10 float height = 2*radius; 11 12 osg::Vec3 v000(center - osg::Vec3(width*0.5f,height*0.5f,0.0f)); 13 osg::Vec3 dx(osg::Vec3(width/((float)numTilesX),0.0,0.0f)); 14 osg::Vec3 dy(osg::Vec3(0.0f,height/((float)numTilesY),0.0f)); 15 16 // fill in vertices for grid, note numTilesX+1 * numTilesY+1... 17 osg::Vec3Array* coords = new osg::Vec3Array; 18 int iy; 19 for(iy=0;iy<=numTilesY;++iy) 20 { 21 for(int ix=0;ix<=numTilesX;++ix) 22 { 23 coords->push_back(v000+dx*(float)ix+dy*(float)iy); 24 } 25 } 26 27 //Just two colours - black and white. 28 osg::Vec4Array* colors = new osg::Vec4Array; 29 colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); // white 30 colors->push_back(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); // black 31 32 osg::ref_ptr<osg::DrawElementsUShort> whitePrimitives = new osg::DrawElementsUShort(GL_QUADS); 33 osg::ref_ptr<osg::DrawElementsUShort> blackPrimitives = new osg::DrawElementsUShort(GL_QUADS); 34 35 int numIndicesPerRow=numTilesX+1; 36 for(iy=0;iy<numTilesY;++iy) 37 { 38 for(int ix=0;ix<numTilesX;++ix) 39 { 40 osg::DrawElementsUShort* primitives = ((iy+ix)%2==0) ? whitePrimitives.get() : blackPrimitives.get(); 41 primitives->push_back(ix +(iy+1)*numIndicesPerRow); 42 primitives->push_back(ix +iy*numIndicesPerRow); 43 primitives->push_back((ix+1)+iy*numIndicesPerRow); 44 primitives->push_back((ix+1)+(iy+1)*numIndicesPerRow); 45 } 46 } 47 48 // set up a single normal 49 osg::Vec3Array* normals = new osg::Vec3Array; 50 normals->push_back(osg::Vec3(0.0f,0.0f,1.0f)); 51 52 osg::Geometry* geom = new osg::Geometry; 53 geom->setVertexArray(coords); 54 55 geom->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET); 56 57 geom->setNormalArray(normals, osg::Array::BIND_OVERALL); 58 59 geom->addPrimitiveSet(whitePrimitives.get()); 60 geom->addPrimitiveSet(blackPrimitives.get()); 61 62 osg::Geode* geode = new osg::Geode; 63 geode->addDrawable(geom); 64 65 return geode; 66 }
createBase函数用于建立模型模拟时的地板,作为飞机飞行的参照。
23行中,循环向变量coords中添加坐标点,作为地板的控制点。
36-46行中,交替取出白色面元和黑色面元,并向其中每次添加四个顶点(索引值),指示面元的角点坐标(按照索引值从coords数组中取出)。
随后设置所有面元的法向量,并将黑白面元分别添加进绘制几何节点中,并将绘制几何节点添加到集合节点中,由函数返回。
接下来分析第三个函数:
1 osg::Node* createMovingModel(const osg::Vec3& center, float radius) 2 { 3 float animationLength = 10.0f; 4 5 osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength); 6 7 osg::ref_ptr<osg::Group> model = new osg::Group; 8 9 osg::ref_ptr<osg::Node> glider = osgDB::readRefNodeFile("glider.osgt"); 10 if (glider) 11 { 12 const osg::BoundingSphere& bs = glider->getBound(); 13 14 float size = radius/bs.radius()*0.3f; 15 osg::MatrixTransform* positioned = new osg::MatrixTransform; 16 positioned->setDataVariance(osg::Object::STATIC); 17 positioned ->setMatrix(osg::Matrix::translate(-bs.center())* 18 osg::Matrix::scale(size,size,size)* 19 osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,0.0f,1.0f)); 20 21 positioned->addChild(glider); 22 23 osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform; 24 xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0)); 25 xform->addChild(positioned); 26 27 model->addChild(xform); 28 } 29 30 osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("cessna.osgt"); 31 if (cessna) 32 { 33 const osg::BoundingSphere& bs = cessna->getBound(); 34 35 float size = radius/bs.radius()*0.3f; 36 osg::MatrixTransform* positioned = new osg::MatrixTransform; 37 positioned->setDataVariance(osg::Object::STATIC); 38 positioned->setMatrix(osg::Matrix::translate(-bs.center())* 39 osg::Matrix::scale(size,size,size)* 40 osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,1.0f)); 41 42 positioned->addChild(cessna); 43 44 osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform; 45 xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0)); 46 xform->addChild(positioned); 47 48 model->addChild(xform); 49 } 50 51 #ifndef OSG_GLES2_AVAILABLE 52 model->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); 53 #endif 54 55 return model.release(); 56 }
这个函数的作用是创建运动模型。
首先利用上一节介绍的createAnimationPath 函数创建模拟路径,并以此为基础加载模型,并控制模型的运动。
动态更新的核心就是设置数据变度属性DataVariance,它决定了OSG在多线程渲染的过程中的执行策略:只有所有DYNAMIC属性的对象被渲染 完毕之后,OSG才会开始执行下一帧的用户更新操作;这样有效地可以避免数据的过快更新造成当前的渲染动作出错,以致系统崩溃。
将模型进行平移,缩放,并绕z轴旋转180度。创建转换函数,并设置其更新回调函数。AnimationPathCallback的构造函数为:
osg::AnimationPathCallback::AnimationPathCallback ( AnimationPath * ap, double timeOffset = 0.0, double timeMultiplier = 1.0 )
该函数的第三个参数决定了节点旋转的速度。因此cessna模型的旋转速度是glider的二倍。这两个模型的加载和回调更新函数的设定过程相同,只是参数有所不同。