2016-11-18 67 views
5

我通过执行两个拉伸添加阴影到在OpenGL场景通过,一个以一个深度图和一个到正常帧缓冲器。OpenGL的阴影彼得平摇

在使用深度图时不使用偏差,有很多阴影痤疮。

shadow acne without bias

这是通过添加一个偏压施加到深度图检查固定的。

shadow with bias

然而,这导致从对象的阴影,以“分离”当光被移动到不同的角度。

peter panning

相信这种效果被称为彼得-平移和由较大偏压引起被用于不同的角度。

对于这个通常的解决方法似乎是在绘制阴影贴图时剔除背面三角形,但是由于地平面是2D对象,我不相信这会正常工作。

我使用的实际地形是程序生成的,所以创建它的3D版本并不像在这个简单的例子中那么简单。

如何将平移到像这样的二维物体上?


顶点着色器

#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

你可以在阴影过程中绘制地形两次,然后翻转三角法线并在着色器中沿着视线方向偏移一次 - 它将使所绘制的三角形加倍,但它可以让您启用背面剔除(所以它应该甚至在最低限度)。是的,在这种技术中,彼此一直在爬行。 – BeyelerStudios

+0

通常在阴影贴图构建阶段引入坡度偏差以解决此问题。查找'glDepthOffset'。知道这将在渲染过程中破坏某些深度缓冲区优化,但这可能并不重要,因为您只是填充深度缓冲区而不运行复杂的片段着色器。 –

+0

谢谢,我会试试这些。 – Caw

回答

2

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战斗仍然存在。 如果你应用非常大的偏移量,那么彼得平宁将变得明显的 。偏移量应取决于阴影图的精度,以及表面相对于光源方向的斜率。

OpenGL可以自动计算并将偏移量添加到存储在Z缓冲区中的值 。您可以使用glPolygonOffset 函数设置偏移量。两个参数是可用的:乘法器,用于偏移 取决于表面的斜率,和值,它确定的 附加最小可能的偏移量(取决于阴影 地图格式):

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml