2012-10-04 11 views
5

Apple's Best Practices for OpenGL ES zaleca się rozgałęzianie wyników obliczanych w module cieniującym fragmentu. Ale ogólnie, Phong shading ogólnie obejmuje pomijanie określenia lustrzanego, gdy źródło światła znajduje się na "niewłaściwym" boku powierzchni, dla którego proste podejście polega na dot w jednostce kierunku normalnym N i kierunku światła i sprawdzić wynik dodatni.Niespójności urządzenia/systemu operacyjnego w wynikach algorytmu GLSL ES Phong:

próbowałem to zrobić bez oddziału w moim shader: zamiast używać oświadczenie if, robię wszystkie obliczenia dla terminu zwierciadlanym, a następnie nadać mu współczynnik, który jest 1.0 jeśli dot(N, L) jest większa niż zero i 0.0 inaczej . (I to osiągnąć za pomocą wbudowanego step() funkcję. Łącząc max() i sign() daje te same wyniki, ale mówi się, że nieco wolniej.)

to jednak wydaje się prowadzić do nieparzyste, od urządzenia i/lub iOS w wersji specyficznych wyniki:

with branchwithout branch

  • na moim iPhone 4 z systemem iOS 6.0, wersja z branży posiada szeroki podświetlenie zwierciadlane (lewy obraz); bez gałęzi widzę wąski podświetlony punkt (prawy obrazek), pomimo tego, że wykładnik "lśnienia" pozostaje taki sam.
  • Na symulatorze iOS 6.0 widzę drugi obraz z obu wersjami modułu cieniującego.
  • Na moim iPadzie (oryginalny model 2010, zatrzymany na iOS 5.1), widzę pierwszy obraz z obu wersjami modułu cieniującego.

To jest problem, nie jego rozgałęzienia ani braku. (The prawy obraz jest "poprawne" rendering, nawiasem mówiąc).

Oto mój fragment shader:

precision mediump float; 

uniform lowp vec3 ambientLight; 
uniform lowp vec3 light0Color; 
uniform lowp vec3 materialAmbient; 
uniform lowp vec3 materialDiffuse; 
uniform lowp vec3 materialSpecular; 
uniform lowp float materialShininess; 

// input variables from vertex shader (in view coordinates) 
varying vec3 NormDir; 
varying vec3 ViewDir; 
varying vec3 LightDir; 

void main (void) 
{ 
    vec3 L = normalize(LightDir); 
    vec3 N = normalize(NormDir); 
    vec3 E = normalize(ViewDir); 

    lowp vec3 ambient = ambientLight * materialAmbient; 

    float cos_theta = dot(L, N); 

    lowp vec3 diffuse = materialDiffuse * light0Color * max(0.0, cos_theta); 

    lowp vec3 specular = vec3(0.0, 0.0, 0.0); 
// if (cos_theta > 0.0) { 
     lowp vec3 R = reflect(-L, N); 
     lowp vec3 V = normalize(-E); 
     float cos_alpha = dot(R, V); 
     specular = step(0.0, cos_theta) * materialSpecular * light0Color * pow(max(0.0, cos_alpha), materialShininess); 
     //   ~~~~~~~~~~~~~~~~~~~~~~ 
     //   should produce the same results as the commented branch, right? 
// } 
    gl_FragColor = vec4(ambient + diffuse + specular, 1.0); 
} 

Cieszę dalsze sugestie dotyczące poprawy wydajności tego modułu cieniującego na sprzęcie z iOS, też!

+6

Czy może to być artefakt precyzyjny? Wiem, że widziałem znaczące różnice w sposobie, w jaki wartości lowp są zaokrąglane pomiędzy różnymi urządzeniami iOS. W szczególności zastanawiam się, czy użycie lowp dla niektórych wartości prowadzących do 'cos_alpha' i' materialShininess' nie mogło spowodować dziwnych rzeczy w twojej operacji 'pow()'. Nie sądzę, że użycie mediump zwolniłoby cię zbyt mocno. –

+0

Oba podejścia nie są całkowicie równoważne. step (0.0, cos_theta) jest równoważne "if (cos_theta> = 0)", ponieważ step() zwraca 1, gdy cos_theta = 0, ponieważ (0.0 <0) jest fałszywe. ale nie sądzę, że to czyni różnicę. –

+4

Zajęło mi trochę czasu, aby znaleźć czas na eksperymenty z tym więcej, ale @BradLarson ma rację: precyzja na 'materialShininess' jest to. Gdy to jest 'mediump', niespójności urządzenia/systemu OS znikną i wszystkie będą renderować" prawidłowy "sposób (obraz po prawej stronie). (Naprawdę, oddziału/bez gałęzi rzeczy okazało się być czerwonym śledziem.) Napisz jako odpowiedź i przyjmuję. – rickster

Odpowiedz

1

Jak odnotowano w komentarzu @ BradLarson, kwalifikator lowp na materialShininess okazał się problemem; z tym ustawieniem na mediump renderuje on poprawnie (obraz po prawej stronie) na wszystkich urządzeniach i wersjach systemu operacyjnego, które mam pod ręką, niezależnie od tego, czy użyto wersji modułu cieniującego gałęzi czy bez gałęzi (z wersją step).

(przy użyciu lowp porównaniu mediump dla wejść R i V z których cos_alpha oblicza nie sprawia żadnych widocznych różnic, które ma sens. Te są znormalizowane wektory, więc ich elementy posiadają rzędy wielkości w zakresie 0,0 do 1,0 To taki sam zakres, jak komponenty koloru, dla których wydaje się być zamierzony lowp).