osg示例解析之osganimationskinning

转载 原文网址 http://blog.csdn.net/csxiaoshui/article/details/22814373


  • 简介

osgAnimationSkinning这个示例主要使用了osgAnimation中的骨骼蒙皮动画,关于骨骼蒙皮动画的介绍可以参考Skinned Mesh原理解析和一个最简单的实现示例这篇CSDN的博客,里面用Glut实现了一个简单的蒙皮动画,整篇文章对骨骼动画和蒙皮进行了详尽的阐述,相信读完之后可以对骨骼动画有更深的理解。

  • 示例

源码中createAxis创建了一个坐标系,代码十分的简单,仅仅是画出三条坐标轴线而已。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. osg::Geode* createAxis()  
  2. {  
  3.     osg::Geode* geode (new osg::Geode());  
  4.     osg::Geometry* geometry (new osg::Geometry());  
  5.   
  6.     osg::Vec3Array* vertices (new osg::Vec3Array());  
  7.     vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));  
  8.     vertices->push_back (osg::Vec3 ( 1.0, 0.0, 0.0));  
  9.     vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));  
  10.     vertices->push_back (osg::Vec3 ( 0.0, 1.0, 0.0));  
  11.     vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));  
  12.     vertices->push_back (osg::Vec3 ( 0.0, 0.0, 1.0));  
  13.     geometry->setVertexArray (vertices);  
  14.   
  15.     osg::Vec4Array* colors (new osg::Vec4Array());  
  16.     colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));  
  17.     colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));  
  18.     colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));  
  19.     colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));  
  20.     colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));  
  21.     colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));  
  22.     geometry->setColorArray (colors, osg::Array::BIND_PER_VERTEX);  
  23.     geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));  
  24.   
  25.     geode->addDrawable( geometry );  
  26.     return geode;  
  27. }  
createTesselatedBox这个函数做的是创建了骨骼动画的蒙皮Mesh,相当于给骨骼做了一件“衣服”,我们看看它怎么创建的:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. float step = size / static_cast<float>(nsplit);  
  2. float s = 0.5f/4.0f;  
  3. for (int i = 0; i < nsplit; i++)  
  4. {  
  5.     float x = -1.0f + static_cast<float>(i) * step;  
  6.     std::cout << x << std::endl;  
  7.     vertices->push_back (osg::Vec3 ( x, s, s));  
  8.     vertices->push_back (osg::Vec3 ( x, -s, s));  
  9.     vertices->push_back (osg::Vec3 ( x, -s, -s));  
  10.     vertices->push_back (osg::Vec3 ( x, s, -s));  
  11.     osg::Vec3 c (0.0f,0.0f,0.0f);  
  12.     c[i%3] = 1.0f;  
  13.     colors->push_back (c);  
  14.     colors->push_back (c);  
  15.     colors->push_back (c);  
  16.     colors->push_back (c);  
  17. }  
  18.   
  19. osg::ref_ptr<osg::UIntArray> array = new osg::UIntArray;  
  20. for (int i = 0; i < nsplit - 1; i++)  
  21. {  
  22.     int base = i * 4;  
  23.   
  24.     //Top  
  25.     array->push_back(base);  
  26.     array->push_back(base+1);  
  27.     array->push_back(base+4);  
  28.     array->push_back(base+1);  
  29.     array->push_back(base+5);  
  30.     array->push_back(base+4);  
  31.   
  32.     //Back  
  33.     array->push_back(base+3);  
  34.     array->push_back(base);  
  35.     array->push_back(base+4);  
  36.     array->push_back(base+7);  
  37.     array->push_back(base+3);  
  38.     array->push_back(base+4);  
  39.   
  40.     //Front  
  41.     array->push_back(base+5);  
  42.     array->push_back(base+1);  
  43.     array->push_back(base+2);  
  44.     array->push_back(base+2);  
  45.     array->push_back(base+6);  
  46.     array->push_back(base+5);  
  47.   
  48.     //Bottom  
  49.     array->push_back(base+2);  
  50.     array->push_back(base+3);  
  51.     array->push_back(base+7);  
  52.     array->push_back(base+6);  
  53.     array->push_back(base+2);  
  54.     array->push_back(base+7);  
  55. }  

通过上面的注解可以知道,函数createTesselatedBox(int nsplit, float size)的两个参数,其中nsplit是把这个立方体柱分成了nsplit-1段,然后每段一个立方体的4个面,这段代码使用的是DrawElement的方式创建的,因此它传入的是索引值。

接下来就是Skin info的操作,给不同的顶点绑定到骨骼上,并且给这些顶点赋予权值,这个示例中设置权值的方式比较简单,所有X在-1到0之间的顶点只受到骨骼Bon0的影响,所有X在0到1之间的顶点只受Bone1的影响,所有X值大于1的顶点只受到Bone2的影响。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void initVertexMap(osgAnimation::Bone* b0,  
  2.                    osgAnimation::Bone* b1,  
  3.                    osgAnimation::Bone* b2,  
  4.                    osgAnimation::RigGeometry* geom,  
  5.                    osg::Vec3Array* array)  
  6. {  
  7.     //osgAnimation::VertexInfluenceSet vertexesInfluences;  
  8.     osgAnimation::VertexInfluenceMap* vim = new osgAnimation::VertexInfluenceMap;  
  9.   
  10.     (*vim)[b0->getName()].setName(b0->getName());  
  11.     (*vim)[b1->getName()].setName(b1->getName());  
  12.     (*vim)[b2->getName()].setName(b2->getName());  
  13.   
  14.     for (int i = 0; i < (int)array->size(); i++)  
  15.     {  
  16.         float val = (*array)[i][0];  
  17.         std::cout << val << std::endl;  
  18.         if (val >= -1.0f && val <= 0.0f)  
  19.             (*vim)[b0->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f));  
  20.         else if ( val > 0.0f && val <= 1.0f)  
  21.             (*vim)[b1->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f));  
  22.         else if ( val > 1.0f)  
  23.             (*vim)[b2->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f));  
  24.     }  
  25.   
  26.     geom->setInfluenceMap(vim);  
  27. }  
主函数main里面主要创建了骨骼动画:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;  
  2. skelroot->setDefaultUpdateCallback();  
  3. osg::ref_ptr<osgAnimation::Bone> root = new osgAnimation::Bone;  
  4. root->setInvBindMatrixInSkeletonSpace(osg::Matrix::inverse(osg::Matrix::translate(-1.0,0.0,0.0)));  
  5. root->setName("root");  
  6. osgAnimation::UpdateBone* pRootUpdate = new osgAnimation::UpdateBone("root");  
  7. pRootUpdate->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate",osg::Vec3(-1.0f,0.0f,0.0f)));  
  8. root->setUpdateCallback(pRootUpdate);  
  9.   
  10. osg::ref_ptr<osgAnimation::Bone> right0 = new osgAnimation::Bone;  
  11. right0->setInvBindMatrixInSkeletonSpace(osg::Matrix::inverse(osg::Matrix::translate(0.0,0.0,0.0)));  
  12. right0->setName("right0");  
  13. osgAnimation::UpdateBone* pRight0Update = new osgAnimation::UpdateBone("right0");  
  14. pRight0Update->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate", osg::Vec3(1.0f,0.0f,0.0f)));  
  15. pRight0Update->getStackedTransforms().push_back(new osgAnimation::StackedRotateAxisElement("rotate", osg::Vec3(0.0f,0.0f,1.0f), 0.0));  
  16. right0->setUpdateCallback(pRight0Update);  
  17.   
  18. osg::ref_ptr<osgAnimation::Bone> right1 = new osgAnimation::Bone;  
  19. right1->setInvBindMatrixInSkeletonSpace(osg::Matrix::inverse(osg::Matrix::translate(1.0,0.0,0.0)));  
  20. right1->setName("right1");  
  21. osgAnimation::UpdateBone* pRight1Update = new osgAnimation::UpdateBone("right1");  
  22. pRight1Update->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate", osg::Vec3(1.0f,0.0f,0.0f)));  
  23. pRight1Update->getStackedTransforms().push_back(new osgAnimation::StackedRotateAxisElement("rotate", osg::Vec3(0.0f,0.0f,1.0f), 0.0));  
  24. right1->setUpdateCallback(pRight1Update);  
  25.   
  26. root->addChild(right0.get());  
  27. right0->addChild(right1.get());  
  28. skelroot->addChild(root.get());  
以上代码创建了骨骼的框架,这个创建骨骼的模式还是比较固定的,需要注意的是UpdateBone的名称需要和下面Channel的SetTargetName名称一致,UpdateBone里面StackedTransformElement需要和Channel的Name一致

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. osg::Group* scene = new osg::Group;  
  2. osg::ref_ptr<osgAnimation::BasicAnimationManager> manager = new osgAnimation::BasicAnimationManager;  
  3. scene->setUpdateCallback(manager.get());  
  4.   
  5. osgAnimation::Animation* anim = new osgAnimation::Animation;  
  6. {  
  7.     osgAnimation::FloatKeyframeContainer* keys0 = new osgAnimation::FloatKeyframeContainer;  
  8.     keys0->push_back(osgAnimation::FloatKeyframe(0.0,0.0f));  
  9.     keys0->push_back(osgAnimation::FloatKeyframe(3.0,osg::PI_2));  
  10.     keys0->push_back(osgAnimation::FloatKeyframe(6.0,osg::PI_2));  
  11.     osgAnimation::FloatLinearSampler* sampler = new osgAnimation::FloatLinearSampler;  
  12.     sampler->setKeyframeContainer(keys0);  
  13.     osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel(sampler);  
  14.     channel->setName("rotate");  
  15.     channel->setTargetName("right0");  
  16.     anim->addChannel(channel);  
  17. }  
  18.   
  19. {  
  20.     osgAnimation::FloatKeyframeContainer* keys1 = new osgAnimation::FloatKeyframeContainer;  
  21.     keys1->push_back(osgAnimation::FloatKeyframe(0.0,0.0f));  
  22.     keys1->push_back(osgAnimation::FloatKeyframe(3.0,0.0f));  
  23.     keys1->push_back(osgAnimation::FloatKeyframe(6.0,osg::PI_2));  
  24.     osgAnimation::FloatLinearSampler* sampler = new osgAnimation::FloatLinearSampler;  
  25.     sampler->setKeyframeContainer(keys1);  
  26.     osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel(sampler);  
  27.     channel->setName("rotate");  
  28.     channel->setTargetName("right1");  
  29.     anim->addChannel(channel);  
  30. }  
  31. manager->registerAnimation(anim);  
  32. //manager->buildTargetReference();  
  33.   
  34. // let's start !  
  35. manager->playAnimation(anim);  
这段代码创建了骨骼动画运行的关键帧。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. osg::MatrixTransform* rootTransform = new osg::MatrixTransform;  
  2. rootTransform->setMatrix(osg::Matrix::rotate(osg::PI_2,osg::Vec3(1.0f,0.0f,0.0f)));  
  3. right0->addChild(createAxis());  
  4. right0->setDataVariance(osg::Object::DYNAMIC);  
  5. right1->addChild(createAxis());  
  6. right1->setDataVariance(osg::Object::DYNAMIC);  
  7. osg::MatrixTransform* trueroot = new osg::MatrixTransform;  
  8. trueroot->setMatrix(osg::Matrix(root->getMatrixInBoneSpace().ptr()));  
  9. trueroot->addChild(createAxis());  
  10. trueroot->addChild(skelroot.get());  
  11. trueroot->setDataVariance(osg::Object::DYNAMIC);  
  12. rootTransform->addChild(trueroot);  
  13. scene->addChild(rootTransform);  
上面的这段代码把可绘制实体添加到骨骼动画之中,这样我们才能看见骨骼动画的实际效果。这些Geode将抽象的骨骼变换具体化,能让我们看见Geode上面绑定着的骨骼的运动效果。

最后一步当然是进行骨骼动画的蒙皮操作了,将蒙皮Mesh设置好与骨骼的绑定以及权值之后,将这个节点添加到Skeleton节点之下就可以了:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. osgAnimation::RigGeometry* geom = createTesselatedBox(4, 4.0f);  
  2. osg::Geode* geode = new osg::Geode;  
  3. geode->addDrawable(geom);  
  4. skelroot->addChild(geode);  
  5. osg::ref_ptr<osg::Vec3Array> src = dynamic_cast<osg::Vec3Array*>(geom->getSourceGeometry()->getVertexArray());  
  6. geom->getOrCreateStateSet()->setMode(GL_LIGHTING, false);  
  7. geom->setDataVariance(osg::Object::DYNAMIC);  
  8.   
  9. initVertexMap(root.get(), right0.get(), right1.get(), geom, src.get());  
最后编译运行程序


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页