点和向量的转换 Transforming Points and Vectors
2016-09-07 15:35
211 查看
计算机图形学数学基础译自 ScratchaPixel 网站,数学基础部分共八篇,本篇为第四篇,感兴趣的同学可以参考我的 GitBook 镜像。
![](http://www.forkosh.com/mathtex.cgi? \begin{array}{l}
P'.x = P.x + Tx\\
P'.y = P.y + Ty\\
P'.z = P.z + Tz\end{array})
先来看点使用矩阵的转换:
![](http://www.forkosh.com/mathtex.cgi? \begin{array}{l}
P'.x = P.x * M_{00} + P.y * M_{10} + P.z * M_{20}\\
P'.y = P.x * M_{01} + P.y * M_{11} + P.z * M_{21}\\
P'.z = P.x * M_{02} + P.y * M_{12} + P.z * M_{22}\end{array})
我们如何才能使转换也能加上平移的量,比如:
![](http://www.forkosh.com/mathtex.cgi? \begin{array}{l}
P'.x = P.x * M_{00} + P.y * M_{10} + P.z * M_{20} + T_X\\
P'.y = P.x * M_{01} + P.y * M_{11} + P.z * M_{21} + T_Y\\
P'.z = P.x * M_{02} + P.y * M_{12} + P.z * M_{22} + T_Z\end{array})
可以考虑将矩阵变为
![](http://www.forkosh.com/mathtex.cgi? \begin{array}{l}
P'.x = P.x * M_{00} + P.y * M_{10} + P.z * M_{20} + M_{30}\\
P'.y = P.x * M_{01} + P.y * M_{11} + P.z * M_{21} + M_{31}\\
P'.z = P.x * M_{02} + P.y * M_{12} + P.z * M_{22} + M_{32}\end{array})
但是
![](http://www.forkosh.com/mathtex.cgi? \begin{array}{l}
P'.x = P.x * M_{00} + P.y * M_{10} + P.z * M_{20} + 1 * M_{30}\\
P'.y = P.x * M_{01} + P.y * M_{11} + P.z * M_{21} + 1 * M_{31}\\
P'.z = P.x * M_{02} + P.y * M_{12} + P.z * M_{22} + 1 * M_{32}\end{array})
由于第四个系数一直为1,并且不会随着转换发生改变,因此上面的公式可以简写为:
![](http://www.forkosh.com/mathtex.cgi? \begin{array}{l}
P'.x = P.x * M_{00} + P.y * M_{10} + P.z * M_{20} + M_{30}\\
P'.y = P.x * M_{01} + P.y * M_{11} + P.z * M_{21} + M_{31}\\
P'.z = P.x * M_{02} + P.y * M_{12} + P.z * M_{22} + M_{32}\end{array})
现在的转换矩阵是
对于在C++中的实现通常有2个学派,一些开发者选择在w’不为1的时候让x’,y’,z’都除以w’,以使w’的计算结果为1。如:
然而这种场景只在转换矩阵为投影矩阵时才有效(而且并不常见,特别是光线追踪),结果就是 99%的场景下计算和检验w’都是在浪费CPU资源。另一学派认为始终忽略w和w’,并且转换矩阵的第四列始终设置为(0,0,0,1),只有在处理特殊场景,如投影矩阵时,将点x’,y’,z’都除以w’。因此,你可以选择单一而未经优化的实现,或者可以按照具体场景,选择最优的实现。
在C++代码中:
点的转换 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]; }
相关文章推荐
- 将图像转换为特征向量Transforming Images to Feature Vectors
- Mathematics for 3D Game Programming and Computer Graphics - Transforming Normal Vectors
- Spark特征(提取,转换,选择)extracting, transforming and selecting features
- C++ vector 查找结构体向量变量(Vectors, structs and find)
- 2.2.4 Silhouette Enhancement (about transforming normal vectors) 轮廓增强(关于转换法向量)
- 特征值与特征向量的数值计算; Matrix Eigenvalues and Eigenvectors Calculating
- 【Geometry】Points, Vectors and Normals
- TensorFlow - 特征值与特征向量(Eigenvalues and eigenvectors)
- Rust - Arrays and Vectors | 数组和向量
- x264 编码器选项分析 (x264 Codec Strong and Weak Points) 2
- 温故而知新(二):”Using Flashback Database and Restore Points“ Translate & Notes
- 【POJ 1981 】Circle and Points
- 学习下c++中的向量(Vectors)
- 15.1 End points and reachability
- Extracting, transforming and selecting features - spark.ml
- 准备Mahout所用的向量ApplesToVectors
- x264 编码器选项分析 (x264 Codec Strong and Weak Points) 2
- x264 编码器选项分析 (x264 Codec Strong and Weak Points) 1
- MySQL Transactions, Part III - BDB Tables, Table locking and Savepoints
- Linear Algebra Review ---Vectors and Linear Combinations