我正在尝试按照 SIGGRAPH 2013 中的 Epic 注释来实现区域灯。它们为我已经实现并且正在工作的管状区域灯提供了一种方法。现在我也在尝试实现矩形区域灯,采用与管灯类似的方法。
考虑到管灯只是一个矩形灯,总是对着边缘有两个半球的阴影点,所以我修改了 Epic 给出的最具代表性的点的计算。
这是计算 MRP 计算的输入数据的方式:
vec3 R = reflect(-viewDirection, normal);
vec3 P0 = LightPosition + LightLeft * -halfWidth;
vec3 P1 = LightPosition + LightLeft * halfWidth;
vec3 L0 = P0 - worldPosition;
vec3 L1 = P1 - worldPosition;
vec3 LightVector = GetRectangularLightLForSpecular(L0, L1, R, halfHeight, LightUp);
这是我修改后的计算 MRP 的函数:
vec3 GetRectangularLightLForSpecular(vec3 L0, vec3 L1, vec3 R, float halfHeight, vec3 up)
{
float distL0 = length(L0);
float distL1 = length(L1);
vec3 Ld = L1 - L0;
float RdotL0 = dot(R, L0);
float RdotLd = dot(R, Ld);
float L0dotLd = dot(L0, Ld);
float distLd = length(Ld);
float t = (RdotL0 * RdotLd - L0dotLd) / (distLd * distLd - RdotLd * RdotLd);
vec3 closestPoint = L0 + Ld * clamp(t, 0.0f, 1.0f);
vec3 centerToRay = dot(closestPoint, R) * R - closestPoint;
// This is where I made the change
// This is the original line of code from Epic's notes:
// closestPoint = closestPoint + centerToRay * clamp(radius / length(centerToRay), 0.0f, 1.0f);
// The following line is my version:
closestPoint = closestPoint + centerToRay * halfHeight;
return normalize(closestPoint);
}
正如您从这张图片中看到的那样,结果并不正确,因为平面 surgafe 上反射光的形状在每一端都有“帽子”。