【发布时间】: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 循环,阴影消失,无需任何其他修改。即使删除了循环内的逻辑并且阴影仍然不会出现,我也尝试了这个。
这里有一些额外的信息:我在带有 XCode 的 Mac OS 10.11.6 上运行它。我在编译后和链接后检查我的着色器。没有显示错误。
那么为什么会这样呢?我尝试了一切,但我没有想法,请帮助!
【问题讨论】:
-
在运行时是否按位置正确查询了所有制服?取消注释第二个循环会将
gNumPointLights和gPointLights [...]的状态从非活动更改为活动,并且可能会混淆分配给其他制服的位置。我的直觉告诉我你对统一数组位置做了一个错误的假设(特别是struct数组的工作方式)。您是在查询结构中各个字段的位置吗? -
我相信是的,它们是通过字符串一一查询的:"gPointLights[%d].Base.Color" 其中 %d 将被替换为 0、1、2 和 3。有什么奇怪的是聚光灯的for循环完全没问题(删除或保留它不会改变着色器的行为)。