绕过经典的延迟着色光体积

Bypass classical deferred shading light volumes

我想"bypass"延迟照明的经典光体积方法。

通常,当您想要影响点光源体积内的像素时,您可以简单地渲染一个球体网格。

我想尝试另一种方法来做到这一点,我的想法是渲染一个包含球体的立方体,立方体 "circumscribes" 到球体,因此每个面的中心都是球体的点。然后,如果您改为渲染球体,您只需从您的角度知道哪个片段将成为圆(屏幕上的球体)的一部分。

所以主要的问题是要知道哪个片段必须被丢弃。 我该怎么做: 在片段着色器中,我有 "camera" 世界坐标、片段世界坐标、球体世界中心和球体半径。 因此,我有一条直线,其方向矢量由相机片段世界点建模。 我可以建立我的球体方程。 终于知道直线是否与球体相交了

这样说是正确的,从我的角度,如果直线与球体相交,那么这个片段必须被视为高亮片段(一个片段会如果我渲染了一个球体,就已经被渲染了)?

Thus the check "lenght(fragment - sphereCenter) <= sphereRadius" doesn't really mean something here because the fragment is not on the sphere.

那又怎样?

灯光的标准延迟着色解决方案是渲染全屏四边形。渲染球体的目的是避免对光源效果之外的片段进行大量的逐片段计算。这意味着那个球体的中心是光源,它的半径代表光源产生影响的最大距离。

因此从片段(即,从您的 g 缓冲区数据重建,而不是立方体产生的片段)到球体中心的长度非常相关。那是片段和 光源之间的长度。 如果它大于球体半径(又名:光的最大范围),那么你可以剔除片段。

或者您可以让光衰减计算完成相同的工作。毕竟,为了让灯光看起来不像被裁剪过,球体半径必须 与某种形式的光衰减一起使用。也就是说,当片段在该距离时,光的衰减必须为 0 或小到可以忽略不计。

因此...渲染球体、立方体或全屏四边形并不重要。您可以剔除片段或让光衰减发挥作用。


但是,如果您希望通过在读取任何 g 缓冲区之前丢弃该片段来节省性能,您可以这样做。假设您可以访问 FS 中 sphere/cube 中心的 camera-space 位置:

  1. 将立方体碎片的位置转换为camera-space。您可以通过反向转换 gl_FragCoord 来做到这一点,但将 camera-space 位置传递给片段着色器可能会更快。这不像你的 VS 正在做很多工作或任何事情。

  2. 因为camera-space位置在cameraspace中,已经代表了从camera进入场景的一个方向。所以现在,使用这个方向来执行 part of ray/sphere 交集。也就是说,一旦计算出判别式就停止(以避免昂贵的平方根)。判别式为:

    float A = dot(cam_position, cam_position);
    float B = -2 * (dot(cam_position, cam_sphere_center);
    float C = (dot(cam_sphere_center, cam_sphere_center)) - (radius * radius)
    float Discriminant = (B * B) - 4 * A * C;
    

    如果判别式为负,则丢弃片段。否则,做你平常的事情。