OpenGL ES2.0在顶点着色器或片段着色器中进行照明

时间:2014-08-20 22:37:47

标签: android opengl-es opengl-es-2.0 lighting

我在OpenGL ES2.0中看到了许多关于光照的不同教程。

有些人使用顶点着色器进行所有光照和变换,然后只通过片段着色器传递最终颜色。

其他人从顶点着色器传递位置和其他变量,然后在片段着色器中执行所有光照。

根据我的经验,我一直认为应该在片段着色器中完成照明。任何人都可以告诉我为什么一个在另一个上面?

2 个答案:

答案 0 :(得分:3)

传统的固定管道OpenGL在顶点处进行照明,并且仅对每个片段进行插值。所以它倾向于沿边缘显示可见的接缝:

enter image description here

然而,这被认为是一种可接受的折衷方案,因为每个像素的光照度太高太昂贵了。硬件现在更好,但每个像素的照明仍然是更多。所以我猜那里有潜在的争论。另外我想如果你试图模仿旧的固定管道,你可能会故意不准确地点亮。

然而,我很难想到任何特别复杂的算法。您所看到的示例是否可能只是执行诸如计算每个顶点的切线和余切矢量或其他类似的昂贵步骤,然后插入每个像素并在那里进行绝对最终计算?

答案 1 :(得分:2)

照明计算可能相当昂贵。由于在渲染典型模型时存在比顶点多得多的碎片,因此在顶点着色器中进行光照计算通常更有效,并在片段之间插入结果。除了纯粹的着色器执行次数之外,在片段着色器中执行典型的光照计算也需要更多操作,因为内插法线需要重新规范化,这需要相对昂贵的sqrt操作。

每顶点照明的缺点是,如果照明值在表面上快速变化,它的效果很差。这非常有意义,因为这些值是跨三角形线性插值的。如果所需的值在三角形上没有近似线性变化,则会引入伪影。

典型的例子是镜面高光。如果定义具有相对清晰/小镜面高光的闪亮材质,则可以在对象设置动画时轻松查看高光的亮度变化。看起来高亮似乎在对象上“徘徊”。例如,如果围绕其中心旋转具有镜面高光的球体,则高光应保持完全相同。但是对于每顶点照明,高光的亮度会增加和减少,并且会略微抖动。

有两种主要方法可以避免这些影响,或者至少将它们降低到不再令人不安的程度:

  • 使用每片段照明。
  • 为几何体使用更精细的镶嵌细分。

哪种解决方案更好需要逐案决定。当然,使用更精细的镶嵌会增加几何处理方面的开销,而使用每个片段的光照会增加片段着色器的开销。

当你想要应用像凹凸贴图这样的效果时,每顶点光照变得更加成问题,其中光照值在表面上变化非常快。在这些情况下,几乎没有办法使用每片段照明。

我已经看到建议GPU现在如此之快以至于不再使用每顶点照明。我认为这是一个严格的简化。即使您可以使用每片段照明获得所需的性能,如今大多数计算机/设备都是电池供电的。为了提高功效,尽可能提高渲染效率与以往一样重要。我相信仍有一些用例,每顶点照明是最有效的方法。