2014-10-02 36 views
5

Próbowałem zaimplementować zamknięcie przestrzeni ekranu zgodnie z instrukcją this samouczek. Zajmuję się problemami z moją implementacją, ponieważ natknąłem się na nie, ale ten problem mnie teraz zaskoczył.OpenGL: Wyświetlanie współrzędnych przestrzeni widoku z NDC, pozornie poza zakresem [-1,1]

Moje zrozumienie metody jest następujące. Czynnik okluzji otoczenia określa się za pomocą próbek pobranych z półkuli wyrównanej do normalnej dla danego fragmentu. Aby określić, czy próbka przyczynia się do współczynnika okluzji otoczenia, muszę sprawdzić głębokość próbki w polu widoku w stosunku do tekstury głębokości przestrzeni widoku (zawartej w lewym dolnym rogu obrazów tego wpisu). Tak więc wiem, które współrzędne, aby pobrać z tekstury głębi, muszę przekształcić współrzędne linii próbki z przestrzeni widoku do znormalizowanych współrzędnych urządzenia (w zakresie [-1,1]), a następnie do zakresu [0 1], więc tekstura głębi skutecznie "odwzorowuje" do okna roboczego.

Poniższy obraz przedstawia moją ambientową okluzję nałożoną na moją scenę. Zdaję sobie sprawę, że mam dość oczywisty problem z samą okluzją otoczenia (zakładam, że półkule są źle zorientowane), z którymi poradzę sobie w porę, ale to, co wzbudza moją ciekawość, to pojawienie się okluzji ", sugerując, że moja operacja przejścia od współrzędnych próbki przestrzeni widoku do współrzędnych tekstury jest nieprawidłowa.

enter image description here

Jak mam brakuje stabilnego Shader Debugger, debugowanie mogę zrobić, jest ograniczona do tego, co można uczynić na ekranie. Następny obraz jest tworzony za pomocą następującego kodu z strategii zwalczania narkotyków jest znormalizowana urządzeniach współrzędnych dla danej próbki .:

if (ndcs.x > 1.0f || ndcs.y > 1.0f || ndcs.x < -1.0f || ndcs.y < -1.0f) 
{ 
    gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f); 
} 
else 
{ 
    gl_FragColor = vec4(vec3(1.0f), 1.0f); 
} 

enter image description here

ja oczekiwać, że obraz jest całkowicie biały (a raczej bity, w których używam tego shadera), jednak wydaje się sugerować, że tworzone przeze mnie centra danych są poza zakresem [-1,1], co moim zdaniem musi być nieprawidłowe. To nie jest zgodne obszaru ekranu albo, jak widać na poniższym obrazie, w którym aparat jest bardzo blisko powierzchni:

enter image description here

nigdy nie używałem tej procedury, aby uzyskać NDCS wcześniej, więc jestem pewien, że moja logika musi gdzieś być nie tak. Pobrałem kod demonstracyjny dostarczony wraz z samouczkiem i nie widzę, gdzie mój kod się różni. Szukałem również w Internecie (w tym na tej stronie) i wydaje mi się, że nie mogę znaleźć nikogo z takimi samymi objawami jak ja.

Oto odpowiedni kod z moich shaderów:

Vert Shader:

v_eye_space_position = u_mvpMatrix * a_position; 
v_world_space_normal = normalize(u_rotationMatrix * a_normal); 
v_eye_space_normal = normalize(u_mvpMatrix * a_normal); 
gl_Position = v_eye_space_position; 

Frag Shader:

// --- SSAO Testing --- 
// Convert from the noise texture back to [-1,1] range 
// We want the noise texture to tile across the screen. 
vec3 kernel_rotation = (texture2D(s_noise, gl_FragCoord.xy * u_noise_scale) * 2.0f - 1.0f).xyz; 
vec3 eye_space_tangent = normalize(kernel_rotation - v_eye_space_normal.xyz * dot(kernel_rotation, v_eye_space_normal.xyz)); 
vec3 eye_space_bitangent = cross(v_eye_space_normal.xyz, eye_space_tangent); 
mat3 tbn = mat3(eye_space_tangent, eye_space_bitangent, v_eye_space_normal); 

float ambient_occlusion = 0.0f; 
const float hemisphere_radius = 0.05f; 

for (int i=0; i<16; i++) 
{ 
    vec3 kernel_sample = tbn * u_ssao_kernel[i]; 
    kernel_sample = kernel_sample * hemisphere_radius + v_eye_space_position.xyz; 

    // Project the sample position into screen space. 
    vec4 offset = vec4(kernel_sample, 1.0f); 
    offset = u_projection_matrix * offset; 
    offset.xy /= offset.w; 
    vec4 ndcs = offset; 
    offset.xy = 1.0f - (offset.xy * 0.5f + 0.5f); 

    // Find the depth at this sample point. 
    float sample_depth = texture2D(s_camera_depth, offset.xy).z; 

    // Check if the sample point is occluded. 
    float range_check = 0.0f; 

    float linear_eye_space_position = (v_eye_space_position.z - u_near_plane)/(u_far_plane - u_near_plane); 

    // Range check. 
    if (abs(linear_eye_space_position - sample_depth) < hemisphere_radius) 
    { 
    range_check = 1.0f; 
    } 

    float linear_kernel_sample_depth = (kernel_sample.z - u_near_plane)/(u_far_plane - u_near_plane); 
    if (sample_depth <= linear_kernel_sample_depth) 
    { 
    ambient_occlusion += 1.0f * range_check; 
    } 
} 

// Average and invert the ambient occlusion. 
ambient_occlusion = 1.0f - (ambient_occlusion/16.0f); 

Szukałem w każdym elemencie w izolacji i nie mogę zobacz problem z nimi.

  • Mam podstawiony za własną pozycję w przestrzeni widok fragmentu jest do projekcji (zamiast pozycji widok przestrzeni w próbce) i dostaję takie same wyniki.
  • Macierz projekcji jest macierzą perspektywa używam do przekształcania wierzchołki modelki (mam skonstruowana macierz MVP w moim vertex shader w celu zapewnienia macierzy projekcji jest osiągnięciem programu cieniującego w takcie i jest).
  • Sama operacja projekcji - nie jest to coś, co robiłem wcześniej, ale przeczytałem artykuły online i pytania od osób z problemami z projekcją i nie widzę, co robię źle.

Mogę tylko stwierdzić, że musi istnieć coś fundamentalnego w moim zrozumieniu projekcji perspektywicznej, która jest wadliwa, ale ja po prostu nie wiem, co. Jeśli ktokolwiek z was mógłby rzucić trochę światła na problem lub dalsze możliwości, które mógłbym sprawdzić, byłbym bardzo wdzięczny. Jeśli są jakieś przydatne informacje, które pominąłem lub cokolwiek, co mogę wyjaśnić, proszę daj mi znać.

Odpowiedz

2

ze swojego vertex shader:

v_eye_space_position = u_mvpMatrix * a_position; 
[...] 

pMatrix * a_normal); gl_Position = v_eye_space_position;

Z tego widzimy, że v_eye_space_position jest nie pozycja przestrzeń oko wierzchołka ale klip przestrzeń pozycja, która również musi być przypisana do gl_Position. Identyfikator macierzy macierzy sugeruje również, że jest to ModelView Projekcja -Matrrix.

W shadererze fragmentów, w zasadzie mutliply, że wynik przez matrycę projekcji ponownie (ponieważ wydaje się zakładać, że jest w przestrzeni oczu).

Więc prawidłowy kod byłoby:

v_eye_space_position = u_mvMatrix * a_position; 
[...] 
gl_Position = u_projection_matrix * v_eye_space_position; 

Teraz można zastosować projekcję do v_eye_space_position ponownie w shadera fragmentów. Ale moje pytanie brzmi: dlaczego znowu to robisz? Jeśli chcesz pracować w przestrzeni ekranu, gl_FragCoord jest już w obszarze okna. Do przejścia z przestrzeni okna do NDC potrzebny jest tylko dodatek multiply, wystarczy odwrócić przekształcenie rzutni (i zakresu głębokości).

+0

Dziękuję bardzo za pomoc w tej sprawie. Po wykonaniu sugestii wyniki są tym, czego oczekiwałem. To zabawne, jak zaślepiłem się na tak prosty błąd. Lekcja: zawsze sprawdzaj "proste" rzeczy (szczególnie współrzędne przestrzeni). Jeszcze raz bardzo dziękuję - uwolniłeś mnie od ogromnego stresu. Miłego dnia! :) –