“完成方式”是使用同质变换和坐标。你在空间中取一个点:
- 使用模型矩阵将其相对于相机定位。
- 使用投影矩阵进行正交投影或透视投影。
- 应用视口转换将其放置在屏幕上。
这变得非常模糊,但我会尝试涵盖重要的部分并将其中一些留给您。我假设您了解矩阵数学的基础知识:)。
同质向量、点、变换
在 3D 中,同质点是 [x, y, z, 1] 形式的列矩阵。最后一个组件是'w',一个比例因子,对于向量来说是0:这意味着你不能翻译向量,这在数学上是正确的。我们不会去那里,我们在谈论要点。
齐次变换是 4x4 矩阵,使用它们是因为它们允许将平移表示为矩阵乘法,而不是加法,这对您的视频卡来说既好又快。也很方便,因为我们可以通过将它们相乘来表示连续的变换。我们通过执行transformation * point来对点应用变换。
有 3 种主要的齐次变换:
还有其他值得探索的,特别是“看”转换。但是,我只想提供一个简短的列表和一些链接。应用于点的移动、缩放和旋转的连续应用统称为模型变换矩阵,并将它们相对于相机放置在场景中。重要的是要意识到我们所做的是类似于在相机周围移动物体,而不是相反。
正交和透视
要将世界坐标转换为屏幕坐标,您首先需要使用投影矩阵,它通常有两种形式:
- 正交,通常用于 2D 和 CAD。
- 透视,适合游戏和 3D 环境。
一个正交投影矩阵的构造如下:
其中参数包括:
-
Top:可见空间上边缘的 Y 坐标。
-
底部:可见空间底部边缘的 Y 坐标。
-
Left:可见空间左边缘的X坐标。
-
Right:可见空间右边缘的X坐标。
我认为这很简单。您建立的是一个将出现在屏幕上的空间区域,您可以对其进行剪辑。这里很简单,因为可见的空间区域是一个矩形。透视剪辑更复杂,因为出现在屏幕上的区域或查看体积是frustrum。
如果您对透视投影的维基百科有困难,这里是构建合适矩阵的代码,courtesy of geeks3D
void BuildPerspProjMat(float *m, float fov, float aspect,
float znear, float zfar)
{
float xymax = znear * tan(fov * PI_OVER_360);
float ymin = -xymax;
float xmin = -xymax;
float width = xymax - xmin;
float height = xymax - ymin;
float depth = zfar - znear;
float q = -(zfar + znear) / depth;
float qn = -2 * (zfar * znear) / depth;
float w = 2 * znear / width;
w = w / aspect;
float h = 2 * znear / height;
m[0] = w;
m[1] = 0;
m[2] = 0;
m[3] = 0;
m[4] = 0;
m[5] = h;
m[6] = 0;
m[7] = 0;
m[8] = 0;
m[9] = 0;
m[10] = q;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = qn;
m[15] = 0;
}
变量是:
-
fov:视野,pi/4 弧度是一个不错的值。
-
aspect:高宽比。
-
znear, zfar:用于裁剪,我将忽略这些。
并且生成的矩阵是column major,上面代码中的索引如下:
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
视口变换,屏幕坐标
这两种转换都需要另一个矩阵矩阵来将事物置于屏幕坐标中,称为视口转换。 That's described here, I won't cover it (it's dead simple).
因此,对于点 p,我们会:
- 执行模型变换矩阵 * p,得到 pm。
- 执行投影矩阵 * pm,得到 pp。
- 根据观看量裁剪 pp。
- 执行视口变换矩阵 * pp,得到 ps: 屏幕上的点。
总结
我希望能涵盖大部分内容。以上有漏洞,有些地方含糊不清,请在下面发布任何问题。这个主题通常值得在教科书中写一整章,我已尽力提炼这个过程,希望对您有所帮助!
我在上面链接到这个,但我强烈建议你阅读这个,并下载二进制文件。这是一个很好的工具,可以进一步了解这些转换以及它如何在屏幕上获得分数:
http://www.songho.ca/opengl/gl_transform.html
就实际工作而言,您需要实现一个 4x4 矩阵类以进行齐次变换,以及一个齐次点类,您可以对其进行乘法以应用变换(请记住,[x, y, z, 1]) .您需要按照上面和链接中的描述生成转换。一旦你了解了程序,这并不是那么困难。祝你好运:)。