第36.1节 动画-刚体动画控制

2023-11-12

本节功能

本节后几个章节会介绍和动画有关的课程。

本节实现一个从3DMAX导出的地板破碎的动画的控制,这类动画叫做刚体动画。所谓刚体动画我理解就是仅物体的位置、方向、缩放这三者发生变化。

当我们点击P时,动画会暂停,当我们点击S时,动画会播放,点击R时动画会复位。点击+时,动画会快速播放2倍,点击 - 时,动画会慢速播放2倍。

在这里插入图片描述
本节的内容在网盘中,目录为/osgChina站长文集/文件中的附件/, 有附件的会根据节的编号存放在该目录:

请使用浏览器打开,平时遇到问题或加群也可以加我微信:13324598743:
【击此打开网盘资源链接】

具体实现

很容易,我们联想到,刚体动画涉及到的变量都是矩阵的变化,它的位置、朝向、缩放发生变化,其实大多数情况下是位置、朝向。而osg中控制矩阵的结点是osg::MatrixTransform,对其设置动画使用的是setUpdateCallback,而刚体动画是osg::AnimationPathCallback,因此我们只需要找到模型中所有结点里的UpdateCallback,判断其是否为AnimationPathCallback就可以了。

存放动画

为此我们申请了一个全局变量:

std::vector<osg::AnimationPathCallback*> g_animateCallback;

这个全局变量是一个向量,里面存放AnimationPathCallback,然后我们使用一个NodeVisitor,来对每一个osg::Transform(因为osg::MatrixTransform继承自osg::Transform,用基类更保险一点),来看它是否有UpdateCallback,如果有的话,是否是AnimationPathCallback,是的话就压入到全局变量中进行控制。现实如下

寻找动画

我们写的NodeVistor类叫做FindAnimate,实现如下:在这里要特别注意的是,在构造函数中我们调用了TRAVERSE_ALL_CHILDREN,代表我们要遍历结点的所有的孩子在apply中,我们调用了traverse(node)代表我们还要向下遍历。

class FindAnimate : public osg::NodeVisitor
{
public:
    FindAnimate():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN){}
    void apply(osg::Transform& node)
    {
        if (node.getUpdateCallback())
        {
            osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(node.getUpdateCallback());
            if (NULL != apc)
            {
                g_animateCallback.push_back(apc);
            }
        }
        traverse(node);
    }
};

它的调用是这样的:

    FindAnimate fa;
    //diban是读取的ive
    diban->accept(fa);

自此动画都压入到了g_animateCallback中。然后我们再写几个简单的函数即可实现控制:

播放/暂停

AnimationPathCallback中有个setPause函数,直接就可以实现这个功能:

//true是播放动画,false是暂停动画
void play(bool isPlay)
{
    for (int i = 0; i < g_animateCallback.size(); i++)
    {
        g_animateCallback.at(i)->setPause(!isPlay);
    }
}

复位

AnimationPathCallback里有个reset可以实现这个功能:

void reset()
{
    for (int i = 0; i < g_animateCallback.size(); i++)
    {
        g_animateCallback.at(i)->reset();
        g_animateCallback.at(i)->setPause(false);
    }
}

加速/减速

AnimationPathCallback里有个setTimeMultiplier函数,下面是按+号加速2倍:

if (ea.getKey() == '+')
{
	for (int i = 0; i < g_animateCallback.size(); i++)
	{
		g_animateCallback.at(i)->setTimeMultiplier(g_animateCallback.at(i)->getTimeMultiplier()*2.0);
	}
}

最后用一个事件响应来联接这一切


class MyEvent : public osgGA::GUIEventHandler
{
public:
    MyEvent(){}
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        if (ea.getEventType() == ea.KEYDOWN)
        {
            if ((ea.getKey() == 'r') || (ea.getKey() == 'R'))
            {
                reset();
            }

            if ((ea.getKey() == 'p') || (ea.getKey() == 'P'))
            {
                play(false);
            }

            if ((ea.getKey() == 's') || (ea.getKey() == 'S'))
            {
                play(true);
            }

            if (ea.getKey() == '+')
            {
                for (int i = 0; i < g_animateCallback.size(); i++)
                {
                    g_animateCallback.at(i)->setTimeMultiplier(g_animateCallback.at(i)->getTimeMultiplier()*2.0);
                }
            }

            if (ea.getKey() == '-')
            {
                for (int i = 0; i < g_animateCallback.size(); i++)
                {
                    g_animateCallback.at(i)->setTimeMultiplier(g_animateCallback.at(i)->getTimeMultiplier() * 0.5);
                }
            }
        }

        return false;
    }
};

所有代码

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/NodeVisitor>
#include <osg/Transform>
#include <osg/AnimationPath>
#include <osgGA/GUIEventHandler>

std::vector<osg::AnimationPathCallback*> g_animateCallback;

class FindAnimate : public osg::NodeVisitor
{
public:
    FindAnimate():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN){}
    void apply(osg::Transform& node)
    {
        if (node.getUpdateCallback())
        {
            osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(node.getUpdateCallback());
            if (NULL != apc)
            {
                g_animateCallback.push_back(apc);
            }
        }
        
        traverse(node);
    }
};

//true是播放动画,false是暂停动画
void play(bool isPlay)
{
    for (int i = 0; i < g_animateCallback.size(); i++)
    {
        g_animateCallback.at(i)->setPause(!isPlay);
    }
}

void reset()
{
    for (int i = 0; i < g_animateCallback.size(); i++)
    {
        g_animateCallback.at(i)->reset();
        g_animateCallback.at(i)->setPause(false);
    }
}

class MyEvent : public osgGA::GUIEventHandler
{
public:
    MyEvent(){}
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        if (ea.getEventType() == ea.KEYDOWN)
        {
            if ((ea.getKey() == 'r') || (ea.getKey() == 'R'))
            {
                reset();
            }

            if ((ea.getKey() == 'p') || (ea.getKey() == 'P'))
            {
                play(false);
            }

            if ((ea.getKey() == 's') || (ea.getKey() == 'S'))
            {
                play(true);
            }

            if (ea.getKey() == '+')
            {
                for (int i = 0; i < g_animateCallback.size(); i++)
                {
                    g_animateCallback.at(i)->setTimeMultiplier(g_animateCallback.at(i)->getTimeMultiplier()*2.0);
                }
            }

            if (ea.getKey() == '-')
            {
                for (int i = 0; i < g_animateCallback.size(); i++)
                {
                    g_animateCallback.at(i)->setTimeMultiplier(g_animateCallback.at(i)->getTimeMultiplier() * 0.5);
                }
            }
        }

        return false;
    }
};


int main()
{
    osgViewer::Viewer viewer;

    osg::Node* diban = osgDB::readNodeFile("diban.ive");

    FindAnimate fa;
    diban->accept(fa);

    viewer.setSceneData(diban);
    viewer.addEventHandler(new MyEvent);
    return viewer.run();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第36.1节 动画-刚体动画控制 的相关文章

  • 第36.1节 动画-刚体动画控制

    目录 本节功能 具体实现 存放动画 寻找动画 播放 暂停 复位 加速 减速 最后用一个事件响应来联接这一切 所有代码 本节功能 本节后几个章节会介绍和动画有关的课程 本节实现一个从3DMAX导出的地板破碎的动画的控制 这类动画叫做刚体动画
  • 纯css实现webpack的logo转动

    原效果 实现效果 源码
  • osgEarth的Rex引擎原理分析(一二七)rex影像层属性及其设置

    目标 一二六 中问题213
  • osg+shader光照半透明

    先记录下 免得时间久了忘了 对于光照 光源有点光源 聚光灯 方向光 每种光源又有ambient diffuse specular emission几个属性 这里用点光源 不考虑衰减 1 diffuse是入射光与物体法线之间的余弦起作用 2
  • osgEarth的Rex引擎原理分析(三十一)osgEarth::TerrainLayer中的_memCache(osgEarth::MemCache)详解

    目标 二十一 中的问题66 继承关系 osgEarth Cache osgEarth MemCache cache中的数据是通过cachebin来实现存放的 cachebin有两种 继承关系为 osgEarth CacheBin MemCa
  • animation 动画的定义和使用

    keyframes 定义动画 keyframes myname 0 50 100 调用动画 div animation name myfirst animation duration 5s animation timing function
  • UE5 Rokoko Studio Live(动捕实时链接)

    UE5 Rokoko动作捕捉实时 一 新建初始化项目 添加插件 打开UE5 1 1 新建 第三人称游戏 文件夹筛选找到模板自带的关卡 新建动画蓝图 gt 然后选择到UE的小白人骨骼 因为我们需要Rokoko的实时动捕 需要在项目里添加Rok
  • CSS鼠标滑过翻转动画图标

    html css鼠标放上去变大效果 效果如下动态图 目录层级 代码如下 html文件 index html li li
  • Unity—反向动力学IK

    每日一句 人生最精彩的不是实现梦想的瞬间 而是坚持梦想的过程 目录 定义 准备 API 设置IK 头部IK 设置人物的头部根据视角旋转 手脚IK 案例 脚步IK 定义 一般来说 骨骼动画都是传统的从父节点到子节点的带动方式 即正向动力学 I
  • OSG学习:纹理映射(四)——三维纹理映射

    以下内容来自 1 OpenSceneGraph三维渲染引擎编程指南 肖鹏 刘更代 徐明亮 清华大学出版社 2 OpenSceneGraph三维渲染引擎设计与实践 王锐 钱学雷 清华大学出版社 3 自己的总结 下载完整工程OSG 12 Tex
  • 【LVGL 学习】样式(style)过渡动画学习

    transition 过渡动画 当一个控件的状态发生改变时 可以让样式也发生变化以提醒用户 通过过渡动画 transition 可以让样式的改变更自然 例如 按钮在点击时 以及开关在切换时 都具有一小段的过渡动画 过渡动画使用 lv sty
  • CSS特效(二):利用html和css制作毛玻璃特效和按钮动画效果

    最终的效果图片 毛玻璃效果 在style标签中 在form表单的before中利用filter的blur属性以及box shadow的值设置 就可以做出form表单后面的毛玻璃效果背景 还要记得设置form表单的display为flex布局
  • 功能实现:Unity中一个动画,只播放中间指定的一截,而且循环播放

    一 要播放的动画 直播中间一截 如图 总的动画为长度为2分钟零8秒 二 Button和对应事件 三 事件的代码 在Start 里面绑定 private void Awake myAnim animGo GetComponent
  • Qt 自定义提示框 类似QMessageBox

    前言 为什么需要设计自定义提示框呢 1 Qt自带的提示框样式单一 2 提示框的太小 3 界面风格跟项目的不搭配 程序执行效果 源码下载地址 https gitee com jiang bin yu qt custom prompt box
  • osg漫游器

    在三维中常见的就是漫游整个场景 所谓漫游就是 观察者的视线从一个位置移动到另外一个位置或者在希望的方向上移动 在OSG中漫游可以通过改变观察者 相机 的位置和姿态来实现 三维世界中的模型的相对位置和形态不会发生变化 只是观察者的角度和位置发
  • Unity动画系统详解5:BlendTree混合树是什么?

    摘要 Animator中有一个功能 用来解决多个动画之间的混合 经常用于移动动画之间的混合 这个功能叫做BlendTree 混合树 洪流学堂 让你快人几步 你好 我是跟着大智学Unity的萌新 我叫小新 这几周一起来复 yu 习 xi 动画
  • 如何在 Openscenegraph 中从 2D 鼠标单击屏幕坐标点计算 3D 点(世界坐标)?

    我试图在 2D 屏幕空间上用户选择的点的 3D 空间上放置一个球体 为此 我尝试使用以下技术从 2d 点计算 3d 点 但该技术没有给出正确的解决方案 mousePosition x clickPos clientX window left
  • 解决错误 MSB8011:无法注册输出

    一个奇怪的错误 错误 MSB8011 无法注册输出 请尝试启用每用户 从命令提示符重定向或注册组件 提升的权限 C 程序 文件 MSBuild Microsoft Cpp v4 0 Microsoft CppCommon targets 7
  • 在 OpenSceneGraph 中创建球体(使用 osg::Geometry)

    我花了相当长的时间才使其正常工作 但我的球体无法显示 使用以下代码来实现我的功能 使用 Visual C 在 Opengl 中创建 3D 球体 https stackoverflow com questions 5988686 creati
  • OpenSceneGraph 将相机设置在初始位置

    我是第一次使用 OpenSceneGraph 我有点迷失 因为文档确实不太清楚 所以 我有这段代码加载一个带有房子的 obj 文件 并且我在我想要的 人 所在的地方淹没了一个小盒子 所以现在 我不想把那个盒子放在那里 而是想把相机放在那里

随机推荐

  • [深入研究4G/5G/6G专题-34]: URLLC-5-《中国联通5G URLLC技术白皮书3.0版本》解读-1-业务场景

    目录 第1章 背景与URLLC的发展历程 1 1 URLLC的应用场景 1 2 URLLC的业务特点 第2章 URLLC的业务需求
  • 南京邮电大学操作系统复试

    目录 第 1 章 计算机系统概述 多道运行的特征 第 2 章 进程与线程 2 1 进程与线程 1 进程与程序 2 PID Process ID 进程ID 3 PCB Process Control Block 进程控制快 4 进程的特征 5
  • 【NAS工具箱】Pytorch中的Buffer

    Parameter 模型中的一种可以被反向传播更新的参数 第一种 直接通过成员变量nn Parameter 进行创建 会自动注册到parameter中 def init self super MyModel self init self p
  • 垃圾收集器知识点4:Java中垃圾收集器的实现

    目录 java8垃圾收集器组合一览 serial GC 串行GC 的实现 串行gc日志分析 Minor GC 小型GC Full GC 完全GC Parallel GC 并行GC 的实现 并行GC日志分析 Minor GC 小型GC Ful
  • 第二十九章、containers容器类部件QFrame框架部件详解

    一 概述 容器部件就是可以在部件内放置其他部件的部件 在Qt Designer中可以使用的容器部件有如下 容器中的Frame为一个矩形的框架对象 对应类QFrame QFrame类是PyQt中带框架部件的所有类的基类 如菜单 进度条 Lab
  • SQLServer 数据加密解密:常用的加密解密(一)

    都是基本示例 更多参考官方文档 1 Transact SQL 函数 2 数据库密钥 3 证书 4 非对称密钥 5 对称密钥 sql view plain copy drop table EnryptTest create table Enr
  • Win10 WSL运行docker报错:Cannot connect to the Docker daemon at unix:///var/run/docker.sock.

    我安装的子系统是Ubuntu 1804 安装docker步骤如下 sudo apt update 更新软件源 sudo apt install y docker io 安装docker sudo usermod aG docker leo
  • 3个技术男搞恋爱版ChatGPT,估值10亿美元

    过去几个月 我们见证了GPT从3 5到4 0 从只能做结构化搜索整合到接近人类思维的对话 我们还看到了 GPT逐步掌握画画 写作 剪辑 制表 做 PPT 等技能 最可怕的是AI的迭代速度 简直是一天一个样 这股这股前所未有的技术浪潮 一时间
  • sklearn中的LogisticRegression

    sklearn中的逻辑回归接口如下 sklearn linear model LogisticRegression penalty l2 dual False tol 0 0001 C 1 0 fit intercept True inte
  • [专利与论文-14]:研究员级(正高)高级工程师评审不通过的常见原因(实际案例)

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 专利与论文 14 研究员级 正高 高级工程师评审不通过的常见原因 实际案例 文火冰糖 王文兵 的博客 CSDN博客 作者主页 文火冰糖的硅基
  • 策略模式+工厂模式的使用

    在项目开发过程中 经常会遇到项目代码中充斥着大量的if else 每次增加类型都要整体代码逻辑看一遍才可以修改 如下代码 if wx equals type do else if zfb equals type do else if ban
  • JSONObject 与 JSON 互转

    使用目的 目前数据交互大多以 JSON 字符串为信息传输 主要格式有 age 22 name 李四 age 21 name 张三 最常见的应用场景是前后端对接 第三方平台文档对接 下面展示转换使用 一 引入 jar 此处引入 com ali
  • IMAU鸿蒙北向开发-2023年9月5日学习日志

    1 5种调试方式 1 1 Previewer 在侧边 Previewer 选项卡内可以预览Entry 如果要单独预览组件 可以在给组件加 Preview 装饰器 1 2 Local Emulator 本地模拟 1 3 Remote Emul
  • 测试框架pytest教程(6)钩子函数hook开发pytest插件

    pytest hook 函数也叫钩子函数 pytest 提供了大量的钩子函数 可以在用例的不同生命周期自动调用 比如 在测试用例收集阶段 可利用 hook 函数修改测试用例名称的编码 pytest的hook是基于Python的插件系统实现的
  • mac mini u盘安装系统_2020年mac系统下制作win10引导安装盘,亲测可用

    一 背景 最近组装了一台电脑 需要安装系统 由于家里只有一台Macbook pro 在网上找了很多关于mac环境下制作支持win10启动盘教程 尝试过下面几种方式都失败 即u盘插入后主板不会识别 无法自动安装 1 利用终端指令拷贝iso镜像
  • Linux提权之内核漏洞提权篇

    前言 在渗透过程中 有时利用某些漏洞可以获取一个低权限的用户 然后想办法提权 提升到root用户权限 从而控制整个系统 在获取到低权限shell后 通常会检查操作系统的发行版本 内核版本 老版本的系统可能会存在一些漏洞 于是我们可以利用这些
  • 点云处理,点云处理算法程序

    点云处理 算法程序代编 top5硕博团队 高质量的服务 基于pcl cgal程序代编 联系方式 q 958417691 或闲鱼id专业点云处理 1 点云分割 单木分割 林下地形提取 DEM制作 等高线制作 地形补洞 2 点云重建 多种方法点
  • H5页面调用扫一扫功能

    想要实现H5页面调用微信扫一扫功能 必须先了解微信JS SDK接口 企业号开发接口文档地址 https qydev weixin qq com wiki index php title E9 A6 96 E9 A1 B5 我们来看下使用的大
  • 将任意一个数解析为2的幂的和的方法

    将任意一个数解析为2的幂的和的方法 递归 规律 如给定 14 2 3 lt 14 lt 2 4 14中必有8 2 3 14 8 6 2 2 lt 6 lt 2 3 6中必有4 2 2 6 4 2 2 2 14 2 3 2 2 2 1 Par
  • 第36.1节 动画-刚体动画控制

    目录 本节功能 具体实现 存放动画 寻找动画 播放 暂停 复位 加速 减速 最后用一个事件响应来联接这一切 所有代码 本节功能 本节后几个章节会介绍和动画有关的课程 本节实现一个从3DMAX导出的地板破碎的动画的控制 这类动画叫做刚体动画