我通过两次绘制通道为一个场景添加阴影,一个是深度图,另一个是普通帧缓冲。
使用深度贴图时不使用偏差,会有很多阴影痤疮。
通过在深度图检查中添加偏差来解决此问题。
然而,当灯光移动到不同的角度时,这会导致阴影从物体上“脱离”。
我认为这种效应称为peter-panning,是由于不同角度使用较大的偏差造成的。
通常的解决方法似乎是在绘制阴影贴图时剔除三角形,但由于地板平面是2D对象,我不相信这会正常工作。
我使用的实际地形是程序生成的,因此创建它的3D版本并不像在这个简单示例中那样简单。
如何将peter-panning固定在2D对象上?
顶点着色器
#version 400
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texture_coords;
out VS_OUT {
vec4 position;
vec3 normal;
vec2 texture_coords;
vec4 shadow_position;
} vs_out;
uniform mat4 model;
uniform mat4 model_view;
uniform mat4 model_view_perspective;
uniform mat3 normal_matrix;
uniform mat4 depth_matrix;
void main() {
vec4 position_v4 = vec4(position, 1.0);
vs_out.position = model_view * position_v4;
vs_out.normal = normal_matrix * normal;
vs_out.texture_coords = texture_coords;
vs_out.shadow_position = depth_matrix * model * position_v4;
gl_Position = model_view_perspective * position_v4;
}
片段着色器
#version 400
in VS_OUT {
vec4 position;
vec3 normal;
vec2 texture_coords;
vec4 shadow_position;
} fs_in;
out vec4 colour;
uniform mat4 view;
uniform mat4 model_view_perspective;
uniform vec3 light_position;
uniform vec3 emissive_light;
uniform float shininess;
uniform int textured;
uniform sampler2D tex;
uniform sampler2DShadow shadow_texture;
void main() {
const vec3 specular_albedo = vec3(1.0, 0.8, 0.6);
colour = vec4(0.8, 0.8, 0.8, 0.8);
if(textured != 0) {
colour = texture(tex, fs_in.texture_coords);
}
vec3 light_direction = normalize(light_position);
vec3 normal = normalize(fs_in.normal);
float visibility = 1.0;
if(fs_in.shadow_position.z <= 1.0) {
float bias = max(0.05 * (1.0 - dot(normal, light_direction)), 0.005);
if(fs_in.shadow_position.z > texture(shadow_texture, fs_in.shadow_position.xyz, 0.0) + bias){
visibility = 0.0;
}
}
/* Ambient */
vec3 ambient = colour.xyz * 0.1;
/* Diffuse */
vec3 diffuse = visibility * (clamp(dot(normal, light_direction), 0, 1) * colour.xyz);
/* Specular */
vec3 specular = vec3(0.0);
if(dot(normal, light_direction) > 0) {
vec3 V = normalize(-fs_in.position.xyz);
vec3 half_dir = normalize(light_direction + V);
specular = visibility * (pow(max(dot(normal, half_dir), 0.0), shininess) * specular_albedo.xyz);
}
colour = vec4(((ambient + diffuse) * colour.xyz) + specular + emissive_light, 1.0);
}
答案 0 :(得分:3)
https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx
计算紧密的近平面和远平面也有助于避免彼得·潘宁。
坡度深度偏差
如前所述,自阴影会导致阴影痤疮。 加入太多偏见会导致彼得潘宁。另外, 陡坡(相对于光线)的多边形受到的影响更大 投影混叠比具有浅斜率的多边形(相对于 光)。因此,每个深度图值可能需要不同 偏移取决于多边形相对于光的斜率。
Direct3D 10+硬件能够根据多边形对多边形进行偏置 相对于视图方向的斜率。这有效果 将大偏差应用于与光边缘相交的多边形 方向,但不对面向光的多边形施加任何偏差 直。图10说明了两个相邻像素的方式 在测试时,在阴影和阴影之间交替 相同的无偏斜率。
http://www.sunandblackcat.com/tipFullView.php?l=eng&topicid=35
问题是确定阴影中每个深度的最佳偏移 地图。如果你没有施加足够的偏移量,那么z-fighting仍将存在。 如果你应用非常大的偏移量,那么Peter Panning将成为 显。偏移量应取决于阴影贴图的精度,以及 在相对于光源方向的表面斜率上。
OpenGL可以自动计算并添加偏移值 存储在Z-Buffer中。您可以使用glPolygonOffset设置偏移量 功能。有两个参数:偏移量乘数 取决于表面的斜率,以及决定数量的值 额外的最小可能偏移(取决于阴影的格式 地图):
https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml