48 votes

Pourquoi mon shader OpenGL Phong se comporte-t-il comme un shader plat?

J'ai été à l'apprentissage d'OpenGL pour les deux dernières semaines et j'ai rencontré quelques difficultés de mise en œuvre d'un module d'éclairage de Phong. Il semble ne pas faire de l'interpolation entre les sommets malgré mon utilisation de l' smooth de qualification. Suis-je manqué quelque chose? Pour donner du crédit lorsque le crédit est dû, le code pour le vertex et fragment shaders crèches fortement de l' OpenGL SuperBible Cinquième Édition. Je recommande vivement ce livre!

Vertex Shader:

#version 330
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix;  // mvp = ModelViewProjection
uniform mat4 mvMatrix; // mv = ModelView
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;

void main(void) {
 vVaryingNormal = normalMatrix * vNormal;
 vec4 vPosition4 = mvMatrix * vVertex;
 vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
 vVaryingLightDir = normalize(vLightPosition - vPosition3);
 gl_Position = mvpMatrix * vVertex;
}

Fragment Shader:

#version 330
out vec4 vFragColor;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;

void main(void) {
 float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
 vFragColor = diff * diffuseColor;
 vFragColor += ambientColor;
 vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir),normalize(vVaryingNormal)));
 float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));

 if(diff != 0) {
   float fSpec = pow(spec, 32.0);
   vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
 }

}

Ce (domaine public), l'image de Wikipedia montre exactement quel genre d'image que je suis et ce que je vise, je suis l'obtention de l'image "flat" mais je veux que la "Phong" de l'image. flatvsphong.jpg

Toute aide serait grandement appréciée. Merci!!!!

edit: Si cela fait une différence, je suis en utilisant PyOpenGL 3.0.1 et Python 2.6.

edit2:

Solution

Il s'avère que le problème était avec mon géométrie; Kos était correcte. Pour quelqu'un d'autre que de l'avoir ce problème avec Blender modèles, Kos a souligné que cela Edit->Faces->Set Smooth fait le tour. J'ai trouvé que les Ailes 3D travaillé "hors de la boîte."

66voto

Bethor Points 2997

Comme un ajout à cette réponse, ici est une simple géométrie shader qui vous permettra de visualiser votre normales. Modifier les accompagnant vertex shader sur la base de votre attribut endroits et comment vous envoyer votre matrices.

Mais tout d'abord, l'image d'un géant à tête de lapin de notre ami le Stanford bunny comme un exemple de résultat !

normals for the Stanford bunny

Les principaux avertissement: ne remarque que je m'en transformant les normales avec la matrice modelview au lieu d'une matrice normale. Cela ne peut pas fonctionner correctement si votre modelview contient non mise à l'échelle uniforme. Aussi, la longueur de votre normales n'est pas correct, mais cela importe peu si vous voulez juste pour vérifier leur direction.

Vertex shader:

#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec4 normal;
layout(location = 2) in mat4 mv;

out Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    mat4 mvp;
} vdata;

uniform mat4 projection;

void main()
{
    vdata.mvp = projection * mv;
    vdata.position = position;
    vdata.normal = normal;
}

Geometry shader:

#version 330
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;

in Data
{
    vec4 position;
    vec4 normal;
    vec4 color;
    mat4 mvp;
} vdata[3];

out Data
{
    vec4 color;
} gdata;

void main()
{
    const vec4 green = vec4(0.0f, 1.0f, 0.0f, 1.0f);
    const vec4 blue = vec4(0.0f, 0.0f, 1.0f, 1.0f);

    for (int i = 0; i < 3; i++)
    {
        gl_Position = vdata[i].mvp * vdata[i].position;
        gdata.color = green;
        EmitVertex();

        gl_Position = vdata[i].mvp * (vdata[i].position + vdata[i].normal);
        gdata.color = blue;
        EmitVertex();

        EndPrimitive();
    }
}

Fragment shader:

#version 330

in Data
{
    vec4 color;
} gdata;

out vec4 outputColor;

void main()
{
    outputColor = gdata.color;
}

49voto

Kos Points 29125

Hmm... Vous êtes interpolation des normales en tant que varying variable, de sorte que le fragment shader doit recevoir le bon pixel par pixel normal.

La seule explication (je pense) du fait que vous avez le résultat comme sur votre image de gauche, c'est que chaque fragment sur un visage donné en fin de compte reçoit la même normale. Vous pouvez le confirmer avec un fragment shader comme:

void main() {
   vFragColor = normalize(vVaryingNormal);
}

Si c'est le cas, la question demeure: Pourquoi? Le vertex shader semble OK.

Alors peut-être il ya quelque chose de mal dans votre géométrie? Qu'est-ce que les données que vous envoyez à l'shader? Êtes-vous sûr que vous avez correctement calculé par vertex normals, pas seulement les faces normales?

normals

Les lignes de couleur orange sont normales de la diagonale de la face, les lignes rouges sont normales de la partie horizontale du visage.

Si vos données ressemble à l'image ci-dessus, alors, même avec un bon shader vous aurez à plat de l'ombrage. Assurez-vous que vous avez la bonne per-vertex normals comme sur l'image du bas. (Ils sont vraiment simple à calculer pour une sphère.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X