由于Minecraft从1.14开始,可能是由于环境光遮蔽实现方式的改变,完整发光方块周围的天空光照会降低(参见MC-161150),导致一众光影在这类方块周围的露天判断异常(比如雨天积水效果在这类方块周围不渲染)

我尝试写一个Shader算法来修复这个问题,原理是完整发光方块周围环境光遮蔽导致的天空亮度的变化随世界空间内坐标变动的变化率远高于正常的天空光照降低,然后利用这个变化率去提升输出到gbuffer缓冲区里的天空光照数值,以达到修正天空光照的目的。
目前这个算法已经有了基本的框架,能在一些情况下正常运作,但是仍然存在不少问题,故发到这里看看有没有人能帮忙完善一下。
目前的算法代码如下:
- /*========= 顶点着色器的输入 =========*/
- blockLight=gl_MultiTexCoord1.xy/255.;
- worldNormal=gl_Normal;
- viewPos=gl_ModelViewMatrix*gl_Vertex;
- gl_Position=gl_ProjectionMatrix*viewPos;
- depth=gl_Position.z;
- screenspace=gl_Position.xy;
- /*========= 片元着色器内代码 =========*/
- vec3 worldPos = (gbufferModelViewInverse * vec4(viewPos.xyz, 0.0)).xyz;
- vec3 worldDir = normalize(worldPos);
- float NdotV = dot(worldDir, -worldNormal);
- #ifdef SKYLIGHT_FIX
- /*======= 算法主部分 =======*/
- vec2 dSkyLight = abs(vec2(dFdx(blockLight.y), dFdy(blockLight.y)));
- vec2 dWorldPos = vec2(length(dFdx(worldPos)),length(dFdy(worldPos)));
- dSkyLight /= dWorldPos;
- //注:我个人认为理论上这个就足够解决了,不知道为什么会在视角边缘产生变化
- /*===== 视角边缘拉伸修正 =====*/
- float FOV = length(dWorldPos) * NdotV / depth; //通过屏幕空间内坐标的变化与某FOV下的理论值比较获取FOV,在视角边缘会发生变化
- float edgeFix = 1.0 + abs(screenspace.x) * 200.0 * FOV;
- /*====== 修正天空光照 ======*/
- float dLight = clamp(max(dSkyLight.x, dSkyLight.y) - 0.064, 0.0, 1.0) * edgeFix * 3.6; //-0.064是为了删去天空光照正常消减的影响
- mcLightmap.y = clamp(mcLightmap.y + mcLightmap.y * dLight, 0.0, 1.0); //mcLightmap已经预先用blockLight赋值
- #endif
目前存在的问题:
1、视角边缘的拉伸修正只是我硬凑各种公式凑出的一个还勉强能用的计算式,需要一个更精确的计算式。目前的计算式仅能保证30-110的游戏正常FOV调节范围内工作正常,在110的FOV下喝下迅捷药水会发现视角边缘仍然有异常;(注意图片左侧视角边缘)

2、一条直线上相邻1的两个完整发光方块之间不工作;

3、靠近室外部分的室内完整发光方块也会受到影响(考虑到我这个算法的本质,这点可能比较难修复)

当然如果有人能写出一个更好更完美的算法的话那自然是最好的,不过目前我是没什么思路了