2015-03-31 10 views
5

Betrachten Sie den folgenden Fragment-Shader. Wenn ich es auf dem Simulator oder iPhone 5 (8.3) starte, zeigt es die erwartete Farbe (rot) an. Wenn ich es auf einem iPhone 6 Plus (8.2) starte geht es zur zweiten if-Klausel (grün), die eindeutig falsch ist, da das korrekte Ergebnis der Berechnung bei 1.22 liegen sollte. Wenn ich die Atan-Parameter direkt als Kompilierzeitkonstanten zur Verfügung stelle, funktioniert die Berechnung.GLSL atan auf iPhone 6 Plus gibt ein falsches Ergebnis

Ich habe sowohl auf dem neuesten Xcode 6.2 als auch dem neuesten 6.3 Beta ausprobiert.

void main() 
{ 
    highp float y = 0.57; 
    highp float x = 0.21; 

    highp float a = atan(y, x); 
    // works if changed to atan(0.57, 0.21); 
    // does not work if changed to atan(y/x); 

    if (a > 1.2 && a < 1.25) 
    { 
     // Should always come here 
     // Works on Simulator, iPhone 5 
     gl_FragColor = vec4(1, 0, 0, 1); 
    } 
    else if (a > 1.5 && a < 1.55) 
    { 
     // Comes here on iPhone 6 Plus 
     gl_FragColor = vec4(0, 1, 0, 1); 
    } 

    return; 
} 

UPDATE: Plot verdickt.

Wenn ich den Shader in der folgenden Weise ändern, verschwindet der Fehler und atan gibt den richtigen Wert zurück. Es scheint, dass alles, was ich in x und y eingegeben habe, etwas anderes sein muss als Kompilierzeitkonstanten. Das behebt das Problem auch in meinem Produktionscode, wo ich überhaupt keine Kompilierzeitkonstanten habe. BTW das gleiche Problem betrifft auch Acos und Asin.

highp float y = texCoord.x; 
highp float x = texCoord.x; 

if (x == x) // Removing this line makes error return 
{ 
    x = 0.21; 
} 

if (y == y) // Removing this line makes error return 
{ 
    y = 0.57; 
} 

Ein anderes Beispiel. So benutze ich das eigentlich.

Wenn ich die Berechnung wie dies zu tun, scheitert es auf iPhone 6:

float y = sin(lon2 - lon1) * cos(lat2); 
float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1); 

float bearing = atan(y, x) + 2.0 * pi; 

return mod(bearing, 2.0 * pi); 

Wenn ich es so machen, es funktioniert:

float y = texCoord.y; 
float x = texCoord.x; 

if (y == y) 
{ 
    y = sin(lon2 - lon1) * cos(lat2); 
} 

if (x == x) 
{ 
    x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1); 
} 

float bearing = atan(y, x) + 2.0 * pi; 

return mod(bearing, 2.0 * pi); 
+0

Aus Interesse ergibt Pi/2 - tan (x, y) Ihnen das Ergebnis, das Sie erwarten (wann immer x

+0

Nein, es gibt genau das gleiche (falsche) Ergebnis. – Seppo

Antwort

1

Dies sieht aus wie eine Kompilierung-Konstante Ausbreitungsfehler.

Ihre if (x == x)-Klausel sieht so aus, als ob sie vom Compiler eliminiert werden könnte, aber da es sich um einen fp-Wert handelt, handelt es sich wirklich um einen Test für NaN.

I.e. Alles für die Gleichheit mit einem NaN zu vergleichen ist immer falsch, selbst wenn man den Wert gegen sich selbst berechnet.

Es sieht so aus, als ob dieser Test den Compiler davon abhält, Ihre konstanten Werte zu propagieren, dies sollte offensichtlich sein, wenn Sie nach Assembler-Ausgaben von Ihren Compiles fragen.

Verwandte Themen