回调
- osg::Node
- setUpdateCallback()
- 参数为osg::NodeCallback
- operator()重载
- 参数为osg::NodeCallback
- addUpdateCallback()
- setEventCallback()
- 参数为osg::NodeCallback
- operator()重载
- 参数为osg::NodeCallback
- setCullCallback()
- 参数为osg::NodeCallback
- operator()重载
- 参数为osg::NodeCallback
- setUpdateCallback()
- osg::Drawable
- setUpdateCallback()
- osg::Drawable::UpdateCallback
- update()重载
- osg::Drawable::UpdateCallback
- setEventCallback()
- osg::Drawable::EventCallback
- event()重载
- osg::Drawable::EventCallback
- setCullCallback()
- osg::Drawable::CullCallback
- cull()重载
- osg::Drawable::CullCallback
- setUpdateCallback()
- osg::StateAttribute
- setUpdateCallback()
- osg:: StateAttributeCallback
- operator()重载
- osg:: StateAttributeCallback
- setEventCallback()
- osg:: StateAttributeCallback
- operator()重载
- osg:: StateAttributeCallback
- setUpdateCallback()
- osg::Uniform
- setUpdateCallback()
- osg::Uniform:: Callback
- operator()重载
- osg::Uniform:: Callback
- setEventCallback()
- osg::Uniform:: Callback
- operator()重载
- osg::Uniform:: Callback
- setUpdateCallback()
- osg::Camera
- setPreDrawCallback()
- osg::Camera:: DrawCallback
- operator()重载
- osg::Camera:: DrawCallback
- setPostDrawCallback()
- osg::Camera:: DrawCallback
- operator()重载
- osg::Camera:: DrawCallback
- setPreDrawCallback()
traverse用法
- node和Nodevisitor中traverse用法

- callback中traverse用法:
- 调用Nodevisitor的traverse方法,如果忘记了,traversal会停止
示例
#include <osg/Switch>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
class SwitchingCallback : public osg::NodeCallback
{
public:
SwitchingCallback() : _count(0) {}
virtual void operator()(osg::Node* node,
osg::NodeVisitor* nv);
protected:
unsigned int _count;
};
void SwitchingCallback::operator()(osg::Node* node,
osg::NodeVisitor* nv)
{
osg::Switch* switchNode = static_cast<osg::Switch*>(node);
if (!((++_count) % 60) && switchNode)
{
switchNode->setValue(0, !switchNode->getValue(0));
switchNode->setValue(1, !switchNode->getValue(1));
}
traverse(node, nv);
}
int main(int argc, char** argv)
{
osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile(
"cessna.osg");
osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile("cessnafire.osg");
osg::ref_ptr<osg::Switch> root = new osg::Switch;
root->addChild(model1.get(), false);
root->addChild(model2.get(), true);
root->setUpdateCallback(new SwitchingCallback);
osgViewer::Viewer viewer;
viewer.setSceneData(root.get());
return viewer.run();
}
避免冲突
osg::Object变量枚举值
-
UNSPECIFIED(default)
-
STATIC update和draw过程中不变
-
DYNAMIC update和cull完成后才能draw
node->setDataVariance( osg::Object::DYNAMIC );
drawable回调中如果顶点和组元改变需调用
- 更新显示列表中顶点和组元
- setUseDisplayList(true)情况下
- drawable->dirtyDisplayList()
- setUseVertexBufferObjects(true)且setUseDisplayList(false)情况下
- vertices->dirty();
- setUseDisplayList(true)情况下
- 更新边界使cull正确
- drawable->dirtyBound()
示例
#include <osg/Geometry>
#include <osg/Geode>
#include <osgViewer/Viewer>
osg::Geometry* createQuad()
{
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
vertices->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));
vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
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, 0.0f, 1.0f, 1.0f));
colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
osg::ref_ptr<osg::Geometry> quad = new osg::Geometry;
quad->setVertexArray(vertices.get());
quad->setNormalArray(normals.get());
quad->setNormalBinding(osg::Geometry::BIND_OVERALL);
quad->setColorArray(colors.get());
quad->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
return quad.release();
}
class DynamicQuadCallback : public osg::Drawable::UpdateCallback
{
public:
virtual void update(osg::NodeVisitor*, osg::Drawable*
drawable);
};
void DynamicQuadCallback::update(osg::NodeVisitor*,
osg::Drawable* drawable)
{
osg::Geometry* quad = static_cast<osg::Geometry*>(drawable);
if (!quad) return;
osg::Vec3Array* vertices = static_cast<osg::Vec3Array*>(
quad->getVertexArray());
if (!vertices) return;
osg::Quat quat(osg::PI*0.01, osg::X_AXIS);
vertices->back() = quat * vertices->back();
quad->dirtyDisplayList();
quad->dirtyBound();
}
int main(int argc, char** argv)
{
osg::Geometry* quad = createQuad();
quad->setDataVariance(osg::Object::DYNAMIC);
quad->setUpdateCallback(new DynamicQuadCallback);
osg::ref_ptr<osg::Geode> root = new osg::Geode;
root->addDrawable(quad);
osgViewer::Viewer viewer;
viewer.setSceneData(root.get());
return viewer.run();
}
运动方程
指定起点值和终点值,不同曲线方式下取值

- update(dt)
- getValue()
路径动画
- osg::AnimationPath
- insert(time in seconds,ControlPoint)
- osg::AnimationPath::ControlPoint
- setLoopMode()
- LOOP
- NO_LOOPING
- SWING
- insert(time in seconds,ControlPoint)
- osg::AnimationPathCallback
- 只影响osg::MatrixTransform and osg::PositionAttitudeTransform
- 继承osg::NodeCallback
- 加入node的updatecallback
- node->setUpdateCallback( animationPathCallback.get() );
- 方法
- setPause
- reset
- setTimeMultiplier
- setTimeOffset
示例
#include <osg/AnimationPath>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
osg::AnimationPath* createAnimationPath(float radius, float time)
{
osg::ref_ptr<osg::AnimationPath> path = new osg::AnimationPath;
path->setLoopMode(osg::AnimationPath::LOOP);
unsigned int numSamples = 32;
float delta_yaw = 2.0f * osg::PI / ((float)numSamples - 1.0f);
float delta_time = time / (float)numSamples;
for (unsigned int i = 0; i<numSamples; ++i)
{
float yaw = delta_yaw * (float)i;
osg::Vec3 pos(sinf(yaw)*radius, cosf(yaw)*radius, 0.0f);
osg::Quat rot(-yaw, osg::Z_AXIS);
path->insert(delta_time * (float)i,osg::AnimationPath::ControlPoint(pos, rot));
}
return path.release();
}
int main(int argc, char** argv)
{
osg::ref_ptr<osg::Node> model =
osgDB::readNodeFile("cessna.osg.0,0,90.rot");
osg::ref_ptr<osg::MatrixTransform> root = new
osg::MatrixTransform;
root->addChild(model.get());
osg::ref_ptr<osg::AnimationPathCallback> apcb = new
osg::AnimationPathCallback;
apcb->setAnimationPath(createAnimationPath(50.0f, 6.0f));
root->setUpdateCallback(apcb.get());
osgViewer::Viewer viewer;
viewer.setSceneData(root.get());
return viewer.run();
}
渲染状态动画
- osg::StateAttributeCallback
- 自定义osg::StateAttributeCallback并重载operator()
- 加入属性的updatecallback
- attribute->setUpdateCallback(attributeCallback);
示例
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/BlendFunc>
#include <osg/Material>
#include <osgAnimation/EaseMotion>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
class AlphaFadingCallback : public osg::StateAttributeCallback
{
public:
AlphaFadingCallback()
{
_motion = new osgAnimation::InOutCubicMotion(0.0f, 1.0f);
}
virtual void operator()(osg::StateAttribute*, osg::NodeVisitor*);
protected:
osg::ref_ptr<osgAnimation::InOutCubicMotion> _motion;
};
void AlphaFadingCallback::operator()(osg::StateAttribute* sa,osg::NodeVisitor* nv)
{
osg::Material* material = static_cast<osg::Material*>(sa);
if (material)
{
_motion->update(0.005);
float alpha = _motion->getValue();
material->setDiffuse(osg::Material::FRONT_AND_BACK,
osg::Vec4(0.0f, 1.0f, 1.0f, alpha)
);
}
}
int main(int argc, char** argv)
{
osg::ref_ptr<osg::Drawable> quad = osg::createTexturedQuadGeometry(
osg::Vec3(-0.5f, 0.0f, -0.5f),
osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 1.0f)
);
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(quad.get());
osg::ref_ptr<osg::Material> material = new osg::Material;
material->setAmbient(osg::Material::FRONT_AND_BACK,
osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
material->setDiffuse(osg::Material::FRONT_AND_BACK,
osg::Vec4(0.0f, 1.0f, 1.0f, 0.5f));
material->setUpdateCallback(new AlphaFadingCallback);
geode->getOrCreateStateSet()->setAttributeAndModes(
material.get());
geode->getOrCreateStateSet()->setAttributeAndModes(
new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
geode->getOrCreateStateSet()->setRenderingHint(
osg::StateSet::TRANSPARENT_BIN);
osg::ref_ptr<osg::Group> root = new osg::Group;
root->addChild(geode.get());
root->addChild(osgDB::readNodeFile("glider.osg"));
osgViewer::Viewer viewer;
viewer.setSceneData(root.get());
return viewer.run();
}
图片动画
- osg::ImageSequence 继承osg::Image
- addImage()
- setImage()
- getImage()
- getNumImages()
- addImageFile()
- setImageFile()
- setLength()
- setTimeMultiplier()
- play()
- pause()
- rewind()
- seek()
- setMode
- PRE_LOAD_ALL_IMAGES
- PAGE_AND_RETAIN_IMAGES
- PAGE_AND_DISCARD_USED_IMAGES
示例
#include <osg/ImageSequence>
#include <osg/Texture2D>
#include <osg/Geometry>
#include <osg/Geode>
#include <osgViewer/Viewer>
osg::Image* createSpotLight(const osg::Vec4& centerColor,
const osg::Vec4& bgColor,
unsigned int size, float power)
{
osg::ref_ptr<osg::Image> image = new osg::Image;
image->allocateImage(size, size, 1, GL_RGBA,
GL_UNSIGNED_BYTE);
float mid = (float(size) - 1) * 0.5f;
float div = 2.0f / float(size);
for (unsigned int r = 0; r<size; ++r)
{
unsigned char* ptr = image->data(0, r);
for (unsigned int c = 0; c<size; ++c)
{
float dx = (float(c) - mid)*div;
float dy = (float(r) - mid)*div;
float r = powf(1.0f - sqrtf(dx*dx + dy*dy), power);
if (r<0.0f) r = 0.0f;
osg::Vec4 color = centerColor*r + bgColor*(1.0f - r);
*ptr++ = (unsigned char)((color[0]) * 255.0f);
*ptr++ = (unsigned char)((color[1]) * 255.0f);
*ptr++ = (unsigned char)((color[2]) * 255.0f);
*ptr++ = (unsigned char)((color[3]) * 255.0f);
}
}
return image.release();
}
int main(int argc, char** argv)
{
osg::Vec4 centerColor(1.0f, 1.0f, 0.0f, 1.0f);
osg::Vec4 bgColor(0.0f, 0.0f, 0.0f, 1.0f);
osg::ref_ptr<osg::ImageSequence> sequence = new
osg::ImageSequence;
sequence->addImage(createSpotLight(centerColor, bgColor, 64,
3.0f));
sequence->addImage(createSpotLight(centerColor, bgColor, 64,
3.5f));
sequence->addImage(createSpotLight(centerColor, bgColor, 64,
4.0f));
sequence->addImage(createSpotLight(centerColor, bgColor, 64,
3.5f));
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
texture->setImage(sequence.get());
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(osg::createTexturedQuadGeometry(
osg::Vec3(), osg::Vec3(1.0, 0.0, 0.0), osg::Vec3(0.0, 0.0, 1.0))
);
geode->getOrCreateStateSet()->setTextureAttributeAndModes(
0, texture.get(), osg::StateAttribute::ON);
sequence->setLength(0.5);
sequence->play();
osgViewer::Viewer viewer;
viewer.setSceneData(geode.get());
return viewer.run();
}
- osg::ImageStream
关键帧动画

- osgAnimation::TemplateKeyframe<>
- osgAnimation::TemplateKeyframeContainer<>
- osgAnimation::TemplateSampler<> 值求解器
- getOrCreateKeyframeContainer
- osgAnimation::TemplateChannel<>
- getOrCreateSampler
- setName
- setTargetName通常为内建的更新回调
- 比如osgAnimation::UpdateMatrixTransform,用channel的值每一帧更新osg::MatrixTransform节点的变换矩阵
- getStackedTransforms
- StackedTranslateElement
- StackedScaleElement
- StackedRotateAxisElement
- StackedQuaternionElement
- StackedMatrixElement
- 加入osg::MatrixTransform节点的更新回调
- transformnode->setDataVariance(osg::Object::DYNAMIC);
- transformnode->setUpdateCallback(updater.get());
- getStackedTransforms
- 比如osgAnimation::UpdateMatrixTransform,用channel的值每一帧更新osg::MatrixTransform节点的变换矩阵
- osg::Animation
- setPlayMode
- addChannel
- getName
- osgAnimation::BasicAnimationManager (root节点的更新回调)
- registerAnimation
- unregisterAnimation
- getAnimationList
- playAnimation
- stopAnimation
- isPlaying
- 加入root节点的回调
- root->setUpdateCallback(manager.get());

示例
#include <osg/MatrixTransform>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/StackedTranslateElement>
#include <osgAnimation/StackedQuaternionElement>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
void createAnimationPath(float radius, float time,
osgAnimation::Vec3KeyframeContainer* container1,
osgAnimation::QuatKeyframeContainer* container2)
{
unsigned int numSamples = 32;
float delta_yaw = 2.0f * osg::PI / ((float)numSamples - 1.0f);
float delta_time = time / (float)numSamples;
for (unsigned int i = 0; i<numSamples; ++i)
{
float yaw = delta_yaw * (float)i;
osg::Vec3 pos(sinf(yaw)*radius, cosf(yaw)*radius, 0.0f);
osg::Quat rot(-yaw, osg::Z_AXIS);
container1->push_back(
osgAnimation::Vec3Keyframe(delta_time * (float)i, pos)
);
container2->push_back(
osgAnimation::QuatKeyframe(delta_time * (float)i, rot)
);
}
}
int main(int argc, char** argv)
{
osg::ref_ptr<osgAnimation::Vec3LinearChannel> ch1 =
new osgAnimation::Vec3LinearChannel;
ch1->setName("position");
ch1->setTargetName("PathCallback");
osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> ch2 =
new osgAnimation::QuatSphericalLinearChannel;
ch2->setName("quat");
ch2->setTargetName("PathCallback");
createAnimationPath(50.0f, 6.0f,
ch1->getOrCreateSampler()->getOrCreateKeyframeContainer(),
ch2->getOrCreateSampler()->getOrCreateKeyframeContainer());
osg::ref_ptr<osgAnimation::Animation> animation = new
osgAnimation::Animation;
animation->setPlayMode(osgAnimation::Animation::LOOP);
animation->addChannel(ch1.get());
animation->addChannel(ch2.get());
osg::ref_ptr<osgAnimation::UpdateMatrixTransform> updater =
new osgAnimation::UpdateMatrixTransform("PathCallback");
updater->getStackedTransforms().push_back(
new osgAnimation::StackedTranslateElement("position"));
updater->getStackedTransforms().push_back(
new osgAnimation::StackedQuaternionElement("quat"));
osg::ref_ptr<osg::MatrixTransform> animRoot = new
osg::MatrixTransform;
animRoot->addChild(osgDB::readNodeFile("cessna.osg.0,0,90.rot"));
animRoot->setDataVariance(osg::Object::DYNAMIC);
animRoot->setUpdateCallback(updater.get());
osg::ref_ptr<osgAnimation::BasicAnimationManager> manager =
new osgAnimation::BasicAnimationManager;
manager->registerAnimation(animation.get());
osg::ref_ptr<osg::Group> root = new osg::Group;
root->addChild(animRoot.get());
root->setUpdateCallback(manager.get());
manager->playAnimation(animation.get());
osgViewer::Viewer viewer;
viewer.setSceneData(root.get());
return viewer.run();
}
人物动画
注意
节点必须为osgAnimation::Bone或者osgAnimation::Skeleton
制作
- 工具
- Autodesk 3dsmax
- Autodesk Maya
- Blender
- 三方库
- osgCal2
- http://cal3d.sourceforge.net/
- http://osgcal.sourceforge.net/
- osgCal2
- 格式
- 输出FBX格式
- 工具输出为OSG格式
- http://hg.plopbyte.net/osgexport/
示例
#include <osgAnimation/BasicAnimationManager>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <iostream>
int main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc, argv);
bool listAll = false;
std::string animationName;
arguments.read("--animation", animationName);
if (arguments.read("--listall")) listAll = true;
osg::ref_ptr<osg::Node> model =
osgDB::readNodeFile("bignathan.osg");
if (!model) return 1;
osgAnimation::BasicAnimationManager* manager =
dynamic_cast<osgAnimation::BasicAnimationManager*>
(model->getUpdateCallback());
if (!manager) return 1;
const osgAnimation::AnimationList& animations =
manager->getAnimationList();
if (listAll) std::cout << "**** Animations ****" << std::endl;
for (unsigned int i = 0; i<animations.size(); ++i)
{
const std::string& name = animations[i]->getName();
if (name == animationName)
manager->playAnimation(animations[i].get());
if (listAll) std::cout << name << std::endl;
}
if (listAll)
{
std::cout << "********************" << std::endl;
return 0;
}
osgViewer::Viewer viewer;
viewer.setSceneData(model.get());
return viewer.run();
}
本文详细介绍了osg中的动画实现,包括回调机制、traverse用法、避免更新冲突的方法,以及路径动画、渲染状态动画、图片动画、关键帧动画和人物动画的创建与示例。内容涵盖osg::Node、osg::Drawable、osg::StateAttribute等的更新回调,以及osg::AnimationPath、osgAnimation等关键组件的使用。
540

被折叠的 条评论
为什么被折叠?



