【问题标题】:GLSL 330 Point-Light and Shadow map wierdnessGLSL 330 点光和阴影贴图怪异
【发布时间】:2016-11-26 14:13:28
【问题描述】:

我有一个片段着色器,可以计算方向光、点光源和聚光灯。没有阴影贴图,这工作正常。奇怪的是,在添加了阴影贴图(sampler2D)之后,点光源是如何踩踏阴影的。这是我的片段着色器:(跳到底部查看 cmets 了解详情)

#version 330 core

const int MAX_POINT_LIGHTS = 4;
const int MAX_SPOT_LIGHTS = 4;

in vec2 TexCoord0;
in vec3 WorldNormal0;
in vec3 WorldPos0;
in vec4 LightSpacePos0;
in vec3 Tangent0;

out vec4 FragmentColor;

struct BaseLight
{
    vec3 Color;
    float AmbientIntensity;
    float DiffuseIntensity;
};

struct DirectionalLight
{
    BaseLight Base;
    vec3 Direction;
};

struct Attenuation
{
    float Constant;
    float Linear;
    float Exp;
};

struct PointLight
{
    BaseLight Base;
    vec3 Position;
    Attenuation Atten;
};

struct SpotLight
{
    PointLight Base;
    vec3 Direction;
    float Cutoff;
};

uniform int gNumPointLights;
uniform int gNumSpotLights;
uniform DirectionalLight gDirectionalLight;
uniform PointLight gPointLights[MAX_POINT_LIGHTS];
uniform SpotLight gSpotLights[MAX_SPOT_LIGHTS];
uniform sampler2D gTextureSampler0; //unit 0
uniform sampler2D gShadowMap;       //unit 1
uniform vec3 gEyeWorldPos;
uniform float gMatSpecularIntensity;
uniform float gSpecularPower;

float CalculateShadowFactor(vec4 light_space_pos)
{
    //perspective divide
    vec3 projected_coords = light_space_pos.xyz / light_space_pos.w;
    //map [-1, 1] to [0, 1]
    vec2 uv_coords;
    uv_coords.x = 0.5 * projected_coords.x + 0.5;
    uv_coords.y = 0.5 * projected_coords.y + 0.5;
    float z = 0.5 * projected_coords.z + 0.5;
    float depth = texture(gShadowMap, uv_coords).x;
    if (depth < z - 0.0005)
    {
        return 0.5; //in shadow
    }
    else
    {
        return 1.0;
    }
}

vec4 CalculateLightInternal(BaseLight light, vec3 direction, vec3 normal)
{
    vec4 ambient_color = vec4(light.Color * light.AmbientIntensity, 1.0f);
    float diffuse_factor = dot(normal, -direction);

    vec4 diffuse_color  = vec4(0, 0, 0, 0);
    vec4 specular_color = vec4(0, 0, 0, 0);

    if (diffuse_factor > 0)
    {
        diffuse_color = vec4(light.Color * light.DiffuseIntensity * diffuse_factor, 1.0f);
        vec3 vertex_to_eye = normalize(gEyeWorldPos - WorldPos0);
        vec3 light_reflect = normalize(reflect(direction, normal));
        float specular_factor = dot(vertex_to_eye, light_reflect);
        if (specular_factor > 0)
        {
            specular_factor = pow(specular_factor, gSpecularPower);
            specular_color = vec4(light.Color * gMatSpecularIntensity * specular_factor, 1.0f);
        }
    }

    return ambient_color + diffuse_color + specular_color;
}

vec4 CalculateDirectionalLight(vec3 normal)
{
    return CalculateLightInternal(gDirectionalLight.Base, gDirectionalLight.Direction, normal);
}

vec4 CalculatePointLight(PointLight light, vec3 normal)
{
    vec3 light_direction = WorldPos0 - light.Position;
    float dist = length(light_direction);
    light_direction = normalize(light_direction);

    vec4 color = CalculateLightInternal(light.Base, light_direction, normal);
    float inv_attenuation =  1.0 / (light.Atten.Constant + light.Atten.Linear * dist + light.Atten.Exp * dist * dist);

    return color * inv_attenuation;
}

vec4 CalculateSpotLight(SpotLight light, vec3 normal)
{
    vec3 light_to_pixel = normalize(WorldPos0 - light.Base.Position);
    float spot_factor = dot(light_to_pixel, light.Direction);

    if (spot_factor > light.Cutoff)
    {
        vec4 color = CalculatePointLight(light.Base, normal);
        return color * (1.0 - (1.0 - spot_factor) * 1.0/(1.0 - light.Cutoff));   //remaps to [0,1] from cosine value so that it's a smooth fall-off
    }
    else
    {
        return vec4(0,0,0,0);
    }
}

void main()
{
    float shadow_factor = CalculateShadowFactor(LightSpacePos0);
    vec4 texture_color = texture( gTextureSampler0, TexCoord0 );
    vec3 pixel_normal = normalize(WorldNormal0);
    vec4 total_light = CalculateDirectionalLight(pixel_normal);

    for (int i = 0; i < gNumSpotLights; ++i)
    {
        total_light += CalculateSpotLight(gSpotLights[i], pixel_normal);
    }

    //If uncomment the for-loop below, the shadow disappears ...
    //I have tried even setting gNumPointLights to 0 and some how
    //it still "kills" the shadow ...
    //I also tried changing the logic to total_light += vec4(0);
    //magically this still kills it.
    /*
    for (int i = 0; i < gNumPointLights; ++i)
    {
        total_light += CalculatePointLight(gPointLights[i], pixel_normal);
    }
     */

    FragmentColor = texture_color * total_light * shadow_factor;
}

注释掉了for循环,阴影很好!

取消注释 for 循环,阴影消失,无需任何其他修改。即使删除了循环内的逻辑并且阴影仍然不会出现,我也尝试了这个。

这里有一些额外的信息:我在带有 XCode 的 Mac OS 10.11.6 上运行它。我在编译后和链接后检查我的着色器。没有显示错误。

那么为什么会这样呢?我尝试了一切,但我没有想法,请帮助!

【问题讨论】:

  • 在运行时是否按位置正确查询了所有制服?取消注释第二个循环会将gNumPointLightsgPointLights [...] 的状态从非活动更改为活动,并且可能会混淆分配给其他制服的位置。我的直觉告诉我你对统一数组位置做了一个错误的假设(特别是struct 数组的工作方式)。您是在查询结构中各个字段的位置吗?
  • 我相信是的,它们是通过字符串一一查询的:"gPointLights[%d].Base.Color" 其中 %d 将被替换为 0、1、2 和 3。有什么奇怪的是聚光灯的for循环完全没问题(删除或保留它不会改变着色器的行为)。

标签: opengl glsl


【解决方案1】:

经过一些调试,原来是未使用的统一变量搞砸了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    • 2015-06-22
    • 2012-03-28
    • 1970-01-01
    相关资源
    最近更新 更多