2014-06-18 5 views
5

Ich habe wirklich seltsames Problem Ich kann seit Tagen nicht pin down. Ich mache eine einfache Per-Vertex-Beleuchtung und es funktioniert gut auf Nvidia, aber macht nichts schattiert mit Lichtern auf AMD/ATI. Ich habe herausgefunden, dass das Problem etwas mit Attributen zu tun hat - besonders mit dem Attribut color.
Das ist mein Vertex-Shader:GLSL Shader funktioniert nicht auf AMD/ATI, funktioniert aber auf NVIDIA

#version 140 
uniform mat4 modelViewProjectionMatrix; 
in vec3 in_Position;     // (x,y,z) 
in vec4 in_Color;     // (r,g,b,a) 
in vec2 in_TextureCoord;    // (u,v) 

out vec2 v_TextureCoord; 
out vec4 v_Color; 

uniform bool en_ColorEnabled; 
uniform bool en_LightingEnabled; 

void main() 
{ 
    if (en_LightingEnabled == true){ 
     v_Color = vec4(0.0,1.0,0.0,1.0); 
    }else{ 
     if (en_ColorEnabled == true){ 
     v_Color = in_Color; 
     }else{ 
     v_Color = vec4(0.0,0.0,1.0,1.0); 
     } 
    } 
    gl_Position = modelViewProjectionMatrix * vec4(in_Position.xyz, 1.0); 

    v_TextureCoord = in_TextureCoord; 
} 

Dies ist Pixel-Shader:

#version 140 
uniform sampler2D en_TexSampler; 
uniform bool en_TexturingEnabled; 
uniform bool en_ColorEnabled; 
uniform vec4 en_bound_color; 
in vec2 v_TextureCoord; 
in vec4 v_Color; 
out vec4 out_FragColor; 

void main() 
{ 
    vec4 TexColor; 
    if (en_TexturingEnabled == true){ 
     TexColor = texture2D(en_TexSampler, v_TextureCoord.st) * v_Color; 
    }else if (en_ColorEnabled == true){ 
     TexColor = v_Color; 
    }else{ 
     TexColor = en_bound_color; 
    } 
    out_FragColor = TexColor; 
} 

Also dieser Shader erlaubt 3 Staaten - wenn ich Lichter verwenden, wenn ich nicht Lichter verwenden, aber ein verwenden Per-Vertex-Farbe und wenn ich eine einzige Farbe für alle Ecken verwende. Ich habe den gesamten Lichtberechnungscode entfernt, weil ich das Problem auf ein Attribut aufmerksam gemacht habe. Dies ist die Ausgabe aus dem Shader:
Shader with bug Wie Sie sehen können, ist alles blau (so dass alles, was keine Schattierung oder Farbe hat (en_LightingEnabled == false and en_ColorEnabled == false)).

Wenn ich diesen Code in Vertex-Shader ersetzen:

if (en_ColorEnabled == true){ 
    v_Color = in_Color; 
}else{ 

mit diesem:

if (en_ColorEnabled == true){ 
    v_Color = vec4(1.0,0.0,0.0,1.0); 
}else{ 

ich folgendes:
Without in_Color attribute
So können Sie sehen, dass es alles ohne Schattierung macht immer noch blau, aber jetzt rendert es auch alles, was Lichter verwendet (en_LightingEnabled == true) grün. So sollte es sein. Das Problem ist, dass in_Color Attribut sollte nie Lichter stören, wie es nie einmal ausgeführt würde, wenn Lichter aktiviert sind. Sie können auch sehen, dass nichts in dem Bild rot ist, was bedeutet, dass in dieser Szene en_ColorEnabled immer false ist. So in_Color ist hier völlig nutzlos, aber es verursacht Fehler an Orten, die es logisch nicht sollte. Auf Nvidia funktioniert es gut und grüne Flächen zeichnen mit oder ohne in_Color.

Kann ich etwas verwenden AMD wird nicht unterstützt? Benutze ich etwas außerhalb GLSL spec? Ich weiß, AMD ist strenger mit GL spec als Nvidia, so ist es möglich, dass ich etwas undefiniert. Ich habe den Code so einfach wie möglich gemacht und habe immer noch das Problem, also sehe ich es nicht.
Auch habe ich festgestellt, dass es nichts (auch blaue Bereiche) auf dem Bildschirm zeichnet, wenn in_Color Vertex-Attribut deaktiviert ist (nein glEnableVertexAttribArray), aber warum? Ich benutze nicht einmal die Farbe. Deaktivierte Attribute müssen (0,0,0,1) von der Spezifikation zurückgegeben werden, oder? Ich habe versucht, mit glVertexAttrib4f, um diese Farbe zu ändern, aber immer noch schwarz. Compiler und Linker gibt keine Fehler oder Warnungen zurück. Attribut in_Color ist mit glGetAttribLocation in Ordnung. Aber wie gesagt, nichts davon ist wichtig, da diese Verzweigung nie in meinem Code ausgeführt wird. Irgendwelche Ideen?

Getestet am Nvidia660Ti und funktioniert gut, getestet am ATImobility radeon HD 5000 Laptop und habe diesen Fehler. Meine einzige Idee war, dass ich vielleicht die Fähigkeiten der GPU (zu viele Attribute und so weiter) überschreiten würde, aber als ich meinen Code auf diesen reduzierte, dann hörte ich auf zu glauben. Ich verwende hier nur 3 Attribute.
Auch einige meiner Freunde getestet auf viel neuere AMD Karten und bekam das gleiche Problem.

UPDATE 1

Vertex-Attribut gebunden ist, etwa so:

if (useColors){ 
    glUniform1i(uni_colorEnable,1); 
    glEnableVertexAttribArray(att_color); 
    glVertexAttribPointer(att_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, OFFSET(offset)); 
}else{ 
    glUniform1i(uni_colorEnable,0); 
} 

Auch fand ich, wie die Seltsamkeit zu zeigen, noch einfacher - nimm diesen Vertex-Shader:

void main() 
{ 
    v_Color = clamp(vec4(1.,1.,1.,1.) * vec4(0.5,0.5,0.25,1.),0.0,1.0) + in_Color; 

    gl_Position = modelViewProjectionMatrix * vec4(in_Position.xyz, 1.0); 

    v_TextureCoord = in_TextureCoord; 
} 

Also keine Verzweigung. Und ich bekomme diese: Without branching there is still that bug Wenn ich diesen Code ändern, indem in_Color Entfernung etwa so:

void main() 
{ 
    v_Color = clamp(vec4(1.,1.,1.,1.) * vec4(0.5,0.5,0.25,1.),0.0,1.0); 

    gl_Position = modelViewProjectionMatrix * vec4(in_Position.xyz, 1.0); 

    v_TextureCoord = in_TextureCoord; 
} 

ich dieses: Without branching as expected

Das letzte ist, was ich erwarten würde, aber die vorherige doesn‘ t zeichne alles, obwohl ich Addition (+) anstelle von etwas anderem mache. Also wenn attrib nicht gebunden ist und (0,0,0,0) oder (0,0,0,1) angegeben ist, dann sollte es nichts getan haben. Und dennoch versagt es immer noch.

Außerdem sind alle Protokolle leer - Kompilierung, Verknüpfung und Validierung. Keine Fehler oder Warnungen. Obwohl ich festgestellt habe, dass die Shader-Debug-Informationen AMD/ATI gibt, ist weit unterlegen, was Nvidia gibt.

UPDATE 2

Die einzige fix ich fand, war attribarray in allen Fällen zu ermöglichen (so sendet er im Grunde Junk GPU wenn Farbe nicht aktiviert ist), aber als ich eine Uniform für die Farbe zu überprüfen, dann benutze ich es einfach nicht. Es ist also wie folgt aus:

if (useColors){ 
    glUniform1i(uni_colorEnable,1); 
}else{ 
    glUniform1i(uni_colorEnable,0); 
} 
glEnableVertexAttribArray(att_color); 
glVertexAttribPointer(att_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, OFFSET(offset)); 

Ich habe keine Ahnung, warum das geschieht oder warum muss ich diese verwenden. Ich brauche das nicht auf Nvidia. Also ich denke, das ist langsamer und ich verschwende Bandbreite? Aber zumindest funktioniert es ... Hilfe, wie man das besser macht, wäre aber nützlich.

+0

Zeigen Sie, wie Sie die Scheitelpunktattribute binden. Versuchen Sie auch, Ihr Programm zu validieren und das Validierungsprotokoll anzuzeigen. – sbabbi

+1

versuchen, ohne die Bedingungen neu zu schreiben ... (Programme stattdessen wechseln) ... Ich lief gerade in ein bonkers Problem mit Intel Treiber und Bedingungen: http://StackOverflow.com/Questions/24222343/GLSL-Boolean-Evaluation-wackiness –

+0

Ich habe das Thema aktualisiert. Also auch ohne Verzweigung bekomme ich immer noch Probleme. – user1214513

Antwort

1

Dies passiert wahrscheinlich, weil Sie 3 Eingabewerte für den Shader angeben (in_Position, in_Color und in_TextureCoord), aber Ihre Scheitelpunktdaten nicht immer alle 3 enthalten. Wenn die Scheitelpunktattribute nicht exakt mit diesem Format übereinstimmen in undefiniertes Verhaltensgebiet eindringen und jede Implementierung kann tun, was sie will.

Es scheint so, als ob der Nvidia-Treiber das, was er hat, an die entsprechenden Vertex-Attribute bindet und damit rendert.

Das heißt, sehen Ihre Daten wie die Anordnung unten an den Shader:

in_Position  = Position.xyz 
in_Color   = ??? 
in_TextureCoords = TextureCoords.xy 

Der AMD-Treiber wahrscheinlich versucht, die Vertex-Daten, da alle drei Attribute zu interpretieren, auch wenn Farbe nicht enthalten ist. Nach dem ersten Scheitelpunkt ist die Position nicht mehr synchron mit der Position im Datenarray, was dazu führen würde, dass sie überall gerendert wird. Ich vermute, dass der Grund, dass es bei AMD funktioniert, wenn Sie die Verwendung des in_Color-Attributs entfernen, darin liegt, dass der Shader-Compiler erkennt, dass es nicht verwendet wird, und die Tatsache, dass Sie es spezifiziert haben, optimiert.

in_Position  = Position[0].xyz 
in_Color   = TextureCoords[0].xy,Position[1].xy 
in_TextureCoords = Position[1].z,TextureCoords[1].x 

Mögliche Lösungen sind zu tun, was Sie getan haben und Müll Farbdaten angeben, wenn Sie es nicht brauchen, oder Sie können Ihre Vertex-Shader in 2 separaten solchen mit verschiedenem Vertex-Attribute und binden, um die geeigneten geteilt abhängig ob Sie Eckpunktdaten haben oder nicht.