2016-11-18 69 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