2016-05-27 3 views
1

Ich kaufte vor kurzem das "opengl Schattierungssprache Kochbuch". Ich versuche eines der Beispiele zu kodieren: speziell die Reflektions-Cubemap.OpenGL Shader: wenn Zustand falsch zu falsch bewertet

Wie es jetzt ist, stürzt meine Software ab.

Ich könnte das Problem auf eine if-Bedingung eingrenzen, die vermutlich wahr ist, aber der "falsche" Teil wird scheinbar ausgeführt (weitere Details folgen).

Das Ziel ist:

  • eine Skybox zeichnen.
  • zeichnen Sie ein Objekt (eine Teekanne), die die Skybox widerspiegelt.

Umwelt-Entwicklung: Ich habe versucht, auf 2 PCs (Arbeits Laptop und Home-Gaming-rig) mit QT5.6.0 und auf meinem Laptop PC mit QT 5.3.0. QT 5.6.0 ist die 32-Bit-Version kompiliert mit mingw, nicht sicher über die Version 5.3.0.

Beide PCs haben eine NVIDIA-Karte. Ich werde nicht mehr ins Detail gehen, da ich nicht glaube, dass das Problem dort liegt (sofern in den Antworten nicht anders angegeben).

Ich habe die Teekanne drawcall entfernt. Ich zeichne derzeit nur die Skybox. Das bedeutet die boolesche "DrawSkyBox" Uniform ist immer wahr. Das ist wichtig.

Der Vertex Shader ist, wo das Problem liegt (oder zumindest die, die den Absturz provoziert). Der Code hier ist (dies ist der Code/Projekt aus dem Buch, nicht meint, die ohnehin eine copy/paste ist):

#version 430 

layout (location = 0) in vec3 VertexPosition; 
layout (location = 1) in vec3 VertexNormal; 
layout (location = 2) in vec2 VertexTexCoord; 

out vec3 ReflectDir; 

uniform bool DrawSkyBox; 
uniform vec3 WorldCameraPosition; 

uniform mat4 ModelViewMatrix; 
uniform mat4 ModelMatrix; 
uniform mat3 NormalMatrix; 
uniform mat4 ProjectionMatrix; 
uniform mat4 MVP; 

void main() 
{ 
    if(DrawSkyBox) { 
     ReflectDir = VertexPosition; 
    } else { 
     vec3 worldPos = vec3(ModelMatrix * vec4(VertexPosition,1.0)); 
     vec3 worldNorm = vec3(ModelMatrix * vec4(VertexNormal, 0.0)); 
     vec3 worldView = normalize(WorldCameraPosition - worldPos); 

     ReflectDir = reflect(-worldView, worldNorm); 
    } 

    gl_Position = MVP * vec4(VertexPosition,1.0); 
} 

Die Fragment-Shader hier:

#version 430 

in vec3 ReflectDir; 

layout(binding=0) uniform samplerCube CubeMapTex; 

uniform bool DrawSkyBox; 
uniform float ReflectFactor; 
uniform vec4 MaterialColor; 

layout(location = 0) out vec4 FragColor; 

void main() { 
    // Access the cube map texture 
    vec4 cubeMapColor = texture(CubeMapTex, ReflectDir); 

    if(DrawSkyBox) 
     FragColor = cubeMapColor; 
    else 
     FragColor = mix(MaterialColor, cubeMapColor, ReflectFactor); 
} 

Also, was ich tat, um das Problem zu erforschen:

1) im Fragment Shader ich nicht holen die Cubemap Textur aber Farben (innerhalb der If/sonst). Ich sehe deutlich die Skybox in rot und die Teekanne in grün (in diesem Test zeichne ich immer noch beides) -> die Zeichnungsaufrufe und Objektdaten sind korrekt.

2) Ich habe versucht mit einem "Standard" 2D-Textur. Ich habe die Standard-Textur-Koordinaten übergeben und der Fragment-Shader hat einfach die Textur abgerufen (no if/else) -> funktioniert perfekt.

3) Ich fand heraus, dass einige Treiber/APIs die boolean in einen int verwandeln konnte (es ist wahrscheinlich ein Problem der alten Zeiten, aber ich entfernt auch diese Möglichkeit): Ich habe versucht, durch einen int Senden und den Zustand zu ändern wenn bis (DrawSkyBox> 0) {...} und 1 auf die Uniform vorbei:

mProgram->setUniformValue("DrawSkyBox", 1); 

sogar mit Typumwandlung:

mProgram->setUniformValue("DrawSkyBox", (int) 1); 

der Shader noch wurde die Ausführung der "else" Teil.

4) Ich habe die Ausführungsteile in bestimmten Funktionen verschoben, das gleiche Ergebnis.

void CalcSkyBox() 
{ 
    ReflectDir = VertexPosition; 
} 

void ObjReflect() 
{ 
    vec3 worldPos = vec3(ModelMatrix * vec4(VertexPosition, 1.0)); 
    vec3 worldNorm = vec3(ModelMatrix * vec4(VertexNormal, 0.0)); 
    vec3 worldView = normalize(WorldCameraPosition - worldPos); 

    ReflectDir = reflect(-worldView, worldNorm);  
} 

void main() 
{ 

    if (DrawSkyBox) { 
     CalcSkyBox(); 
    } else { 
     ObjReflect(); 
    } 

    gl_Position = MVP * vec4(VertexPosition, 1.0); 
} 

Warum sage ich, dass es den "else" -Teil von Anfang an ausführt? Nun ...:

Am Ende fand ich heraus, dass durch die Änderung "ReflectDir" im else Teil des Vertex-Shader (->ReflectDir = reflect(-worldView, worldNorm); ersetzt durch ReflectDir = VertexPosition;) dann funktioniert es perfekt! (Ich meine keinen Absturz und die Skybox wird angezeigt).

So neu formulieren ich die Frage: warum wird der Shader die sonst Teil der Ausführung?

Imarion

PS: ist es ein lange so Vielen Dank im Voraus lesen, wenn Sie diesen Punkt erreicht und für jede Antwort.

+0

Wenn durch „* Absturz *“ Sie „die Anwendung Schließkraft“ bedeutet dann, was in der Core-Dump oder den Debugger Ihrer IDE gefunden (wenn Sie verwenden)? –

+0

Danke für die Bearbeitung :). Ich benutze QT Creator. Es heißt "Die Anwendung hat aufgehört zu arbeiten", ja, es ist eine Art Kraftschluss. Dies ist ein Segmentierungsfehler beim Zeichenaufruf. (In meinem cpp: glDrawElements (...) -> In qopenglfunctions.h: d_ptr-> DrawElements (Modus, Anzahl, Typ, Indizes); Beachten Sie, dass d_ptr korrekt initialisiert wurde (DrawElements \t 0x58790c60 \t void (GLenum, GLsizei, GLenum, const GLvoid *)) Qt ist ganz in einem instabilen Zustand, ich kann nicht eine Core-Dump erhalten. – Imarion

+0

einen neuen Test gemacht, siehe 4 in meiner ursprünglichen Nachricht. – Imarion

Antwort

0

Einige GPUs können beide Seiten einer Verzweigung auswerten und dann eine verwerfen. Siehe: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter34.html

das nicht erklären, warum Sie einen Absturz bekommen würde. Könnte der Vektor, den Sie normalisieren, Null sein, so dass die Normalisierung eine Division durch Null verursacht?

+0

ich supected eine Art von Optimierung. Was die Normalisierung, das ist richtig, ich habe die Berechnung so geändert: ReflectDir = reflect (-worldView, vec3 (0.0, 1.0, 0.0)) und stürzt nicht ab, später werde ich genauer nachforschen, ich habe gerade keine Zeit Jedenfalls danke :) Das heißt, es sollte diesen Teil nicht ausführen. Es gibt dieses Problem, weil für die Skybox diese Vektoren nicht übergeben werden ... Sie werden nicht verwendet. – Imarion

0

Ich habe 2 Programme erstellt, um das "if" im Vertex-Shader loszuwerden. Ich benutze genau den gleichen Fragment-Shader, der das "if" hat.

Dann funktioniert alles gut.

Ich bin versucht, dieses Problem zu schließen bedenken, dass dies ist ein Optimierungs Bug von Nvidia Vertex-Shader-Compiler.