带阴影的聚光灯变为方形

时间:2015-06-15 22:31:09

标签: c++ opengl graphics shader shadow

我已经关注了OGLDev(part 1part 2)关于阴影映射的两部分教程,现在已经有几天了,我几乎已经完成了它的实施。

我的问题是,当我启用阴影贴图时,阴影出现的照明区域显示为" strip"我不确定这是否适用于教程。

也许图像有助于解释我的问题。 enter image description here

然而阴影功能正常: enter image description here

我的聚光灯顶点着色器:

#version 330

in vec2 textureCoordinate;
in vec4 vertex;

uniform mat4 mMatrix;
uniform mat4 pMatrix;
uniform mat4 vMatrix;
uniform mat4 lightV;
uniform mat4 lightP;
uniform vec3 normal;
uniform vec3 eye;

out vec2 TexCoord0;
out vec4 LightSpacePos;
out vec3 Normal0;
out vec3 WorldPos0;
out vec3 EyePos;

void main()
{   
    EyePos = eye;
    TexCoord0 = textureCoordinate;
    WorldPos0 = (mMatrix * vertex).xyz;
    Normal0 = (mMatrix * vec4(normal, 0.0)).xyz;   

    mat4 lightMVP = lightP * inverse(lightV) * mMatrix;
    LightSpacePos =  lightMVP * vertex; 

    mat4 worldMVP = pMatrix * vMatrix * mMatrix;
    gl_Position = worldMVP * vertex;
}

和片段着色器:

#version 330

struct BaseLight
{
    vec4 color;
    float intensity;
};

struct Attenuation
{
    float constant;
    float linear;
    float exponent;
};

struct PointLight
{
    BaseLight base;
    Attenuation atten;
    vec3 position;
    float range;
};

struct SpotLight
{
    struct PointLight base;
    vec3 direction;
    float cutoff;
};

in vec2 TexCoord0;
in vec3 WorldPos0;
in vec3 EyePos;
in vec4 LightSpacePos;
out vec4 fragColor;        
uniform sampler2D sampler;                        
uniform sampler2D shadowMap;                             

in vec3 Normal0;
uniform float specularIntensity;
uniform float specularPower;
uniform SpotLight spotLight;

float CalcShadowFactor(vec4 LightSpacePos)                                                  
{                                                                                           
    vec3 ProjCoords = LightSpacePos.xyz / LightSpacePos.w;                                  
    vec2 UVCoords;                                                                          
    UVCoords.x = 0.5 * ProjCoords.x + 0.5;                                                  
    UVCoords.y = 0.5 * ProjCoords.y + 0.5;                                                  
    float z = 0.5 * ProjCoords.z + 0.5;                                                     
    float Depth = texture(shadowMap, UVCoords).x;                                          
    if (Depth < z + 0.00001)                                                                 
        return 0.5;                                                                         
    else                                                                                    
        return 1.0;                                                                         
} 

vec4 CalcLightInternal(BaseLight Light, vec3 LightDirection, vec3 Normal, float ShadowFactor)                                                  
{                                                                                           
    vec4 AmbientColor = Light.color * Light.intensity;                   
    float DiffuseFactor = dot(Normal, -LightDirection);                                     

    vec4 DiffuseColor  = vec4(0, 0, 0, 0);                                                  
    vec4 SpecularColor = vec4(0, 0, 0, 0);                                                  

    if (DiffuseFactor > 0) {                                                                
        DiffuseColor = Light.color * Light.intensity * DiffuseFactor;    

        vec3 VertexToEye = normalize(EyePos - WorldPos0);                             
        vec3 LightReflect = normalize(reflect(LightDirection, Normal));                     
        float SpecularFactor = dot(VertexToEye, LightReflect);                              
        SpecularFactor = pow(SpecularFactor, specularPower);                               
        if (SpecularFactor > 0) {                                                           
            SpecularColor = Light.color * specularIntensity * SpecularFactor;                         
        }                                                                                   
    }                                                                                       

    return (AmbientColor + ShadowFactor * (DiffuseColor + SpecularColor));                  
}   

vec4 CalcPointLight(PointLight l, vec3 Normal, vec4 LightSpacePos)                   
{                                                                                           
    vec3 LightDirection = WorldPos0 - l.position;                                           
    float Distance = length(LightDirection);                                                
    LightDirection = normalize(LightDirection);                                             
    float ShadowFactor = CalcShadowFactor(LightSpacePos);                                   

    vec4 Color = CalcLightInternal(l.base, LightDirection, Normal, ShadowFactor);           
    float Attenuation =  l.atten.constant +                                                 
                         l.atten.linear * Distance +                                        
                         l.atten.exponent * Distance * Distance;                                 

    return Color / Attenuation;                                                             
}   

vec4 CalcSpotLight(SpotLight l, vec3 Normal, vec4 LightSpacePos)                     
{                                                                                           
    vec3 LightToPixel = normalize(WorldPos0 - l.base.position);                             
    float SpotFactor = dot(LightToPixel, l.direction);                                      

    if (SpotFactor > l.cutoff) {                                                            
        vec4 Color = CalcPointLight(l.base, Normal, LightSpacePos);                         
        return Color * (1.0 - (1.0 - SpotFactor) * 1.0/(1.0 - l.cutoff));                   
    }                                                                                       
    else {                                                                                  
        return vec4(0,0,0,0);                                                               
    }                                                                                       
}

void main(void)
{       
    fragColor = texture2D(sampler, TexCoord0.xy) * CalcSpotLight(spotLight, normalize(Normal0), LightSpacePos);
}

1 个答案:

答案 0 :(得分:2)

这是有意的。由于阴影贴图覆盖了太空中的金字塔状区域,因此聚光灯的锥体可能会被遮挡。这种情况正在发生,因为在渲染阴影摄像机视图之外的东西时,它将被视为未点亮。因此,阴影相机的视图金字塔将是可见的。

enter image description here
src

要解决此问题,您需要 2个选项

1:使阴影贴图相机的fov更大,使阴影相机的金字塔变得比聚光灯的锥体更宽

2:更改在越界区域计算阴影的方式。目前,当您对阴影贴图进行采样时,如果它位于阴影纹理之外,则会在其中应用阴影。如果你改变这个,那么如果你认为它被点燃的阴影纹理之外,这个问题就会消失。

修改: 我推荐第二种选择。解决方案可能是: 在float Depth = ...部分

之前将以下行插入FragmentShader :: CalcShadowFactor()
if (UVCoords.x < 0.0 || UVCoords.x > 1.0 || UVCoords.y < 0.0 || UVCoords.y > 1.0) return 1.0;

注意: 没有通用的方法可以说哪个更好。在涉及阳光的地形环境中,您可能希望将越界区域视为 litten 。但是,当您使用手电筒时,您必须将越界区域视为 unlitten