Dlaczego mój shader OpenGL Phong zachowuje się jak płaski shader?

Uczę się OpenGL przez ostatnie kilka tygodni i mam pewne problemy z implementacją Phong shader. Wydaje się, że nie wykonuje interpolacji między wierzchołkami, pomimo mojego użycia kwalifikatora smooth. Coś mnie ominęło? Aby dać kredyt tam, gdzie kredyt jest należny, kod dla shaderów wierzchołków i fragmentów w dużej mierze pochodzi z OpenGL SuperBible Fifth Edition. Gorąco polecam tę książkę!

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

}

Ten (public domain) obraz z Wikipedii pokazuje dokładnie, jaki rodzaj obrazu otrzymuję i do czego zmierzam -- dostaję "płaski" obraz, ale chcę obraz "Phong".

Każda pomoc będzie bardzo mile widziana. Dziękuję!

Edit: jeśli to robi różnicę, używam PyOpenGL 3.0.1 i Pythona 2.6.

Edit2:

Rozwiązanie

Okazało się, że problem był z moją geometrią; Kos miał rację. Dla każdego, kto ma ten problem z modelami blenderów, Kos wskazał, że robienie Edit->Faces->Set Smooth robi sztuczkę. Okazało się, że Wings 3D działa " po wyjęciu z pudełka."
Author: Jonba, 2011-01-16

2 answers

Hmm... Interpolujesz normalną jako zmienną varying, więc Shader fragmentów powinien otrzymać poprawną normalną dla piksela.

Jedyne wytłumaczenie (jakie przychodzi mi do głowy) faktu, że masz wynik jak na lewym obrazku, to to, że każdy fragment na danej twarzy otrzymuje ostatecznie ten sam normalny . Możesz to potwierdzić za pomocą shadera fragmentu, takiego jak:

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

Jeśli tak jest, pozostaje pytanie: dlaczego? Vertex shader wygląda OK.

Więc może coś jest nie tak w Twojej geometrii ? Jakie dane wysyłasz do shadera? Czy jesteś pewien, że prawidłowo obliczyłeś normalną wartość na wierzchołek, a nie tylko na twarz?

Normalsi

Pomarańczowe linie są normalnymi na przekątnej twarzy, czerwone linie są normalnymi na poziomej twarzy.

Jeśli Twoje dane wyglądają jak powyższy obrazek, to nawet z odpowiednim shaderem otrzymasz płaskie cieniowanie. Upewnij się, że masz poprawne statystyki per-vertex jak na Dolnym obraz. (Są naprawdę proste do obliczenia dla kuli.)

 48
Author: Kos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-16 14:00:38

Jako dodatek do tej odpowiedzi, Oto prosty Shader geometry, który pozwoli Ci wizualizować swoje normalne. Zmodyfikuj dołączony do niego Shader wierzchołków w zależności od lokalizacji atrybutów i sposobu wysyłania macierzy.

[3]}ale najpierw zdjęcie gigantycznej głowy królika od naszego przyjaciela Stanford bunny jako przykład wyniku !

normals for the Stanford bunny

Główne Ostrzeżenie: zwróć uwagę, że ujdzie mi na sucho przekształcanie normalnych za pomocą matrycy modelview zamiast prawidłowa macierz normalna. To nie będzie działać poprawnie, jeśli modelview zawiera nierównomierne skalowanie. Również długość twoich normalnych nie będzie poprawna, ale to ma niewielkie znaczenie, jeśli chcesz tylko sprawdzić ich kierunek.

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

Geometria 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;
}
 64
Author: Nicolas Lefebvre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-28 14:18:34