2015-03-31 20 views
5

Rozważ następujące cieniowanie fragmentów. Gdy uruchomię go na symulatorze lub iPhonie 5 (8.3), pokazuje oczekiwany kolor (czerwony). Jeśli uruchomię go na iPhonie 6 Plus (8.2), przechodzi do drugiej klauzuli if (zielonej), która jest wyraźnie błędna, ponieważ poprawny wynik obliczeń powinien wynosić około 1,22. Jeśli dostarczę parametry atan bezpośrednio jako stałe czasu kompilacji, wówczas obliczenie działa.GLSL atan na iPhone 6 Plus daje zły wynik

Próbowałem zarówno na najnowszym Xcode 6.2 i najnowszej wersji 6.3 Beta.

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

AKTUALIZACJA: Fabuła pogrubia.

Jeśli zmieniam moduł cieniujący w następujący sposób, błąd zniknie, a atan zwróci prawidłową wartość. Wygląda na to, że cokolwiek dodam do x i y musi być czymś innym niż kompilacja stałych czasowych. Rozwiązało to problem w moim kodzie produkcyjnym, w którym nie mam żadnych stałych czasowych kompilacji. BTW ten sam problem dotyczy również acos i 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; 
} 

Inny przykład. Tak właśnie to używam.

Gdybym wykonać obliczenia takiego, to nie działa na 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); 

Jeśli zrobić to w ten sposób, to działa:

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

Poza obszarem zainteresowania pi/2 - tan (x, y) daje oczekiwany efekt (ilekroć x

+0

Nie, daje dokładnie taki sam (nieprawidłowy) wynik. – Seppo

Odpowiedz

1

To wygląda jak kompilacji stałą błąd propagacji.

Twoja klauzula wygląda tak, jakby mogła zostać usunięta przez kompilator, ale ponieważ jest to wartość fp, jest to naprawdę test dla NaN.

tj. porównywanie czegokolwiek dla równości z NaN jest zawsze fałszywe, nawet gdy porównasz wartość z samym sobą.

Wygląda na to, że ten test powstrzymuje kompilator przed propagowaniem stałych wartości, powinno to być oczywiste, jeśli poprosisz o dane wyjściowe asemblera ze swoich kompilacji.

Powiązane problemy