OpenGL ES 2.0中的非预定义多个光源

时间:2012-09-28 16:25:55

标签: opengl-es opengl-es-2.0 glsl

关于GLSL中有多个光源的文章很多 http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Multiple_Lights
但是着色器代码中描述的 light0 light1 参数,如果必须绘制闪光枪射击,例如每个闪光灯都有自己的位置,颜色并且必须照亮周围环境。我们如何管理其他对象着色器来处理未知(屏幕上最大耀斑的限制)位置,耀斑的颜色?例如,屏幕上会有8个最大耀斑,即使它们目前不存在,我必须通过8 * 2制服吗?
或者想象你制作水平编辑器,用户可以放置灯具,其他物体如何“知道”新光源并渲染,然后添加新灯? 我认为必须有一个聪明的解决方案,但我找不到一个。

1 个答案:

答案 0 :(得分:4)

照明方程通常依赖于加色。所以输出是光的颜色加上光的颜色2加上光的颜色三等等。

OpenGL提供的一种帧内缓冲混合模式是加性混合。因此,您绘制的任何新内容的颜色输出都将添加到缓冲区中已有的内容中。

因此,最天真的解决方案是将着色器编写为完成一个灯光。如果您有多个灯光,请多次绘制场景,每次使用不同的指定线条。这是multipass rendering的一个例子。

更好的解决方案包括编写着色器一次做两个,四个,八个或任何一个灯,比如说15个灯作为8个灯光抽取然后是4个灯光然后是2个灯光然后是1个灯光绘制,并且当您执行该过程时,仅包括每个灯光范围内的几何体。这往往意味着找到按地点分组灯光的智能方法。

编辑:稍微考虑一下,我应该补充说deferred shading中还有另一个选项,但由于输出缓冲区的选项有限,它目前在大多数GL ES设备上并不完全有用。

从理论上讲,您可以精确渲染几何体并存储每个像素所需的任何内容。因此,您不会只输出颜色,例如,输出三维空间中的位置,法线,漫反射颜色,镜面反射颜色和镜面反射指数。那些将全部在每像素缓冲区中。

然后你可以通过以下方式渲染每个光源:(i)计算投影到屏幕上时可以占用的最大可能空间(因此,直接与像素相关的2d矩形); (ii)将光线渲染为该尺寸的单个四边形,为每个像素从您刚刚设置的缓冲区读取相关值并输出适当亮度的颜色。

然后,您只需在场景中完成一次所有实际几何体,并且每个额外的光线最多只需要一个全屏四边形。

实际上你不能真的这样做,因为你倾向于在ES中使用的输出缓冲区提供的存储空间太小。但是你通常可以做的是渲染到带有附加深度缓冲区的32位颜色缓冲区。因此,您可以在深度缓冲区中存储深度,并从中加工出世界(x,y,z)以及光着色器中相机的[均匀]位置。您可以将8位版本的普通x和y存储在颜色缓冲区中,以便花费16位并在颜色缓冲区中计算出z,因为您知道法线始终是单位长度。然后,为了随机选择一个具体的例子,也许你可以在剩下的空间中存储一个16位版本的漫反射颜色,可能在YCrCb中存储Y的额外存储空间。

主要的缺点是,硬件抗锯齿不会因为与透明度和深度缓冲区有太多相同的问题。但是,如果你达到了大幅度节省光照的程度,那么通过渲染大型场景然后在最后一次传递中缩小它来进行手动抗锯齿可能仍然有意义。