随笔 - 17,  文章 - 0,  评论 - 0,  阅读 - 2204

坐标转换

一个向量可以被表示为v=xi+yj+zk,其中ijk为坐标系的基向量:

i=[100]j=[010]k=[001]

基向量可写成矩阵的方式:

[ixiyizjxjyjzkxkykz]

一个坐标系可以使用任意线性无关的基向量构成,如lmn

使用由lmn构成的矩阵乘以一个任意向量[abc]

[abc][lxlylzmxmymznxnynz]=[alx+bmx+cnxaly+bmy+cnyalz+bmz+cnz]

[alx+bmx+cnxaly+bmy+cnyalz+bmz+cnz]=a[lxlylz]+b[mxmymz]+c[nxnynz]=al+bm+cn

最终得到了由基向量表示的结果,由此可见

如果把矩阵的行解释为坐标系的基向量,那么乘以该矩阵就相当于执行了一次坐标转换,若有aM=b,我们就可以说,Ma转换到b

从另一个角度看,x,y,z分量分别代表了向量在每个基向量方向上分别“走了多少个单位”,变换的只是基向量的方向,而在每个方向上走多远却没有改变。

旋转

使用单位且正交的基向量xyz构成新的坐标系,使用基向量构成的矩阵乘以向量v

[vxvyvz][xxxyxzyxyyyzzxzyzz]=[vxvyvz]

可以发现,在矩阵变换向量的过程中,也完成了旋转。

应用

首先确定一个forward正方向,利用世界空间的up方向(0,1,0)通过叉积运算得到与forward正交的right方向,然后再利用计算得到的right方向通过叉积运算得到正确的up方向。

float3 forward = direction;
half isParallel = step(0.999, forward.y);
float3 up = isParallel * float3(0, 0, 1) + (1 - isParallel) * float3(0, 1, 0);
float3 right = normalize(cross(up, forward));
up = normalize(cross(forward, right));

up的计算中,为了防止forward方向与世界空间的up方向平行得到错误的计算,加入判断选择需要使用的向量。

例如可以使用计算得到的三个基向量变换模型空间的顶点位置,以此达到旋转模型的目的:

float3 newPos = positionOS.x * right + positionOS.y * up + positionOS.z * forward;

或者构成矩阵用以旋转向量:

float3x3 rotationMatrix = float3x3(right, up, forward);

在实际使用过程中注意左乘和右乘的区别,即行向量与列向量的使用区别:
向量以行表示,则矩阵以行构建,向量以列表示,则矩阵以列构建。
[abc][lxlylzmxmymznxnynz]=[alx+bmx+cnxaly+bmy+cnyalz+bmz+cnz]

[lxmxnxlymynylzmznz][abc]=[alx+bmx+cnxaly+bmy+cnyalz+bmz+cnz]

在Unity Shader中, float3x3(right, up, forward) 表示将向量以行向量的方式组成矩阵,故变换向量时使用 mul(vector, rotationMatrix) 方式计算,若 rotationMatrix 以列向量方式存储,故变换向量时使用 mul(rotationMatrix, vector) 方式计算。

参考

《3D数学基础:图形与游戏开发》

posted on   WoBok  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示