OSG 路径动画学习

9 篇文章 2 订阅

1、动画的实现方法:

要点1)、通过设置回调函数使得节点按路径移动。这个路径回调只能是添加到osg::PositionAttitudeTransform(位置变换节点)或者osg::MatrixTransform(矩阵变换节点)等节点上面才会有效,因为路径动画的实现原理就是改变节点的位置和旋转角度。

要点2)、动画的实体节点作为子节点添加到添加了路径动画回调的那个节点上面。

给节点添加回调函数

// 位置节点,用来添加动画路径(用一个旋转节点也行)
		osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
		//创建路径
		osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
		animationPath = createAnimationPath(ptStart, ptEnd, timeRange.GetStartTime(), timeRange.GetEndTime()) ;// 创建一个路径

		//设置更新回调
		pat->setUpdateCallback(new osg::AnimationPathCallback(animationPath.get(),0.0f,1.0f));
我们在来看看AnimationPathCallback::update函数里面做了些什么

bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const// 根据时间计算出该时间对应的位置和旋转量
{
    if (_timeControlPointMap.empty()) return false;

    switch(_loopMode)
    {
        case(SWING):
        {
            double modulated_time = (time - getFirstTime())/(getPeriod()*2.0);
            double fraction_part = modulated_time - floor(modulated_time);
            if (fraction_part>0.5) fraction_part = 1.0-fraction_part;

            time = getFirstTime()+(fraction_part*2.0) * getPeriod();
            break;
        }
        case(LOOP):
        {
            double modulated_time = (time - getFirstTime())/getPeriod();
            double fraction_part = modulated_time - floor(modulated_time);
            time = getFirstTime()+fraction_part * getPeriod();
            break;
        }
        case(NO_LOOPING):
            // no need to modulate the time.
            break;
    }



    TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time);
    if (second==_timeControlPointMap.begin())
    {
        controlPoint = second->second;
    }
    else if (second!=_timeControlPointMap.end())
    {
        TimeControlPointMap::const_iterator first = second;
        --first;

        // we have both a lower bound and the next item.

        // delta_time = second.time - first.time
        double delta_time = second->first - first->first;

        if (delta_time==0.0)
            controlPoint = first->second;
        else
        {
            controlPoint.interpolate((time - first->first)/delta_time,
                            first->second,
                            second->second);
        }
    }
    else // (second==_timeControlPointMap.end())
    {
        controlPoint = _timeControlPointMap.rbegin()->second;
    }
    return true;
}
double AnimationPathCallback::getAnimationTime() const
{
    return ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier;// 获得对应时间
}
void AnimationPathCallback::update(osg::Node& node)
{
    AnimationPath::ControlPoint cp;
    if (_animationPath->getInterpolatedControlPoint(getAnimationTime(),cp))
    {
        AnimationPathCallbackVisitor apcv(cp,_pivotPoint,_useInverseMatrix);
        node.accept(apcv);
    }
}
其它AnimationPathCallback相关具体代码参考osg源代码文件

反正就是在某个时间会更新它的_latestTime,然后调用update这个就获得这个时间的位置和旋转量,然后将其设置到对应节点上。

下面给出我写的直线路径的计算函数(起始时间在起点,到终止时间移动到终点)

//创建路径
osg::ref_ptr<osg::AnimationPath> createAnimationPath(osg::Vec3& ptStart,osg::Vec3 &ptEnd,float timeBegin, float timeEnd)
{
	//创建一个Path对象
	osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath() ;
	//设置动画模式为循环(LOOP)(LOOP:循环,SWING:单摆,NO_LOOPING:不循环)
	animationPath->setLoopMode(osg::AnimationPath::NO_LOOPING) ;

	
	//插入Path,把关键点与时间压入形成Path
	animationPath->insert(timeBegin,osg::AnimationPath::ControlPoint(ptStart));
	animationPath->insert(timeEnd,osg::AnimationPath::ControlPoint(ptEnd));

	//返回Path
	return animationPath.get() ;
}
这个是最简单的路径,没有旋转,而且只有两个路径数据值。




  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值