osgAnimation例子的注释的注释
转自:http://www.cnblogs.com/sunliming/archive/2011/12/12/2284995.html
1 #include <osg/Notify> 2 #include <osg/MatrixTransform> 3 #include <osg/PositionAttitudeTransform> 4 #include <osg/Geometry> 5 #include <osg/Geode> 6 7 #include <osgUtil/Optimizer> 8 9 #include <osgDB/Registry> 10 #include <osgDB/ReadFile> 11 12 #include <osgGA/TrackballManipulator> 13 #include <osgGA/FlightManipulator> 14 #include <osgGA/DriveManipulator> 15 16 #include <osgSim/OverlayNode> 17 18 #include <osgViewer/Viewer> 19 #include <iostream> 20 21 // 创建动画路径,参数有中心点,半径,以及循环时间 22 osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime) 23 { 24 // 实例化动画路径类 25 // set up the animation path 26 osg::AnimationPath* animationPath = new osg::AnimationPath; 27 // 设置动画路径的播放模式,当前使用循环模式(SWING LOOP NO_LOOPING )SWING就是在一个区间内顺逆方向循环,LOOP是顺一个方向循环 28 animationPath->setLoopMode(osg::AnimationPath::LOOP); 29 30 31 // 分40个阶段 这个意思就是分为四十个控制点,犹如四十条边的多边形,沿着这个路线飞行 32 int numSamples = 40; 33 float yaw = 0.0f; 34 // 偏航的分量,这是一个角度分量,算出来每一个多边形的边对应的角度分量2*PI/(n-1) 35 float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f); 36 // 旋转角度为30度 37 float roll = osg::inDegrees(30.0f); 38 39 // 时间分量 40 double time=0.0f; 41 //平均的两个控制点之间的时间 42 double time_delta = looptime/(double)numSamples; 43 // 将时间控制点与位置坐标插入到动画路径中 44 for(int i=0;i<numSamples;++i) 45 { 46 //这儿是计算出来每个多边形的顶点的坐标,(sinx*r,cosx*r,0.0)是相当于中心点的增量 47 osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f)); 48 //四元数表示方向,表示在3D空间中的旋转方向**四元数很复杂**这个表示,绕x轴旋转roll,y轴旋转-(yaw+90),z轴0 49 osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0))); 50 51 //和flash动画类似,控制点有位置和转动角度,这样控制点之间是均匀运动 52 animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation)); 53 54 //递增yaw和time 55 yaw += yaw_delta; 56 time += time_delta; 57 58 } 59 return animationPath; 60 } 61 62 63 // 创建底板,中心点位置在center,半径为radius 64 osg::Node* createBase(const osg::Vec3& center,float radius) 65 { 66 67 // 一个10x10的底板 68 int numTilesX = 10; 69 int numTilesY = 10; 70 71 // 长度与宽度的尺寸 72 float width = 2*radius; 73 float height = 2*radius; 74 75 // 计算初始位置与x、y的分量 76 osg::Vec3 v000(center - osg::Vec3(width*0.5f,height*0.5f,0.0f)); 77 osg::Vec3 dx(osg::Vec3(width/((float)numTilesX),0.0,0.0f)); 78 osg::Vec3 dy(osg::Vec3(0.0f,height/((float)numTilesY),0.0f)); 79 80 // 计算每个小格子的顶点坐标并压入数组中 81 // fill in vertices for grid, note numTilesX+1 * numTilesY+1... 82 osg::Vec3Array* coords = new osg::Vec3Array; 83 int iy; 84 for(iy=0;iy<=numTilesY;++iy) 85 { 86 for(int ix=0;ix<=numTilesX;++ix) 87 { 88 coords->push_back(v000+dx*(float)ix+dy*(float)iy); 89 } 90 } 91 92 // 设置颜色的数组,当前为黑白色两种颜色 93 //Just two colours - black and white. 94 osg::Vec4Array* colors = new osg::Vec4Array; 95 colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); // white 96 colors->push_back(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); // black 97 int numColors=colors->size(); 98 99 // 设置绘制四边形的顶点索引与每个四边形的颜色 100 int numIndicesPerRow=numTilesX+1; 101 osg::UByteArray* coordIndices = new osg::UByteArray; // assumes we are using less than 256 points... 102 osg::UByteArray* colorIndices = new osg::UByteArray; 103 for(iy=0;iy<numTilesY;++iy) 104 { 105 for(int ix=0;ix<numTilesX;++ix) 106 { 107 // four vertices per quad. 108 coordIndices->push_back(ix +(iy+1)*numIndicesPerRow); 109 coordIndices->push_back(ix +iy*numIndicesPerRow); 110 coordIndices->push_back((ix+1)+iy*numIndicesPerRow); 111 coordIndices->push_back((ix+1)+(iy+1)*numIndicesPerRow); 112 113 // one color per quad 114 colorIndices->push_back((ix+iy)%numColors); 115 } 116 } 117 118 119 // 设置法线向量 120 // set up a single normal 121 osg::Vec3Array* normals = new osg::Vec3Array; 122 normals->push_back(osg::Vec3(0.0f,0.0f,1.0f)); 123 124 125 // 设置顶点坐标数组 126 osg::Geometry* geom = new osg::Geometry; 127 geom->setVertexArray(coords); 128 geom->setVertexIndices(coordIndices); 129 130 // 设置颜色数组 131 geom->setColorArray(colors); 132 geom->setColorIndices(colorIndices); 133 geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE); 134 135 // 设置法线数组 136 geom->setNormalArray(normals); 137 geom->setNormalBinding(osg::Geometry::BIND_OVERALL); 138 139 // 需要绘制什么形状的图形,当前为四边形 140 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,coordIndices->size())); 141 142 // 将绘制的的图形添加到osg::Geode中 143 osg::Geode* geode = new osg::Geode; 144 geode->addDrawable(geom); 145 146 return geode; 147 } 148 149 // 创建移动的模型,中心点在center,半径为radius 150 osg::Node* createMovingModel(const osg::Vec3& center, float radius) 151 { 152 float animationLength = 10.0f; 153 154 // 创建动画路径,中心点在center,半径为radius,循环时间为10.0f 155 osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength); 156 157 osg::Group* model = new osg::Group; 158 159 // 从外部读取一个模型glider.osg作为飞行的模型 160 osg::Node* glider = osgDB::readNodeFile("glider.osg"); 161 if (glider) 162 { 163 // 根据模型的包围球来计算矩阵 164 // 平移到原点,缩放模型,然后沿z轴旋转-90度 165 const osg::BoundingSphere& bs = glider->getBound(); 166 167 float size = radius/bs.radius()*0.3f; 168 osg::MatrixTransform* positioned = new osg::MatrixTransform; 169 //设置这个值在对象生命周期内为静态的不可改变的数值,或者动态的在对象生命周期内变化的值 170 positioned->setDataVariance(osg::Object::STATIC); 171 //设置转移矩阵参数 172 positioned->setMatrix(osg::Matrix::translate(-bs.center())* /*表示平移物体,注意osg的坐标系是z轴是向上的*/ 173 osg::Matrix::scale(size,size,size)* /*x,y,z轴的放缩比例*/ 174 osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,0.0f,1.0f)); /*x,y,z轴的旋转角度*/ 175 176 positioned->addChild(glider); 177 178 // 设置动画路径的回调函数,使在渲染循环中不停的沿动画路径移动,设置坐标系变换 179 osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform; 180 xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0)); 181 xform->addChild(positioned); 182 183 model->addChild(xform); 184 } 185 186 // 从外部读取一个模型cessna.osg 187 // 操作同上,设置动画路径的回调函数,使在渲染的循环中不停的沿动画路径移动 188 osg::Node* cessna = osgDB::readNodeFile("cessna.osg"); 189 if (cessna) 190 { 191 const osg::BoundingSphere& bs = cessna->getBound(); 192 193 float size = radius/bs.radius()*0.3f; 194 osg::MatrixTransform* positioned = new osg::MatrixTransform; 195 positioned->setDataVariance(osg::Object::STATIC); 196 positioned->setMatrix(osg::Matrix::translate(-bs.center())* 197 osg::Matrix::scale(size,size,size)* 198 osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,1.0f)); 199 200 positioned->addChild(cessna); 201 202 osg::MatrixTransform* xform = new osg::MatrixTransform; 203 xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0)); 204 xform->addChild(positioned); 205 206 model->addChild(xform); 207 } 208 209 return model; 210 } 211 212 // 创建覆盖图,根据覆盖的实现技术来设置 213 osg::Node* createModel(bool overlay, osgSim::OverlayNode::OverlayTechnique technique) 214 { 215 osg::Vec3 center(0.0f,0.0f,0.0f); 216 float radius = 100.0f; 217 218 osg::Group* root = new osg::Group; 219 220 // 创建底板与飞行的模型 221 float baseHeight = center.z()-radius*0.5; 222 osg::Node* baseModel = createBase(osg::Vec3(center.x(), center.y(), baseHeight),radius); 223 osg::Node* movingModel = createMovingModel(center,radius*0.8f); 224 225 // 是否设置覆盖图 226 if (overlay) 227 { 228 // 根据命令行传入的参数来设置 229 osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique); 230 overlayNode->setContinuousUpdate(true); 231 // 需要设置的覆盖的图的模型为飞行的模型,当前为从外部加载的模型 232 overlayNode->setOverlaySubgraph(movingModel); 233 // 设置覆盖图距离底板的高度 234 overlayNode->setOverlayBaseHeight(baseHeight-0.01); 235 overlayNode->addChild(baseModel); 236 // 将覆盖图的节点加入到根节点中 237 root->addChild(overlayNode); 238 } 239 else 240 { 241 // 不设置覆盖图 242 root->addChild(baseModel); 243 } 244 245 root->addChild(movingModel); 246 247 return root; 248 } 249 250 251 int main( int argc, char **argv ) 252 { 253 // 是否使用覆盖模拟 254 bool overlay = false; 255 // 使用命令行参数实例化osg::ArgumentParset类,方便以后的操作 256 osg::ArgumentParser arguments(&argc,argv); 257 while (arguments.read("--overlay")) overlay = true; 258 259 // 获得覆盖节点采用哪种技术实现,提供三种实现技术 260 osgSim::OverlayNode::OverlayTechnique technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; 261 while (arguments.read("--object")) { technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; overlay=true; } 262 while (arguments.read("--ortho") || arguments.read("--orthographic")) { technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; overlay=true; } 263 while (arguments.read("--persp") || arguments.read("--perspective")) { technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY; overlay=true; } 264 265 266 // initialize the viewer. 267 osgViewer::Viewer viewer; 268 269 // 创建底板与飞行的物体,飞行物体通过外部读取 270 // load the nodes from the commandline arguments. 271 osg::Node* model = createModel(overlay, technique); 272 if (!model) 273 { 274 return 1; 275 } 276 277 // 创建一个osg::MatrixTransform并设置场景沿x轴旋转30度 278 // tilt the scene so the default eye position is looking down on the model. 279 osg::MatrixTransform* rootnode = new osg::MatrixTransform; 280 rootnode->setMatrix(osg::Matrix::rotate(osg::inDegrees(30.0f),1.0f,0.0f,0.0f)); 281 rootnode->addChild(model); 282 283 /// 对整个场景进行优化 284 // run optimization over the scene graph 285 osgUtil::Optimizer optimzer; 286 optimzer.optimize(rootnode); 287 288 // 将整个节点设置到场景中进行渲染 289 // set the scene to render 290 viewer.setSceneData(rootnode); 291 292 // 设置相机的操作器,当前使用跟踪球的模式进行操作 293 viewer.setCameraManipulator(new osgGA::TrackballManipulator()); 294 295 // viewer.setUpViewOnSingleScreen(1); 296 297 // 提供两中渲染的循环模式 298 // 第一中采用老式的模式 299 // 第二中采用封装模式 300 #if 0 301 302 // use of custom simulation time. 303 304 viewer.realize(); 305 306 double simulationTime = 0.0; 307 308 while (!viewer.done()) 309 { 310 viewer.frame(simulationTime); 311 simulationTime += 0.001; 312 } 313 314 return 0; 315 #else 316 317 // normal viewer usage. 318 return viewer.run(); 319 320 #endif 321 }