转载 原文网址 http://blog.csdn.net/csxiaoshui/article/details/22814373
-
简介
osgAnimationSkinning这个示例主要使用了osgAnimation中的骨骼蒙皮动画,关于骨骼蒙皮动画的介绍可以参考Skinned Mesh原理解析和一个最简单的实现示例这篇CSDN的博客,里面用Glut实现了一个简单的蒙皮动画,整篇文章对骨骼动画和蒙皮进行了详尽的阐述,相信读完之后可以对骨骼动画有更深的理解。
源码中createAxis创建了一个坐标系,代码十分的简单,仅仅是画出三条坐标轴线而已。
- osg::Geode* createAxis()
- {
- osg::Geode* geode (new osg::Geode());
- osg::Geometry* geometry (new osg::Geometry());
- osg::Vec3Array* vertices (new osg::Vec3Array());
- vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
- vertices->push_back (osg::Vec3 ( 1.0, 0.0, 0.0));
- vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
- vertices->push_back (osg::Vec3 ( 0.0, 1.0, 0.0));
- vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
- vertices->push_back (osg::Vec3 ( 0.0, 0.0, 1.0));
- geometry->setVertexArray (vertices);
- osg::Vec4Array* colors (new osg::Vec4Array());
- colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
- colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
- colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
- colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
- colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
- colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
- geometry->setColorArray (colors, osg::Array::BIND_PER_VERTEX);
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
- geode->addDrawable( geometry );
- return geode;
- }
- float step = size / static_cast<float>(nsplit);
- float s = 0.5f/4.0f;
- for (int i = 0; i < nsplit; i++)
- {
- float x = -1.0f + static_cast<float>(i) * step;
- std::cout << x << std::endl;
- vertices->push_back (osg::Vec3 ( x, s, s));
- vertices->push_back (osg::Vec3 ( x, -s, s));
- vertices->push_back (osg::Vec3 ( x, -s, -s));
- vertices->push_back (osg::Vec3 ( x, s, -s));
- osg::Vec3 c (0.0f,0.0f,0.0f);
- c[i%3] = 1.0f;
- colors->push_back (c);
- colors->push_back (c);
- colors->push_back (c);
- colors->push_back (c);
- }
- osg::ref_ptr<osg::UIntArray> array = new osg::UIntArray;
- for (int i = 0; i < nsplit - 1; i++)
- {
- int base = i * 4;
- //Top
- array->push_back(base);
- array->push_back(base+1);
- array->push_back(base+4);
- array->push_back(base+1);
- array->push_back(base+5);
- array->push_back(base+4);
- //Back
- array->push_back(base+3);
- array->push_back(base);
- array->push_back(base+4);
- array->push_back(base+7);
- array->push_back(base+3);
- array->push_back(base+4);
- //Front
- array->push_back(base+5);
- array->push_back(base+1);
- array->push_back(base+2);
- array->push_back(base+2);
- array->push_back(base+6);
- array->push_back(base+5);
- //Bottom
- array->push_back(base+2);
- array->push_back(base+3);
- array->push_back(base+7);
- array->push_back(base+6);
- array->push_back(base+2);
- array->push_back(base+7);
- }
通过上面的注解可以知道,函数createTesselatedBox(int nsplit, float size)的两个参数,其中nsplit是把这个立方体柱分成了nsplit-1段,然后每段一个立方体的4个面,这段代码使用的是DrawElement的方式创建的,因此它传入的是索引值。
接下来就是Skin info的操作,给不同的顶点绑定到骨骼上,并且给这些顶点赋予权值,这个示例中设置权值的方式比较简单,所有X在-1到0之间的顶点只受到骨骼Bon0的影响,所有X在0到1之间的顶点只受Bone1的影响,所有X值大于1的顶点只受到Bone2的影响。
- void initVertexMap(osgAnimation::Bone* b0,
- osgAnimation::Bone* b1,
- osgAnimation::Bone* b2,
- osgAnimation::RigGeometry* geom,
- osg::Vec3Array* array)
- {
- //osgAnimation::VertexInfluenceSet vertexesInfluences;
- osgAnimation::VertexInfluenceMap* vim = new osgAnimation::VertexInfluenceMap;
- (*vim)[b0->getName()].setName(b0->getName());
- (*vim)[b1->getName()].setName(b1->getName());
- (*vim)[b2->getName()].setName(b2->getName());
- for (int i = 0; i < (int)array->size(); i++)
- {
- float val = (*array)[i][0];
- std::cout << val << std::endl;
- if (val >= -1.0f && val <= 0.0f)
- (*vim)[b0->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f));
- else if ( val > 0.0f && val <= 1.0f)
- (*vim)[b1->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f));
- else if ( val > 1.0f)
- (*vim)[b2->getName()].push_back(osgAnimation::VertexIndexWeight(i,1.0f));
- }
- geom->setInfluenceMap(vim);
- }
- osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;
- skelroot->setDefaultUpdateCallback();
- osg::ref_ptr<osgAnimation::Bone> root = new osgAnimation::Bone;
- root->setInvBindMatrixInSkeletonSpace(osg::Matrix::inverse(osg::Matrix::translate(-1.0,0.0,0.0)));
- root->setName("root");
- osgAnimation::UpdateBone* pRootUpdate = new osgAnimation::UpdateBone("root");
- pRootUpdate->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate",osg::Vec3(-1.0f,0.0f,0.0f)));
- root->setUpdateCallback(pRootUpdate);
- osg::ref_ptr<osgAnimation::Bone> right0 = new osgAnimation::Bone;
- right0->setInvBindMatrixInSkeletonSpace(osg::Matrix::inverse(osg::Matrix::translate(0.0,0.0,0.0)));
- right0->setName("right0");
- osgAnimation::UpdateBone* pRight0Update = new osgAnimation::UpdateBone("right0");
- pRight0Update->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate", osg::Vec3(1.0f,0.0f,0.0f)));
- pRight0Update->getStackedTransforms().push_back(new osgAnimation::StackedRotateAxisElement("rotate", osg::Vec3(0.0f,0.0f,1.0f), 0.0));
- right0->setUpdateCallback(pRight0Update);
- osg::ref_ptr<osgAnimation::Bone> right1 = new osgAnimation::Bone;
- right1->setInvBindMatrixInSkeletonSpace(osg::Matrix::inverse(osg::Matrix::translate(1.0,0.0,0.0)));
- right1->setName("right1");
- osgAnimation::UpdateBone* pRight1Update = new osgAnimation::UpdateBone("right1");
- pRight1Update->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate", osg::Vec3(1.0f,0.0f,0.0f)));
- pRight1Update->getStackedTransforms().push_back(new osgAnimation::StackedRotateAxisElement("rotate", osg::Vec3(0.0f,0.0f,1.0f), 0.0));
- right1->setUpdateCallback(pRight1Update);
- root->addChild(right0.get());
- right0->addChild(right1.get());
- skelroot->addChild(root.get());
- osg::Group* scene = new osg::Group;
- osg::ref_ptr<osgAnimation::BasicAnimationManager> manager = new osgAnimation::BasicAnimationManager;
- scene->setUpdateCallback(manager.get());
- osgAnimation::Animation* anim = new osgAnimation::Animation;
- {
- osgAnimation::FloatKeyframeContainer* keys0 = new osgAnimation::FloatKeyframeContainer;
- keys0->push_back(osgAnimation::FloatKeyframe(0.0,0.0f));
- keys0->push_back(osgAnimation::FloatKeyframe(3.0,osg::PI_2));
- keys0->push_back(osgAnimation::FloatKeyframe(6.0,osg::PI_2));
- osgAnimation::FloatLinearSampler* sampler = new osgAnimation::FloatLinearSampler;
- sampler->setKeyframeContainer(keys0);
- osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel(sampler);
- channel->setName("rotate");
- channel->setTargetName("right0");
- anim->addChannel(channel);
- }
- {
- osgAnimation::FloatKeyframeContainer* keys1 = new osgAnimation::FloatKeyframeContainer;
- keys1->push_back(osgAnimation::FloatKeyframe(0.0,0.0f));
- keys1->push_back(osgAnimation::FloatKeyframe(3.0,0.0f));
- keys1->push_back(osgAnimation::FloatKeyframe(6.0,osg::PI_2));
- osgAnimation::FloatLinearSampler* sampler = new osgAnimation::FloatLinearSampler;
- sampler->setKeyframeContainer(keys1);
- osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel(sampler);
- channel->setName("rotate");
- channel->setTargetName("right1");
- anim->addChannel(channel);
- }
- manager->registerAnimation(anim);
- //manager->buildTargetReference();
- // let's start !
- manager->playAnimation(anim);
- osg::MatrixTransform* rootTransform = new osg::MatrixTransform;
- rootTransform->setMatrix(osg::Matrix::rotate(osg::PI_2,osg::Vec3(1.0f,0.0f,0.0f)));
- right0->addChild(createAxis());
- right0->setDataVariance(osg::Object::DYNAMIC);
- right1->addChild(createAxis());
- right1->setDataVariance(osg::Object::DYNAMIC);
- osg::MatrixTransform* trueroot = new osg::MatrixTransform;
- trueroot->setMatrix(osg::Matrix(root->getMatrixInBoneSpace().ptr()));
- trueroot->addChild(createAxis());
- trueroot->addChild(skelroot.get());
- trueroot->setDataVariance(osg::Object::DYNAMIC);
- rootTransform->addChild(trueroot);
- scene->addChild(rootTransform);
最后一步当然是进行骨骼动画的蒙皮操作了,将蒙皮Mesh设置好与骨骼的绑定以及权值之后,将这个节点添加到Skeleton节点之下就可以了:
- osgAnimation::RigGeometry* geom = createTesselatedBox(4, 4.0f);
- osg::Geode* geode = new osg::Geode;
- geode->addDrawable(geom);
- skelroot->addChild(geode);
- osg::ref_ptr<osg::Vec3Array> src = dynamic_cast<osg::Vec3Array*>(geom->getSourceGeometry()->getVertexArray());
- geom->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
- geom->setDataVariance(osg::Object::DYNAMIC);
- initVertexMap(root.get(), right0.get(), right1.get(), geom, src.get());