2016-02-24 1 views
2

Je fais de l'éclairage par pixel (ombrage phong) sur mon terrain. J'utilise un heightmap pour générer la hauteur du terrain et ensuite calculer la normale pour chaque sommet. Les normales sont interpolées dans le fragment shader et également normalisées. Je reçois des lignes sombres étranges près des bords de triangles où il ne devrait pas y avoir. Artefacts d'éclairage de terrain OpenGL 3D

J'ai vérifié si les normales étaient correctes en utilisant un geometry shader pour dessiner les normales sur le terrain et elles semblent correctes. http://imgur.com/FrJpdXI

Il ne sert à rien d'utiliser une carte normale pour le terrain, elle donnera juste à peu près les mêmes normales. Le problème réside dans la façon dont les normales sont interpolées à travers un triangle.

Je n'ai pas idée de la façon de résoudre ce problème. Je n'ai pas trouvé de solution de travail en ligne.

Terrain Vertex Shader:

#version 330 core 

layout (location = 0) in vec3 position; 
layout (location = 1) in vec3 normal; 
layout (location = 2) in vec2 textureCoords; 

out vec2 pass_textureCoords; 
out vec3 surfaceNormal; 
out vec3 toLightVector; 
out float visibility; 

uniform mat4 transformationMatrix; 
uniform mat4 viewMatrix; 
uniform mat4 projectionMatrix; 

uniform vec3 lightPosition; 

const float density = 0.0035; 
const float gradient = 5.0; 

void main() 
{ 
    vec4 worldPosition = transformationMatrix * vec4(position, 1.0f); 
    vec4 positionRelativeToCam = viewMatrix * worldPosition; 

    gl_Position = projectionMatrix * positionRelativeToCam; 
    pass_textureCoords = textureCoords; 

    surfaceNormal = (transformationMatrix * vec4(normal, 0.0f)).xyz; 
    toLightVector = lightPosition - worldPosition.xyz; 

    float distance = length(positionRelativeToCam.xyz); 
    visibility = exp(-pow((distance * density), gradient)); 
    visibility = clamp(visibility, 0.0, 1.0); 
} 

Fragment Terrain Shader:

#version 330 core 

in vec2 pass_textureCoords; 
in vec3 surfaceNormal; 
in vec3 toLightVector; 
in float visibility; 

out vec4 colour; 

uniform vec3 lightColour; 
uniform vec3 fogColour; 

uniform sampler2DArray blendMap; 
uniform sampler2DArray diffuseMap; 

void main() 
{ 
    vec4 blendMapColour = texture(blendMap, vec3(pass_textureCoords, 0)); 

    float backTextureAmount = 1 - (blendMapColour.r + blendMapColour.g + blendMapColour.b); 
    vec2 tiledCoords = pass_textureCoords * 255.0; 
    vec4 backgroundTextureColour = texture(diffuseMap, vec3(tiledCoords, 0)) * backTextureAmount; 
    vec4 rTextureColour = texture(diffuseMap, vec3(tiledCoords, 1)) * blendMapColour.r; 
    vec4 gTextureColour = texture(diffuseMap, vec3(tiledCoords, 2)) * blendMapColour.g; 
    vec4 bTextureColour = texture(diffuseMap, vec3(tiledCoords, 3)) * blendMapColour.b; 

    vec4 diffuseColour = backgroundTextureColour + rTextureColour + gTextureColour + bTextureColour; 

    vec3 unitSurfaceNormal = normalize(surfaceNormal); 
    vec3 unitToLightVector = normalize(toLightVector); 

    float brightness = dot(unitSurfaceNormal, unitToLightVector); 
    float ambient = 0.2; 
    brightness = max(brightness, ambient); 
    vec3 diffuse = brightness * lightColour; 

    colour = vec4(diffuse, 1.0) * diffuseColour; 
    colour = mix(vec4(fogColour, 1.0), colour, visibility); 
} 
+0

La façon dont mes tuiles de terrain sont triangulées est la suivante: http://imgur.com/t8DOkTJ J'ai essayé une autre méthode de triangulation mais j'ai juste obtenu différentes lignes sombres près des bords des triangles. L'effet que je recherche sur mon terrain est comme ceci: http://imgur.com/9Jx2g24 Ceci est de vanille wow. –

+0

Veuillez fournir deux autres images: géométrie filaire + normales codées en couleur à partir du pixel shader. Cela devrait nous rapprocher de la solution. – mrVoid

+0

Je suis sry mrVoid qu'est-ce que tu veux dire? Le shader de la géométrie et le fragment shader code pour dessiner les vecteurs normaux? –

Répondre

0

Cela peut être deux questions:

1. Normales incorrect: Il y a différents types de ombrage: ombrage plat, ombrage Gouraud et ombrage Phong (différent de Phong spéculaire) example:

Vous souhaitez généralement faire un ombrage Phong. Pour ce faire, OpenGL facilite votre vie et interpole pour vous les normales entre chaque sommet de chaque triangle, donc à chaque pixel vous avez la normale correcte pour ce point: mais vous avez toujours besoin de lui donner les valeurs normales appropriées, qui sont la moyenne des normales de tous les triangles attachés à ce sommet. Ainsi, dans votre fonction qui crée le sommet, les normales et les UV, vous devez calculer la normale à chaque sommet en faisant la moyenne de chaque triangle normal attaché à ce sommet. illustration

2. problème de lotissement: L'autre question possible est que votre terrain ne suffit pas divisé, ou votre résolution heightmap est trop faible, ce qui à ce genre de pépin en raison de la différence de hauteur entre deux sommets en un triangle (donc entre deux pixels dans votre heightmap). Peut-être que si vous pouvez fournir une partie de votre code et shaders, peut-être même la heightmap afin que nous puissions épingler exactement ce qui se passe dans votre cas.

+0

Oui, je fais de l'ombrage Phong, mais je n'utilise pas encore d'éclairage spéculaire, je le fais plus tard, ce n'est pas dur. Pour calculer le vecteur normal j'utilise cette méthode: http://stackoverflow.com/questions/13983189/opengl-how-to-calculate-normals-in-a-terrain-height-grid –

+0

J'utilise un 256x256 heightmap: http://imgur.com/GHm9GbD Un pixel sur la heightmap représente un sommet sur le terrain donc mon terrain a 256x256 sommets. J'ai une taille de tuile de 3,0 donc la largeur et la hauteur du terrain seront 256 x 3 –

+0

J'ai défini une valeur de hauteur maximale de 50, donc le point le plus haut (complètement blanc) est 50 et le point le plus bas (complètement noir) est -50. Ce qui signifie que la différence de hauteur d'une couleur de pixel est de 0,39. Donc, la hauteur d'un pixel avec la couleur (128, 128, 128) est 0 et (129,129,129) est 0,39 –

0

Ceci est ancien, mais je soupçonne que vous ne transformez pas votre normal en utilisant l'inverse transposé de la partie supérieure 3x3 de votre matrice modelview. Voir this. Vous ne savez pas ce qu'il y a dans "transformationMatrix", mais si vous l'utilisez pour transformer le vertex et que quelque chose de normal est probablement louche ...