物体投射的阴影确实远离光源

时间:2019-03-11 13:27:35

标签: opengl shadow

我遇到一个问题,即物体所投射的阴影确实远离光源。我正在使用深度图方法在太阳系仿真中渲染阴影。太阳是点光源,我想观察月球在地球上的阴影。但是由于相对于月亮与太阳之间的距离而言,月亮是一个非常小的物体,并且由于深度图的分辨率受到限制,因此在渲染深度立方体图纹理时,会忽略月亮和地球的存在。

太阳能系统深度图:

enter image description here

您可以看到,即使月亮的大小被夸大了,它在深度立方体图上也只留下了很小的足迹。在月球如此大的情况下,日食确实起作用,但是一旦我将月球缩小到其实际大小,就不再在深度图中进行渲染,因此不再将其用于阴影计算。我正在使用4096 X 4096纹理。有没有办法解决这个问题,还是我的方法注定要失败?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

有一个至关重要的发现:当您抬头近地时,您可能根本不在乎火星上的阴影。因此,不要使用立方体贴图对整个太阳系进行阴影贴图,而应使用平面阴影贴图仅覆盖近地区域。

使用4096x4096深度图,到月球的距离为384000 km,您可以获得每个texel约100km的分辨率,并且月亮在阴影图上将占据半径约20 texels的圆盘。

但是,有一种更好的方法。由于行星和卫星大约是球形的,并且只有少数几个,因此您可以简单地对每个片段进行射线-球形相交以计算阴影。可以计算月亮和太阳圆盘之间的交点的角区域,以获得实时的本影/半影渲染。这是一个近似着色器中阴影因子的函数:

float soft_shadow(vec3 light, float light_radius,
    vec3 occluder, float occluder_radius, vec3 fragment)
{
    vec3 v0 = light - fragment;
    vec3 v1 = occluder - fragment;

    float R0 = length(v0);
    float R1 = length(v1);

    float a0 = light_radius/R0;
    float a1 = occluder_radius/R1;

    float a = length(cross(v0, v1))/(R0*R1);
    a = smoothstep(a0 - a1, a0 + a1, a);
    return 1 - (1 - a)*pow(a1/a0, 2);
}

这里0.0表示完整阴影,1.0表示完全没有阴影。 lightoccluderfragment是太阳,月亮和碎片在非投影空间中的位置,而light_radius和{ occluder_radius是太阳和月亮的半径。

对于实际尺寸,此代码为我提供了这些图像:

如果我将太阳的大小减半,我会得到: