Hi,
I’ve made some progress using the stencil culling and it amlost works :). There is however one more issue: Depending on the view of the camera the stencilbuffer seems to have trouble culling out fragments that are completely in front of the sphere.
Screenshot below shows the sphere with a view in direction (0,0,-1):
[ATTACH=CONFIG]370[/ATTACH]
Well this looks pretty good actually. The blue background is intentional by the way ;).
Now lets see how the result is when the camera is in direction (-1,0,0):
[ATTACH=CONFIG]371[/ATTACH]
And in direction (0,0,1):
[ATTACH=CONFIG]372[/ATTACH]
It seems that some floor and ceiling fragments covering the part of the sphere hat reaches below the floor/ceiling failed the stencil test. This is especially strange since it depends on the viewpount. How can I fix that?
Below the code:
FBO/MRT setup:
// create main framebuffer object
glGenFramebuffers(1, &ids[framebuffer]);
glBindFramebuffer(GL_FRAMEBUFFER, ids[framebuffer]);
// create MRT textures
// color / diffuse
glGenTextures(1, &ids[colorbuffer]);
glBindTexture(GL_TEXTURE_2D, ids[colorbuffer]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, dim[0], dim[1], 0, GL_RGBA,
GL_UNSIGNED_BYTE, 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,
GL_TEXTURE_2D, ids[colorbuffer], 0);
glBindTexture(GL_TEXTURE_2D, 0);
// normal
glGenTextures(1, &ids[normalbuffer]);
glBindTexture(GL_TEXTURE_2D, ids[normalbuffer]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, dim[0], dim[1], 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_ATTACHMENT1,
GL_TEXTURE_2D, ids[normalbuffer], 0);
glBindTexture(GL_TEXTURE_2D, 0);
// depth
glGenTextures(1, &ids[depthbuffer]);
glBindTexture(GL_TEXTURE_2D, ids[depthbuffer]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, dim[0], dim[1], 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, ids[depthbuffer], 0);
// aux
glGenTextures(1, &ids[auxbuffer]);
glBindTexture(GL_TEXTURE_2D, ids[auxbuffer]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, dim[0], dim[1], 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2,
GL_TEXTURE_2D, ids[auxbuffer], 0);
glBindTexture(GL_TEXTURE_2D, 0);
// populate textures to framebuffer (color and normals)
GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, buffers);
And the code to render the geometry to the gbuffer:
// enable for writing to FBO
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ids[framebuffer]);
GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, buffers); // attach albedo and normal/specular buffer to FBO
//------------------------------------------------>
// Only the geometry pass updates the depth buffer
SubSys_Set3DMode();
SubSys_SetViewport(SubSys_GetVideoResolution());
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE); // enable depth buffer for writing
glClearColor(0,0,0,1); // clear color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// set depth buffer range from 0..1
glDepthRange(0, 1);
// disable blending
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
// set camera position
SubSys_LookAt(eye, dir);
// enable backface culling
SubSys_SetState(r_cull, true);
SubSys_EnableShaderStage(shader_fillMRT, false);
DR_Draw(dr_geometry, 0xffff); // populate geometry to gbuffer
SubSys_DisableShaderStage();
SubSys_SetState(r_cull, false);
//------------------------------------------------>
glDepthMask(GL_FALSE); // make depth buffer readonly
glDisable(GL_DEPTH_TEST);
The stencil pass:
// stencil pass
SubSys_EnableShaderStage(shader_null, false);
glEnable(GL_STENCIL_TEST);
glDrawBuffer(GL_NONE); // detach MRTs from FBO
glEnable(GL_DEPTH_TEST); // we definately want to use the depth buffer
glDisable(GL_CULL_FACE); // no culling during stencil pass!
glClear(GL_STENCIL_BUFFER_BIT); // clear stencil buffer
glStencilFunc(GL_ALWAYS, 0, 0); // preset buffer to all-pass
// increment stencil if we enter/leave a polyon on its backside
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);
// decrement stencil if we enter/leave a polyon on its frontside
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);
DisplaySphere(lpos); // draw shpere
glDisable(GL_DEPTH_TEST);
SubSys_DisableShaderStage();
The light pass:
// bind new target colorbuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ids[framebuffer]);
glDrawBuffer(GL_COLOR_ATTACHMENT2); // attach auxiliary color buffer
glClearColor(0,0,1,1); // set fallback color for non touched fragments
glClear(GL_COLOR_BUFFER_BIT); // set buffer color
// activate MRTs
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, ids[colorbuffer]);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, ids[normalbuffer]);
glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, ids[depthbuffer]);
// do the light pass
SubSys_EnableShaderStage(shader_deferred, true);
glStencilFunc(GL_NOTEQUAL, 0, 0xFF); // pass all stencil values > 1
glEnable(GL_CULL_FACE); // enable culling
glCullFace(GL_FRONT);
DisplaySphere(lpos); // draw the sphere
glCullFace(GL_BACK);
glDisable(GL_BLEND);
SubSys_DisableShaderStage();
// disable MRT TMUs
glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_STENCIL_TEST); // disable stencil
// blit FBO to screen
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, ids[framebuffer]);
glReadBuffer(GL_COLOR_ATTACHMENT2);
int16* sdim = SubSys_GetVideoResolution();
glBlitFramebuffer(0, 0, sdim[0], sdim[1], 0, 0, sdim[0], sdim[1],
GL_COLOR_BUFFER_BIT, GL_LINEAR);
And finally the (messy) code to draw the sphere:
void DisplaySphere(vec3f32_t* pos) {
int r = 145; // TODO: variable
int lats = 20; // TODO: static
int longs = 20;// TODO: static
int16 i, j;
for(i = 0; i <= lats; i++) {
float32 lat0 = MATH_PI * (-0.5 + (float32) (i - 1) / lats);
float32 z0 = r * M_fsin(lat0);
float32 zr0 = r * M_fcos(lat0);
float32 lat1 = MATH_PI * (-0.5 + (float32) i / lats);
float32 z1 = r * M_fsin(lat1);
float32 zr1 = r * M_fcos(lat1);
// TODO: VBO THIS!
glBegin(GL_QUAD_STRIP);
for(j = 0; j <= longs; j++) {
float32 lng = 2 * MATH_PI * (float32) (j - 1) / longs;
float32 x = M_fcos(lng);
float32 y = M_fsin(lng);
glVertex3f(x * zr1 + pos->x, y * zr1 + pos->y, z1 + pos->z);
glVertex3f(x * zr0 + pos->x, y * zr0 + pos->y, z0 + pos->z);
//glVertex3f(x * zr1 + pos->x, y * zr1 + pos->y, z1 + pos->z);
}
glEnd();
}
}
Any ideas?
Thanks for your time and best regards
Saski