CSharpGL(32)矩阵与四元数与角度旋转轴的相互转换
CSharpGL(32)矩阵与四元数与角度旋转轴的相互转换
三维世界里的旋转(rotate),可以用一个3x3的矩阵描述;可以用(旋转角度float+旋转轴vec3)描述。数学家欧拉证明了这两种形式可以相互转化,且多次地旋转可以归结为一次旋转。这实际上就是著名的轨迹球(arcball)方式操纵模型的理论基础。
本文中都设定float angleDegree为旋转角度,vec3 axis为旋转轴。

四元数
定义(angleDegree+axis到四元数)
四元数就是一个四维向量(w, x, y, z),其中w描述旋转的角度(但不是直接的angleDegree值),(x, y, z)描述旋转轴。从angleDegree和axis得到一个四元数的方式比较简单。
public struct Quaternion
{
private float w;
private float x;
private float y;
private float z; /// <summary>
/// Quaternion from a rotation angle and axis.
/// </summary>
/// <param name="angleDegree">angle in degree.</param>
/// <param name="axis">rotation axis.</param>
public Quaternion(float angleDegree, vec3 axis)
{
vec3 normalized = axis.normalize();
double radian = angleDegree * Math.PI / 180.0;
double halfRadian = radian / 2.0;
this.w = (float)Math.Cos(halfRadian);
float sin = (float)Math.Sin(halfRadian);
this.x = sin * normalized.x;
this.y = sin * normalized.y;
this.z = sin * normalized.z;
}
}
先别管为什么四元数是这么定义的,只要知道这个定义就好。这里引入四元数只是为了方便提取出矩阵中蕴含的angleDegree和aixs。四元数的其他用途本文不涉及。
四元数到angleDegree+axis
从上面的定义可以很容易推算出四元数里蕴含的angleDegree和axis。显然得到的axis已经失去了原有的长度,但是axis的长度并不重要,保持在单位长度才是最方便的。
public void Parse(out float angleDegree, out vec3 axis)
{
angleDegree = (float)(Math.Acos(w) * * 180.0 / Math.PI);
axis = (new vec3(x, y, z)).normalize();
}
四元数到矩阵
从四元数到矩阵的推导有点复杂,有很多相关文章,本文就只贴代码了。代码还是很简练的。
/// <summary>
/// Transform this quaternion to equivalent matrix.
/// </summary>
/// <returns></returns>
public mat3 ToRotationMatrix()
{
vec3 col0 = new vec3(
* (x * x + w * w) - ,
* x * y + * w * z,
* x * z - * w * y);
vec3 col1 = new vec3(
* x * y - * w * z,
* (y * y + w * w) - ,
* y * z + * w * x);
vec3 col2 = new vec3(
* x * z + * w * y,
* y * z - * w * x,
* (z * z + w * w) - ); return new mat3(col0, col1, col2);
}

矩阵到四元数
矩阵到四元数的推导也有点复杂,借助了一些数学技巧,本文不详述,直接贴代码。
/// <summary>
/// Transform this matrix to a <see cref="Quaternion"/>.
/// </summary>
/// <returns></returns>
struct mat3
{
public Quaternion ToQuaternion()
{
// input matrix.
float m11 = this.col0.x, m12 = this.col1.x, m13 = this.col2.x;
float m21 = this.col0.y, m22 = this.col1.y, m23 = this.col2.y;
float m31 = this.col0.z, m32 = this.col1.z, m33 = this.col2.z;
// output quaternion
float x = , y = , z = , w = ;
// detect biggest in w, x, y, z.
float fourWSquaredMinus1 = +m11 + m22 + m33;
float fourXSquaredMinus1 = +m11 - m22 - m33;
float fourYSquaredMinus1 = -m11 + m22 - m33;
float fourZSquaredMinus1 = -m11 - m22 + m33;
int biggestIndex = ;
float biggest = fourWSquaredMinus1;
if (fourXSquaredMinus1 > biggest)
{
biggest = fourXSquaredMinus1;
biggestIndex = ;
}
if (fourYSquaredMinus1 > biggest)
{
biggest = fourYSquaredMinus1;
biggestIndex = ;
}
if (fourZSquaredMinus1 > biggest)
{
biggest = fourZSquaredMinus1;
biggestIndex = ;
}
// sqrt and division
float biggestVal = (float)(Math.Sqrt(biggest + ) * 0.5);
float mult = 0.25f / biggestVal;
// get output
switch (biggestIndex)
{
case :
w = biggestVal;
x = (m23 - m32) * mult;
y = (m31 - m13) * mult;
z = (m12 - m21) * mult;
break; case :
x = biggestVal;
w = (m23 - m32) * mult;
y = (m12 + m21) * mult;
z = (m31 + m13) * mult;
break; case :
y = biggestVal;
w = (m31 - m13) * mult;
x = (m12 + m21) * mult;
z = (m23 + m32) * mult;
break; case :
z = biggestVal;
w = (m12 - m21) * mult;
x = (m31 + m13) * mult;
y = (m23 + m32) * mult;
break; default:
break;
} return new Quaternion(w, -x, -y, -z);
}
}
matrix to quaternion
好了,现在矩阵 ⇋ 四元数 ⇋ (angleDegree+axis)之间的转换就全有了。
BTW,OpenGL里的glRotate{fd}(angle, axis)里的angle是以角度为单位的。为了统一,我将CSharpGL里的所有angle都设定为以角度为单位了。
下载
CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL)
总结
现在解决了矩阵与(angleDegree+axis)之间的转换问题,就可以从容地解析轨迹球算出的旋转矩阵,抽取出里面蕴含的(angleDegree+axis)了。这就可以单独更新模型的旋转角度和旋转轴,避免了对整个模型矩阵的破坏。
CSharpGL(32)矩阵与四元数与角度旋转轴的相互转换的更多相关文章
- 从矩阵(matrix)角度讨论PCA(Principal Component Analysis 主成分分析)、SVD(Singular Value Decomposition 奇异值分解)相关原理
0. 引言 本文主要的目的在于讨论PAC降维和SVD特征提取原理,围绕这一主题,在文章的开头从涉及的相关矩阵原理切入,逐步深入讨论,希望能够学习这一领域问题的读者朋友有帮助. 这里推荐Mit的Gilb ...
- Matrix4x4矩阵变换、欧拉角转四元数、角度转弧度
Matrix4x4 // 重置矩阵 ][]) { m[][] = ; m[][] = ; m[][] = ; m[][] = ; m[][] = ; m[][] = ; m[][] = ; m[][] ...
- BIT祝威博客汇总(Blog Index)
+BIT祝威+悄悄在此留下版了个权的信息说: 关于硬件(Hardware) <穿越计算机的迷雾>笔记 继电器是如何成为CPU的(1) 继电器是如何成为CPU的(2) 关于操作系统(Oper ...
- Unity手游之路<四>3d旋转-四元数,欧拉角和变幻矩阵
http://blog.csdn.net/janeky/article/details/17272625 今天我们来谈谈关于Unity中的旋转.主要有三种方式.变换矩阵,四元数和欧拉角. 定义 变换矩 ...
- opengl矩阵向量
如何创建一个物体.着色.加入纹理,给它们一些细节的表现,但因为它们都还是静态的物体,仍是不够有趣.我们可以尝试着在每一帧改变物体的顶点并且重配置缓冲区从而使它们移动,但这太繁琐了,而且会消耗很多的处理 ...
- 四元数(Quaternions)简介
经常在代码中看到Quaternions,也知道它是用来表达三维空间的旋转的,但一直没有更深的理解.这两天终于花点时间看了看维基百科的介绍,算是多了解了点.做个记录吧! 本质上而言,四元数是一个数学概念 ...
- 四元数与欧拉角(RPY角)的相互转换
RPY角与Z-Y-X欧拉角 描述坐标系{B}相对于参考坐标系{A}的姿态有两种方式.第一种是绕固定(参考)坐标轴旋转:假设开始两个坐标系重合,先将{B}绕{A}的X轴旋转$\gamma$,然后绕{A} ...
- 【转载】Unity中矩阵的平移、旋转、缩放
By:克森 简介 在这篇文章中,我们将会学到几个概念:平移矩阵.旋转矩阵.缩放矩阵.在学这几个基本概念的同时,我们会用到 Mesh(网格).数学运算.4x4矩阵的一些简单的操作.但由于克森也是新手,文 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第二十二章:四元数(QUATERNIONS)
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第二十二章:四元数(QUATERNIONS) 学习目标 回顾复数,以及 ...
随机推荐
- 【.net 深呼吸】细说CodeDom(5):类型成员
前文中,老周已经厚着脸皮介绍了类型的声明,类型里面包含的自然就是类型成员了,故,顺着这个思路,今天咱们就了解一下如何向类型添加成员. 咱们都知道,常见的类型成员,比如字段.属性.方法.事件.表示代码成 ...
- 简单粗暴地理解js原型链--js面向对象编程
原型链理解起来有点绕了,网上资料也是很多,每次晚上睡不着的时候总喜欢在网上找点原型链和闭包的文章看,效果极好. 不要纠结于那一堆术语了,那除了让你脑筋拧成麻花,真的不能帮你什么.简单粗暴点看原型链吧, ...
- 高性能Javascript--脚本的无阻塞加载策略
Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 .原因是,事实上,大多数浏览器使用单进程处理U ...
- 【Web动画】SVG 线条动画入门
通常我们说的 Web 动画,包含了三大类. CSS3 动画 javascript 动画(canvas) html 动画(SVG) 个人认为 3 种动画各有优劣,实际应用中根据掌握情况作出取舍,本文讨论 ...
- C#多线程之线程池篇3
在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...
- 我这么玩Web Api(二):数据验证,全局数据验证与单元测试
目录 一.模型状态 - ModelState 二.数据注解 - Data Annotations 三.自定义数据注解 四.全局数据验证 五.单元测试 一.模型状态 - ModelState 我理解 ...
- 走进缓存的世界(三) - Memcache
系列文章 走进缓存的世界(一) - 开篇 走进缓存的世界(二) - 缓存设计 走进缓存的世界(三) - Memcache 简介 Memcache是一个高性能的分布式内存对象缓存系统,用于动态Web应用 ...
- .NET设计模式访问者模式
一.访问者模式的定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 二.访问者模式的结构和角色: 1.Visitor 抽象访问者角色,为该 ...
- python 数据类型 --- 集合
1. 注意列表和集合的区别 set 列表表现形式: list_1 = [1,3,4]; 集合表现形式:set_1= set() list_1 = [1,2,3,4,23,4,2] print(lis ...
- BPM费控管理解决方案分享
一.方案概述费用是除经营成本外企业的最主要支出,费用管理是财务管理的核心之一,加强企业内控管理如:费用申请.费用报销.费用分摊.费用审批.费用控制和费用支付等,通过科学有效的管理方法规范企业费用管理, ...