我正在尝试在基于libGDX的游戏上实现一个简单的2D光引擎。我们的想法是创建没有着色器的光引擎。我不打算暂时渲染任何阴影。 我设法渲染了一个带有三角形和渐变的光照贴图,但问题是当多个光源重叠时,我得到了一些像这样的图片中的人工制品:
黄色光源在与其他光源重叠时产生暗边框。
我使用以下混合函数来渲染灯光:
Gdx.gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE);
有没有办法摆脱这个黑暗的边界?
渐变从黄色变为黑色完全不透明度。由于GL_ONE
被认为是加性的,颜色应该只是变亮了吗?
更新1:
使用Nico Schertler解释的着色器肯定更好,但仍有一些我不确定的参数。
这是我想出的片段着色器
void main() {
float intensity = 0.02;
vec2 pos = vPosition;
float dist = distance(pos, u_origin) / u_radius;
vec4 color = vec4(intensity * (vColor.rgb / ((dist * dist) + 0.01)), 1);
gl_FragColor = color;
}
问题是我不确定常量intensity = 0.02
和0.01
我已添加到函数中以使其看起来不错。此外,半径变量现在是屏幕高度和宽度之间的最大值。
更新2:
我终于选择了以下等式:
void main() {
float dist = distance(vPosition, u_origin) / u_radius;
vec4 color = vec4((vColor.rgb) / (pow(dist, 2) + 0.01), vColor.a);
gl_FragColor = color;
}
然后基于相同的等式与遮挡图组合(以使非照明的地方变暗)。这是最终输出:
答案 0 :(得分:2)
这在很大程度上取决于你如何照亮灯光。
E.g。如果你使用一些截断的二次函数作为光的亮度(相对于距中心的距离),即类似的东西:
如果您添加两个灯光,您将获得此个人资料:
在此配置文件中,您会看到明显的不连续性。这种不连续性的原因是截断原始函数。所以你很可能在你的图像中有任何形式的截断光功能(无论是二次,线性还是其他),这会导致两个光交叉处的明亮区域。
那么如何解决这个问题?物理上正确的光分布随着二次距离而下降(在2D中你也可以争论线性衰减),x
是距光源的距离:
light = factor / x^2
此功能有两个问题。首先,它没有紧凑的支持。这意味着你必须绘制一个无限大的splat(或至少与屏幕一样大)。这可能不是一个大问题。一旦它变得非常小,你也可以切断它。第二个问题更严重。如果x
转到0
(即您直接位于灯光位置),则无法计算此值(它会趋于无穷大,因为所有光能都聚焦在没有区域的点上)。所以它真的取决于你想要用光照贴图做什么。当然,您可以采用类似于
light = factor / ((x)^2 + epsilon)
,其中epsilon
是一个非常小的数字。如果你的场景是从上面看的东西,这个epsilon可能是地面上光线的高度(平方)。然后,您将获得如下的个人资料:
Voila,没有不连续性。但是你很可能需要一个片段着色器来实现这一点。
如果你不关心身体的正确性,高斯啪啪也可能会给出漂亮的效果:
light = factor * exp(-x^2 / variance)