我想"绕过"延迟照明的经典光量方法。
通常,如果要影响点光源体积内的像素,可以简单地渲染球体网格。
我想尝试另一种方法,这个想法是渲染一个包含球体的立方体,立方体与球体"外接",因此每个面的中心都是球体的点。然后,如果你渲染球体,你只需要从你的角度知道哪个片段会是圆(屏幕上的球体)的一部分。
因此,主要的问题是知道哪些片段将被丢弃。我怎么能做到:在片段着色器中,我有我的"摄影机"世界坐标、片段世界坐标、球体世界中心和球体半径。因此,我有一条直线,它的方向向量是由相机碎片世界点建模的。我可以建立我的球面方程。最后我可以知道这条线是否与球体相交。
从我的角度来看,如果直线与球体相交,那么这个片段必须被视为高亮片段(如果我渲染了一个球体,这个片段就会被渲染),这是正确的吗?
因此,检查"lenght(fragment-sphereCenter)<=sphereRadius"在这里并没有真正的意义,因为碎片不在球体上。
那又怎样?
灯光的标准延迟着色解决方案是渲染全屏四边形。渲染球体的目的是避免对光源效果之外的碎片进行大量的逐碎片计算。这意味着该球体的中心是光源,其半径表示光源具有效果的最大距离。
因此,从片段(也就是说,从g缓冲区数据重建,而不是立方体产生的片段)到球体中心的长度非常相关。这是碎片和光源之间的长度如果大于球体半径(AKA:光线的最大范围),则可以剔除碎片。
或者你可以让你的光衰减计算做同样的工作。毕竟,为了使灯光看起来不像是被裁剪的,球体半径必须也与某种形式的光衰减一起使用。也就是说,当碎片处于该距离时,光的衰减必须为0或以其他方式可忽略不计。
因此。。。渲染球体、立方体或全屏四边形都无关紧要。您可以剔除碎片,也可以让灯光衰减来完成它的工作。
但是,如果您想在读取任何g缓冲区之前丢弃片段来节省性能,您可以这样做。假设您可以访问FS:中球体/立方体中心的相机空间位置
-
将立方体碎片的位置转换为摄影机空间。可以通过反向变换
gl_FragCoord
来实现这一点,但只将摄影机空间位置传递给片段着色器可能会更快。这不像你的VS做了很多工作或其他什么。 -
因为摄影机空间位置在摄影机空间中,所以它已经表示了从摄影机到场景的方向。现在,使用此方向执行光线/球体相交的部分。也就是说,一旦计算出判别式,就停止(以避免昂贵的平方根)。判别式为:
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;
如果判别式为负,则丢弃该片段。否则,做你平常的事。