渲染器中的场景节点运动
2013-01-31 18:03
127 查看
一般渲染器都有场景节点的概念,用于挂载可渲染可运动的实体。
运动是相对的,这里主要写3种运动空间:
TS_LOCAL:本地空间
TS_PARENT:相对空间
TS_WORLD:世界空间,所有变换的起始空间,这不同于物理任何运动都是相对的
以下是场景节点的头文件:
为节省内存,和运动相关的信息只存了相对的位置mRelPosition和朝向mRelOrientation,朝向用四元数表示。
为提高效率,需要存一下绝对变换mAbsTransform,因为这货每一帧都要提交到gpu,不能渲染前重复去计算。
这里没有写缩放变换,因为类似且比较简单。
复习一下矩阵变换的意义,先声明,这是非官方非严谨且是个人理解的M*P=Q
最简单的构造变换矩阵的方法是确定新的坐标系的xyz,也就是基,将它们逐列排成一个矩阵(这里用的是列优先矩阵,与glsl一致)
M就是把新坐标系中的P变换为父坐标系的Q
以下是SceneNode的实现:
可见都是以父节点作为基准,因为SceneNode存的是相对位置与相对朝向,运动时需要改变这两个属性。
当value是本地坐标时需要把local位置转变为相对位置 mRelOrientation*value
当value是世界坐标时需要把世界坐标转化为本地坐标再转化为相对坐标 mRelOrientation*(inverse(mat3(mAbsTransform))*value)
这里只是演示一个可以正确运行的代码,实际代码并不会这么写,因为效率低,优化的可以参考ogre的Node和SceneNode
运动是相对的,这里主要写3种运动空间:
TS_LOCAL:本地空间
TS_PARENT:相对空间
TS_WORLD:世界空间,所有变换的起始空间,这不同于物理任何运动都是相对的
以下是场景节点的头文件:
#ifndef EGG_SCENENODE_H #define EGG_SCENENODE_H #include <vector> #include <glm/glm.hpp> #include <glm/ext.hpp> using namespace std; using namespace glm; enum TransformSpace{ TS_LOCAL,TS_PARENT,TS_WORLD }; class SceneNode{ public: void translate(const vec3& value,TransformSpace ts); void setPosition(const vec3& value,TransformSpace ts); void rotate(float degree,const vec3& axis,TransformSpace ts); inline mat4 getRelTransform(){ mat4 ret=toMat4(mRelOrientation); ret[3]=vec4(mRelPosition,1.0); return ret; } protected: void updateTransform(); protected: SceneNode* mParent; vector<SceneNode*> mChildren; vec3 mRelPosition; quat mRelOrientation; mat4 mAbsTransform; }; #endif
为节省内存,和运动相关的信息只存了相对的位置mRelPosition和朝向mRelOrientation,朝向用四元数表示。
为提高效率,需要存一下绝对变换mAbsTransform,因为这货每一帧都要提交到gpu,不能渲染前重复去计算。
这里没有写缩放变换,因为类似且比较简单。
复习一下矩阵变换的意义,先声明,这是非官方非严谨且是个人理解的M*P=Q
最简单的构造变换矩阵的方法是确定新的坐标系的xyz,也就是基,将它们逐列排成一个矩阵(这里用的是列优先矩阵,与glsl一致)
M就是把新坐标系中的P变换为父坐标系的Q
以下是SceneNode的实现:
#include "SceneNode.h" void SceneNode::translate(const vec3& value,TransformSpace ts){ vec3 relDist; if(ts==TS_LOCAL){ relDist=mRelOrientation*value; }else if(ts==TS_PARENT){ relDist=value; }else if(ts==TS_WORLD){ relDist=mRelOrientation*(inverse(mat3(mAbsTransform))*value); } setPosition(relDist,TS_PARENT); } void SceneNode::setPosition(const vec3& value,TransformSpace ts){ if(ts==TS_LOCAL){ mRelPosition=vec3(getRelTransform()*vec4(value,1.0)); }else if(ts==TS_PARENT){ mRelPosition=value; }else if(ts==TS_WORLD){ vec4 localPos=inverse(mAbsTransform)*vec4(value,1.0); mRelPosition=vec3(getRelTransform()*localPos); } updateTransform(); } void SceneNode::rotate(float degree,const vec3& axis,TransformSpace ts){ vec3 rotAxis; if(ts==TS_LOCAL){ rotAxis=mRelOrientation*axis; }else if(ts==TS_PARENT){ rotAxis=axis; }else if(ts==TS_WORLD){ rotAxis=mat3(inverse(mAbsTransform))*axis; rotAxis=mRelOrientation*axis; } rotAxis=normalize(rotAxis); mRelOrientation=angleAxis(degree,rotAxis)*mRelOrientation; mRelOrientation=normalize(mRelOrientation); updateTransform(); } void SceneNode::updateTransform(){ mAbsTransform=mParent->mAbsTransform*getRelTransform(); for(int i=0;i<mChildren.size();i++){ mChildren[i]->updateTransform(); } }
可见都是以父节点作为基准,因为SceneNode存的是相对位置与相对朝向,运动时需要改变这两个属性。
当value是本地坐标时需要把local位置转变为相对位置 mRelOrientation*value
当value是世界坐标时需要把世界坐标转化为本地坐标再转化为相对坐标 mRelOrientation*(inverse(mat3(mAbsTransform))*value)
这里只是演示一个可以正确运行的代码,实际代码并不会这么写,因为效率低,优化的可以参考ogre的Node和SceneNode
相关文章推荐
- 创建基于实体节点的BSP编译器和渲染器 (第一节 概要和第一棵BSPTree)
- ns2 运动场景及传输负载(TCP、CBR)生成
- 微信小程序节点查询方法:wx.createSelectorQuery()的使用场景与注意事项
- cocos2d中场景、导演、层、精灵、菜单、节点等概念理解
- 复变函数自身运动的三个节点
- ogre代码实例-场景、摄像机的创建,节点的平移旋转缩放
- ns2 运动场景及传输负载(TCP、CBR)生成
- 2 weekend110的zookeeper的原理、特性、数据模型、节点、角色、顺序号、读写机制、保证、API接口、ACL、选举、 + 应用场景:统一命名服务、配置管理、集群管理、共享锁、队列管理
- Unity微端场景加载(一)资源打包和记录位置节点信息
- 使用第三方插件Curvy为unity场景快速生成运动轨迹与赛道
- Ogre场景节点SceneNode类(不定时更新)
- (3) OGRE的基石:场景管理器、场景节点、实体
- X3D场景效果节点--Background立体空间背景节点
- 用Shell脚本在推出的RAC节点上批量部署32个Oracle11gR2 RAC备份恢复案例场景的方法PART1 推荐
- 生成节点场景的方法
- 流程节点多场景多表单
- 流程节点多场景多表单
- 用Shell脚本在推出的RAC节点上批量部署32个Oracle11gR2 RAC备份恢复案例场景的方法PART2
- Ogre笔记二:基础教程一—场景管理器、场景节点和实体
- Mongodb集群节点故障恢复场景分析