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);
Related
I am currently trying to draw lines with polygon mode LINES. I have been able to do this sucsessfully many times with immediate mode. But now I am trying to do this with VBOs and can not figure out why.
Here is a sample of the code. As far as I can tell all of the offset, blending, and color methods work fine but It will not draw lines unless I do GL_LINES under glDrawArays.
glPolygonMode(GL_FRONT_AND_BACK, GL_LINES);
glLineWidth(3.0f);
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
glEnable(GL_POLYGON_OFFSET_LINE);
glPolygonOffset (-5.8f, -1.0f);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vHandle);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vBuffer, GL_STATIC_DRAW_ARB);
glVertexPointer(3, GL_FLOAT, 3 << 2, 0L);
glDrawArrays(GL_TRIANGLES, 0, count /* elements */);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_POLYGON_OFFSET_LINE);
You were using GL_LINES instead of GL_LINE. If you are unsure about which enum to use, just check the documentation and it will give you a list of possible values. If you want more help with debugging your app, try calling glGetError ( http://www.opengl.org/sdk/docs/man/xhtml/glGetError.xml) after every opengl call, that way you will be able to see the function where the error appears and then you can just google that.
Below is a piece of code I use to achieve a demo about how blending works:
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glBegin(GL_QUADS);
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
glVertex3i(2, 0, 0);
glVertex3i(2, 6, 0);
glVertex3i(6, 6, 0);
glVertex3i(6, 0, 0);
glEnd();
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
glBegin(GL_QUADS);
glColor4f(0.0, 1.0, 0.0, 0.5f);
glVertex3i(3, 2, -1);
glVertex3i(3, 8, -1);
glVertex3i(8, 8, -1);
glVertex3i(8, 2, -1);
glEnd();
The problem is: It shows what I want on my laptop, which means that the intersection of the two quads is blended, and the area of the green quad left out on black background also blended with background whose alpha is 0.0. However, on another PC, only the red quad appears...
The OpenGL on the laptop is 2.0, and the one on the PC is over 4.0. I want to know whether the problem is the edition of OpenGL or not.
BTW: I know the order I should follow when I want to draw a translucent and an opaque object; I only use this demo to show how much trouble there will be if we do not follow it...
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.
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.
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);