1. 简介
3D动画效果在一些软件中很常见 , 动画有助于使用者观察模型或视角的变化轨迹,避免画面突变 , 提升交互体验 。
在OCC中3D视图中显示物体位置动画变换和相机视角动画变换是由实现的 。对象变换动画为 、相机变换动画为:
2. 使用方法
由于没有单独的渲染子线程 , 动画时采用阻塞主线程的方式刷新的:
Handle(AIS_Animation) anim = ...;anim_object->SetOwnDuration(obj_duration); // 设置时间ais_animation->StartTimer(0, 1.0, true); // 开始定时器while (!anim->IsStopped()){anim->UpdateTimer();_context->UpdateCurrentViewer();}
一个动画可以理解为一个时间轴 , 在一个时间轴上通过方法Add添加多个动画,实现同时播放多个动画的效果 。因为的继承关系,对象动画和相机动画是可以同时播放的,如2.3节所示 。
//! Add single animation to the timeline.//! @param theAnimation input animationStandard_EXPORT void Add (const Handle(AIS_Animation)& theAnimation);
多个动画时间轴的效果与视频编辑中的时间轴类似 。
2.1. 对象变换动画
初始化接口为:
文章插图
【Open Cascade 7.7.1 动画 AIS_Animation】
//! Constructor with initialization.//! Note that start/end transformations specify exactly local transformation of the object,//! not the transformation to be applied to existing local transformation.//! @param[in] theAnimationName animation identifier//! @param[in] theContextinteractive context where object have been displayed//! @param[in] theObjectobject to apply local transformation//! @param[in] theTrsfStartlocal transformation at the start of animation (e.g. theObject->LocalTransformation())//! @param[in] theTrsfEndlocal transformation at the endof animationStandard_EXPORT AIS_AnimationObject (const TCollection_AsciiString& theAnimationName,const Handle(AIS_InteractiveContext)& theContext,const Handle(AIS_InteractiveObject)&theObject,const gp_Trsf& theTrsfStart,const gp_Trsf& theTrsfEnd);
这里需要注意,输入参数的和是指对象的 “局部变换”——是对象位置的绝对值、而非相对值,例如可以直接取对象当前的位置变换 ->() 。而当起始变换不是对象当前位置的变换 ->() 时,对象会出现跳动的现象,即由指定的起始位置变换到终止位置,而与当前位置无关 。例如,对象起始位置为单位变换 , 终止位置为绕轴ax1旋转90°,实现代码:
gp_Trsf start_trsf, end_trsf;gp_Ax1 ax1(gp_Pnt(10, 0, 0), gp_Vec(0, 1, 0));end_trsf.SetRotation(ax1, M_PI_2);Handle(AIS_AnimationObject) ani_object = new AIS_AnimationObject("Object", _context, first_obj, start_pnt, end_pnt);
重复执行上一段代码 , 会出现跳动的现象:
这里引入了一个概念:对象位置 。可以简单理解为物体在渲染时,对物体本身的三角形数据施加一个变换,从而将物体显示在所需的位置 。例如,希望将一个球心在原点的单位球,渲染显示在(10, 10, 10)这个位置 , 只需设置物体显示对象的位置变换即可:
Handle(AIS_InteractiveObject) ais_ball;gp_Trsf ball_trsf;ball_trsf.SetTranslation(gp_Vec(10, 10, 10));ais_ball->SetLocalTransformation(ball_trsf);
详细可参考OCC官方文档:t
2.2. 相机变换动画
//! Define camera start position.void SetCameraStart (const Handle(Graphic3d_Camera)& theCameraStart) { myCamStart = theCameraStart; }//! Define camera end position.void SetCameraEnd (const Handle(Graphic3d_Camera)& theCameraEnd) { myCamEnd = theCameraEnd; }
视角切换动画是在两个相机视角之间完成的,分别设置起始相机位置、终止相机位置 。实现代码:
gp_Trsf end_trsf;gp_Ax1 ax1(gp_Pnt(10, 0, 0), gp_Vec(0, 1, 0));end_trsf.SetRotation(ax1, M_PI_2);Handle(Graphic3d_Camera) camera_start = _view->GetView()->Camera();Handle(Graphic3d_Camera) camera_end = new Graphic3d_Camera();camera_end->Copy(camera_start);camera_end->Transform(end_trsf);Handle(AIS_AnimationCamera) ani_camera = new AIS_AnimationCamera("Camera", _view->GetView());ani_camera->SetCameraStart(camera_start);ani_camera->SetCameraEnd(camera_end);
文章插图
将相机绕轴ax1正向旋转90° 。注意:在同一个3D视图中相机变换和模型变换在视觉上是相反的 。
2.3. 多对象+相机同时变换动画
3. OCC 7.7.1 升级说明
在 OCC 7.7.1 版本中优化了对旋转变换的支持,新增专门针对旋转变换的对象动画ation,以解决此前版本中对象旋转动画中间过程不正确的问题( 绕轴旋转动画中间过程不正确),参考 OCC 开发者对该问题的回复 。
以对象变换动画为例,更新动画帧时以变换插值的方式获取中间变换 , 即分别对平移、旋转、缩放进行插值,并组合成新的变换 , 无法得到正确的变换路径 。
void NCollection_Lerp::Interpolate (double theT, gp_Trsf& theResult) const{...gp_XYZ aLoc;gp_Quaternion aRot;Standard_Real aScale = 1.0;myLocLerp.Interpolate (theT, aLoc);myRotLerp.Interpolate (theT, aRot);myScaleLerp.Interpolate (theT, aScale);theResult = gp_Trsf();theResult.SetRotation (aRot);theResult.SetTranslationPart (aLoc);theResult.SetScaleFactor (aScale);}
因此在之前版本或新版本使用 , 对象变换动画的效果为:
但是,对于绕轴旋转的相机动画 , 在最新版 OCC 7.7.1 中仍无法得到正确的中间过程 。显然,这同样是因为动画中对的平移分量、旋转分量分别采用线性插值引起的 。
4. 疑问如何才能使动画对任意变换均沿着正确的变换路径播放呢?动画实际播放时间小于主线程阻塞时间?动画快速播放完成后 , 仍阻塞至设定时间结束 。
?
本文源码
- 咖说 | Hashmasks赝品大量现身OpenSea,如何辨别NFT正品?
- 在openSUSE上安装搜狗输入法2.3.1.0112
- 解决ArchLinux下OpenCV-Python和PyQt无法配合使用的问题
- 使用OPENCV3图像对齐
- 转 一 OpenCV iOS开发——安装
- 喷血记录 Pycharm导入 Opencv的CV2 包过程
- 北京航空航天大学开通CnOpenData试用
- OpenGL.Shader:11-阴影实现 - 定向光阴影
- openpnp - 设备矫正的零碎记录
- [Linux+OpenCV]创建自己的第一个文件