您的位置:首页 > 其它

点和向量的转换 Transforming Points and Vectors

2016-09-07 15:35 211 查看
计算机图形学数学基础译自 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'转换为1
if (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];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学