简体   繁体   English

顶点着色器或片段着色器中的OpenGL ES2.0 Lighting

[英]OpenGL ES2.0 Lighting in the vertex shader or fragment shader

I have seen many different tutorials on lighting in OpenGL ES2.0. 我看过许多关于OpenGL ES2.0中照明的教程。

Some use the vertex shader to do all the lighting and transforms and then just pass the final colour through the fragment shader. 有些人使用顶点着色器进行所有照明和变换,然后仅将最终颜色传递通过片段着色器。

Others pass the position and other variables from the vertex shader and then do all the lighting in the fragment shader. 其他的则从顶点着色器传递位置和其他变量,然后在片段着色器中进行所有照明。

From my experience i always thought lighting should be done in the fragment shader. 根据我的经验,我一直认为应该在片段着色器中进行照明。 Can anyone tell my why do one over the other? 谁能告诉我为什么要互相反对?

Traditional, fixed-pipeline OpenGL did lighting at the vertices and merely interpolated per fragment. 传统的固定流水线OpenGL在顶点处进行照明,并且仅对每个片段进行插值。 So it tended to show visible seaming along edges: 因此,它倾向于在边缘显示可见的接缝:

在此处输入图片说明

That was considered an acceptable compromise however, because lighting was too expensive to do per-pixel. 但是,这被认为是可以接受的折衷方案,因为照明过于昂贵,无法按像素进行照明。 Hardware is better now but lighting is still more expensive to do per pixel. 现在硬件更好,但每个像素的照明成本仍然更高 So I guess there's a potential argument there. 所以我想那儿有潜在的争论。 Also I guess if you were trying to emulate the old fixed pipeline you might deliberately do lighting inaccurately. 另外,我想如果您尝试模仿旧的固定管道,则可能会故意使照明不准确。

However I'm struggling to think of any particularly sophisticated algorithm that would be amenable. 但是,我正在努力思考任何可以接受的特别复杂的算法。 Is it possible that the examples you've seen are just doing things like figuring out the tangent and cotangent vectors per vertex, or some other similar expensive step, then interpolating those per pixel and doing the absolute final calculations in there? 您所看到的示例是否可能只是在做一些事情,例如找出每个顶点的切线和余切矢量,或其他类似的昂贵步骤,然后对每个像素进行插值并在那里进行绝对最终计算?

Lighting calculations can be fairly expensive. 照明计算可能会非常昂贵。 Since there are a lot more fragments than vertices while rendering a typical model, it's generally more efficient to do the lighting calculations in the vertex shader, and interpolate the results across the fragments. 由于在渲染典型模型时片段比顶点多得多,因此通常在顶点着色器中进行光照计算并在片段上进行插值会更有效。 Beyond the pure number of shader executions, performing typical lighting calculations in the fragment shader can also need more operations because interpolated normal need to be re-normalized, which requires relatively expensive sqrt operations. 除了纯粹的着色器执行次数以外,在片段着色器中执行典型的光照计算还可能需要更多操作,因为需要重新内插法线,这需要相对昂贵的sqrt操作。

The downside of per-vertex lighting is that it works poorly if the lighting values change quickly across a surface. 每顶点照明的缺点是,如果整个表面上的照明值快速变化,则效果不佳。 This makes perfect sense, because the values are interpolated linearly across triangles. 这是很合理的,因为这些值是在三角形之间线性插值的。 If the desired value does not change approximately linearly across the triangle, this will introduce artifacts. 如果所需值在整个三角形上没有近似线性变化,则将引入伪影。

The prototypical example are specular highlights. 原型示例是镜面反射高光。 If you define a shiny material with relatively sharp/small specular highlights, you can easily see the brightness of the highlight changing while the object is animated. 如果定义具有相对较亮/较小的镜面反射高光的发光材料,则在为对象设置动画时,可以轻松地看到高光的亮度发生变化。 It also looks like the highlight seems to "wander" around on the object. 看起来高光似乎在对象上“徘徊”。 For example, if you rotate a sphere with a specular highlight around its center, the highlight should stay exactly the same. 例如,如果旋转球面高光高光围绕其中心的球,则高光应保持完全相同。 But with per-vertex lighting, the brightness of the highlight will increase and decrease, and it will wobble slightly. 但是,使用逐顶点照明时,高光的亮度将增加和减少,并且会稍微摆动。

There's two main ways to avoid these effects, or at least reduce them to a level where they don't look disturbing anymore: 有两种主要方法可以避免这些影响,或者至少将它们减少到看起来不再造成干扰的程度:

  • Use per-fragment lighting. 使用每片段照明。
  • Use a finer tessellation for the geometry. 对几何图形使用更精细的细分。

Which solution is better needs to be decided case by case. 哪种解决方案更好,需要逐案确定。 Of course using a finer tessellation adds overhead on the geometry processing side, while using per-fragment lighting adds overhead in the fragment shader. 当然,使用更精细的细分会增加几何处理方面的开销,而使用每片段照明会增加片段着色器的开销。

Per-vertex lighting becomes even more problematic when you want to apply effects like bump mapping, where the lighting values change very quickly across the surface. 当您要应用凹凸贴图等效果时,逐顶点照明会变得更加棘手,因为凹凸值在整个曲面上变化非常快。 In those cases, there's almost no way around using per-fragment lighting. 在这种情况下,几乎没有办法使用每片段照明。

I have seen advice suggesting that GPUs were so fast now that per-vertex lighting should never be used anymore. 我看到的建议表明,GPU如此之快,以至于不再应该使用逐顶点照明。 I think that's a gross simplification. 我认为这是一个简单的简化。 Even if you can get the desired performance with per-fragment lighting, most computers/devices these days are battery powered. 即使您使用单片段照明可以获得理想的性能,但如今大多数计算机/设备都由电池供电。 To be power efficient, making your rendering as efficient as possible is as important as it ever was. 为了提高能效,使渲染尽可能高效与以往一样重要。 And I believe that there are still use cases where per-vertex lighting is the most efficient approach. 而且我认为,在某些情况下,逐顶点照明是最有效的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM