我有一个简单的基于摄像头的“现代”OpenGL 3D图形显示,用于渲染相对简单的对象,这些对象是由指定的点、线和曲线(例如,立方体、圆柱体等)。绘制了三条不同颜色的固定长度的线,它们在世界空间的中心彼此相交,以直观地表示XYZ笛卡尔轴。用户可以通过鼠标控制来平移视图、旋转视图以及放大/缩小(通过鼠标滚轮移动)。
如果我尝试对轴的原点进行大量放大,使其能够在视觉上分离位于原点附近的一些非常接近的渲染点(例如,相距0.000001长度单位),则渲染精度会出现问题:
(1)三条轴线开始无法在同一点(原点)相交。两个轴相交,第三个轴线分别与这两条线中的每一条相交,离开原点一小段距离。第三轴的分离量随着观察旋转而略微变化。
与
(2)例如,旨在精确地位于其中一个轴上的点不再如此渲染,而是看起来稍微偏离轴线(点与轴的分离量再次随着观看旋转而变化)。
为了提高准确性,我已经从使用默认的“GLfloat”改为“GLdouble”,并修改了所有与模型几何相关的代码,例如指定顶点位置,距离等。以双精度(即,使用‘dvec 3’而不是默认的‘vec 3’等)。但这并没有什么区别。[注意:唯一继续使用GLfloat而不是GLdouble的项目是为渲染的点或线的颜色指定RGB值]
如何在极端放大到非常小的比例时保持渲染的准确性?
1条答案
按热度按时间mm9b1k5b1#
您必须仅使用两个远离原点的点(如(-1,0,0)和(1,0,0))来渲染直线。
当它们被投影到放大的视口上时(假设以S的比例),它们的浮点坐标变得非常大(S的数量级)。然后,光栅化器需要在将它们渲染到屏幕上时对其进行裁剪,其中视口内的坐标相对较小(<1)。这导致精度损失:由于线的端点不精确(舍入误差ε·S),因此视口内的内插结果将同样不精确(即最大ε·S偏离理论值)。
如果内部使用32位浮点数,我预计光栅化器的精度约为ε = 2−23 ≈ 0.0000001,这与您开始观察效果的尺度一致。请注意,它不受属性精度的影响,而是在光栅化器内部,并且可以在电路中很好地硬连线。
解决办法其实很简单。你所需要做的就是分割你的线,使它们显式地通过原点。即,将其呈现为两个片段:(-1,0,0)至(0,0,0)和(0,0,0)至(1,0,0)。这样,原点将被投影到其精确位置,并且视口外部端点的舍入误差对绘制线的其余部分的影响极小。