在三维空间中进行纹理坐标的透视校正

13
我正在编写一个软件渲染器,目前已经工作良好,但我正在尝试获得纹理坐标的透视校正,但似乎不正确。我在我的渲染器中使用了与OpenGL相同的矩阵数学。为了光栅化三角形,我执行以下操作:
1. 使用模型视图和投影矩阵转换顶点,并转换为剪辑坐标。 2. 对于每个三角形中的每个像素,计算重心坐标以插值属性(颜色、纹理坐标、法线等)。 3. 为了进行透视校正插值,我使用透视校正插值公式: (w是顶点的深度坐标,c是顶点的纹理坐标,b是顶点的重心权重)
1/w = b0*(1/w0) + b1*(1/w1) + b2*(1/w2)
c/w = b0*(c0/w0) + b1*(c1/w1) + b2*(c2/w2)
c = (c/w)/(1/w)
这应该可以纠正透视,有一定帮助,但仍然存在明显的透视问题。我是否遗漏了某些内容,可能是四舍五入问题(我在所有数学计算中都使用浮点数)?
请查看此图像中沿对角线明显的纹理坐标错误,这是通过深度坐标进行除法运算的结果。

image showing incorrect perspective correction

另外,这通常用于纹理坐标...其他属性(如法线等)也需要吗?


1
屏幕截图可能会有帮助。 - genpfault
我必须获得10分的评分才能添加屏幕截图 :( - James Edge
4个回答

3

最近我破解了这个问题的代码。如果你计划在将纹理分配给表面之前修改内存中的纹理,则可以使用单应性变换。那会增加程序的计算负担并且需要额外的依赖项。有一种好的技巧可以解决这个问题。

OpenGL自动对渲染的纹理进行透视校正。你所需要做的是将平面每个角落的Z分量(XYZ位置向量的世界空间深度)与纹理坐标(UV-0.0f-1.0f)相乘,它会 “扰乱” OpenGL的透视校正。

我最近遇到并解决了这个问题。你可以试试这个链接:

在OpenGL中使用正方形纹理映射梯形

我阅读的那篇解决此问题的论文名为"Navigating Static Environments Using Image-Space Simplification and Morphing" - page 9 appendix A.。希望这能帮到你!

2
将UV坐标转换为3D平面的唯一正确方式是进行一个单应性变换。

http://en.wikipedia.org/wiki/Homography

你在计算中必须要有它。
如果想自己找到它,可以写出纹理中任意像素(与顶点相同)的投影,并将其反转以从屏幕坐标得到纹理坐标。这会以同质变换的形式呈现。

1

您需要告知OpenGL,在像素上需要进行透视校正。

glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)

你所观察到的是线性纹理映射的典型失真。在不支持每像素透视校正的硬件上(例如PS1),标准解决方案就是将多边形细分为更小的部分,以使缺陷不那么明显。

2
这是一个软件渲染器,不是OpenGL(可能是因为有人添加了那个标签)...但我在使用OpenGL数学库进行所有的变换。 - James Edge
抱歉...我看到OpenGL标签,所以假设你正在使用OpenGL(如果硬件无法提供某个功能,则应切换到软件渲染)。无论如何,您观察到的是所谓的“线性透视投影”问题,当您计算顶点的正确UV值但多边形渲染器在渲染多边形时线性插值它们时会发生这种情况。 - 6502

1

是的,那看起来像是传统的透视失真凹痕。不过你的算法看起来没问题,所以我真的不确定哪里出了问题。我建议你检查一下在渲染时是否确实使用了新计算出的值?这看起来就像你费尽心思计算了透视校正值,然后在渲染时使用了基本的非校正值。


仅从数字上看,已更正和未更正的纹理坐标之间的差异约为1.0e-4的数量级(纹理坐标在[0.0,1.0]范围内)。也许存在缩放问题?我是否正确地使用了剪辑深度坐标进行缩放? - James Edge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接