OpenGL Water Reflection - opengl

I am trying to reflect a bunch of trees from a forest into a nearby lake.I followed all the standard steps to draw a reflection using the Stencil Buffer.But the "water" doesn't seem to allow the objects below to be seen.This is my function: draw_sea() - draws the plan on which to reflect and drawFigTree(fig_tree) - draws the trees below. Where's the problem?
void draw_mirror()
{
glEnable(GL_STENCIL_TEST);
//glColorMask(0, 0, 0, 0);
glDisable(GL_DEPTH_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
draw_sea();
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glPushMatrix();
glTranslatef(0.0, SEA_LEVEL, 0.0);
glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, clip_plane0 );
glPopMatrix();
glPushMatrix();
glTranslatef(-25.0, 2*(-1), 0.0);
glScalef(1.0, -1.0, 1.0);
drawFigTree(fig_tree);
glPopMatrix();
glDisable(GL_CLIP_PLANE0);
glDisable(GL_STENCIL_TEST);
}

Blending doesn't work together with depth testing. For blending to work you must sort visible surfaces far-to-near. In case of the water you must draw the reflection first (it's like looking "through" the water surface at the reflected scene) and then the water.

glDisable(GL_DEPTH_TEST);
You are correct in turning off depth tests. But you must also turn off depth writes; otherwise, you'll have polluted the depth buffer when it comes time to render the reflected geometry.
glDepthMask(GL_FALSE);
Note: Don't forget to turn the depth writes back on after rendering the lake.

Related

Intersection detection with stencil buffer

In order to implement deferred lightning, I render light sources as a sphere with a radius of light.
I rendered only actual positions of light to screen. The result is below.
so I thought maybe if I can render the intersection of this spheres then I can get rid of for loop for each light in the deferred shader.
by using the following document in the link https://kayru.org/articles/deferred-stencil/
I implemented the intersection of light spheres with my actual scene, and I save it to the texture below.
The problem is the result is a bit different than what I expect. Intersection also includes other spheres. Light volumes should not intersect with each other. How can I implement a proper intersection method?
int k = 0;
for(GLXlight & glxlightdata : entitySystem->glxlights){
lBufferShader->uniform4f(lBufferShader->lightPos[k], &glxlightdata.lightPos[0]);
k++;
}
lBufferShader->uniformMatrix4(lBufferShader->ViewMatrix, &entitySystem->view[0][0]); //ViewMatrix
lBufferShader->uniform3f(lBufferShader->viewPos, &(*entitySystem->viewpos)[0]); //viewPos
lBufferShader->uniformMatrix4(lBufferShader->ProjectionMatrix, &entitySystem->projection[0][0]); //ProjectionMatrix
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lightObject->glxobject.elementBufferID);
glCullFace(GL_BACK); //Front (near) faces only
glColorMask(GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE); //Colour write is disabled
glDepthMask(GL_FALSE); //Z-write is disabled
glDepthFunc(GL_LEQUAL); //Z function is 'Less/Equal'//
glStencilFunc(GL_ALWAYS, 0, 0x00); //Stencil test result does not modify Stencil buffer
glStencilMask(0xFF);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); //Z-Fail writes non-zero value to Stencil buffer
glDrawElementsInstanced(GL_TRIANGLES, lightObject->glxobject.size, GL_UNSIGNED_SHORT, (void *) 0, lightObject->glxinstances.size());
glCullFace(GL_FRONT); //Back (far) faces only
glColorMask(GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE); //Colour write is enabled
glDepthMask(GL_FALSE); //Z-write is disabled
glDepthFunc(GL_GEQUAL); //Z function is 'Greater/Equal'
glStencilFunc(GL_EQUAL, 0, 0xFF); //Stencil test result does not modify Stencil buffer
glStencilMask(0xFF);
glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP); //Z-Fail writes non-zero value to Stencil buffer
glDrawElementsInstanced(GL_TRIANGLES, lightObject->glxobject.size, GL_UNSIGNED_SHORT, (void *) 0, lightObject->glxinstances.size());
I solved this problem.
After rendering geometry to buffer, instead of drawing quad to screen, I rendered spheres in the following.
First, render light spheres in the null pass with the following states.
glEnable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDepthFunc(GL_LESS);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0, 0);
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
glDepthMask(GL_FALSE);//disable writing to depth buffer
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);//!! disable writing to color buffer
Render light spheres again now with the following states.
glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);

opengl stencil buffer multiple simultaneous uses

I've managed to successfully use OpenGL's stencil buffer for a single instance in a scene. However, I'm unsure of how to use it in two different places in the same scene. Defining two stencil shapes in sequence prevents either from working, and my attempts to nest one use inside of the other didn't work either. I've seen examples of multiple uses of stencil buffer in the same scene, but I was not able to understand or adapt the code. Here is what I've been able to get working so far.
void display(void) {
// store floor shape in stencil buffer
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilMask(1);
glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
floor->draw();
glBegin(GL_QUADS); //
glVertex3f(0.0, 0.0, 0.0); //
glVertex3f(0.0, 100.0, 0.0); //
glVertex3f(0.0, 100.0, 100.0); //
glVertex3f(0.0, 0.0, 100.0); //
glEnd(); //
// draw scene outside floor
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene();
// draw reflection of scene in floor
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glPushMatrix();
glScalef(1.0, 1.0, -1.0);
scene();
glPopMatrix();
glDisable(GL_STENCIL_TEST);
// draw translucent floor
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0, 1.0, 1.0, 0.7);
floor->draw();
//windowHole();
glDisable(GL_BLEND);
glFlush();
glutSwapBuffers();
glutPostRedisplay();
}

OpenGL using GL_STENCIL with a sphere

I'm working with OpenGL and I am trying to create a sphere that has a reflective surface. I have it reflecting but the reflection isn't correct. The object in the reflection should be bent and deformed according to the curve of the surface, instead I'm getting only a straight reflection. I haven't used GL_STENCIL much so help would be very much appreciated. I have provided pieces of code such as the creation of the sphere and the draw method. If anyone needs more let me know.
Creation:
sphere = gluNewQuadric();
gluQuadricDrawStyle(sphere, GLU_FILL);
gluQuadricNormals(sphere, GLU_SMOOTH);
gluSphere(sphere, 1, 100, 100);
gluDeleteQuadric(sphere);
Drawing:
glClearColor (0.0,0.0,0.0,1);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -10);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //disable the color mask
glDepthMask(GL_FALSE); //disable the depth mask
glEnable(GL_STENCIL_TEST); //enable the stencil testing
glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); //set the stencil buffer to replace our data
sphereDraw(); //the mirror surface
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); //enable the color mask
glDepthMask(GL_TRUE); //enable the depth mask
glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); //set the stencil buffer to keep our next lot of data
glPushMatrix();
glScalef(1.0f, -1.0f, 1.0f); //flip the reflection vertically
glTranslatef(0,2,-20); //translate the reflection onto the drawing plane
glRotatef(angle,0,1,0); //rotate the reflection
//draw object as our reflection
glPopMatrix();
glDisable(GL_STENCIL_TEST); //disable the stencil testing
glEnable(GL_BLEND); //enable alpha blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //set the blending function
sphereDraw(); //draw our bench
glDisable(GL_BLEND); //disable alpha blending
//draw object
Since I'm new to using GL_STENCIL I wasn't sure if it's just something small or if much more needs to be done to detect that angle of reflection.
Have you considered using reflection/environment mapping?
There are 2 main forms. Spherical environment mapping usually works by having a pre-calculated environment map. It can, however, been done dynamically. Its main drawback is that it is view dependent.
The other system is Cubic Environment mapping. Cubic is very easy to set up and involves simply rendering your scene 6 times in 6 different direction (ie on to each face of the cube). Cubic env mapping is view independent.
There is another system that sits between spherical and cubic. Its called dual paraboloid environment mapping. It has the draw back that generating the dual paraboloids is quite complex (like spherical) but (like cubic) it is view independent.

Shadow volumes - final stage

I continue to work on shadow volumes in OpenGL, after finishing with volume itself, i need to draw a shadow using stencil buffer, and thats where i'm stuck :) I rendered this scene: http://prntscr.com/17lyr
As you see, sphere represents light source, and one mushroom has its volume drawn directly to the screen, and one hasnt(i expect to see shadow instead). They are absolutely equal, made be translating one model some units on the X axis. Here is the code im working with:
void Display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
glLightfv(GL_LIGHT1,GL_POSITION,light_position[0]);
cam.SetPrespective();
DrawDebugObject(true);
glTranslatef(15,0,0);
DrawDebugObject(false);
glFinish();
glutSwapBuffers();
}
void DrawDebugObject(bool draw_sil){
glPushMatrix();
glTranslatef(light_position[1][0],light_position[1][1],light_position[1][2]);
glColor3ub(255,255,0);
gluSphere(gluNewQuadric(),0.5,10,10);
glPopMatrix();
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
glColor3f(1,1,1);
glVertex3f(-100,0,-100);
glVertex3f(-100,0,100);
glVertex3f(100,0,100);
glVertex3f(100,0,-100);
glEnd();
glEnable(GL_LIGHTING);
pModel->draw();
if(draw_sil)
pModel->markSilouette(light_position[1]);
castShadow(pModel,light_position[1]);
}
void castShadow(Model* model,float* lp){
glDisable(GL_LIGHTING);
glDepthMask(GL_FALSE);
glDepthFunc(GL_LEQUAL);
pModel->markVisible(lp);
glEnable(GL_STENCIL_TEST);
glColorMask(0, 0, 0, 0);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
// first pass, stencil operation decreases stencil value
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
pModel->markSilouette(lp);
// second pass, stencil operation increases stencil value
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
pModel->markSilouette(lp);
glFrontFace(GL_CCW);
glColorMask(1, 1, 1, 1);
//draw a shadowing rectangle covering the entire screen
glColor4f(1.0f, 0.0f, 0.0f, 0.4f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
glVertex3f(-0.1f, 0.1f,-0.10f);
glVertex3f(-0.1f,-0.1f,-0.10f);
glVertex3f( 0.1f, 0.1f,-0.10f);
glVertex3f( 0.1f,-0.1f,-0.10f);
glEnd();
glPopMatrix();
glDisable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glEnable(GL_LIGHTING);
glDisable(GL_STENCIL_TEST);
}
Here is my GL initialization function:
void InitGL(){
glEnable(GL_NORMALIZE);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearDepth(1.0f); // Depth Buffer Setup
glClearStencil(0); // Stencil Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glHint(GL_FOG_HINT, GL_NICEST);
...nothing important after that
And in my main function:
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE|GLUT_STENCIL|GLUT_ACCUM);
glutInitWindowSize(Width,Height);
glutCreateWindow("Spheres");
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutKeyboardFunc(Keyboard);
glutKeyboardUpFunc(KeyboardUp);
glutTimerFunc(TIMEOUT,Timer,TIMEOUT);
glutPassiveMotionFunc(MouseMove);
Is everything ok with my code? Because i dont see shadow and dont even know how to check if stencil values are set correctly.
There is no way to check stencils afaik. I am going to assume you are using depth fail. I recommend using glStencilOpSeperate like so.
glClear(GL_STENCIL_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_STENCIL_TEST);
glEnable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_CULL_FACE);
glStencilFunc(GL_ALWAYS, 0x00, 0xFF);
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
glPolygonOffset(0.0f, 5.0f);
glDepthFunc(GL_LESS);
Then when you draw the actual geometry make sure you are replacing stencil values like so:
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_CULL_FACE);
glDisable(GL_POLYGON_OFFSET_FILL);
glCullFace(GL_BACK);
glDepthFunc(GL_GEQUAL);
glStencilFunc(GL_EQUAL, 0x00, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

OpenGl: Stencil buffer problem (Wall + Window)?

I want to create a wall with a window inside, using stencil buffer.
My code looks like this:
glEnable(GL_STENCIL_TEST);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilMask(1);
glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glDisable(GL_DEPTH_TEST);
glColor3f(1,1,1);
//Window
glBegin(GL_POLYGON);
glVertex3d(-5,0,-20);
glVertex3d(-5,0,40);
glVertex3d(-20,0,40);
glVertex3d(-20,0,-20);
glEnd();
glEnable(GL_DEPTH_TEST);
glStencilFunc(GL_NOTEQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, eqr);
glBindTexture(GL_TEXTURE_2D,texture[1]);
glBegin(GL_POLYGON);
glNormal3f(0.0f,-1.0,0.0f);
//Wall
glTexCoord2f(0.0f, 0.0f);glVertex3d(20,0,-20);
glTexCoord2f(1.0f, 0.0f);glVertex3d(20,0,40);
glTexCoord2f(1.0f, 0.0f);glVertex3d(-20,0,40);
glTexCoord2f(1.0f, 0.0f);glVertex3d(-20,0,-20);
glEnd();
glDisable(GL_STENCIL_TEST);
But that doesn't work out, I got the whole fill wall without the window in it, any suggestions??
Make sure you request an OpenGL context with a stencil buffer from your windowing system. You may not get one by default unless you specifically ask for it.
Here's an example using GLUT. You'll want to look at the glutInitDisplayMode() call.
Here's another example using raw Win32. The PIXELFORMATDESCRIPTOR bit is the important part.
glXChooseVisual() is probably where you want to look if you're using X11.
I'd recommend SDL if you want cross-platform context management.
I haven't tested your code, but I think that you should change
glStencilFunc(GL_NOTEQUAL, 1, 1);
to
glStencilFunc(GL_EQUAL, 1, 1);