2014-04-16 16 views
6

Jaki jest najlepszy sposób wypróbowania pełnoekranowych tekstur w module cieniującym fragmenty, na przykład bufor g w odroczonym rendererze lub tekstura sceny w shaderze postprocesowym?Najlepszy sposób na przetestowanie pełnoekranowej tekstury

Obecnie używam dwóch następujących sposobów:

  • Pass rozmiar ekranu do modułu cieniującego jako jednolite i obliczyć (u, v) od gl_FragCoord:

    vec2 texCoord = gl_FragCoord.xy/vScreenSize; 
    vec3 c = texture(tex, texCoord).rgb; 
    

    nie działa wydają się idealne, ponieważ wymagany jest podział, a dostarczanie cieniowania z rozmiarem ekranu jest kłopotliwe.

  • Konwersja gl_FragCoord.xy w produkt ivec i używać texelFetch:

    vec3 c = texelFetch(tex, ivec2(gl_FragCoord.xy), 0).rgb; 
    

    także nie jest idealny, ponieważ wymagana jest konwersja z float do int.

Czy istnieje lepszy sposób? Naprawdę chcę tylko wypróbować bufor dokładnie w punkcie, w którym rysuje się mój moduł cieniujący pikseli.


// EDIT:


Ok, z sugestiami interpolowana współrzędnych tekstury, które pochodzą z vertex shader udało mi się zorientować się następujący kod:

Vertex shader:

#version 150 

uniform mat4 im_ModelViewProjectionMatrix; 

in vec3 iv_Vertex; 
noperspective out vec2 vVertCoord; 

void main(void) 
{ 
    gl_Position = im_ModelViewProjectionMatrix * vec4(iv_Vertex, 1.0); 
    vVertCoord = (gl_Position.xy/gl_Position.w) * (0.5) + vec2(0.5); 
} 

Zasadniczo obliczam znormalizowane współrzędne urządzenia (NDC) z odległości między klipami e pozycję z podziałem perspektywicznym, a następnie zmapuj NDC (w zakresie od [-1,1]) do przedziału [0,1]. Działa to doskonale na quadach pełnoekranowych (nawet bez podziału perspektywy, ponieważ współrzędne są tak proste). Arbitralna geometria, którą muszę narysować jako geometrię światła w moim odroczonym rendererze, ma jednak pewne problemy. W wyjściu I vertex shader vVertCoord jako kolor na czerwony = x i zielony = Y:

#version 150 

noperspective in vec2 vVertCoord; 
out vec4 colorOut; 

void main(void) 
{ 
    colorOut = vec4(vVertCoord.x, vVertCoord.y, 0, 1); 
} 

Wynika to gdy jestem w środku punktu światła sfery, wszystko wygląda w porządku (czarne linie są renderowane na cel):

All fine

jednak gdybym zbliżyć się do światła geometrii jest to wynik:

Not ok

Co to jest ta czerwona plama w lewym górnym rogu? Nie chcesz widzieć rezultatów w kolorze rzeczywistym z wyłączonymi kolorami debugowania, ponieważ wygląda na to, że lsd-trip, wszystko kręci się wokół, gdy poruszasz aparatem. Czy ta precyzja jest powiązana? Zauważ, że wszystko jest w porządku, gdy używam gl_FragCoord w pixel shader.

+0

Czy istnieje jakiś szczególny powód, dla którego współrzędne tekstury są oparte na gl_FragCoord, a nie na zwykłym atrybucie interpolowanym? W pierwszym przykładzie, który już wyeliminowałby potrzebę podziału. p.s. zamiast vScreenSize możesz mieć odwrotność rozmiaru ekranu (zmieniając podział na mnożenie). –

+0

Prawdopodobnie nie chcesz tego drugiego, co wyeliminuje możliwość wykonania filtrowania tekstur. Choć może się wydawać, że tak naprawdę nie dbasz o to, w odroczonym mechanizmie cieniowania może być przydatne generowanie G-bufora i cieniowanie w różnych rozdzielczościach (szczególnie w przypadku sprzętu niższego rzędu, który jest zwykle dość ograniczony). –

Odpowiedz

2

Nie musisz wykonywać żadnej specjalnej matematyki, jeśli po prostu przekazujesz interpolowaną współrzędną wierzchołka z wierzchołka modułu cieniującego.

Na przykład, jeśli były rysunek prosty kwadrat jednostkowy, który pokryty ekran, można po prostu i będzie wtedy otrzymywać pełnym ekranie konsystencję, można po prostu zrobić coś takiego:

vertex shader pseudocode: 
layout(position = 0) in vec3 in_vertex; 
out vec3 out_vertex; 
void main() 
{ 
    //Do your matrix multiplications to your in_vertex to get its final position... 
    out_vertex = in_vertex; 
} 

Twój vertex shader następnie poprawnie interpoluje in_vertex tak, aby znajdował się w zakresie x: 0 ... 1, y: 0 ... 1 (tak długo, jak rysujesz kwadrat jednostki) i przekazuje go do shadera fragmentów. Twój fragment shader będzie następnie używać go tak:

fragment shader pseudocode: 
in vec3 out_vertex; 
uniform sampler2D tex; 
void main() 
{ 
    gl_fragcolor = texture(tex,vec2(out_vertex.x,out_vertex.y)); 
} 

Żadna inna matematyka jest potrzebna, tak długo, jak dbać że out_vertex będzie tylko kiedykolwiek być w zakresie od 0 ... 1. Aby przedłużyć ten przykład nieco, wyobraź tutaj jest nasz kwadrat:

(0,1)+-----------+(1,1) | | | | | | | | | | (0,0)+-----------+(0,1)

I chcieliśmy spróbować ten punkt w samym centrum:

(0,1)+-----------+(1,1) | | | | | * | | | | | (0,0)+-----------+(0,1)

Nasz vertex shader automatycznie interpolacji że pozycję z pozostałych 4 pozycji i przekazuj następujący vec3 do modułu cieniującego fragment:

out_vertex = vec3(0.5,0.5,0); 

Które mogą następnie zostać użyte do pomyślnego przetestowania tekstury?

+0

Wierzę, że nadal musisz ustawić 'gl_Position' w twoim cieniurze. Jeśli narysujesz kwadrat jednostki, jak zasugerował @redsoxfantom, możesz użyć czegoś takiego jak 'gl_Position = vec4 (2.0 * out_vertex, 0.0) - 1.0;'. Nie potrzebujesz żadnych multiplikacji macierzy. Daj mi znać, jeśli potrzebujesz więcej wyjaśnień i szczegółów. Trudno to zakryć w komentarzu, ale mogę to opublikować jako odpowiedź. –

+0

Dobra odpowiedź, mimo że skończyłem z innym kodem, ponieważ nie zawsze rysuję pełnoekranowe quady, ale także geometrię światła, w którym to przypadku współrzędne wierzchołków nie są zbyt użyteczne. – Marius

Powiązane problemy