从本质上讲,我们在这个问题上有三个重要的坐标系:
我们有通常的3D世界坐标系,可以任意定义。我们有一个飞机的2D坐标系。该坐标系的原点位于飞机的中心(请注意,我使用的是该术语 平面 同义词 长方形 为此目的),坐标范围从-1到+1。最后,我们有一个图像的2D坐标。实际上,我们有两个用于图像:无符号坐标系(如图所示),原点位于左下角,坐标范围为0到1,有符号坐标系的坐标范围为-1到1。
我们知道世界空间中平面的四个角和3x4视图/投影矩阵 P 这允许我们使用齐次坐标将世界空间中的任何点投影到图像空间:
P
p_image,signed = P * p_world
如果您的投影矩阵是4x4,则只需删除第三行(最后但是1),因为我们对图像空间深度不感兴趣。
我们并不真正关心世界空间,因为这有点武断。给定平面空间中的2D点,我们可以使用以下方法将其转换为世界空间:
p_world = 1/4 (p0 + p1 + p2 + p3) + u * 1/2 * (p1 - p0) + v * 1/2 * (p3 - p0)
第一部分是平面的原点,第二和第三项的点差是坐标轴。我们可以用矩阵形式表示
/ x \ / p1_x - p0_x p2_x - p0_x 1/4 (p0_x + p1_x + p2_x + p3_x) \ / u \ | y | = | p1_y - p0_y p2_x - p0_x 1/4 (p0_y + p1_y + p2_y + p3_y) | * | v | | z | | p1_z - p0_z p2_x - p0_x 1/4 (p0_z + p1_z + p2_z + p3_z) | \ 1 / \ 1 / \ 0 0 1 /
我们称之为矩阵 M 。
M
现在,我们可以直接从平面空间到图像空间:
p_image,signed = P * M * p_plane
矩阵 P * M 现在是3x3矩阵。它是地平面和图像平面之间的单应性。
P * M
那么,我们可以用它做什么呢?我们可以用它在平面空间中绘制图像。那么,这就是我们要做的事情:
我们将生成一个渲染目标,我们将使用单个绘制调用来填充。然后,此渲染目标将包含我们平面的纹理。为了得到这个,我们:
(-1, -1), (1, -1), (1, 1), (-1, 1)
有趣的部分是4号。我们几乎知道我们需要做什么。我们已经知道如何去签名的图像空间。现在,我们只需要转到无符号图像空间。这是一个简单的转变和规模:
/ 1/2 0 1/2 \ p_image,unsigned = | 0 1/2 1/2 | * p_image,signed \ 0 0 1 /
如果我们称这个矩阵 S ,我们可以计算出来 S * P * M 得到一个3x3矩阵 T 。此矩阵可用于顶点着色器,以根据传入的平面空间点计算纹理坐标:
S
S * P * M
T
texCoords = p_image,unsigned = T * p_plane
将整个3D矢量传递给片段着色器并仅在像素着色器中进行透视分割以生成正确的透视图非常重要。