2015-03-28 2 views
2

Я только что реализовал отложенный рендеринг, и у меня проблемы с работой моего skybox. Я пытаюсь сделать свой skybox в самом конце цикла рендеринга, и все, что я получаю, это черный экран. Вот цикл рендеринга:Отложенный рендеринг Skybox OpenGL

//binds the fbo 
    gBuffer.Bind(); 

    //the shader that writes info to gbuffer 
    geometryPass.Bind(); 

    glDepthMask(GL_TRUE); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glEnable(GL_DEPTH_TEST); 
    glDisable(GL_BLEND); 

    //draw geometry 
    geometryPass.SetUniform("model", transform.GetModel()); 
    geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform.GetModel()); 

    mesh3.Draw(); 

    geometryPass.SetUniform("model", transform2.GetModel()); 
    geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform2.GetModel()); 
    sphere.Draw(); 

    glDepthMask(GL_FALSE); 
    glDisable(GL_DEPTH_TEST); 

    glEnable(GL_BLEND); 
    glBlendEquation(GL_FUNC_ADD); 
    glBlendFunc(GL_ONE, GL_ONE); 

    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    //shader that calculates lighting 
    pointLightPass.Bind(); 
    pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition()); 

    for (int i = 0; i < 2; i++) 
    { 
     pointLightPass.SetUniformPointLight("light", pointLights[i]); 
     pointLightPass.SetUniform("mvp", glm::mat4(1.0f)); 
     //skybox.GetCubeMap()->Bind(9); 
     quad.Draw(); 
    } 

    //draw skybox 
    glEnable(GL_DEPTH_TEST); 
    skybox.Render(camera); 

    window.Update(); 
    window.SwapBuffers(); 

Ниже приводится скайбокс визуализирует функцию

glCullFace(GL_FRONT); 
glDepthFunc(GL_LEQUAL); 

m_transform.SetPosition(camera.GetTransform().GetPosition()); 
m_shader->Bind(); 

m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel()); 
m_shader->SetUniform("cubeMap", 0); 

m_cubeMap->Bind(0); 
m_cubeMesh->Draw(); 

glDepthFunc(GL_LESS); 
glCullFace(GL_BACK); 

А вот скайбокс в вершинном шейдер:

layout (location = 0) in vec3 position; 

out vec3 TexCoord; 

uniform mat4 mvp; 

void main() 
{ 
    vec4 pos = mvp * vec4(position, 1.0); 
    gl_Position = pos.xyww; 
    TexCoord = position; 
} 

пиксельный шейдер скайбокс просто устанавливает выходной цвет до texture(cubeMap, TexCoord). Как вы можете видеть из вершинного шейдера, я устанавливаю компонент z позиции w так, чтобы он всегда имел глубину 1. Я также устанавливаю функцию глубины GL_LEQUAL, чтобы она не прошла проверку глубины , Должно ли это не только рисовать skybox в местах, где другие объекты еще не были нарисованы? Почему это приводит к черному экрану?

Я знаю, что я правильно установил skybox, потому что, если я просто рисую skybox сам по себе, это проявляется просто отлично.

+0

Я думаю, ваше последнее предложение говорит все это. Он работает без рисования ранее. Либо предыдущие обратные вызовы меняют состояние GL, такие как включение GL_DEPTH_TEST для пропуска освещения, или рисование вашей геометрии меняет значения глубины во всем мире. Я не заметил ничего очевидного. Я бы установил 'gl_FragDepth', а не' gl_Position.z', потому что я предполагал, что это будет беспорядок с отсечением, но если он работает, он работает. – jozxyqk

+0

Я не знаю, как геометрия меняет значения глубины всюду, но пропуска света или любой проход после прохождения геометрии не изменяет 'GL_DEPTH_TEST'. Я также попытался установить 'gl_FragDepth', но это все еще приводит к черному экрану. Я не знаю, почему он не работает. Если я не включил 'GL_DEPTH_TEST' перед отображением skybox, он появляется, но ни одна из других геометрий не показывает, потому что skybox находится поверх всего. – theonewhoknocks

+0

О, право. Дело в черном экране довольно странно (я предположил, что вы имели в виду, что фон был черным). Если вы рисуете что-то, что перезаписывает предыдущие значения черным, то что-то действительно рисует. Если вы видите небо без глубины, я могу предположить, что небо перезаписывает черную геометрию. Хотя 'TexCoord' должен гарантировать, что вы не получите черное, если ваша текстура не будет и связана, если координата не равна нулю (что поместило бы геометрию за камеру в любом случае). Я бы попытался сузить то, что вызывает черный цвет. Возможно, начните с установки постоянного цвета в шейдере фрагмента. – jozxyqk

ответ

1

Я могу вкратце увидеть на несколько секунд геометрию, которая должна быть нарисована до того, как skybox будет нарисован поверх всего.

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

В вашем случае вы хотите, чтобы буфер глубины по умолчанию был таким же, как и GBuffer при рисовании skybox. Быстрый способ добиться этого с glBlitFramebuffer, а также избежать необходимости очистить его:

glBindFramebuffer(GL_READ_FRAMEBUFFER, gbuffer); 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
glBlitFramebuffer(..., GL_DEPTH_BUFFER_BIT, ...); 

Теперь, чтобы объяснить черный экран, когда скайбокс заполняет экран. Без теста глубины, конечно, Skybox просто рисует. С помощью теста глубины skybox по-прежнему рисует первый кадр, но вскоре после того, как второй кадр очистит только цветовой буфер. Буфер глубины по-прежнему содержит устаревшие значения skybox, поэтому он не получает повторную ничью для этого кадра, и вы остаетесь черным ...

Однако ваша геометрия проходит ничьи без проверки глубины, поэтому это должно быть еще видимым даже если skybox нет. Также это произойдет только с GL_LESS, и у вас есть GL_LEQUAL. И у у вас есть glDepthMask false, что означает, что ничего не нужно писать в буфер глубины по умолчанию в вашем коде. Это указывает на буфер глубины, содержащий другие значения, возможно, неинициализированные, но по моему опыту он изначально равен нулю. Также это происходит, когда skybox не заполняет экран, нарисованный как куб от камеры, что сдувает этот аргумент. Теперь, возможно, если геометрия не смогла привлечь второй кадр, который бы объяснил это. В этом случае вопиющие ошибки драйвера тоже будут, но я не вижу никаких проблем в данном коде.

TLDR: Многие необъяснимые вещи, так ** Я пробовал сам и не может воспроизвести вашу проблему ...

Вот краткий пример, основанный на коде и она отлично работает для меня ...

(зеленая сфера является геометрией, красный куб является скайбокс)

gl_Position = pos:
enter image description here

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

gl_Position = pos.xyww:
enter image description here

Теперь код ...

//I haven't enabled back face culling, but that shouldn't affect anything 

//binds the fbo 
fbo.bind(); 

//the shader that writes info to gbuffer 
//geometryPass.Bind(); //fixed pipeline for now 

glDepthMask(GL_TRUE); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glEnable(GL_DEPTH_TEST); 
glDisable(GL_BLEND); 

glColor3f(0,1,0); 
fly.uploadCamera(); //glLoadMatrixf 
sphere.draw(); 

glDepthMask(GL_FALSE); 
glDisable(GL_DEPTH_TEST); 

glEnable(GL_BLEND); 
glBlendEquation(GL_FUNC_ADD); 
glBlendFunc(GL_ONE, GL_ONE); 

fbo.unbind(); //glBindFramebuffer(GL_FRAMEBUFFER, 0); 
glClear(GL_COLOR_BUFFER_BIT); 

//shader that calculates lighting 
drawtex.use(); 
//pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition()); 
drawtex.set("tex", *(Texture2D*)fbo.colour[0]); 

for (int i = 0; i < 2; i++) 
{ 
    //pointLightPass.SetUniformPointLight("light", pointLights[i]); 
    //pointLightPass.SetUniform("mvp", glm::mat4(1.0f)); 
    //skybox.GetCubeMap()->Bind(9); 
    drawtex.set("modelviewMat", mat44::identity()); 
    quad.draw(); 
} 

drawtex.unuse(); 

//draw skybox 
glEnable(GL_DEPTH_TEST); 

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 
glBlitFramebuffer(0, 0, fbo.size.x, fbo.size.y, 0, 0, fbo.size.x, fbo.size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST); 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

//glCullFace(GL_FRONT); 
glDepthFunc(GL_LEQUAL); 

//m_transform.SetPosition(camera.GetTransform().GetPosition()); 
skybox.use(); 

skybox.set("mvp", fly.camera.getProjection() * fly.camera.getInverse() * mat44::translate(1,0,0)); 
//m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel()); 
//m_shader->SetUniform("cubeMap", 0); 

//m_cubeMap->Bind(0); 
cube.draw(); 
skybox.unuse(); 

glDepthFunc(GL_LESS); 
//glCullFace(GL_BACK); 

//window.Update(); 
//window.SwapBuffers(); 
+0

Большое спасибо за помощь! Я очень ценю это. Использование 'glBlitFramebuffer' для копирования буфера глубины действительно решило мою проблему. Мне интересно, есть ли более подходящее место для рисования skybox, поэтому мне не нужно копировать буфер глубины из gbuffer в стандартный фреймбуфер. Пока я буду использовать это исправление. Спасибо еще раз за помощь. – theonewhoknocks

+0

@ theonewhoknocks Не беспокойтесь, рад, что это сработало. Я думаю, что блин. Чтобы избежать копирования, вы хотите использовать текстуру в качестве буфера глубины по умолчанию, что невозможно. Попытка визуализации skybox сначала или в GBuffer не будет чистой. Если позже по дорожке вы выполняете некоторую пост-обработку и оказываетесь в другом FBO, вы можете использовать текстуру глубины GBuffer прямо там, но blit настолько быстр по сравнению с другими вещами, которые вы будете делать. Я не думаю, что вы обратите внимание на разницу. – jozxyqk

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