三维旋转矩阵

news2025/1/6 19:28:25

前言

本文讲述三维旋转的矩阵推导,推导过程遵循下面的规则:

  • 本文的坐标系是基于右手坐标系的
  • 逆时针旋转为正向旋转

围绕坐标轴的旋转

x x x

在这里插入图片描述

我们假设旋转的点为 P P P
假设旋转之前 P P P的坐标为 ( x 0 , y 0 , z 0 ) (x_0,y_0,z_0) (x0,y0,z0)

当围绕 x x x轴做正向旋转,即逆时针旋转,我们取 x = x 0 x = x_0 x=x0的平面作为旋转的坐标系平面
此时,我们将旋转就转化为了二维旋转
因为是右手坐标系,所以此时 y y y轴向右, z z z轴向上,原点为平面与 x x x轴的交点 O O O

假设旋转之前 P P P到原点 O O O的线段与 y y y轴的夹角弧度为 α \alpha α
假设旋转的弧度为 β \beta β
假设点 P P P到原点 O O O的距离为 R R R
假设旋转之后 P P P的坐标为 ( x 1 , y 1 , z 1 ) , x 1 = x 0 (x_1,y_1,z_1), x_1 = x_0 (x1,y1,z1),x1=x0

那么,旋转前
y 0 = c o s ( α ) ∗ R z 0 = s i n ( α ) ∗ R (1) y_0 = cos(\alpha) \tag{1}*R\\ z_0 = sin(\alpha) *R y0=cos(α)Rz0=sin(α)R(1)

旋转后(注意,因为是逆时针旋转,所以旋转后的弧度 = 旋转前弧度 + 旋转弧度)
y 1 = c o s ( α + β ) ∗ R = c o s ( α ) c o s ( β ) ∗ R − s i n ( α ) s i n ( β ) ∗ R = y 0 ∗ c o s ( β ) − z 0 ∗ s i n ( β ) z 1 = s i n ( α + β ) ∗ R = s i n ( α ) c o s ( β ) ∗ R + c o s ( α ) s i n ( β ) ∗ R = y 0 ∗ s i n ( β ) + z 0 ∗ c o s ( β ) x 1 = x 0 (2) \begin{aligned} y_1 & = cos(\alpha + \beta)*R \\ & = cos(\alpha)cos( \beta)*R - sin(\alpha)sin( \beta)*R\\ & = y_0*cos( \beta) - z_0*sin( \beta)\\ \\ z_1 &= sin(\alpha + \beta)*R \\ & = sin(\alpha)cos( \beta) *R +cos(\alpha)sin( \beta)*R\\ & = y_0*sin( \beta) + z_0*cos( \beta)\\ \\ x_1 &= x_0 \end{aligned} \tag{2} y1z1x1=cos(α+β)R=cos(α)cos(β)Rsin(α)sin(β)R=y0cos(β)z0sin(β)=sin(α+β)R=sin(α)cos(β)R+cos(α)sin(β)R=y0sin(β)+z0cos(β)=x0(2)

我们可以得到绕 x x x轴旋转的矩阵:
M r x = ( 1 0 0 0 0 c o s ( β ) − s i n ( β ) 0 0 s i n ( β ) c o s ( β ) 0 0 0 0 1 ) M_{rx}= \begin{pmatrix} 1 & 0 & 0& 0\\ 0 & cos( \beta)& -sin( \beta)& 0\\ 0 & sin( \beta)& cos( \beta)& 0\\ 0 & 0& 0& 1\\ \end{pmatrix} Mrx= 10000cos(β)sin(β)00sin(β)cos(β)00001

下面是实现代码

static matrix4d rotationX(float angle)
{
	matrix4d m;
	T c = cos(angle);
	T s = sin(angle);
	m[5] = m[10] = c;
	m[9] = -s;
	m[6] = s;
	return m;
}

注意,代码中的矩阵数组是列主序的

y y y

围绕 y y y轴的旋转和 x x x轴类似
在这里插入图片描述

只不过此时向右变成了 z z z轴,向上变成了 x x x
所以,我们直接上公式
z 1 = z 0 ∗ c o s ( β ) − x 0 ∗ s i n ( β ) x 1 = z 0 ∗ s i n ( β ) + x 0 ∗ c o s ( β ) y 1 = y 0 \begin{aligned} z_1 & = z_0*cos( \beta) - x_0*sin( \beta)\\ \\ x_1 & = z_0*sin( \beta) + x_0*cos( \beta)\\ \\ y_1 &= y_0 \end{aligned} z1x1y1=z0cos(β)x0sin(β)=z0sin(β)+x0cos(β)=y0
M r y = ( c o s ( β ) 0 s i n ( β ) 0 0 1 0 0 − s i n ( β ) 0 c o s ( β ) 0 0 0 0 1 ) M_{ry}= \begin{pmatrix} cos( \beta) & 0 & sin( \beta)& 0\\ 0 & 1& 0& 0\\ -sin( \beta) & 0& cos( \beta)& 0\\ 0 & 0& 0& 1\\ \end{pmatrix} Mry= cos(β)0sin(β)00100sin(β)0cos(β)00001
下面是代码

static matrix4d rotationY(float angle)
{
	matrix4d m;
	T c = cos(angle);
	T s = sin(angle);
	m[0] = m[10] = c;
	m[8] = s;
	m[2] = -s;
	return m;
}

注意,代码中的矩阵数组是列主序的

z z z

围绕 z z z轴的旋转和 x x x轴类似
在这里插入图片描述

只不过此时向右变成了 x x x轴,向上变成了 y y y
所以,我们直接上公式
x 1 = x 0 ∗ c o s ( β ) − y 0 ∗ s i n ( β ) y 1 = x 0 ∗ s i n ( β ) + y 0 ∗ c o s ( β ) z 1 = y 0 \begin{aligned} x_1 & = x_0*cos( \beta) - y_0*sin( \beta)\\ \\ y_1 & = x_0*sin( \beta) + y_0*cos( \beta)\\ \\ z_1 &= y_0 \end{aligned} x1y1z1=x0cos(β)y0sin(β)=x0sin(β)+y0cos(β)=y0
M r z = ( c o s ( β ) − s i n ( β ) 0 0 s i n ( β ) c o s ( β ) 0 0 0 0 1 0 0 0 0 1 ) M_{rz}= \begin{pmatrix} cos( \beta) & -sin( \beta) & 0& 0\\ sin( \beta) & cos( \beta)& 0& 0\\ 0& 0& 1& 0\\ 0 & 0& 0& 1\\ \end{pmatrix} Mrz= cos(β)sin(β)00sin(β)cos(β)0000100001
下面是代码

static matrix4d rotationY(float angle)
{
	matrix4d m;
	T c = cos(angle);
	T s = sin(angle);
	m[0] = m[5] = c;
	m[4] = -s;
	m[1] = s;
	return m;
}

注意,代码中的矩阵数组是列主序的

围绕任意轴的旋转

如果对象绕与每个坐标轴均不平行的轴旋转,则需要进行额外的变换。此时,还需要进行使旋转轴与某一选定坐标轴对齐的旋转,以后要将此轴变回到原始位置。若给定旋转轴和旋转角, 我们可以按照5个步骤来完成所需旋转:

  • 平移对象,使得旋转轴通过坐标原点
  • 旋转对象使得旋转轴与某一坐标轴重合
  • 绕该坐标轴完成指定的旋转
  • 利用逆旋转使旋转轴回到其原始方向
  • 利用逆平移使旋转轴回到其原始位置

从之前我们在坐标轴进行旋转时,发现其实绕 z z z轴的旋转是最符合我们平时的认知的,因为向右是 x x x轴,向上是 y y y轴,这就是我们使用的二维坐标系,下面讨论使用 z z z轴旋转矩阵的变换序列

我们假设旋转轴由两个点确定, P 1 P_1 P1 P 2 P_2 P2,方向是从 P 1 P_1 P1 P 2 P_2 P2,方向决定了旋转方向
P 1 = ( x 1 , y 1 , z 1 ) P 2 = ( x 2 , y 2 , z 2 ) P_1 = (x_1, y_1, z_1)\\ P_2 = (x_2, y_2, z_2) P1=(x1,y1,z1)P2=(x2,y2,z2)
V V V为旋转轴的方向向量,则:
V = P 2 − P 1 = ( x 2 − x 1 , y 2 − y 1 , z 2 − z 1 ) \begin{aligned} V & = P_2 - P_1\\ & = (x_2 - x_1,y_2 - y_1,z_2 - z_1) \end{aligned} V=P2P1=(x2x1,y2y1,z2z1)
u u u为旋转轴单位方向向量,则:
u = V ∣ V ∣ = ( a , b , c ) u = \frac{V}{|V|} = (a,b,c) u=VV=(a,b,c)
其中:
a = x 2 − x 1 ∣ V ∣ ,    b = y 2 − y 1 ∣ V ∣ ,    c = z 2 − z 1 ∣ V ∣ a = \frac{x_2 - x_1}{|V|}, \ \ b = \frac{y_2 - y_1}{|V|}, \ \ c = \frac{z_2 - z_1}{|V|} a=Vx2x1,  b=Vy2y1,  c=Vz2z1
下面给出初始位置图:
在这里插入图片描述

平移到原点

我们把 P 1 P_1 P1平移到原点,下面是平移矩阵,平移后 P 2 P_2 P2也变成了 P 2 ′ P_2^{'} P2
( 1 0 0 − x 1 0 1 0 − y 1 0 0 1 − z 1 0 0 0 1 ) \begin{pmatrix} 1&0&0&-x_1\\ 0&1&0&-y_1\\ 0&0&1&-z_1\\ 0&0&0&1\\ \end{pmatrix} 100001000010x1y1z11
在这里插入图片描述

将旋轴转旋转到z轴

将旋轴转旋转到 z z z轴的思路是:

  • 先将旋转轴绕 x x x轴旋转到 x z xz xz平面
  • 然后绕 y y y轴旋转到与 z z z轴重合

在这里插入图片描述

x x x轴旋转到 x z xz xz平面

旋转角度为 α \alpha α
在这里插入图片描述

绕x轴的旋转矩阵我们上面已经介绍了,最重要的是要知道绕 x x x轴旋转到 x z xz xz平面的弧度的正弦余弦值

如果我们把 u u u投影到 y z yz yz平面 u ′ u^{'} u,则 u ′ u^{'} u z z z轴正向的夹角即为 α \alpha α
在这里插入图片描述

我们前面已经获取到了 u u u的坐标,所以
c o s ( α ) = c d ,    d = b 2 + c 2 s i n ( α ) = b d ,    d = b 2 + c 2 cos(\alpha) = \frac{c}{d},\ \ d = \sqrt{b^2 + c^2}\\ sin(\alpha) = \frac{b}{d},\ \ d = \sqrt{b^2 + c^2}\\ cos(α)=dc,  d=b2+c2 sin(α)=db,  d=b2+c2

此时我们可以获取到绕x轴旋转到 x z xz xz平面的旋转矩阵了
R x = ( 1 0 0 0 0 c d − b d 0 0 b d c d 0 0 0 0 1 ) R_x = \begin{pmatrix} 1&0&0&0\\ 0&\frac{c}{d}&-\frac{b}{d}&0\\ 0&\frac{b}{d}&\frac{c}{d}&0\\ 0&0&0&1\\ \end{pmatrix} Rx= 10000dcdb00dbdc00001
旋转后的 x z xz xz平面的向量记为 u ′ ′ u^{''} u′′

y y y轴旋转到 z z z

下一步需要确定变换矩阵,此矩阵将 x x x平面上的单位向量绕 y y y轴逆时针旋转到 z z z轴的正方向
x x x轴旋转后, x x x平面上单位向量的方向如下:
在这里插入图片描述

到目前为止,我们先理清 u ′ ′ u^{''} u′′的部分情况:

  • 因为绕 x x x轴的旋转保持 x x x分量不变,故其 x x x分量值仍为 a a a
  • 因为绕 x x x轴的旋转使 u ′ u^{'} u旋转到了 z z z轴上,所以 u ′ ′ u^{''} u′′ z z z分量为 d d d
  • u ′ ′ u^{''} u′′ y y y分量为0

根据上面的条件,我们可以得出 u ′ ′ u^{''} u′′旋转到 z z z轴正向的正弦余弦值
c o s ( β ) = d s i n ( β ) = − a cos(\beta) = d\\ sin(\beta) = -a cos(β)=dsin(β)=a

所以,旋转矩阵为
R y = ( d 0 − a 0 0 1 0 0 a 0 d 0 0 0 0 1 ) R_y = \begin{pmatrix} d&0&-a&0\\ 0&1&0&0\\ a&0&d&0\\ 0&0&0&1\\ \end{pmatrix} Ry= d0a00100a0d00001

z z z轴旋转

直接给出旋转矩阵了:
R z = ( c o s ( θ ) − s i n ( θ ) 0 0 s i n ( θ ) c o s ( θ ) 0 0 0 0 1 0 0 0 0 1 ) R_z= \begin{pmatrix} cos( \theta) & -sin( \theta) & 0& 0\\ sin( \theta) & cos( \theta)& 0& 0\\ 0& 0& 1& 0\\ 0 & 0& 0& 1\\ \end{pmatrix} Rz= cos(θ)sin(θ)00sin(θ)cos(θ)0000100001

最终的矩阵

到现在,很容易就能得出绕任意轴进行旋转的矩阵表示
R ( θ ) = T − 1 ∗ R x ( α ) ∗ R y − 1 ( β ) ∗ R z ( θ ) ∗ R y ( β ) ∗ R x ( α ) ∗ T R(\theta) = T^{-1}*R_x^{}(\alpha)*R_y^{-1}(\beta)*R_z(\theta)*R_y(\beta)*R_x(\alpha)*T R(θ)=T1Rx(α)Ry1(β)Rz(θ)Ry(β)Rx(α)T

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

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

相关文章

CAN总线中注入拓展帧、远程帧,CAPL通用函数。

🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】🍅 玩转CANoe,博客目录大全,点击跳转👉 【测试需求】:CAN总线要求DUT 接收到非预期的扩展帧、远程帧时,通信正常,…

vulhub:nginx解析漏洞nginx_parsing

这个解析漏洞其实是PHP CGI的漏洞,在PHP的配置文件中有一个关键的选项cgi.fix_pathinfo默认是开启的,当URL中有不存在的文件,PHP就会向前递归解析。在一个文件/xx.jpg后面加上/.php会将 /xx.jpg/xx.php 解析为 php 文件 条件: Ngi…

釉面陶瓷器皿和玻璃器皿 SOR/2016-175认证

釉面陶瓷制品和釉面玻璃制品设计用于盛装食品,包括扁平餐具、杯子或马克杯、小号或大号凹形器皿(杯子或马克杯除外)以及水罐。这些法规适用于以下釉面陶瓷制品和釉面玻璃制品: 完全或部分由陶瓷或玻璃制成完全或部分覆盖含铅或镉…

MATLAB(12)预测模型

一、前言 在MATLAB中创建一个预测模型通常涉及多个步骤,包括数据准备、模型选择、训练模型、评估模型以及使用模型进行预测。以下是一个简化的例子,说明如何使用MATLAB中的内置函数来创建一个基于线性回归的预测模型。这个例子将使用MATLAB的fitlm函数来…

C语言函数初识

文章目录 🍊自我介绍🍊函数初识前言概念具体实例解释函数的实用性 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞关注评论收藏(一键四连)哦~ 🍊自我介绍 Hello,大家好,我是小珑也…

院人全年无休计划背后,芒果把To C综艺玩明白了

《种地吧》掉粉闹得沸沸扬扬,不少禾伙人希望芒果把“十个勤天”挖走,毕竟芒果做综艺群像确实是一把好手,“院人”就是最好的例子。 在#种地吧粉丝让芒果把十个勤天挖走#的话题登上热搜之后,“学分们”(院人粉丝&#…

JS等待所有方法执行完成在执行下一个方法,promise All

在工作中会遇到这样一个场景,前端需要拿到不同接口返回的结果在执行某个逻辑,当使用链式那样的方式去请求,等一个接口响应完在请求下一个接口,这种方法就会导致请求时间特别长。这个时候就可以使用promise all,同时请求…

国产麒麟操作系统下搞单机版

去年纪委单位的一个项目,因为单位保密性质,档案必须要保密,要求采用单机版, 要求跟EXE那样,双击打开,阿公单位信息人员电脑操作水平化滞后还是相当严重啊。 去年已经给他花了时间按他们的要求实现了。 上周…

【直角三角形】python刷题记录

R3-新增每日一题打卡。 目录 思路(遍历中间乘法原理): 乘法原理如下: ps: python的zip操作 矩阵转置 并行遍历 对象组合 创建字典 处理不等迭代长度 思路: 这题遍历主要从直角点开始遍历,用到了…

软科中国大学排名爬虫+数据可视化

这一期是关于软科中国大学排名的爬虫分析 目标网址:https://www.shanghairanking.cn/rankings/bcur/2024 每页30所学校信息,共20页 点击翻页,你发现网址没有发生变化,说明该页面信息应该是利用js实现动态加载数据的方式展示的&am…

基于51单片机的篮球计分器Protues仿真设计(LCD12864显示)

目录 一、设计背景 二、设计要求 三、仿真演示 四、程序展示(部分) 一、设计背景 近年来,随着国家对体育事业的日益重视,体育运动在全民中的普及程度显著提高,篮球作为一项广受欢迎的运动项目,其比赛与…

Linux云计算 |【第二阶段】CLUSTER-DAY1

主要内容: 集群概念、LVS概述、LVS-NAT集群、LVS-DR集群 一、集群概念 集群(Cluster)是指将多台计算机(节点)通过网络连接在一起,形成一个统一的计算资源池,共同完成一项或多项任务的系统。集…

如何使用 FTP 将文件上传到 WordPress

作为新手站长,在学习如何管理和维护自己的网站时,掌握一些基本的文件管理技能是非常重要的。通过FTP上传文件到WordPress网站是其中一个必备的技能。本文将详细介绍如何使用FTP将文件上传到WordPress,并分享一些在使用Hostease主机的过程中积…

场外个股期权是什么?20倍奇迹,神仙操作的场外个股期权!

今天带你了解场外个股期权是什么?20倍奇迹,神仙操作的场外个股期权!场外期权交易具有独特的特点和优势,它结合了“彩票”和“保险”的双重属性,为投资者提供了一种灵活且高效的投资工具。 场外个股期权是一种金融合约…

Linux内存不够了?看看如何开启虚拟内存增加内存使用量

1、为什么要使用虚拟内存 当我们没有多余的钱去购买大内存的云服务器时,但是当前服务器里面的软件和程序运行的比较多导致内存不够用了。这个时候可以通过增加虚拟内存来扩大内存容量。但是在启用虚拟内存时,需要仔细考虑系统的实际需求和硬件配置&#…

前端技术回顾系列 14 | 总结 + Vue 3.x 必修课

欢迎关注公众号:CodeFit 创作不易,如果你觉得这篇文章对您有帮助,请不要忘了 点赞、分享 和 关注,为我的 持续创作 提供 动力! 1. 回顾系列的初衷和目标 在六月初,我开始编写 「前端技术回顾系列 2024」&a…

⭕️【读论文】Learning To Count Everything

2021 IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR) 任务名称: visual counting ; few shot counting;crowd counting;cell counting 目录 Abstract 1. Introduction 2. Related Works 3. Few-…

JavaScript (十)——JavaScript 比较 和 逻辑运算符

目录 JavaScript 比较 和 逻辑运算符 比较运算符 如何使用 逻辑运算符 条件运算符 语法 JavaScript 比较 和 逻辑运算符 比较和逻辑运算符用于测试 true 或者 false 比较运算符 比较运算符在逻辑语句中使用,以测定变量或值是否相等。 如何使用 可以在条件语…

Vulnhub靶机:JANGOW_ 1.0.1

目录 前言: 一、安装虚拟机Jangow:1.0.1靶机 二、Web部分 前言: 难度:简单,本文使用VirtualBox打开,下载地址: https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova 一、安装虚拟机J…

JMeter接口测试-6.JMeter项目实战

1.项目介绍 知识点: 微信小程序项目及接口文档介绍 1.1 微信小程序项目介绍 微信开发者工具 下载:微信开发者工具下载地址与更新日志 | 微信开放文档 项目代码运行 使用登录扫码,登录开发者工具 登录成功后,选择小程序 点击…