【OSG学习笔记】Day 12: 回调机制——动态更新场景

在这里插入图片描述

UpdateCallback

在OpenSceneGraph(OSG)里,UpdateCallback是用来动态更新场景的关键机制。

借助UpdateCallback,你能够实现节点的动画效果,像旋转、位移等。

NodeCallback

osg::NodeCallback 是一个更通用的回调类,它能在节点遍历的任何阶段被调用。

osg::UpdateCallback 实际上是 osg::NodeCallback 的一个子类,专门用于更新遍历。

NodeCallback 可用于在不同的遍历阶段执行自定义操作,例如在裁剪遍历、绘制遍历等阶段。。

实现旋转动画的RotateCallback

我们借用上一届可得钢铁侠模型来实现效果。

直接上代码,代码里注释很明白:

#include <osg/NodeCallback>
#include <osg/MatrixTransform>
#include <osgViewer/Viewer>// 自定义旋转更新回调类
class RotateCallback : public osg::NodeCallback
{
public:RotateCallback(float speed) : _speed(speed), _angle(0.0f) {}virtual void operator()(osg::Node* node, osg::NodeVisitor* nv){// 转换为MatrixTransform节点osg::MatrixTransform* transform = dynamic_cast<osg::MatrixTransform*>(node);if (transform){// 计算时间间隔double deltaTime = nv->getFrameStamp()->getSimulationTime() - _lastTime;_lastTime = nv->getFrameStamp()->getSimulationTime();// 更新旋转角度_angle += _speed * deltaTime;// 设置旋转矩阵osg::Matrix matrix;matrix.makeRotate(_angle, osg::Vec3(0.0f, 0.0f, 1.0f));transform->setMatrix(matrix);}// 继续遍历子节点traverse(node, nv);}private:float _speed;  // 旋转速度float _angle;  // 旋转角度double _lastTime = 0.0;  // 上一帧的时间
};int main()
{// 创建Viewer对象osgViewer::Viewer viewer;// 创建一个MatrixTransform节点osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;// 创建一个简单的几何体,例如一个立方体osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f));osg::ref_ptr<osg::Geode> geode = new osg::Geode;geode->addDrawable(shape);// 将几何体添加到MatrixTransform节点transform->addChild(geode);// 创建旋转回调并添加到节点transform->setUpdateCallback(new RotateCallback(0.5f));// 创建场景图的根节点osg::ref_ptr<osg::Group> root = new osg::Group;root->addChild(transform);// 设置场景数据viewer.setSceneData(root);// 运行Viewerreturn viewer.run();
}

运行效果

在这里插入图片描述

实现位移动画的TranslateCallback

嗯,继续上代码,一切都在代码里。

#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/MatrixTransform>
#include <osg/NodeCallback>
#include <osgViewer/Viewer>
#include <osg/FrameStamp>
#include <osg/ShapeDrawable>
#include <osgDB/ReadFile>
#include <iostream>
#include <cstdlib>class TranslateCallback : public osg::NodeCallback
{
public:TranslateCallback(const osg::Vec3& direction, float speed, float boundary) : _direction(direction), _speed(speed), _boundary(boundary), _reverse(false) {}virtual void operator()(osg::Node* node, osg::NodeVisitor* nv){// 转换为MatrixTransform节点osg::MatrixTransform* transform = dynamic_cast<osg::MatrixTransform*>(node);if (transform){// 计算时间间隔// double deltaTime = nv->getFrameStamp()->getSimulationTime() - _lastTime;// _lastTime = nv->getFrameStamp()->getSimulationTime();// 根据是否反转来确定方向osg::Vec3 currentDirection = _reverse ? -_direction : _direction;// osg::Vec3 currentDirection = _direction;// 计算位移量osg::Vec3 translation = currentDirection * _speed;// 获取当前矩阵osg::Matrix matrix = transform->getMatrix();// 更新矩阵的位移部分matrix.postMultTranslate(translation);transform->setMatrix(matrix);// 获取当前位置osg::Vec3 currentPosition = matrix.getTrans();float dotProduct  = std::abs(currentPosition * currentDirection);std::cout<< "  dotProduct=" << dotProduct<<std::endl;// 判断是否到达边界if (dotProduct >= _boundary || dotProduct <= 0){_reverse = !_reverse;}}// 继续遍历子节点traverse(node, nv);}private:osg::Vec3 _direction;  // 位移方向float _speed;          // 位移速度float _boundary;       // 边界距离bool _reverse;         // 是否反转方向double _lastTime = 0.0;  // 上一帧的时间};int main(int argc, char** argv)
{// 初始化 OpenSceneGraph 的默认设置osg::ArgumentParser arguments(&argc, argv);// 禁用着色器管道osg::DisplaySettings::instance().get()->setShaderPipeline(false);// 创建三个 MatrixTransform 节点,分别代表三个模型osg::ref_ptr<osg::MatrixTransform> transform1 = new osg::MatrixTransform;osg::ref_ptr<osg::MatrixTransform> transform2 = new osg::MatrixTransform;osg::ref_ptr<osg::MatrixTransform> transform3 = new osg::MatrixTransform;// 设置初始变换矩阵(可选)transform1->setMatrix(osg::Matrix::translate(osg::Vec3(-200.0f, 100.0f, 0.0f)));transform2->setMatrix(osg::Matrix::translate(osg::Vec3(0.0f, 100.0f, 0.0f)));  // 调整Y轴位置transform3->setMatrix(osg::Matrix::translate(osg::Vec3(200.0f, 100.0f, 0.0f)));// 创建几何体(例如立方体、球体、圆柱体)osg::ref_ptr<osg::Geode> geode1 = new osg::Geode;geode1->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, 0.0f), 100.0f)));  // 左边的立方体osg::ref_ptr<osg::Geode> geode2 = new osg::Geode;geode2->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), 50.0f)));  // 中间的球体// 加载模型(支持.osg/.obj格式)osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../IronMan.osg");  // 替换为你的模型路径// 检查模型是否加载成功if (!model) {std::cerr << "模型加载失败!请检查路径和格式。" << std::endl;return 1;}// 将几何体添加到对应的变换节点transform1->addChild(geode1);transform2->addChild(geode2);transform3->addChild(model);// 为每个变换节点设置不同的 UpdateCallbacktransform1->setUpdateCallback(new TranslateCallback(osg::Vec3(0.0f, 0.0f, 1.0f), 1.0f, 200));  // 绕 Z 轴旋转,速度较慢transform2->setUpdateCallback(new TranslateCallback(osg::Vec3(0.0f, -1.0f, 0.0f), 1.0f, 100));  // 绕 X 轴旋转,速度中等transform3->setUpdateCallback(new TranslateCallback(osg::Vec3(1.0f, 0.0f, 0.0f), 1.0f, 400));  // 绕 Y 轴旋转,速度较快// 创建一个组节点,将三个变换节点添加到场景中osg::ref_ptr<osg::Group> root = new osg::Group;root->addChild(transform1);root->addChild(transform2);root->addChild(transform3);// 创建 Viewer 并设置场景数据osgViewer::Viewer viewer(arguments);viewer.setSceneData(root);// 运行 Viewerreturn viewer.run();
}

运行效果

在这里插入图片描述
钢铁侠今天也累了,下课。_

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/78792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全新升级:BRAV-7601-T003高性能无风扇AI边缘计算系统,助力智能未来!

在数字化与智能化飞速发展的今天&#xff0c;AI边缘计算正成为各行各业的核心驱动力。BRAV-7601作为一款高性能无风扇AI边缘计算系统&#xff0c;凭借其强大的硬件配置与丰富的扩展能力&#xff0c;为车路协同、特种车辆车载、机器视觉、医疗影像等领域提供了卓越的解决方案。最…

删除 Git 远程记录并重新设置

删除 Git 远程记录并重新设置 以下是在 Windows 平台上删除当前项目的 Git 远程记录并重新设置远程存储库的步骤&#xff1a; 步骤一&#xff1a;查看当前远程仓库 首先&#xff0c;检查当前设置的远程仓库&#xff1a; git remote -v这会显示所有已配置的远程仓库及其 URL…

有哪些和PPT自动生成有关的MCP项目?

随着AI技术的快速发展, Model Context Protocol(MCP) 作为一种连接大型语言模型(LLMs)与外部工具的开放协议,正在重塑自动化办公领域。在PPT自动生成场景中,MCP通过标准化接口实现了AI模型与设计工具、数据源的无缝整合。以下从技术框架、项目案例、应用场景三个维度展开…

PostgreSQL psql 命令和常用的 SQL 语句整理

PostgreSQL psql 命令和常用的 SQL 语句整理 1、登录PostgreSQL数据库2、psql 命令3、数据库操作4、模式操作5、表操作6、数据操作7、索引操作8、视图操作9、权限操作 1、登录PostgreSQL数据库 在系统的命令行界面&#xff08;如 Windows 的 cmd 或者 PowerShell、Linux 的终端…

【unity游戏开发入门到精通——UGUI】文本输入控件 —— InputField旧控件

注意&#xff1a;考虑到UGUI的内容比较多&#xff0c;我将UGUI的内容分开&#xff0c;并全部整合放在【unity游戏开发——UGUI】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言1、文本输入控件2、InputField旧文本输入控件组成 一、InputField文本输入…

获得ecovadis徽章资格标准是什么?ecovadis评估失败的风险

EcoVadis徽章资格标准 EcoVadis徽章是对企业在可持续发展&#xff08;环境、劳工与人权、商业道德、可持续采购&#xff09;方面表现的认可。获得徽章需满足以下条件&#xff1a; 完成评估&#xff1a; 企业必须完成EcoVadis的问卷评估&#xff0c;并提交所有必要文件。 评分…

Python初学 有差异的知识点总结(一)

目录 一、基础语法规则 1.注释 2.代码编写 二、基础语法 1.变量 2.数据类型 3.数据类型的转换 &#xff08;1&#xff09;隐式转换 &#xff08;2&#xff09;显示转换 4.标识符 5.运算符 6.字符串 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;拼接 …

Java面试场景深度解析

Java面试场景深度解析 在互联网大厂Java求职者的面试中&#xff0c;经常会被问到关于Java项目中的各种技术场景题。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我们公司的面试现场。请问您对Java内存模型…

【数据可视化艺术·应用篇】三维管线分析如何重构城市“生命线“管理?

在智慧城市、能源管理、工业4.0等领域的快速发展中&#xff0c;地下管线、工业管道、电力通信网络等“城市血管”的复杂性呈指数级增长。传统二维管理模式已难以应对跨层级、多维度、动态变化的管线管理需求。三维管线分析技术应运而生&#xff0c;成为破解这一难题的核心工具。…

Spring-全面详解(学习总结)

一&#xff1a;概述 1.1 为什么学 解决了两个主要问题 1. 2 学什么 1.3 怎么学 二&#xff1a;系统架构 作用&#xff1a;web开发、微服务开发、分布式系统开发 容器&#xff1a;用于管理对象 AOP:面向切面编程&#xff08;不惊动原始程序下对其进行加强&#xff09; 事…

企业架构之旅(2):解锁TOGAF ADM

文章目录 一、什么是 TOGAF ADM二、TOGAF ADM 的关键阶段架构愿景&#xff08;Phase A&#xff09;业务架构&#xff08;Phase B&#xff09;信息系统架构&#xff08;Phase C&#xff09;技术架构&#xff08;Phase D&#xff09;机会与解决方案&#xff08;Phase E&#xff0…

MySQL 中 SQL 语句的详细执行过程

MySQL 中 SQL 语句的详细执行过程 当一条 SQL 语句在 MySQL 中执行时&#xff0c;它会经历多个阶段的处理。下面我将详细描述整个执行流程&#xff1a; 1. 连接阶段 (Connection) 客户端与 MySQL 服务器建立连接服务器验证用户名、密码和权限连接器负责管理连接状态和权限验…

ETL架构、数据建模及性能优化实践

ETL&#xff08;Extract, Transform, Load&#xff09;和数据建模是构建高性能数据仓库的核心环节。下面从架构设计、详细设计、数据建模方法和最佳实践等方面系统阐述如何优化性能。 一、ETL架构设计优化 1. 分层架构设计 核心分层&#xff1a; 数据源层&#xff1a;对接O…

快速上手Prism WPF 工程

1、Prism 介绍 ​定位​&#xff1a; Prism 是 ​微软推出的框架&#xff0c;专为构建 ​模块化、可维护的复合式应用程序​ 设计&#xff0c;主要支持 WPF、Xamarin.Forms、UWP 等平台。​核心功能​&#xff1a; ​模块化开发​&#xff1a;将应用拆分为独立模块&#xff0c…

React 单一职责原则:优化组件设计与提高可维护性

单一职责原则&#xff08;SRP&#xff09; 在 React 中&#xff0c;组件是构建 UI 的核心单位&#xff0c;而良好的组件设计是保证应用质量和可维护性的关键。单一职责原则是一种设计原则&#xff0c;也适用于 React 组件的开发。它强调每个组件应该只关注一个职责&#xff0c…

css网格布局Grid

一、网格布局适应场景 当涉及到的布局是二维布局&#xff08;元素不止一行或者一列&#xff09;且比较复杂的时候&#xff0c;可以用网格布局&#xff0c;看下面的一个例子&#xff1a; 上图上一个四行三列的网格&#xff0c;布局相对比较复杂。如果你用别的布局方案&#xff…

利用Python生成Xilinx FPGA ROM IP核 .coe初始化文件

以下是一个 Python 脚本&#xff0c;用于生成 Xilinx IP ROM 的.coe 格式初始化文件&#xff0c;假设ROM 深度为 1024&#xff0c;数据位宽为 32bit&#xff0c;使用随机的 32 位无符号数进行初始化&#xff1a; import random# 定义ROM的深度和数据位宽 rom_depth 1024 data…

8.2 段落格式

在word里&#xff0c;段落格式包括首行缩进、行间距、段前、段后等。LaTex同样支持这些功能。 段落间距 全局设置 段落间距用setlength命令来指定。如以下代码 \documentclass{article} \usepackage{ctex} \begin{document}\setlength{\parskip}{11em plus 1em minus 1em}\p…

OpenVLA-OFT

TL;DR 2025 年斯坦福提出的 OpenVLA 工作的续作 OpenVLA-OFT&#xff0c;优化 VLA 能够有效适应新的机器人平台和任务&#xff0c;优化的技术主要有并行解码、动作块处理、连续动作、L1 回归和&#xff08;可选的&#xff09;FiLM 语言调节 Paper name Fine-Tuning Vision-La…

SpringBoot 接口国际化i18n 多语言返回 中英文切换 全球化 语言切换

介绍 Spring Boot通过MessageSource接口来实现国际化&#xff0c;它可以加载不同的消息资源文件&#xff0c;通常是.properties格式。通过定义不同的语言文件&#xff08;例如&#xff1a;messages_en.properties、messages_zh.properties等&#xff09;&#xff0c;可以根据用…