解构变换矩阵

给定一个转换的复合矩阵,关于组成该转换的任何单个转换的信息就会丢失。 我们如果有一个复合矩阵,怎么能使其分解为TRS三个矩阵呢?即如何完成下述变化:

其中M是给定的变换矩阵,T是平移矩阵,R是旋转矩阵,S是缩放矩阵。其中提取T矩阵使非常简单的。因为我们知道平移矩阵形式为:

所以我们可以通过M[0][3],M[1][3],M[2][3]来分别找到xyz的位移量。我们可以写出:

T->x = m.m[0][3];
T->y = m.m[1][3];
T->z = m.m[2][3];

我们的M矩阵删除掉平移的元素,就只剩下旋转和缩放了。因此在删除平移后,剩下的是上面的3*3矩阵,它们一起表示缩放和旋转。 该矩阵被复制到新矩阵M中以进行进一步处理:

//获取除去平移的新矩阵M
Matrix4x4 M = m;
for (int i = 0; i < 3; ++i)M.m[i][3] = M.m[3][i] = 0.0f;
M.m[3][3] = 1.0f;

接下来就是如何去获取旋转矩阵了。只要获得旋转矩阵,那么缩放矩阵也就可以直接通过:

计算得出。接下来,我们要提取M的纯旋转分量R。我们将使用一种称为"极分解(polar decomposition)"的技术来做到这一点。 可以证明,矩阵M的极分解可以分解为旋转R和缩放S。该方法通过对M的逆的转置进行连续平均来计算:

直到收敛,此时Mi = R。(很容易看出,如果M是纯旋转,则对其进行求逆再转置平均将使其保持不变,因为其逆等于其转置)。我们可以看旋转矩阵的形式:

因为旋转矩阵为正交阵,满足上述操作。Shoemake和Duff(1992)讨论了该级数收敛的证明,所得矩阵是最接近M的正交矩阵,这是理想的特性。为了计算该序列,我们迭代应用公式,直到连续项之间的差很小或执行了固定的迭代次数为止。 实际上,该系列通常会很快收敛。我们代码如下:

// 从M分离出RFloat norm;int count = 0;Matrix4x4 R = M;do {// 计算Mi+1Matrix4x4 Rnext;Matrix4x4 Rit = Inverse(Transpose(R));for (int i = 0; i < 4; ++i)for (int j = 0; j < 4; ++j)Rnext.m[i][j] = 0.5f * (R.m[i][j] + Rit.m[i][j]);// 计算Mi和Mi+1之间的差norm = 0;for (int i = 0; i < 3; ++i) {Float n = std::abs(R.m[i][0] - Rnext.m[i][0]) +std::abs(R.m[i][1] - Rnext.m[i][1]) +std::abs(R.m[i][2] - Rnext.m[i][2]);norm = std::max(norm, n);}R = Rnext;} while (++count < 100 && norm > .0001)//当迭代次数超过上限,或者连续项之间的差足够小,则退出循环;

获得R之后就可以轻松计算S:

*S = Matrix4x4::Mul(Inverse(R), M);

我们完整的解构代码如下:

void AnimatedTransform::Decompose(const Matrix4x4 &m, Vector3f *T,Quaternion *Rquat, Matrix4x4 *S) {// 获取平移TT->x = m.m[0][3];T->y = m.m[1][3];T->z = m.m[2][3];// 获取除去平移的新矩阵MMatrix4x4 M = m;for (int i = 0; i < 3; ++i) M.m[i][3] = M.m[3][i] = 0.f;M.m[3][3] = 1.f;// 从M分离出RFloat norm;int count = 0;Matrix4x4 R = M;do {// 计算Mi+1Matrix4x4 Rnext;Matrix4x4 Rit = Inverse(Transpose(R));for (int i = 0; i < 4; ++i)for (int j = 0; j < 4; ++j)Rnext.m[i][j] = 0.5f * (R.m[i][j] + Rit.m[i][j]);// 计算Mi和Mi+1之间的差norm = 0;for (int i = 0; i < 3; ++i) {Float n = std::abs(R.m[i][0] - Rnext.m[i][0]) +std::abs(R.m[i][1] - Rnext.m[i][1]) +std::abs(R.m[i][2] - Rnext.m[i][2]);norm = std::max(norm, n);}R = Rnext;} while (++count < 100 && norm > .0001)//当迭代次数超过上限,或者连续项之间的差足够小,则退出循环;// 获取旋转矩阵的四元数形式*Rquat = Quaternion(R);// 计算缩放矩阵S*S = Matrix4x4::Mul(Inverse(R), M);
}

解构变换矩阵:如何使变换矩阵分解为位移(T),旋转(R),缩放(S)矩阵相关推荐

  1. 前端面试不用怕!一分钟带你了解es6的解构赋值

    解构赋值(★★★)!!!!! ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构 <script>var stus=['李钟硕','刘诗诗','易烊千玺']//访问数 ...

  2. ES6 入门—ES6 解构赋值

    文章目录 前言 一.解构赋值概述 二.数组模型的解构赋值 二.对象的解构赋值 三.可嵌套可忽略 四.解构默认值 五.不完全解构 六.剩余运算符 七.注意事项 八.字符串的解构赋值 九.圆括号问题 总结 ...

  3. ES6读书笔记--一入解构深似海

    解构为何有用? 在 ES5 及更早版本中,从对象或数组中获取信息.并将特定数据存入本地变量,需要书写许 多并且相似的代码.例如: let options = {repeat: true,save: f ...

  4. 三维空间坐标的旋转算法详解_三维空间几何坐标变换矩阵.ppt

    三维空间几何坐标变换矩阵 第7章 三维变换 7.1 简介 7.2 三维几何变换 7.3 三维坐标变换 7.1 简介 三维平移变换.比例变换可看成是二维情况的直接推广.但旋转变换则不然,因为我们可选取空 ...

  5. DEKR 解构式关键点回归(一):算法思想与原理

    前言 CW前阵子玩了下人体姿态估计,用上了微软新鲜出炉的算法--DEKR: Bottom-Up Human Pose Estimation Via Disentangled Keypoint Regr ...

  6. CVPR 2021 | 微软提出“解构式关键点回归“, 刷新COCO自底向上多人姿态检测记录!

    随着深度学习的发展,运用计算机视觉中的人体姿态估计技术已经能够高精度地从人体的图片中检测出人体关键点,并恢复人体位姿.在应用端,此技术也已经在人机交互.影视制作.运动分析.游戏娱乐等各领域大放异彩. ...

  7. TypeScript入门教程 之 解构

    TypeScript入门教程 之 解构 TypeScript支持以下形式的解构(以解构的名义命名,即分解结构): 对象分解 阵列解构 人们很容易将解构视为结构的逆.JavaScript中的结构化方法是 ...

  8. javascript编写_如何在JavaScript中使用解构来编写更简洁,功能更强大的代码

    javascript编写 by Ashay Mandwarya ?️?? 由Ashay Mandwarya提供吗? 如何在JavaScript中使用解构来编写更简洁,功能更强大的代码 (How to ...

  9. es6中数组的解构_ES6中的数组解构简介

    es6中数组的解构 by Kevwe Ochuko 通过Kevwe Ochuko Destructuring in JavaScript is a simplified method of extra ...

最新文章

  1. 转行学python后悔了-你是多少岁转行的?转行后你后悔了吗?
  2. android fragment contextmenu,在 fragment 中,无法为listView项创建 contextMenu_android_开发99编程知识库...
  3. poj3261(求至少出现k次的可重叠的子串的长度)
  4. wxWidgets:显示如何从 DLL 使用 wx 的示例
  5. Android开发之旅:HelloWorld项目的目录结构
  6. C/S构架和B/S架构的比较
  7. file watchers怎么默认打开_Python读写文件怎么和我之前学的不一样?
  8. Android RecyclerView封装下拉刷新与上拉加载更多
  9. 使用IntelliJ IDEA 构建Maven的web项目
  10. linux centos java 应用服务器配置
  11. 谢谢你,阅读了这篇文章
  12. like not like 优化
  13. android aso优化工具,如何使用ASO优化工具优化安卓应用商店
  14. 计算机英语四六级考试时间,2019年12月英语四六级考试时间
  15. java18天map和线程
  16. 蒋宇捷——程序员的进化 - 在拉勾1024程序员节上的演讲
  17. Ubuntu-的前世今生
  18. 阿里云服务器CentOS部署Minio服务实现远程访问
  19. 十、快速入门线性代数的向量和矩阵篇
  20. 计算机我的手机选项在哪里设置方法,手把手教你用手机轻松设置无线wifi路由器的方法...

热门文章

  1. python1000行代码_用好这3行代码,可以让你的Python脚本速度提升5倍!
  2. html三张图片的轮播代码_vue写了个轮播图
  3. 对于scanf,strcpy等函数报4996错误的粗暴而简单解决办法
  4. c语言编程输出年月日,C语言程序设计: 输入年月日 然后输出是星期几
  5. java 回收器_Java虚拟机-经典垃圾回收器
  6. centos 安装java sdk_Linux——CentOS7使用yum命令安装Java SDK
  7. python把数字阿拉伯数字转换成中文10以内_Python实现把数字转换成中文
  8. onvif协议_大华的录像机添加海康摄像头,使用了onvif协议,为啥也添加不进去?...
  9. mysql dba环境验收_面对一个全新的环境,作为一个Mysql DBA,应该了解
  10. byte是什么数据类型_PLC基本数据类型的解读(避免在使用中的误解)