2016-09-14 11 views
2

Tout d'abord, je dois m'excuser d'avoir posté une autre question à ce sujet (il y en a déjà beaucoup!). J'ai cherché d'autres questions et réponses, mais malheureusement, aucune d'entre elles ne m'a montré la solution. Maintenant, je suis désespéré! : DGLSL3 Coordonnées de l'espace tangent et mappage normal

Il est à noter que le code affiché ci-dessous donne un effet «cahoteux» satisfaisant. C'est l'illumination de la scène qui semble avoir tort.

La scène: est un jeu d'enfant! Un cube au centre, une source de lumière tournant autour de lui (parallèle au sol) et au-dessus.

Mon approche est de démarrer à partir de mon shader de base, ce qui me donne des sorties adéquates (ou du moins je pense!). La première étape est de le modifier pour faire les calculs dans l'espace tangent, puis d'utiliser la normale extraite d'une texture.

J'ai essayé de commenter le code bien, mais en bref j'ai deux questions:

1) Faire seulement l'éclairage de base (pas de cartographie normale), je pense la scène de regarder exactement la même chose, avec ou sans transformer mes vecteurs en espace tangent avec la matrice TBN. Ai-je tort?

2) Pourquoi est-ce que je reçois une illumination incorrecte?

Quelques captures d'écran pour vous donner une idée (EDITED) - suite au commentaire de LJ, je ne suis plus en train de sommer les normales et tangentes par vertex/face. Fait intéressant, il met en évidence le problème (voir sur la capture, j'ai marqué comment la lumière se déplace).

Fondamentalement, il se passe comme si le cube a été tourné de 90 degrés vers la gauche, ou, si la lumière a été Turing verticalement au lieu d'horizontalement

Résultat de la cartographie normale:

Result with normal mapping

version avec lumière simple:

Version with simple light

Vertex shader:

// Information about the light. 
// Here we care essentially about light.Position, which 
// is set to be something like vec3(cos(x)*9, 5, sin(x)*9) 
uniform Light_t Light; 

uniform mat4 W; // The model transformation matrix 
uniform mat4 V; // The camera transformation matrix 
uniform mat4 P; // The projection matrix 

in vec3 VS_Position; 
in vec4 VS_Color; 
in vec2 VS_TexCoord; 
in vec3 VS_Normal; 
in vec3 VS_Tangent; 

out vec3 FS_Vertex; 
out vec4 FS_Color; 
out vec2 FS_TexCoord; 
out vec3 FS_LightPos; 
out vec3 FS_ViewPos; 
out vec3 FS_Normal; 

// This method calculates the TBN matrix: 
// I'm sure it is not optimized vertex shader code, 
// to have this seperate method, but nevermind for now :) 
mat3 getTangentMatrix() 
{ 
    // Note: here I must say am a bit confused, do I need to transform 
    // with 'normalMatrix'? In practice, it seems to make no difference... 
    mat3 normalMatrix = transpose(inverse(mat3(W))); 
    vec3 norm = normalize(normalMatrix * VS_Normal); 
    vec3 tang = normalize(normalMatrix * VS_Tangent); 
    vec3 btan = normalize(normalMatrix * cross(VS_Normal, VS_Tangent)); 
    tang = normalize(tang - dot(tang, norm) * norm); 
    return transpose(mat3(tang, btan, norm)); 
} 

void main() 
{ 
    // Set the gl_Position and pass color + texcoords to the fragment shader 
    gl_Position = (P * V * W) * vec4(VS_Position, 1.0); 
    FS_Color = VS_Color; 
    FS_TexCoord = VS_TexCoord; 

    // Now here we start: 
    // This is where supposedly, multiplying with the TBN should not 
    // change anything to the output, as long as I apply the transformation 
    // to all of them, or none. 
    // Typically, removing the 'TBN *' everywhere (and not using the normal 
    // texture later in the fragment shader) is exactly the code I use for 
    // my basic light shader. 
    mat3 TBN = getTangentMatrix(); 
    FS_Vertex = TBN * (W * vec4(VS_Position, 1)).xyz; 
    FS_LightPos = TBN * Light.Position; 
    FS_ViewPos = TBN * inverse(V)[3].xyz; 

    // This line is actually not needed when using the normal map: 
    // I keep the FS_Normal variable for comparison purposes, 
    // when I want to switch to my basic light shader effect. 
    // (see later in fragment shader) 
    FS_Normal = TBN * normalize(transpose(inverse(mat3(W))) * VS_Normal); 
} 

Et le fragment shader:

struct Textures_t 
{ 
    int SamplersCount; 
    sampler2D Samplers[4]; 
}; 

struct Light_t 
{ 
    int Active; 
    float Ambient; 
    float Power; 
    vec3 Position; 
    vec4 Color; 
}; 

uniform mat4 W; 
uniform mat4 V; 
uniform Textures_t Textures; 
uniform Light_t Light; 

in vec3 FS_Vertex; 
in vec4 FS_Color; 
in vec2 FS_TexCoord; 
in vec3 FS_LightPos; 
in vec3 FS_ViewPos; 
in vec3 FS_Normal; 

out vec4 frag_Output; 

vec4 getPixelColor() 
{ 
    return Textures.SamplersCount >= 1 
     ? texture2D(Textures.Samplers[0], FS_TexCoord) 
     : FS_Color; 
} 

vec3 getTextureNormal() 
{ 
    // FYI: the normal texture is always at index 1 
    vec3 bump = texture(Textures.Samplers[1], FS_TexCoord).xyz; 
    bump = 2.0 * bump - vec3(1.0, 1.0, 1.0); 
    return normalize(bump); 
} 

vec4 getLightColor() 
{ 
    // This is the one line that changes between my basic light shader 
    // and the normal mapping one: 
    // - If I don't do 'TBN *' earlier and use FS_Normal here, 
    // the enlightenment seems fine (see second screenshot) 
    // - If I do multiply by TBN (including on FS_Normal), I would expect 
    // the same result as without multiplying ==> not the case: it looks 
    // very similar to the result with normal mapping 
    // (just has no bumpy effect of course) 
    // - If I use the normal texture (along with TBN of course), then I get 
    // the result you see in the first screenshot. 
    vec3 N = getTextureNormal(); // Instead of 'normalize(FS_Normal);' 

    // Everything from here on is the same as my basic light shader 
    vec3 L = normalize(FS_LightPos - FS_Vertex); 
    vec3 E = normalize(FS_ViewPos - FS_Vertex); 
    vec3 R = normalize(reflect(-L, N)); 

    // Ambient color: light color times ambient factor 
    vec4 ambient = Light.Color * Light.Ambient; 

    // Diffuse factor: product of Normal to Light vectors 
    // Diffuse color: light color times the diffuse factor 
    float dfactor = max(dot(N, L), 0); 
    vec4 diffuse = clamp(Light.Color * dfactor, 0, 1); 

    // Specular factor: product of reflected to camera vectors 
    // Note: applies only if the diffuse factor is greater than zero 
    float sfactor = 0.0; 
    if(dfactor > 0) 
    { 
     sfactor = pow(max(dot(R, E), 0.0), 8.0); 
    } 

    // Specular color: light color times specular factor 
    vec4 specular = clamp(Light.Color * sfactor, 0, 1); 

    // Light attenuation: square of the distance moderated by light's power factor 
    float atten = 1 + pow(length(FS_LightPos - FS_Vertex), 2)/Light.Power; 

    // The fragment color is a factor of the pixel and light colors: 
    // Note: attenuation only applies to diffuse and specular components 
    return getPixelColor() * (ambient + (diffuse + specular)/atten); 
} 

void main() 
{ 
    frag_Output = Light.Active == 1 
     ? getLightColor() 
     : getPixelColor(); 
} 

Ca y est! J'espère que vous avez assez d'informations et bien sûr, votre aide sera grandement appréciée! :) Prends soin.

+0

Sans regarder votre code, à partir des images, il semble que votre cube se compose de 8 sommets partagés avec des normales gouraud ?! Donc vos normales ainsi que vos tangentes sont fausses, l'ombrage de gauraud est utilisé pour approximer les surfaces lisses, un cube n'est certainement pas une surface lisse. Avant de faire quoi que ce soit d'autre, corrigez vos normales de surface (indice qu'elles devraient être perpendiculaires aux surfaces, indice supplémentaire: oui cela signifie pas de sommets partagés). –

+0

Mille mercis LJ - les normales gourauds n'étaient pas la racine du problème, mais votre remarque a rendu le problème plus évident que je trouve: maintenant le visage à gauche est toujours dans la lumière, comme s'il était en haut - et celui à droite (non visible sur la capture d'écran) est toujours dans l'obscurité! – Smoove

Répondre

0

J'experiancing un problème très similaire, et je ne peux pas expliquer pourquoi l'éclairage ne fonctionne pas bien, mais je ne peux répondre à votre première question et à tout le moins expliquer comment je suis en quelque sorte l'éclairage de travail acceptablement (bien que votre problème ne soit pas forcément le même est le mien).Premièrement, en théorie Si vous calculez correctement les tangentes et les bitangents, vous obtiendrez exactement le même résultat lors du calcul dans l'espace tangent avec un espace tangent normal [0,0,1]. Deuxièmement, alors qu'il est de notoriété publique que vous devez transformer vos normales du modèle à l'espace de caméra en multipliant par la matrice de transposition inversée modèle-vue as explained by this tutorial, j'ai trouvé que le problème avec l'éclairage transformé peut être résolu tangente par la matrice modèle-vue plutôt que par la vue-modèle transposée inverse. C'est-à-dire utiliser normalMatrix = mat3(W); au lieu de normalMatrix = transpose(inverse(mat3(W)));.

Dans mon cas cela a «réparer» les problèmes avec la lumière, mais je ne sais pas pourquoi cela l'a fixé, mais je ne fais aucune garantie que ce n'est pas le cas (en fait je suppose qu'il fait) introduire d'autres problèmes avec l'ombrage