2015-02-23 2 views
3

Я пытаюсь использовать отложенное затенение для реализации SSAO, и у меня есть проблемы с доступом к моим текстурам в отложенном шейдере фрагмента. Код находится в C++/Qt5 и использует Coin3D для создания остальной части пользовательского интерфейса (но это не имеет никакого значения здесь).Отложенные текстуры шейдеров с экрана FBO как черный

Фрагмента шейдер из отсроченного перевала:

#version 150 compatibility 

uniform sampler2D color; 
uniform sampler2D position; 
uniform sampler2D normal; 

uniform vec3 dim; 
uniform vec3 camPos; 
uniform vec3 camDir; 

void main() 
{ 
    // screen position 
    vec2 t = gl_TexCoord[0].st; 

    // the color 
    vec4 c = texture2D(color, t); 

    gl_FragColor = c + vec4(1.0, t.x, t.y, 1.0); 
} 

Код для запуска отложенного проход

_geometryBuffer.Unbind(); 

// push state 
{ 
    glMatrixMode(GL_MODELVIEW); 
    glPushMatrix(); 
    glLoadIdentity(); 

    glMatrixMode(GL_PROJECTION); 
    glPushMatrix(); 
    glLoadIdentity(); 

    glPushAttrib(GL_DEPTH_BUFFER_BIT | 
       GL_COLOR_BUFFER_BIT | 
       GL_LIGHTING_BIT | 
       GL_SCISSOR_BIT | 
       GL_POLYGON_BIT | 
       GL_CURRENT_BIT); 
    glDisable(GL_DEPTH_TEST); 
    glDisable(GL_ALPHA_TEST); 
    glDisable(GL_LIGHTING); 
    glDisable(GL_COLOR_MATERIAL); 
    glDisable(GL_SCISSOR_TEST); 
    glDisable(GL_CULL_FACE); 
} 

// bind shader 
// /!\ IMPORTANT to do before specifying locations 
_deferredShader->bind(); 

_CheckGLErrors("deferred"); 

// specify positions 
_deferredShader->setUniformValue("camPos", ...); 
_deferredShader->setUniformValue("camDir", ...); 
_geometryBuffer.Bind(GBuffer::TEXTURE_TYPE_NORMAL, 2); 
_deferredShader->setUniformValue("normal", GLint(2)); 
_geometryBuffer.Bind(GBuffer::TEXTURE_TYPE_POSITION, 1); 
_deferredShader->setUniformValue("position", GLint(1)); 
_geometryBuffer.Bind(GBuffer::TEXTURE_TYPE_DIFFUSE, 0); 
_deferredShader->setUniformValue("color", GLint(0)); 

_CheckGLErrors("bind"); 

// draw screen quad 
{ 
    glBegin(GL_QUADS); 
    glTexCoord2f(0, 0); 
    glColor3f(0, 0, 0); 
    glVertex2f(-1, -1); 

    glTexCoord2f(1, 0); 
    glColor3f(0, 0, 0); 
    glVertex2f(1, -1); 

    glTexCoord2f(1, 1); 
    glColor3f(0, 0, 0); 
    glVertex2f(1, 1); 

    glTexCoord2f(0, 1); 
    glColor3f(0, 0, 0); 
    glVertex2f(-1, 1); 
    glEnd(); 
} 

_deferredShader->release(); 

// for debug 
_geometryBuffer.Unbind(2); 
_geometryBuffer.Unbind(1); 
_geometryBuffer.Unbind(0); 
_geometryBuffer.DeferredPassBegin(); 
_geometryBuffer.DeferredPassDebug(); 

// pop state 
{ 
    glPopAttrib(); 

    glMatrixMode(GL_PROJECTION); 
    glPopMatrix(); 

    glMatrixMode(GL_MODELVIEW); 
    glPopMatrix(); 
} 

Я знаю, что текстуры были правильно обработаны в создании геометрии буфера, потому что Я могу сбросить их в файлы и получить ожидаемый результат.

Отложенный проход не работает. Шейдер составлен правильно, и я получаю следующий результат на экране:

Bad result

И последняя часть моего кода (DeferredPassBegin/Debug) должен обратить FBO на экран (как показано на скриншоте), как что GBuffer верен.

Текущий результат, по-видимому, означает, что текстуры не связаны должным образом с их соответствующей униформой, но я знаю, что содержание действительно, поскольку я сбрасывал текстуры в файлы и получал те же результаты, что и выше.

Мои связывающие функции в GBuffer являются:

void GBuffer::Unbind() 
{ 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 
} 

void GBuffer::Bind(TextureType type, uint32_t idx) 
{ 
    glActiveTexture(GL_TEXTURE0 + idx); 
    glEnable(GL_TEXTURE_2D); 
    glBindTexture(GL_TEXTURE_2D, _textures[static_cast<uint32_t>(type)]); 
} 

void GBuffer::Unbind(uint32_t idx) 
{ 
    glActiveTexture(GL_TEXTURE0 + idx); 
    glDisable(GL_TEXTURE_2D); 
    glBindTexture(GL_TEXTURE_2D, 0); 
} 

Наконец, текстуры 512/512, и я создал их в моей GBuffer с:

WindowWidth = WindowHeight = 512; 
// Create the FBO 
glGenFramebuffers(1, &_fbo); 
glBindFramebuffer(GL_FRAMEBUFFER, _fbo); 

const uint32_t NUM = static_cast<uint32_t>(NUM_TEXTURES); 

// Create the gbuffer textures 
glGenTextures(NUM, _textures); 
glGenTextures(1, &_depthTexture); 

for (unsigned int i = 0 ; i < NUM; i++) { 
    glBindTexture(GL_TEXTURE_2D, _textures[i]); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WindowWidth, WindowHeight, 0, GL_RGBA, GL_FLOAT, NULL); 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i + _firstIndex, GL_TEXTURE_2D, _textures[i], 0); 
} 

// depth 
glBindTexture(GL_TEXTURE_2D, _depthTexture); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0); 

GLenum buffers[NUM]; 
for(uint32_t i = 0; i < NUM; ++i){ 
    buffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i + _firstIndex); 
} 
glDrawBuffers(NUM, buffers); 

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
if (status != GL_FRAMEBUFFER_COMPLETE) { 
    printf("FB error, status: 0x%x\n", status); 
    return _valid = false; 
} 

// unbind textures 
glBindTexture(GL_TEXTURE_2D, 0); 

// restore default FBO 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

Как я могу отлаживать дальше в этом сцена? Я знаю, что данные текстуры действительны, но я не могу правильно привязать его к шейдеру (но у меня есть другие шейдеры, которые используют текстуры, загруженные из файлов и которые отлично работают).

--- Edit 1 ---

Как спросил, код для DeferredPassBegin/Debug (в основном наступающем из this tutorial)

void GBuffer::DeferredPassBegin() { 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
    glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); 
} 

void GBuffer::DeferredPassDebug() { 
    GLsizei HalfWidth = GLsizei(_texWidth/2.0f); 
    GLsizei HalfHeight = GLsizei(_texHeight/2.0f); 

    SetReadBuffer(TEXTURE_TYPE_POSITION); 
    glBlitFramebuffer(0, 0, _texWidth, _texHeight, 
        0, 0, HalfWidth, HalfHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); 

    SetReadBuffer(TEXTURE_TYPE_DIFFUSE); 
    glBlitFramebuffer(0, 0, _texWidth, _texHeight, 
        0, HalfHeight, HalfWidth, _texHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); 

    SetReadBuffer(TEXTURE_TYPE_NORMAL); 
    glBlitFramebuffer(0, 0, _texWidth, _texHeight, 
        HalfWidth, HalfHeight, _texWidth, _texHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); 
} 
+0

Только так вы знаете, 'glBindFramebuffer (GL_FRAMEBUFFER, 0);' эквивалентно двумя вызовами, которые приходят после него в 'GBuffer: Unbind()'. Каждый раз, когда вы используете 'GL_FRAMEBUFFER', он применяется как к цели чтения, так и к методу рисования. Кроме того, вы не включаете и не запрещаете «GL_TEXTURE_2D» в программируемом конвейере, это только для затенения с фиксированной функцией. В базовом профиле, позволяющем фактически создать недопустимую ошибку перечисления. –

+0

Хорошо, я ожидал, что GL_FRAMEBUFFER включает как READ, так и DRAW, но я не был уверен (особенно учитывая, что константы не кажутся связанными по значению, GL_FRAMEBUFFER! = GL_READ_FRAMEBUFFER | GL_WRITE_FRAMEBUFFER). –

+0

Да, это не бит-билд, так что это не работает. Если бы это было так, эти имена заканчивались бы '_BIT'. Это на самом деле немного необычно для GL, но это поведение задокументировано на странице руководства для 'glBindFramebuffer (...)' - похоже на 'GL_FRONT_AND_BACK'. Можете ли вы показать код для 'DeferredPassBegin' и' DeferredPassDebug'? У меня довольно хорошая идея, что делать, но они не в вашем вопросе. –

ответ

0

Arghk !!!

Поэтому я ожидал, что параметры текстуры не являются обязательными, но когда я посмотрел на некоторый код, я просто попытался указать параметры текстуры. При создании текстуры FBO, я использую сейчас

for (unsigned int i = 0 ; i < NUM; i++) { 
    glBindTexture(GL_TEXTURE_2D, _textures[i]); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WindowWidth, WindowHeight, 0, GL_RGBA, GL_FLOAT, NULL); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i + _firstIndex, GL_TEXTURE_2D, _textures[i], 0); 
} 

И с этим изменением, я получаю ожидаемый результат (только с c в пиксельный шейдер, и подобных правильных результатов при переходе на визуализации нормальное/положение).

Заключение: необходимо указать параметры текстуры для отложенного затенения для работы (по крайней мере, с графической настройкой моего приложения/машины).

Correct bunny

+1

А, я верю, что смогу пролить свет на это. По умолчанию фильтр миниатюр «GL_NEAREST_MIPMAP_LINEAR», что означает, что при попытке текстурной карты это, поскольку у него нет мип-карт, у вас есть *** неполная *** текстура. Что вы сделали в опубликованном вами коде, то измените фильтр миниатюр, чтобы удалить фильтрацию mipmap. Вы могли бы также назвать 'glGenerateMipmap (GL_TEXTURE_2D)', но избежать фильтрации mipmap в целом гораздо более разумно. –

+0

Почему настройки по умолчанию приводят к неполному состоянию? Разве это не плохой выбор по умолчанию? В чем причина этого? Если предполагается, что mimaps будут использоваться по умолчанию, то не должны ли они быть включенными по умолчанию? –

+0

Я могу честно сказать, что понятия не имею, почему это по умолчанию. Это приводит к множеству проблем. Столь же странно, что текстуры в OpenGL по умолчанию имеют 1000 LOD до тех пор, пока вы не войдете и не измените это значение (оно должно быть точно равно ** 1 ** для непигментированной текстуры). Но вы учитесь жить с причудами OpenGL. –

Смежные вопросы