点和向量的转换 Transforming Points and Vectors

来源:互联网 发布:英语造句软件下载 编辑:程序博客网 时间:2024/05/18 12:35

计算机图形学数学基础译自 ScratchaPixel 网站,数学基础部分共八篇,本篇为第四篇,感兴趣的同学可以参考我的 GitBook 镜像。

点的转换 Transforming Points

点的平移无非是对点的每个坐标增加相应的数,例如我们想让点(1, 1, 1)平移至(2, 3, 4)。我们需要将x,y和z的坐标分别加上1, 2, 3。我们将点看为1 x 3的矩阵:

先来看点使用矩阵的转换:

我们如何才能使转换也能加上平移的量,比如:

可以考虑将矩阵变为4 x 3的单位,这样就会有:

但是1 x 3乘以4 x 3的矩阵不能满足矩阵乘法。解决这个问题我们需要将点转换为1 x 4的矩阵,并将第四个系数设为1。这个点的形式为(x, y, z, 1)。在计算机图形学中,这个点被称为 齐次点(homogenous point) 或点位于 齐次坐标(homogenous coordinates)。基于这样的点,我们可以很便捷地写出转换公式:

由于第四个系数一直为1,并且不会随着转换发生改变,因此上面的公式可以简写为:

现在的转换矩阵是4 x 3的单位,但是计算机图形学中常用的是4 x 4,第四列在 透视投影(perspective projection)剪切(shearing) 中比较常用,通常为(0, 0, 0, 1)。

齐次点的奥义 The Trick About Homogeneous Points

将点表示为齐次点需要将点乘以4 x 4的矩阵,在C++的类中,这些变换可以隐式的进行,前文提到齐次点的坐标为(x, y, z, 1),在非投影转换下,转换矩阵的第四列常为(0,0,0,1),齐次坐标w’为1(w’=x*0+y*0+z*0+w(=1)*1=1)。但是在投影转换下,w’的计算结果通常不为1,为了使点能在笛卡尔坐标系下可以使用,我们需要将w’转换为1,于是可以得到如下的伪代码:

P'.x = P.x * M00 + P.y * M10 + P.z * M20 + M30;p'.y = P.x * M01 + P.y * M11 + P.z * M21 + M31;P'.z = P.x * M02 + P.y * M12 + P.z * M22 + M32;w' = P.x * M03 + P.y * M13 + P.z * M23 + M33;// 若w'不为1,将w'转换为1if (w' != 1 && w` != 0) {  P'.x /= w`;  P'.y /= w`;  P'.z /= w`;}

对于在C++中的实现通常有2个学派,一些开发者选择在w’不为1的时候让x’,y’,z’都除以w’,以使w’的计算结果为1。如:

void multVecMatrix(const Vec3<T> &src, Vec3<T> &dst) const {  dst.x = src.x * m[0][0] + src.y * m[1][0] + src.z * m[2][0] + m[3][0];  dst.y = src.x * m[0][1] + src.y * m[1][1] + src.z * m[2][1] + m[3][1];  dst.z = src.x * m[0][2] + src.y * m[1][2] + src.z * m[2][2] + m[3][2];  T w = src.x * m[0][3] + src.y * m[1][3] + src.z * m[2][3] + m[3][3];  if (w != 1 && w != 0) {    dst.x = x / w;    dst.y = y / w;    dst.z = z / w;  }}

然而这种场景只在转换矩阵为投影矩阵时才有效(而且并不常见,特别是光线追踪),结果就是 99%的场景下计算和检验w’都是在浪费CPU资源。另一学派认为始终忽略w和w’,并且转换矩阵的第四列始终设置为(0,0,0,1),只有在处理特殊场景,如投影矩阵时,将点x’,y’,z’都除以w’。因此,你可以选择单一而未经优化的实现,或者可以按照具体场景,选择最优的实现。

向量的转换 Transforming Vectors

向量的转换相较点的转换更为简单。向量,表示方向,而点则表示在空间的位置。因此向量不需要平移,因为它们的位置是无意义的。对于向量,我们只关注它所指向的点,以及最终它的长度(是解决几何问题和着色问题的关键)。向量可以像点那样转化(我们需要去除平移部分)。例如:

V'.x = V.x * M00 + v.y * M10 + V.z * M20;V'.y = V.x * M01 + v.y * M11 + V.z * M21;V'.x = V.x * M02 + v.y * M12 + V.z * M22;

在C++代码中:

void mulyDirMatrix(const Vec3<T> &src, Vec3<T> &dst) const {  dst.x = src.x * m[0][0] + src.y * m[1][0] + src.z * m[2][0];  dst.y = src.x * m[0][1] + src.y * m[1][1] + src.z * m[2][1];  dst.x = src.x * m[0][2] + src.y * m[1][2] + src.z * m[2][2];}
0 0
原创粉丝点击