三维中旋转矩阵可以用mat3或quat表示。 两者可以转换。在数学上,旋转和反射对应线代中的正交变换。每行(或每列)相互正交的矩阵且每行(或每列)模长为1,叫正交矩阵

unigine中是右手坐标系。顺时针方向的角度为正,逆时针方向角度为负
知道y,z 求x:cross(y,z);(trick:将所求的轴朝向自己的反方向,顺时针代入已知的轴,只是在求轴的时候从这个视角,理解旋转的时候需要让轴朝向自己)
知道x,z 求y:cross(z,x);
知道x,y 求z:cross(x,y);
求两向量夹角:getAngle(Vec3 startvector,Vec3 endvector,vec3 up);

quat q = m_node->getWorldRotation();
mat3 m3 = q.getMat3();

//mat3 和quat之间的转换
quat q;
q.getMat3();
mat3 mat;
mat.getQuat();
quat(mat);
mat3(q);

mat4 表示旋转(rotate)和位移(translate)和缩放(scale)  
mat4 乘法表示变换的结合。

单位旋转矩阵刚好是单位的  -right -forward up 的组合,(也相当于x,y,z 的组合)。unigine中一般right 为-x,forward为-y, up为z,这个可能只是与导入的习惯有关系。

Log::message("%s\n",Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m3.getColumn(0))).getString());
Log::message("%s\n", Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m3.getColumn(1))).getString());
Log::message("%s\n", Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m3.getColumn(2))).getString());
Log::message("%s\n", Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m_node->getWorldTransform())).getString());
Log::message("%s\n", Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m_node->getWorldForward())).getString());
Log::message("%s\n", Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m_node->getWorldRight())).getString());
Log::message("%s\n", Engine::get()->runWorldFunction(Variable("typeinfo"), Variable(m_node->getWorldUp())).getString());

结果:

在2.7之后无forward left right之类的了,不过可以通过tanget normal binormal来获取前方。(还有一种更粗暴的方式是直接从矩阵中获取mat.getColumn3(0),mat.getColumn3(1),mat.getColumn3(2),分别对应tangent,binormal,normal)
对于单位矩阵 三者的值分别为tangent:(1,0,0)(红色,朝外为正),binormal(0,1,0)(绿色,朝外为正),normal(0,0,1)(蓝色,朝外为正)。(tangent,binormal,normal分别与 x,y,z对应)

近期发现通过binormal的方式获取的轴向有问题,binormal偶尔会有突变,这个突变在获取角度时产生很严重的问题,而通过getColumn要稳定很多。原因暂时不明。(cudir为-m_node->getWorldRotation().getBinormal() 。)

        float ifps = Game::get()->getIFps();Vec3 forward = -Vec3(m_node->getWorldRotation().getBinormal());// -m_node->getWorldTransform().getColumn3(1); //current forward in world coordinate  //problem codeVec3 up = -m_node->getWorldTransform().getColumn3(2); //current rotate axis in world coordinateMat4 mat = m_node->getWorldTransform();Vec3 pos = mat.getTranslate();Visualizer::get()->renderLine3D(pos, pos + mat.getColumn3(0) * 1000, vec4(1, 0, 0, 1));Visualizer::get()->renderLine3D(pos, pos + Vec3(m_node->getWorldRotation().getBinormal()) * 1000, vec4(0, 1, 0, 1));Visualizer::get()->renderLine3D(pos, pos + mat.getColumn3(2) * 1000, vec4(0, 0, 1, 1));angleCu = getAngle(vec3(forward), vec3(1, 0, 0), vec3(0, 0, 1));if (fabs(angleCu - anglePre) > 100){Log::message("aaaaaaaaaaaa");int tt = 0;}Log::message("angle:pre %f,cu %f  cudir(%f,%f,%f)\n", anglePre, angleCu, forward.x, forward.y, forward.z);anglePre = angleCu;Mat4 newTrans;// = translate(forward*ifps);Mat4 rot = Mat4(rotate(up, ifps * 30));Mat4 roto = Mat4(rotate(mat.getRotate()));Mat4 transo = translate(mat.getTranslate());mat = transo*newTrans*roto*rot;m_node->setWorldTransform(mat);

变换矩阵描述:

缩放是存放在旋转的部分的,直接将缩放乘到旋转矩阵部分,这个乘法不是矩阵乘向量,而是将元素直接按某种方式乘进去  
将scale设置为(10,10,10)

将scale设置为(10,100,1000);

关于矩阵相乘的顺序及组装。看如下案例
Mat4 mat = translate(pos)*Mat4(rotate(rot))*Mat4(scale(s));
Vec3 p = mat.getTranslate();
quat r = mat.getRotate();
vec3 sc = mat.getScale();
//pos = {x=4.6566128730540935e-10 y=0.032559752464131522 z=10.953591346685917 ...}
//p   = {x=4.6566128730540935e-10 y=0.032559752464131522 z=10.953591346685917 ...}
//s = {x=0.00999999978 y=0.00999999512 z=0.00999999698 ...}
//sc = {x=0.00999999978 y=0.00999999512 z=0.00999999698 ...}
//rot = {x=-0.00148625416 y=-2.32830893e-10 z=0.000000000 ...}
//r = {x=-0.00148625416 y=-2.32830893e-10 z=5.42101732e-20 ...}
c++和C语言一样,表达式都是从左往右计算的。矩阵的组装应该按照translate->rotate->scale 的顺序来进行。否则会导致不一样的结果。
同理矩阵相乘其顺序也是很重要的,矩阵相乘描述的是变换的叠加。上面的组装其实也是矩阵相乘的结果。
类似于这两种变换: “绕x转90度再绕y转90度” 与 “先绕y转90度再绕x转90度”,这两种转换得到的是不一样的结果。矩阵相乘,顺序也是极为重要的!!!矩阵乘法不满足交换律

我平时使用的一种理解方式是:矩阵描述的是一个变换的动作(变换量),比如向左走10米作为一个动作(变换量), 描述为TL = translate(0,10,0) 。 假设物体A 正前方为x(1,0,0),左边为y(0,1,0),上方为z(0,0,1),在A经过变换T0后 ,其前左上依然是(x,y,z)(这里描述一定是使用物体本身的坐标系),如果此时要让A再向左走10米,应当以A当前的矩阵乘上新的变化,就能得到A新的位置了,即 Tnew = T0*TL,这样就得到了当前位置往左走10米的变换了。即一直以变换物体当前位置作为基础,因为物体本身的坐标系是与物体固定的,不变动的。
求变换量的时候最关键的一点就是坐标系了:你必须要使用物体本身的坐标系!!!!因为我们需要的是一个相对的变化量(变换量也必须是一个相对值)。如物体前方为(1,0,0),那他经过各种变换后,他的前方在他的坐标系下还是(1,0,0) ,千万不要与世界坐标系的搞混。
至此再回过去理解矩阵的组装应该就很方便了。而A所描述的T0又可以理解为相对于(0,0,0)且没有旋转变换和缩放变换的 一个总的变换。而那个(0,0,0),就是世界坐标系了。

当然上面的变换量也可以是一个复合变化,比如T1(你先向你的左边走10米再向你的左边转90度) 或者 T2(你先向你的左边转90度再向你的左边走10米)。这两种变换量表示的是不一样的。在T2中明显已经先左转了,左转后的左边10米是左转前的后面的10米。
对于缩放,有点尴尬,缩放会影响平移。所以操作的时候可能需要将缩放抽出,然后再在最后乘上缩放变换。

//we have no scale here
float ifps = Game::get()->getIFps();
Mat4 mat = m_node->getWorldTransform();
Mat4 newMat =  translate(Vec3(0,-1,0)*ifps);//Vec3(0,-1,0) is defined forward of the m_node by me
Mat4 rot = Mat4((rotate(quat(vec3(0, 0, 1), ifps * 10))));//vec3(0, 0, 1) is defined up  of the m_node by me
newMat = newMat*rot;
mat = mat*newMat;
m_node->setWorldTransform(mat);

另外一种求变换的方式是使用全局的变换矩阵来求矩阵,需要将平移和旋转全部拆分开来。
假设物体当前的变换拆分开后编程位移变换矩阵T0 ,旋转变换矩阵R0,缩放矩阵S0.
当前相对于世界的前方的向量*速度*ifps 得到这一帧的全局位移变换T1.旋转矩阵为R1 = rotate(axis,angle*ifps) (axis为当前位置轴向相对于世界坐标系的描述,angle为角速度),缩放不变
那当前位置相对于世界的坐标为T0*T1*R0*R1*S0; 或者T1*T0*R0*R1*S0。永远要记住translate->rotate->scale的顺序。

//have no scale
float ifps = Game::get()->getIFps();
Vec3 forward = -m_node->getWorldTransform().getColumn3(1); //current forward in world coordinate ,it's model correspond ,you should check in you editor,or render it out,to find where is the forward
Vec3 up = -m_node->getWorldTransform().getColumn3(2); //current rotate axis in world coordinate
Mat4 mat = m_node->getWorldTransform();
Mat4 newTrans =  translate(forward*ifps);
Mat4 rot = Mat4(rotate(up, ifps * 10));
Mat4 roto = Mat4(rotate(mat.getRotate()));
Mat4 transo = translate(mat.getTranslate());
mat = transo*newTrans*roto*rot;
m_node->setWorldTransform(mat);

在没有旋转的矩阵中,平移变换的相乘或者绕坐标系同轴旋转变换的相乘在顺序上没有要求容易让人误解!!!!(至于为什么,可以理解下)

向量与旋转的左乘右乘:(quat 同mat3 两者是等价的且可相互替换的)
vec3 v = vec3(1, 0, 0);
vec3 v1 = v*quat(vec3(0, 0, 1), 30); //v1 = {x= 0.866025388 y= -0.500000000 z= 0.000000000 ...}
vec3 v2 = quat(vec3(0, 0, 1), 30)*v; //v2 = {x= 0.866025388 y= 0.500000000 z= 0.000000000 ...}
左乘右乘得出来的结果不一样。按上面的结果来理解,v2表示的是顺时针方向旋转。v1表示逆时针方向旋转。

关于mat4中setRotate(),setTranslate(),setRotateX(),setRotateY(),setRotateZ(),这些函数都会先将mat4中数据全部清空,然后再重新设置,也就是使用setTranslate() ,原来拥有的旋转会被清空;使用setRotate(),原来拥有的translate 会被置为0。(这些容易让人误解)
不过Mat4拥有12个构造函数,可以选择合适的构造函数来使用。或者用过乘法来组装

unigine 三维旋转矩阵(mat3,quat) scale translate 变换矩阵(mat4) 和forward up right 关系 normal binormal tangent相关推荐

  1. 三维旋转矩阵;东北天坐标系(ENU);地心地固坐标系(ECEF);大地坐标系(Geodetic);经纬度对应圆弧距离

    关注即可了解更多相关知识. 欢迎转发.收藏.友善交流. 文章目录 旋转矩阵 三角恒等式 Trigonometric identities 二维旋转矩阵 三维旋转矩阵 Euler Rotations m ...

  2. canvas笔记-图形变换(位移translate、缩放scale、变换矩阵transform)

    这里首先演示下位移,这里使用的函数是translate(x, y)这个函数是叠加的,也就是说,当translate(100, 100),后再次调用translate(200, 200),那么最后圆点的 ...

  3. 三维旋转矩阵_第三讲:三维空间的刚体运动

    题图来自monicore | Pixabay 三维空间的刚体运动 本讲主要主要关注一个问题:一个刚体在三维空间中的运动是如何描述的. 为什么要研究这个问题?因为当我们描述机器人的位姿时,就是在描述一个 ...

  4. 三维旋转矩阵 左乘和右乘分析

    突然发现自己被旋转矩阵的左乘右乘给搞糊涂了,查了不少博客还是有点晕,这里自己总结一下: 本文所讨论均是基于右手坐标系,旋转也是以正方向旋转,如图所示: 左乘: 坐标系不动,点动,则左乘.[若绕静坐标系 ...

  5. matlab三维 旋转矩阵,matlab中的三维坐标系与旋转

    1. matlab中的三维坐标系 matlab中的三维坐标系是使用的右手坐标系: 输入以下代码: >> plot3(0,0,0) >> xlabel('axis X') > ...

  6. 三维旋转矩阵_三维旋转矩阵与旋转向量

    欧拉角是用来表示三维坐标系中方向和方向变换的,我们平时说的欧拉角其实还可以细分为欧拉角(Eular-angles)和泰特布莱恩角(Tait-Bryan-angles),这两种方法都利用了笛卡尔坐标系的 ...

  7. 三维旋转矩阵_旋转之一 - 复数与2D旋转

    定义 先复习一下复数 复数可以看做 这组基 (Basis) 的线性组合(Linear Combination),所以可以用向量来表示复数. 当然也就可以用复平面上的点来表示复数: 乘法 复数的乘法: ...

  8. matlab三维 旋转矩阵,matlab旋转矩阵来旋转三维模型+meshlab旋转模型+matlab基础常用...

    matlab旋转矩阵来旋转三维模型+meshlab旋转模型+matlab基础常用 matlab旋转矩阵来旋转三维模型+meshlab旋转模型+matlab基础常用操作 matlab旋转矩阵实战: ①点 ...

  9. css3transform rotate,CSS3详解:transform [旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix]...

    CSS3详解:transform [旋转rotate.扭曲skew.缩放scale和移动translate以及矩阵变形matrix] transform的属性包括:rotate() / skew() ...

最新文章

  1. C语言中的struct结构体对齐问题
  2. 人均6.5万!鹅厂又双叒叕给员工发股票了
  3. python第五单元答案_中国大学MOOC第五单元测试答案_数据结构与算法Python版慕课答案在哪里可以看...
  4. vue中echarts 5.0版本以上不支持因为官方移除了地图数据和map文件夹
  5. Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks(更快的RCNN:通过区域提议网络实现实时)
  6. Python基础——PyCharm版本——第五章、循环(for、while、break、continue)
  7. 企业非法集资风险预测_2020CCF--企业非法集资风险预测83.35baseline
  8. 用Map构造选择题题库(洛谷P5601题题解,Java语言描述)
  9. Oracle 备份与还原
  10. com词根词缀_词根词缀记忆字典(com.ghosun.dict) - 4.8.8 - 应用 - 酷安网
  11. Asp.net弹出询问窗口
  12. weblogic 下载地址
  13. 用HTML语言制作一个非常浪漫的生日祝福网,手把手教你制作炫酷生日祝福网页
  14. 自己动手搭建免费VoIP服务器
  15. 手动实现一门图灵完备的编程语言——Brainfuck
  16. pt100铂电阻型号_铂热电阻型号(热电阻型号有什么表示)
  17. Unity 使用Mirror制作联机游戏
  18. TouchBar Dino for mac(TouchBar上的小恐龙跑酷游戏)
  19. 问题解决:“nginx: [emerg] unknown directive “ “ in /etc/nginx/conf.d/XXX.conf:122”
  20. bzoj4605 崂山白花蛇草水 权值线段树套kd树

热门文章

  1. 鸡和兔关在一个笼子里,鸡有2只脚,兔有4只脚,螃蟹 ;递归
  2. 用R来求解一元二次方程
  3. 二十八、docker详解
  4. 【升级版】python全自动定时,循环发消息(微信、QQ),零基础应用,
  5. 《响应式Web设计实践》一2.1 布局选项
  6. RK987单色三模键盘使用说明书
  7. centos7 设置外部访问
  8. 各大自媒体平台的收益情况汇总
  9. Pygame放大缩小照片
  10. Revit模型转obj模型插件