fosky 发表于 2010-7-22 09:45:38

OSG动画学习

本帖最后由 fosky 于 2010-7-22 09:52 编辑

学习动画,看了osganimationskinning这个例子,感觉OSG的动画实现的太灵活了.
一个简单的模型节点变换动画过程如下:
1.定义一些变换位置
2.定义动画关键帧,包含了时间,位置,旋转等数据
这里可以设置受变化作用的节点
3.给节点设置一个动画管理器,这个动画管理器是继承自Osg::NodeCallback,所以其实是个Callback类.
4.把定义的关键帧的数据,送给动画管理器
5.创建一个等待变化的节点
6.把变化节点的顶点数据与给出的变换位置进行映射,此时定义的是这些节点中每个顶点的变化方式
7.开始动画

好的东西写不出来,只把这个程序的一些理解记录一下.
这个例子来自OSG的代码中的Example->osganimationskinning

/*-*-c++-*-
*Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version.The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* OpenSceneGraph Public License for more details.
*/
#include <iostream>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgUtil/SmoothingVisitor>
#include <osg/io_utils>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skinning>
#include <osgAnimation/BasicAnimationManager>

// 创建的是些辅助的线条,跟随节点的运动
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);
    geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);   
    geometry->addPrimitiveSet(new osg:rawArrays(osg:rimitiveSet:INES,0,6));
    geode->addDrawable( geometry );
    return geode;
}
// 创建了一个等待变换的BOX
osgAnimation::RigGeometry* createTesselatedBox(int nsplit, float size)
{
    osgAnimation::RigGeometry* geometry = new osgAnimation::RigGeometry;
    osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
    osg::ref_ptr<osg::Vec3Array> colors (new osg::Vec3Array());
    geometry->setVertexArray (vertices.get());
    geometry->setColorArray (colors.get());
    geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);   

    float step = size / nsplit;
    float s = 0.5/4.0;
    for (int i = 0; i < nsplit; i++)
    {
      float x = -1 + 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,0,0);
      c = 1;
      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;
      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);
      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);
      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);
      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);
    }

    geometry->addPrimitiveSet(new osg:rawElementsUInt(osg:rimitiveSet::TRIANGLES, array->size(), &array->front()));
    geometry->setUseDisplayList( false );
    return geometry;
}
// 把变化节点的顶点数据与给出的变换位置进行映射,此时定义的是这些节点中每个顶点的变化方式
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).setName(b0->getName());
    (*vim).setName(b1->getName());
    (*vim).setName(b2->getName());
    for (int i = 0; i < (int)array->size(); i++)
    {
      float val = (*array);
      std::cout << val << std::endl;
      // 把每个顶点的变换分配给变换节点
      if (val >= -1 && val <= 0)
            (*vim).push_back(osgAnimation::VertexIndexWeight(i,1));
      else if ( val > 0 && val <= 1)
            (*vim).push_back(osgAnimation::VertexIndexWeight(i,1));
      else if ( val > 1)
            (*vim).push_back(osgAnimation::VertexIndexWeight(i,1));
    }
    geom->setInfluenceMap(vim);
}

int main (int argc, char* argv[])
{
    osg::ArgumentParser arguments(&argc, argv);
    osgViewer::Viewer viewer(arguments);
    viewer.setCameraManipulator(new osgGA::TrackballManipulator());
    osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;
    skelroot->setDefaultUpdateCallback();
    // 定义一些变换位置,这些位置会在关键帧的设置用到
    osg::ref_ptr<osgAnimation::Bone> root = new osgAnimation::Bone;
    {
      root->setBindMatrixInBoneSpace(osg::Matrix::identity());
      root->setBindMatrixInBoneSpace(osg::Matrix::translate(-1,0,0));
      root->setName("root");
      root->setDefaultUpdateCallback();
    }
    osg::ref_ptr<osgAnimation::Bone> right0 = new osgAnimation::Bone;
    right0->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
    right0->setName("right0");
    right0->setDefaultUpdateCallback("right0");
    osg::ref_ptr<osgAnimation::Bone> right1 = new osgAnimation::Bone;
    right1->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
    right1->setName("right1");
    right1->setDefaultUpdateCallback("right1");
    // 定义变换点之间的父子关系,也就是相对变换的关系
    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中的数据结构定义
    // 定义right0的关键帧,时间和旋转
    osgAnimation::Animation* anim = new osgAnimation::Animation;
    {
      osgAnimation:uatKeyframeContainer* keys0 = new osgAnimation:uatKeyframeContainer;
      osg:uat rotate;
      rotate.makeRotate(osg:I_2, osg::Vec3(0,0,1));
      // osgAnimation:uatKeyframe(0,osg:uat(0,0,0,1))中第一个参数是时间点,单位是秒,第二个参数就是这个时间点,要旋转到的位置,本例中是旋转,也可以换成其它变换方式
      keys0->push_back(osgAnimation:uatKeyframe(0,osg:uat(0,0,0,1)));
      keys0->push_back(osgAnimation:uatKeyframe(3,rotate));
      keys0->push_back(osgAnimation:uatKeyframe(6,rotate));
      osgAnimation:uatSphericalLinearSampler* sampler = new osgAnimation:uatSphericalLinearSampler;
      sampler->setKeyframeContainer(keys0);
      // osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right0->getUpdateCallback());
      osgAnimation:uatSphericalLinearChannel* channel = new osgAnimation:uatSphericalLinearChannel(sampler);
      channel->setName("quaternion");
      channel->setTargetName("right0");
      anim->addChannel(channel);
    }
    // 定义right1的关键帧
    {
      osgAnimation:uatKeyframeContainer* keys1 = new osgAnimation:uatKeyframeContainer;
      osg:uat rotate;
      rotate.makeRotate(osg:I_2, osg::Vec3(0,0,1));
      keys1->push_back(osgAnimation:uatKeyframe(0,osg:uat(0,0,0,1)));
      keys1->push_back(osgAnimation:uatKeyframe(3,osg:uat(0,0,0,1)));
      keys1->push_back(osgAnimation:uatKeyframe(6,rotate));
      osgAnimation:uatSphericalLinearSampler* sampler = new osgAnimation:uatSphericalLinearSampler;
      sampler->setKeyframeContainer(keys1);
      osgAnimation:uatSphericalLinearChannel* channel = new osgAnimation:uatSphericalLinearChannel(sampler);
      //osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right1->getUpdateCallback());
      channel->setName("quaternion");
      channel->setTargetName("right1");
      anim->addChannel(channel);
    }

    // 把时间和位置告诉动画管理器
    manager->registerAnimation(anim);
    manager->buildTargetReference();

    // let's start !   开始动画
    manager->playAnimation(anim);
    // we will use local data from the skeleton
    osg::MatrixTransform* rootTransform = new osg::MatrixTransform;
    rootTransform->setMatrix(osg::Matrix::rotate(osg:I_2,osg::Vec3(1,0,0)));
    // 把创建的线条指示放到变换节点中,主要是一个指示作用
    right0->addChild(createAxis());
    // 使节点数据更新完毕后,再进行渲染动作
    right0->setDataVariance(osg::Object:YNAMIC);
    right1->addChild(createAxis());
    right1->setDataVariance(osg::Object:YNAMIC);
    //
    osg::MatrixTransform* trueroot = new osg::MatrixTransform;
    trueroot->setMatrix(osg::Matrix(root->getMatrixInBoneSpace().ptr()));
    trueroot->addChild(createAxis());
    trueroot->addChild(skelroot.get());
    trueroot->setDataVariance(osg::Object:YNAMIC);
    // trueroot也是节点,需要加到场景中去,现在是把它设置为rootTransform的一个子节点
    rootTransform->addChild(trueroot);
    scene->addChild(rootTransform);

    // 现在创建等待变换的盒子
    osgAnimation::RigGeometry* geom = createTesselatedBox(4, 4.0);
    osg::Geode* geode = new osg::Geode;
    geode->addDrawable(geom);
    skelroot->addChild(geode);
    osg::ref_ptr<osg::Vec3Array> src = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());
    geom->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
    geom->setDataVariance(osg::Object:YNAMIC);
    // 给盒子的每个顶点设置变换方式
    initVertexMap(root.get(), right0.get(), right1.get(), geom, src.get());
    // let's run !
    viewer.setSceneData( scene );
    viewer.realize();
    // 开始运行了
    while (!viewer.done())
    {
      viewer.frame();
    }
    return 0;
}


tianxiao888 发表于 2010-7-22 10:37:15

支持一下

tty1960 发表于 2010-7-22 16:52:03

支持两下

FlySky 发表于 2010-7-22 20:34:08

支持支持:)
页: [1]
查看完整版本: OSG动画学习