Jak wdrożyłbyś aberrację chromatyczną?

22

Jak zaimplementowałbyś efekt aberracji chromatycznej za pomocą shaderów?

Czy renderowanie świata przy różnych odległościach ustawiania ostrości dla każdego koloru rozwiązałoby problem (może przy użyciu tylko jednego przejścia renderowania głębi)?

Quonux
źródło
Dlaczego miałbyś chcieć wprowadzić aberrację chromatyczną?
ashes999
3
Możesz postępować w ten sam sposób, w jaki osiąga się kwitnienie. Powinieneś połączyć swoją normalną scenę z 3 jej rozmytymi wersjami; każda z tych trzech tekstur powinna być zabarwiona głównie w 3 podstawowych kolorach. Oczywiście możliwe są odmiany, jeśli zastosujesz różne strategie rozmycia dla 3 tekstur (np. rozmycie kierunkowe z różnymi przesunięciami kątowymi może załatwić sprawę).
teodron
3
@ ashes999 - Być może celownik snajperski lub inny długi obiektyw, aby dodać odrobinę realizmu? Aberracja chromatyczna jest artefaktem wielu konstrukcji soczewek złożonych.
KeithS
Możesz także zaimplementować aberrację chromatyczną, aby przeciwdziałać aberracji spowodowanej przez obiektyw, przez który oglądana jest gra. Na przykład dobrym pomysłem jest aberracja chromatyczna na krawędziach widoku w grze rozgrywanej za pomocą Oculus Rift.
Joseph Mansfield

Odpowiedzi:

22

Aberracja chromatyczna powstaje, gdy obiektyw nie może ustawić ostrości każdego koloru na ten sam punkt ogniskowania. Prostym sposobem na sfałszowanie tego efektu i renderowanie go jako szybkiego postprocesu na pełnym ekranie jest zastosowanie przesunięcia do każdego kanału kolorów w module cieniującym fragmenty.

Używając innego przesunięcia dla każdego kanału, można uzyskać rozsądny faks żądanego efektu. Przykład tej techniki można znaleźć tutaj ; moduł cieniujący fragmenty wyglądałby mniej więcej tak:

void main () {
    // Previously, you'd have rendered your complete scene into a texture
    // bound to "fullScreenTexture."
    vec4 rValue = texture2D(fullscreenTexture, gl_TexCoords[0] - rOffset);  
    vec4 gValue = texture2D(fullscreenTexture, gl_TexCoords[0] - gOffset);
    vec4 bValue = texture2D(fullscreenTexture, gl_TexCoords[0] - bOffset);  

    // Combine the offset colors.
    gl_FragColor = vec4(rValue.r, gValue.g, bValue.b, 1.0);
}

Ten prosty hack tak naprawdę nie bierze pod uwagę faktu, że aberracja chromatyczna jest efektem soczewki: aby uzyskać lepszą symulację, naprawdę chcesz renderować coś, co działa jak soczewka. Jest to podobne do renderowania obiektów odbijających lub załamujących światło. W związku z tym typowy moduł cieniujący odbicie / załamanie może być podstawą do wprowadzenia aberracji chromatycznej.

Zwykle oblicza się pojedynczy wektor refrakcji na podstawie wektora widoku i określonego indeksu refrakcji , używając funkcji refrakcji GLSL w module cieniującym wierzchołek:

void main () {
    // ...

    // RefractionVector is a varying vec3.
    // 'ratio' is the ratio of the two indices of refraction.
    RefractionVector = refract(incidentVector, normalVector, ratio);

    // ...
}

Następnie użyłbyś tego wektora w module cieniującym fragmenty, aby przeprowadzić wyszukiwanie tekstury kostki (do mapy środowiska). Zwykle odbywa się to również w połączeniu z efektem odbicia i w połączeniu zastosowano obliczony termin Fresnela .

Aby zasymulować aberrację chromatyczną , w module cieniującym wierzchołków można wykonać trzy różne obliczenia wektora załamania, każde nieznacznie przesunięte za pomocą różnych wskaźników załamania:

void main () {
    // ...

    // RefractionVector is a varying vec3, as above.
    // 'ratioR,' et cetera, is the ratio of indices of refraction for
    // the red, green and blue components respectively.
    RedRefractionVector = refract(incidentVector, normalVector, ratioR);
    GreenRefractionVector = refract(incidentVector, normalVector, ratioG);
    BlueRefractionVector = refract(incidentVector, normalVector, ratioB);

    // ...
}

Tych trzech różnych wektorów można użyć do wykonania trzech różnych przeglądów mapy kostki, które można ze sobą mieszać podobnie do sposobu mieszania kolorów w prostym przykładzie:

void main () {
    vec3 color;
    color.r = vec3(textureCube(EnvironmentMap, RedRefractionVector)).r;
    color.g = vec3(textureCube(EnvironmentMap, GreenRefractionVector)).g;
    color.b = vec3(textureCube(EnvironmentMap, BlueRefractionVector)).b;

    gl_FragColor = vec4(color, 1.0);
}

Aby uzyskać więcej informacji, dostępna jest pomarańczowa książka OpenGL, która zawiera przykład podstawowych efektów odbicia i załamania, a także przykład efektu aberracji chromatycznej.


źródło
Czy istnieje podejście, które wykorzystuje tylko jedną próbkę tekstury i po prostu ją zabarwia? Byłoby to bardzo korzystne w zastosowaniach takich jak śledzenie promieni, w których śledzenie trzy vs jeden promień jest bardzo drogie.
Tara