为什么我的frag着色器水平投影长阴影和垂直短阴影?

时间:2017-09-14 09:54:40

标签: opengl glsl orthographic shadow-mapping

我有以下片段着色器:

#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;
}

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

但是,与垂直相比,阴影在水平时显得更长。如果我使窗口大小不同,窗口高于宽,我会得到相反的效果。即,阴影在较长的维度上投射更长。

这告诉我这与我踩到上面着色器的方式有关,但我不能说出问题。

为了说明,这里是uSunAzimuth导致水平投射阴影:

enter image description here

以下是与垂直阴影uSunAzimuth完全相同的代码:

enter image description here

在这些低分辨率图像中并不是很明显,但在较大的分辨率下,效果会更加夸张。实质上;当你测量它在360度方位角上投射的方式时,阴影会清除椭圆而不是圆形。

2 个答案:

答案 0 :(得分:1)

我只需稍微调整方向。

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

答案 1 :(得分:1)

阴影片段着色器在视口的“快照”上运行。渲染场景并生成此“快照”时,顶点位置将由投影矩阵变换。投影矩阵描述了从场景的3D点到视口的2D点的映射,并考虑了视口的纵横比。
(见Both depth buffer and triangle face orientation are reversed in OpenGL
Transform the modelMatrix)。

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

vec3 direction = ....;

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