如何使用OpenGL以特定顺序绘制贴花?

3
为了绘制贴花,我目前使用glPolygonOffset(-1,-1),这可以通过欺骗深度缓冲器中的值来消除一些丑陋的z-fighting现象,使得绘制的贴花的多边形看起来更接近于相机。我还以为可以使用不同的参数来使用glPolygonOffset将贴花相对排序,但这似乎根据摄像机的角度调整,因此当我移动相机时,整个贴花会相互交换顺序。
另一个我尝试过的方法在这个文件中:"Making Decals"
  1. 禁用深度缓冲器的写入,并渲染A。
  2. 启用深度缓冲器的写入,并渲染B。
  3. 再次禁用颜色缓冲器的写入,并渲染A。
  4. 启用颜色缓冲器的写入。
这是我的尝试,但我真的不明白如何将其扩展到相对绘制贴花的顺序上,因为贴花是在启用深度缓冲器写入时绘制的,那我不只会得到更多的z fighting吗?
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  
glEnable(GL_BLEND);

//Render a red solid quad on the color mask
glDepthMask(false);
glColor3f (1.0f, 0.0f, 0.0f);
glBegin (GL_QUADS);
    glVertex2f(-1,-1);
    glVertex2f(-1,1);
    glVertex2f(1,1);
    glVertex2f(1,-1);
glEnd ();

//Render the coincident decal, a transparent square works fine for now
glDepthMask(true);
glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
glTranslatef(0, 1, 0.0f);
glScalef(0.5f, 0.5f, 0.5f);
glBegin (GL_QUADS);
    glVertex2f(-1,-1);
    glVertex2f(-1,1);
    glVertex2f(1,1);
    glVertex2f(1,-1);
glEnd ();

//Render the red quad again but only on the depth buffer
glColorMask(false, false, false, false);
glLoadIdentity();
glColor3f(1.0f, 0.0f, 0.0f);
glBegin (GL_QUADS);
    glVertex2f(-1,-1);
    glVertex2f(-1,1);
    glVertex2f(1,1);
    glVertex2f(1,-1);
glEnd ();
glColorMask(true, true, true, true);

许多游戏中似乎都会这样做,所以我相信有更好的解决方案,但是我已经进行了大量搜索,没有找到任何有关在OpenGL中类似于这样排序贴花的教程。也许我的搜索术语不正确?这个过程还有其他的称呼吗?

1个回答

2
使用您建议的 glPolygonOffset 并按顺序渲染物体很可能比其他选项性能更好,因为这应该充分利用GPU中的“早期Z”优化。您可以尝试将更大的数字传递给 glPolygonOffset,例如对于第一张贴花 (-4, -4),第二张为 (-8, -8),等等--这不是精确的科学;当然,在您的 glPolygonOffset 变得如此大到超过它所需时,还有绘制图案的限制。
关于相机角度问题: glPolygonOffsetfactor 参数应该为高角度多边形添加额外的调整。
另一种方法是:
  • 正常渲染所有常规几何体
  • 禁用深度写入(但保留深度测试)
  • glPolygonOffset(-1,-1)
  • 依次从后向前绘制所有贴花
还有另一种可能更高效的方法:
  • 在帧开始时将模板缓冲区清零(与清除其他缓冲区同时进行)
  • 正常渲染所有常规几何体
  • 禁用深度写入(但保留深度测试)
  • glPolygonOffset(-1,-1)
  • glStencilFunc(GL_NOTEQUAL, 1, 1)glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
  • 依次从前向后绘制所有贴花

关于您列出的第一种(4点)方法:启用深度测试不会导致贴花之间的z-fighting,从而使渲染顺序无关紧要吗?或者我对深度测试的工作方式有误解吗? - Lockyer
我无法通过使用更大的值来使glPolygon偏移正常工作,我不知道它使用什么方程来处理高度倾斜的多边形,但我认为它并不是真的打算以那种方式堆叠。在进一步思考您发布的(4点)方法后,我认为它有潜力可以使用。我会尝试并将结果发布在这里。 - Lockyer
@Lockyer 深度测试和深度写入是单独的启用项。如果只启用了深度测试,则遮挡像素仍将被丢弃(这是我们想要的),但z缓冲区不会更新,因此您将无法在后续贴花中获得z-fighting。 - dave
@Lockyer glPolygonOffset 应该是“可堆叠”的:请参见例如 http://www.idevgames.com/forums/thread-5474.html。可能是您的 GPU/驱动程序实现有问题。 - dave
感谢您的详细解释,Dave。我现在明白它在做什么了,并且在我的测试中它完美地工作了。是的,奇怪的是,对于我来说堆叠“glPolygonOffset”并没有起作用,我正在运行ATI Radeon HD 4670。但是,我认为您的(4点)方法更加灵活。 - Lockyer

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