2016-11-18 3 views
5

J'ajoute des ombres à une scène dans OpenGL en effectuant deux passes, une pour une carte de profondeur et une autre pour le frame frame normal.OpenGL shadow peter-panning

Sans utiliser de biais lors de l'utilisation de la carte de profondeur, il y a beaucoup d'acné cachée.

shadow acne without bias

Ceci est corrigé en ajoutant une polarisation à la vérification de la carte de profondeur.

shadow with bias

Cependant, cela provoque l'ombre à « détacher » de l'objet lorsque la lumière est déplacé vers un autre angle.

peter panning

Je crois que cet effet est appelé Pierre-mouvement horizontal et est causé par un biais plus utilisé pour des angles différents. La solution habituelle pour cela semble être de reculer les triangles en vis-à-vis lorsque vous dessinez la carte d'ombre, cependant comme le plan du sol est un objet 2D, je ne crois pas que cela fonctionnerait correctement. Le terrain réel que j'utilise est généré de manière procédurale et il n'est donc pas aussi simple de créer une version 3D que dans cet exemple simple.

Comment le peter-panning peut-il être fixé sur un objet 2D tel que celui-ci?


Vertex shader

#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; 
} 

Fragment shader

#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

Vous pouvez dessinez votre terrain deux fois dans le passage d'ombre en renversant les normales du triangle et en les décalant par le biais dans le sens du regard dans le shader une fois - cela va doubler les triangles tracés mais cela vous permettra d'activer l'abattage égaliser au minimum). Et oui, dans cette technique, peter-panning se faufile, toujours. – BeyelerStudios

+0

La distorsion d'échelle de pente est généralement introduite pendant la phase de construction de la carte d'ombre pour résoudre ce problème. Recherche 'glDepthOffset'. Sachez que cela va casser certains types d'optimisations de tampons de profondeur pendant le rendu, mais cela peut ne pas être si important puisque vous ne faites que remplir le tampon de profondeur et ne pas exécuter un fragment de shader compliqué. –

+0

Merci, je vais essayer ceux-ci. – Caw

Répondre

2

https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx

Le calcul de plans rapprochés et éloignés permet également d'éviter Peter Panning. Comme mentionné précédemment

Profondeur Pente échelle Bias

, l'auto-ombrage peut conduire à l'ombre de l'acné. Ajouter trop de biais peut entraîner Peter Panning. En outre, polygones avec des pentes raides (par rapport à la lumière) souffrent plus de aliasing projectif que les polygones avec des pentes peu profondes (par rapport à la lumière ). Pour cette raison, chaque valeur de carte de profondeur peut nécessiter un décalage différent en fonction de la pente du polygone par rapport à la lumière.

Le matériel Direct3D 10+ a la capacité de polariser un polygone en fonction de sa pente par rapport à la direction de la vue. Ceci a pour effet d'appliquer une polarisation importante à un polygone qui est vu de côté à la direction de la lumière, mais n'applique pas de polarisation directe à un polygone faisant face à la lumière .La figure 10 illustre la manière dont deux pixels voisins peuvent alterner entre ombragé et non ombré lors d'un test par rapport à la même pente non biaisée .

http://www.sunandblackcat.com/tipFullView.php?l=eng&topicid=35

Le problème est de déterminer décalage optimal pour chaque profondeur dans l'ombre carte . Si vous n'appliquez pas assez d'offset, le z-fighting sera toujours présent. Si vous appliquez un décalage très important, Peter Panning deviendra . Le décalage doit dépendre de la précision de la carte ombrée et sur la pente de la surface par rapport à la direction de la source lumineuse. OpenGL peut automatiquement calculer et ajouter un décalage aux valeurs qui sont stockées dans Z-Buffer. Vous pouvez configurer le décalage avec la fonction glPolygonOffset . Deux paramètres sont disponibles: multiplicateur pour compenser cette dépend de la pente de la surface, et la valeur qui détermine quantité de les plus petits décalages possibles supplémentaires (en fonction du format d'ombre carte ):

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