OpenGL中的齐次坐标

偶然看到WikiBook上的OpenGL教程中的第一个例程给出使用openGL在显示器上画出三角形的例子:

https://gitlab.com/wikibooks-opengl/modern-tutorials/blob/master/tut01_intro-sdl2/triangle.cpp

这个例程几乎是所有OpenGL教程的Hellow World。然而,几乎所有的教程都会忽略一个非常重要的细节——即,在OpenGL中究竟是如何表示顶点坐标的。比如,上面的这段程序中,定义三角形顶点坐标的代码有两处:

第一处非常直观,在render函数中,该程序定义了在平面坐标系上的三个点:

GLfloat triangle_vertices[] = {
    0.0,  0.8,
   -0.8, -0.8,
    0.8, -0.8,
};

如果将这三个点在平面直角坐标系画出来的话,应该是这样的:

2d-triangle

另一处,这些顶点的坐标在Vertex Shader之中进行了变换:

const GLchar* vs_sources[] = {
	version,
	"attribute vec2 coord2d;                  "
	"void main(void) {                        "
	"  gl_Position = vec4(coord2d, 0.0, 1.0); "
	"}"
};

对于每一个代入到该Shader Kernel的顶点,这个计算会将二维坐标转变为一个三维空间中的齐次坐标。中文的解释非常难懂,所以,这里给出英文链接。简而言之,一个三维空间中的点,用直角坐标系表示时,这个点是一个有三个元素的向量:

\begin{bmatrix}  x \\ y \\ z  \end{bmatrix}

但是,使用齐次坐标之后,三维空间中的点需要用含有四个元素的向量表示:

\begin{bmatrix}  x\\   y\\   z\\   W  \end{bmatrix}

在齐次坐标中,如果两个坐标成比例,那么这两个坐标表示的就是同一个点;例如,(1, 2, 3, 0.5)(2, 4, 6, 1)表示的是同一个点。在这种情况下,坐标(0, 0, 0)是原点,且唯一。

当读到这段代码的时候,不禁要问,为什么在Vertext Shader中要采用如此多次一举的方式表达一个三维空间中的点?直接使用直角坐标系的(x, y, z)不是更直观吗?

之所以在图形计算中使用齐次坐标而不是直角坐标的原因在于——为了简化计算!在未加入这第四维时,三维的图形变化用矩阵表示如下:

{P}' = T + P
{P}' = S \cdot P
{P}' = R \cdot P

其中TSR分别代表平移、缩放和旋转操作。但是,这三个操作之中缩放和旋转都是矩阵乘法,仅有平移操作是加法。如果这些变换不能被统一成为同一种运算的话,用来专门做图形计算的硬件的设计复杂度就会大大增加。数学先贤们想出来的办法就是给坐标加一个维度,将以上三个操作全部统一成矩阵乘法。具体如何?Google一下就知道啦!这里是斯坦福给大答案

发表评论