Setup Framebuffer object:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glGenTextures(1, &bufferTextures[GBUFFER_TEXTURE_COLOR]);
glBindTexture(GL_TEXTURE_2D, bufferTextures[GBUFFER_TEXTURE_COLOR]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, bufferTextures[GBUFFER_TEXTURE_COLOR],0);
glGenTextures(1, &bufferTextures[GBUFFER_TEXTURE_POSITION]);
glBindTexture(GL_TEXTURE_2D, bufferTextures[GBUFFER_TEXTURE_POSITION]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, bufferTextures[GBUFFER_TEXTURE_POSITION],0);
glGenTextures(1, &bufferTextures[GBUFFER_TEXTURE_NORMAL]);
glBindTexture(GL_TEXTURE_2D, bufferTextures[GBUFFER_TEXTURE_NORMAL]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, bufferTextures[GBUFFER_TEXTURE_NORMAL],0);
glGenTextures(1, &outputTexture);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, outputTexture,0);
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture,0);
glBindBuffer(GL_DRAW_FRAMEBUFFER, 0);
Here how I setup the vertex array object:
for (unsigned int i = 0; i < m_Meshes.size(); ++i)
{
//clear error buffer
glGetError();
// generate Vertex Array for mesh
glGenVertexArrays(1,&(m_Meshes[i]->VertexArrayObject));
glBindVertexArray(m_Meshes[i]->VertexArrayObject);
GLenum err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
// buffer for indices
glGenBuffers(1, &buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_Meshes[i]->numIndices, m_Meshes[i]->indices, GL_STATIC_DRAW);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
// buffer for vertex positions
if (m_Meshes[i]->numVertices != 0) {
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D)*m_Meshes[i]->numVertices, m_Meshes[i]->vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(MODEL_VERTEX_LOCATION);
glVertexAttribPointer(MODEL_VERTEX_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
}
// buffer for vertex normals
if (m_Meshes[i]->normals->Length() != 0) {
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D)*m_Meshes[i]->numVertices, m_Meshes[i]->normals, GL_STATIC_DRAW);
glEnableVertexAttribArray(MODEL_NORMAL_LOCATION);
glVertexAttribPointer(MODEL_NORMAL_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
}
// buffer for vertex texture coordinates
if (m_Materials.size() != 0) {
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * m_Meshes[i]->numVertices, m_Meshes[i]->textureCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(MODEL_TEXCOORD_LOCATION);
glVertexAttribPointer(MODEL_TEXCOORD_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
}
// buffer for tangents
if(m_Meshes[i]->tangents != NULL)
{
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * m_Meshes[i]->numVertices, m_Meshes[i]->tangents, GL_STATIC_DRAW);
glEnableVertexAttribArray(MODEL_TANGENT_LOCATION);
glVertexAttribPointer(MODEL_TANGENT_LOCATION,3,GL_FLOAT,GL_FALSE,0,(void*)0);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
}
// buffer for bitangents
if(m_Meshes[i]->Bitangents != NULL)
{
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * m_Meshes[i]->numVertices, m_Meshes[i]->Bitangents, GL_STATIC_DRAW);
glEnableVertexAttribArray(MODEL_BITANGENT_LOCATION);
glVertexAttribPointer(MODEL_BITANGENT_LOCATION,3,GL_FLOAT,GL_FALSE,0,(void*)0);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
}
// unbind buffers
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
// create material uniform buffer
glGenBuffers(1,&(m_Meshes[i]->materialUniformIndex));
glBindBuffer(GL_UNIFORM_BUFFER,m_Meshes[i]->materialUniformIndex);
glBufferData(GL_UNIFORM_BUFFER, sizeof(Material), (void *)(m_Meshes[i]->material), GL_STATIC_DRAW);
err = glGetError();
if(err != GL_NO_ERROR)
{
printf("Error occured: %i", err);
}
}
Here the rendering to GBuffer:
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glCullFace(GL_BACK);
glDisable(GL_BLEND);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
GLenum DrawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(GBUFFER_NUM_TEXTURES, DrawBuffers);
glUseProgram(gBufferShader);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[matrices setup and uniforms etc]
for (unsigned int n=0; n < m_Meshes.size(); ++n)
{
glBindVertexArray(m_Meshes[n]->VertexArrayObject);
glDrawElementsBaseVertex(GL_TRIANGLES, m_Meshes[n]->numIndices, GL_UNSIGNED_INT, 0, 0);
}
How i render the gbuffer:
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth/2, screenHeight/2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glReadBuffer(GL_COLOR_ATTACHMENT1);
glBlitFramebuffer(0, 0, screenWidth, screenHeight, screenWidth/2, 0, screenWidth, screenHeight/2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glReadBuffer(GL_COLOR_ATTACHMENT2);
glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, screenHeight/2, screenWidth/2, screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);