为什么我的片段着色器水平投射长阴影而垂直投射短阴影?

Why is my frag shader casting long shadows horizontally and short shadows vertically?

我有以下片段着色器:

#version 330

layout(location=0) out vec4 frag_colour;

in vec2 texelCoords;

uniform sampler2D uTexture;                 // the color
uniform sampler2D uTextureHeightmap;        // the heightmap
uniform float uSunDistance = -10000000.0;   // really far away vertically
uniform float uSunInclination;              // height from the heightmap plane
uniform float uSunAzimuth;                  // clockwise rotation point
uniform float uQuality;                     // used to determine number of steps and steps size
void main()
{
    vec4 c = texture(uTexture,texelCoords);

    vec2 textureD = textureSize(uTexture,0);
    float d = max(textureD.x,textureD.y);       // use the largest dimension to determine stepsize etc

    // position the sun in the centre of the screen and convert from spherical to cartesian coordinates
    vec3 sunPosition = vec3(textureD.x/2,textureD.y/2,0) + vec3(    uSunDistance*sin(uSunInclination)*cos(uSunAzimuth),
                                                                    uSunDistance*sin(uSunInclination)*sin(uSunAzimuth),
                                                                    uSunDistance*cos(uSunInclination)   );

    float height = texture2D(uTextureHeightmap, texelCoords).r;         // starting height
    vec3 direction = normalize(vec3(texelCoords,height) - sunPosition); // sunlight direction

    float sampleDistance = 0;
    float samples = d*uQuality;
    float stepSize = 1.0 / ((samples/d) * d);

    for(int i = 0; i < samples; i++)
    {
        sampleDistance += stepSize; // increase the sample distance

        vec3 newPoint = vec3(texelCoords,height) + direction * sampleDistance; // get the coord for the next sample point

        float newHeight = texture2D(uTextureHeightmap,newPoint.xy).r;   // get the height of that sample point

        // put it in shadow if we hit something that is higher than our starting point AND is heigher than the ray we're casting
        if(newHeight > height && newHeight > newPoint.z)    
        {
            c *= 0.5;
            break;
        }
    }

    frag_colour = c;
}

目的是根据高度图投射阴影。非常漂亮,结果看起来不错。

但是,存在一个问题,即阴影在水平方向比垂直方向显得更长。如果我使 window 尺寸不同,window 高比宽,我会得到相反的效果。即,阴影在更长的维度上投射的时间更长。

这告诉我这与我在上述着色器中的步进方式有关,但我不能说出问题。

为了说明,这里有一个 uSunAzimuth 会产生水平投射的阴影:

下面是完全相同的代码,其中 uSunAzimuth 用于垂直阴影:

它在这些低分辨率图像中不是很明显,但在较大的分辨率中效果会变得更加夸张。本质上;当您测量它如何在所有 360 度方位角上投射时,阴影会清除椭圆而不是圆形。

我只是需要稍微调整一下方向。

float aspectCorrection = textureD.x / textureD.y;
...
vec3 direction = normalize(vec3(texelCoords,height) - sunPosition);
direction.y *= aspectCorrection;

阴影片段着色器在视口的 "snapshot" 上运行。渲染场景并生成此 "snapshot" 时,顶点位置将由投影矩阵转换。投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射,并考虑了视口的纵横比。
(参见
).

这会导致高图 (uTextureHeightmap) 表示一个矩形视场,具体取决于纵横比。
但是用于访问高度贴图的纹理坐标描述了范围为 (0, 0) 到 (1, 1) 的四边形。
这种不匹配必须通过缩放纵横比来平衡。

vec3 direction = ....;

float aspectRatio = textureD.x / textureD.y;
direction.xy *= vec2( 1.0/aspectRatio, 1.0 );