2013-03-11 14 views
9

Próbuję zrobić raytracing w OpenGL za pomocą shadera obliczeniowego i natknąłem się na dziwny problem. W tej chwili chcę wyświetlić kulę bez cieniowania. Mój Compute shader uruchamia ray dla każdego piksela i wygląda następująco:Raytracing w OpenGL przez moduł cieniujący Compute

#version 430 
struct Sphere{ 
    vec4 position; 
    float radius; 
}; 

struct Ray{ 
    vec3 origin; 
    vec3 dir; 
}; 

uniform image2D outputTexture; 
uniform uint  width; 
uniform uint  height; 

float hitSphere(Ray r, Sphere s){ 

    float s_vv = dot(r.dir, r.dir); 
    float s_ov = dot(r.origin, r.dir); 
    float s_mv = dot(s.position.xyz, r.dir); 
    float s_mm = dot(s.position.xyz, s.position.xyz); 
    float s_mo = dot(s.position.xyz, r.origin); 
    float s_oo = dot(r.origin, r.origin); 

    float d = s_ov*s_ov-2*s_ov*s_mv+s_mv*s_mv-s_vv*(s_mm-2*s_mo*s_oo-s.radius*s.radius); 

    if(d < 0){ 
     return -1.0f; 
    } else if(d == 0){ 
     return (s_mv-s_ov)/s_vv; 
    } else { 
     float t1 = 0, t2 = 0; 
     t1 = s_mv-s_ov; 

     t2 = (t1-sqrt(d))/s_vv; 
     t1 = (t1+sqrt(d))/s_vv; 

     return t1>t2? t2 : t1 ; 
    } 
} 

layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 
void main(){ 
    uint x = gl_GlobalInvocationID.x; 
    uint y = gl_GlobalInvocationID.y; 

    if(x < 1024 && y < 768){ 
     float t = 0.0f; 
     Ray r = {vec3(0,0,0), vec3(width/2-x, height/2-y, 1000)}; 
     Sphere sp ={vec4(0, 0, 35, 1), 5.0f}; 

     t = hitSphere(r, sp); 

     if(t <= -0.001f){ 
      imageStore(outputTexture, ivec2(x, y), vec4(0.0, 0.0, 0.0, 1.0)); 
     } else { 
      imageStore(outputTexture, ivec2(x, y), vec4(0.0, 1.0, 0.0, 1.0)); 
     } 

     if(x == 550 && y == 390){ 
      imageStore(outputTexture, ivec2(x, y), vec4(1.0, 0.0, 0.0, 1.0)); 
     } 
    } 
} 

Po uruchomieniu aplikacji pojawia się następujący obraz: enter image description here

Ale kiedy uruchomić ten sam algorytm na CPU otrzymuję następujący bardziej przekonujący obraz: enter image description here

Najpierw pomyślałem, że nie wysłałem wystarczającej liczby grup roboczych, aby nie każdy piksel otrzymał własne wywołanie modułu cieniującego, ale tak nie jest. Jak widać na obrazie renderowanym GPU, w środku znajduje się czerwony piksel, który jest spowodowany ostatnimi liniami w module cieniującym Compute. Można to odtworzyć dla każdego innego piksela.

używam rozdzielczości 1024x768 w tej chwili i to, jak się wysyła mój obliczeniową shadera:

#define WORK_GROUP_SIZE 16 
void OpenGLRaytracer::renderScene(int width, int height){ 
    glUseProgram(_progID); 

    glDispatchCompute(width/WORK_GROUP_SIZE, height/WORK_GROUP_SIZE,1); 

    glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); 
} 

Gdzie jest błąd? Może być problem z dokładnością obliczeń zmiennoprzecinkowych?

+0

Weird ta aplikacja wygląda dokładnie jak coś zrobiłem w sobotę .. –

+0

Czy można natknąć takiego dziwnego zachowania? – Stan

+0

Gdzie jest twoja dyrektywa '# version'? – genpfault

Odpowiedz

3

Błędem jest w tym wierszu:

Ray r = {vec3(0,0,0), vec3(width/2-x, height/2-y, 1000)}; 

Ponieważ szerokość, wysokość, x i y są zmiennymi uint będę się problemy, gdy szerokość termin/2-x staje się ujemny.

To rozwiązuje problem:

Ray r = {vec3(0,0,0), vec3(float(width)/2.0f-float(x), float(height)/2.0f-float(y), 1000)};