Good day.
I draw a scene with shadows using shadow maps method (when we're rendering scene from light point of view to retrieve depth buffer, making shadow texture and projecting it on the scene, rendered from a camera point of view)
As I use shadowmap texture, all other textured objects, of course, lose their texturing.
But I really DO want textured scene with shadows:)
I read about multitexturing, I actually tried to apply it, but failed.
What exactly should I do?
(I took code from OpenGl superbible)
Here is the main setup procedure's code. I marked new strings (those for multitexturing) with //<====
void SetupRC()
{
ambientShadowAvailable = GL_TRUE;
npotTexturesAvailable = GL_TRUE;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
fprintf(stdout, "Controls:\n");
fprintf(stdout, "\tRight-click for menu\n\n");
fprintf(stdout, "\tx/X\t\tMove +/- in x direction\n");
fprintf(stdout, "\ty/Y\t\tMove +/- in y direction\n");
fprintf(stdout, "\tz/Z\t\tMove +/- in z direction\n\n");
fprintf(stdout, "\tf/F\t\tChange polygon offset factor +/-\n\n");
fprintf(stdout, "\tq\t\tExit demo\n\n");
// Black background
glClearColor(0.32f, 0.44f, 0.85f, 0.5f );
// Hidden surface removal
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glPolygonOffset(factor, 0.0f);
// Set up some lighting state that never changes
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
glEnable(GL_LIGHT0);
// Set up some texture state that never changes
glActiveTexture(GL_TEXTURE1); //<=====
glGenTextures(1, &shadowTextureID);
glBindTexture(GL_TEXTURE_2D, shadowTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
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_DEPTH_TEXTURE_MODE, GL_INTENSITY);
// if (ambientShadowAvailable)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB,
0.5f);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
::scene->fog->init();
RegenerateShadowMap();
}
Here is shadowmap generation procedure:
void RegenerateShadowMap(void)
{
GLfloat lightToSceneDistance, nearPlane, fieldOfView;
GLfloat lightModelview[16], lightProjection[16];
GLfloat sceneBoundingRadius = 200.0f; // based on objects in scene
// Save the depth precision for where it's useful
lightToSceneDistance = sqrt(lightPos[0] * lightPos[0] +
lightPos[1] * lightPos[1] +
lightPos[2] * lightPos[2]);
nearPlane = lightToSceneDistance - sceneBoundingRadius;
// Keep the scene filling the depth texture
fieldOfView = (GLfloat)m3dRadToDeg(2.0f * atan(sceneBoundingRadius / lightToSceneDistance));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fieldOfView, 1.0f, nearPlane, nearPlane + (2.0f * sceneBoundingRadius));
glGetFloatv(GL_PROJECTION_MATRIX, lightProjection);
// Switch to light's point of view
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(lightPos[0], lightPos[1], lightPos[2],
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightModelview);
glViewport(0, 0, shadowWidth, shadowHeight);
// Clear the depth buffer only
glClear(GL_DEPTH_BUFFER_BIT);
// All we care about here is resulting depth values
glShadeModel(GL_FLAT);
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_NORMALIZE);
glActiveTexture(GL_TEXTURE0); //<=====
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1); //<=====
glColorMask(0, 0, 0, 0);
// Overcome imprecision
glEnable(GL_POLYGON_OFFSET_FILL);
// Draw objects in the scene except base plane
// which never shadows anything
DrawModels(GL_FALSE);
// Copy depth values into depth texture
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
0, 0, shadowWidth, shadowHeight, 0);
// Restore normal drawing state
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
glActiveTexture(GL_TEXTURE0); //<=====
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColorMask(1, 1, 1, 1);
glDisable(GL_POLYGON_OFFSET_FILL);
// Set up texture matrix for shadow map projection,
// which will be rolled into the eye linear
// texture coordinate generation plane equations
M3DMatrix44f tempMatrix;
m3dLoadIdentity44(tempMatrix);
m3dTranslateMatrix44(tempMatrix, 0.5f, 0.5f, 0.5f);
m3dScaleMatrix44(tempMatrix, 0.5f, 0.5f, 0.5f);
m3dMatrixMultiply44(textureMatrix, tempMatrix, lightProjection);
m3dMatrixMultiply44(tempMatrix, textureMatrix, lightModelview);
// transpose to get the s, t, r, and q rows for plane equations
m3dTransposeMatrix44(textureMatrix, tempMatrix);
}
Scene render proc:
void RenderScene(void)
{
// Track camera angle
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (windowWidth > windowHeight)
{
GLdouble ar = (GLdouble)windowWidth / (GLdouble)windowHeight;
glFrustum(-ar * cameraZoom, ar * cameraZoom, -cameraZoom, cameraZoom, 1.0, 1000.0);
}
else
{
GLdouble ar = (GLdouble)windowHeight / (GLdouble)windowWidth;
glFrustum(-cameraZoom, cameraZoom, -ar * cameraZoom, ar * cameraZoom, 1.0, 1000.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
glViewport(0, 0, windowWidth, windowHeight);
// Track light position
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (showShadowMap)
{
// Display shadow map for educational purposes
glActiveTexture(GL_TEXTURE1); //<=====
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
// Show the shadowMap at its actual size relative to window
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(((GLfloat)shadowWidth/(GLfloat)windowWidth)*2.0f-1.0f,
-1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(((GLfloat)shadowWidth/(GLfloat)windowWidth)*2.0f-1.0f,
((GLfloat)shadowHeight/(GLfloat)windowHeight)*2.0f-1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f,
((GLfloat)shadowHeight/(GLfloat)windowHeight)*2.0f-1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
gluPerspective(45.0f, 1.0f, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
}
else if (noShadows)
{
// Set up some simple lighting
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
// Draw objects in the scene including base plane
DrawModels(GL_TRUE);
}
else
{
if (!ambientShadowAvailable)
{
GLfloat lowAmbient[4] = {0.1f, 0.1f, 0.1f, 1.0f};
GLfloat lowDiffuse[4] = {0.35f, 0.35f, 0.35f, 1.0f};
// Because there is no support for an "ambient"
// shadow compare fail value, we'll have to
// draw an ambient pass first...
glLightfv(GL_LIGHT0, GL_AMBIENT, lowAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lowDiffuse);
// Draw objects in the scene, including base plane
DrawModels(GL_TRUE);
// Enable alpha test so that shadowed fragments are discarded
glAlphaFunc(GL_GREATER, 0.9f);
glEnable(GL_ALPHA_TEST);
}
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
// Set up shadow comparison
glActiveTexture(GL_TEXTURE1); //<=====
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
GL_COMPARE_R_TO_TEXTURE);
// Set up the eye plane for projecting the shadow map on the scene
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
glTexGenfv(GL_S, GL_EYE_PLANE, &textureMatrix[0]);
glTexGenfv(GL_T, GL_EYE_PLANE, &textureMatrix[4]);
glTexGenfv(GL_R, GL_EYE_PLANE, &textureMatrix[8]);
glTexGenfv(GL_Q, GL_EYE_PLANE, &textureMatrix[12]);
// Draw objects in the scene, including base plane
DrawModels(GL_TRUE);
//glPushMatrix();
//glScalef(1, -1, 1);
//DrawModels(GL_TRUE);
//glPopMatrix();
glDisable(GL_ALPHA_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
}
if (glGetError() != GL_NO_ERROR)
fprintf(stderr, "GL Error!\n");
//glBindTexture
// Flush drawing commands
glutSwapBuffers();
//RegenerateShadowMap();
}
And an example of textured object draw:
CTeapot::CTeapot(std::string fn, float s, float iX, float iY, float iZ)
{
this->setCoords(iX, iY, iZ);
this->size = s;
glActiveTexture(GL_TEXTURE0); //<=====
try
{
this->texture = new C2DTexture(fn);
}
catch(ERR::CError err)
{
throw err;
}
glActiveTexture(GL_TEXTURE1); //<=====
}
void CTeapot::draw()
{
glPushMatrix();
glTranslatef(this->coords[0], this->coords[1], this->coords[2]);
if(this->angle[0] != 0.0f)
glRotatef(this->angle[0], 1.0f, 0.0f, 0.0f);
if(this->angle[1] != 0.0f)
glRotatef(this->angle[1], 0.0f, 1.0f, 0.0f);
if(this->angle[2] != 0.0f)
glRotatef(this->angle[2], 0.0f, 0.0f, 1.0f);
glScalef(this->size, this->size, this->size);
glActiveTexture(GL_TEXTURE0); //<=====
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->texture->getGLTexture());
glutSolidTeapot(this->size);
glPopMatrix();
glActiveTexture(GL_TEXTURE1); //<=====
//glEnable(GL_TEXTURE_2D);
}
C2DTexture texture generaton proc:
C2DTexture::C2DTexture(std::string fn)
{
this->filename = fn;
this->imgTexture = auxDIBImageLoad(this->filename.c_str());
if(this->imgTexture == NULL)
throw ERR::CError(ERR::ERR_NOSUCHFILE, ERR::ERR_NOSUCHFILETEXT + this->filename);
// Creating a texture
glGenTextures(1, &this->glTexture);
glBindTexture(GL_TEXTURE_2D, this->glTexture);
// Setting filters
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, this->imgTexture->sizeX, this->imgTexture->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, this->imgTexture->data);
}
You tried to apply multi-texturing ? It does not show in your code. You do need to use it. One texture unit for the shadow texture, one for your diffuse map. If you tried, you should show the code with multi-texturing.
Multi-texturing is handled through glActiveTexture (and for fixed function that you seem to be using, glClientActiveTexture to handle the texture coordinates specifications).
Some pieces of advice:
it's easier to understand exactly what you're doing if you use shaders.
you want to map the depth texture to the texture unit 1: the setup of the texture unit for shadow mapping needs to be preceded by a glActiveTexture(GL_TEXTURE1) -- the BindTexture, the TexGen, and the texturing related Enable/Disable. Of course, you need to switch back to the texture unit 0 for the rest.
you don't want any texturing when you draw to the depth map.
It is faster to draw directly to the texture with the framebuffer_object extension, than to copy to it
Hope this helps.
Edit: Since you've changed quite a bit your question, let me add some pieces of advice and answers to your comments:
A single texture unit will always fetch from a single texture object. You use glActiveTexture followed by glBindTexture to specify which texture will be fetched from on that texture unit. Note that to get any texturing on that unit, you still need to call glEnable(GL_TEXTURE_2D) for that unit.
What to apply first... Well, this is where using shaders simplifies quite a lot the discussion. In general, the order of application completely depends on what fragment math you want to end up with. Let's put the following nomenclature:
T_0 the result of the first texture fetch,
T_1 the result of the second texture fetch.
C_f The input color that OpenGL computed and rasterized for this fragment (You're using the fixed function lighting, that's what I'm talking about)
C_o The final color of the fragment
T_s the result of the shadow texture fetch,
T_d the result of the diffuse texture fetch.
The result you'll get, with 2 texture units enabled, is something like
C_o = TexEnv1(TexEnv0(C_f,T_0), T_1)
The result you want is likely
C_o = C_f * T_s * T_d
What does that tell us ?
to implement the multiplications, you want modulate as your TexEnv for both texture unit 0 and texture unit 1
the order does not matter in this case (this is because the multiplication -aka modulation- is commutative)
what I showed is pretty much shader code. A lot easier to read than TexEnv settings.
Now to get back to your problem... At this point, I hope you understand what OpenGL state you should have come draw time. However, trying to know exactly what state you actually have from reading your code is a perilous exercise at best. If you are serious about using OpenGL, I recommend either of the following:
use an OpenGL debugger. There are a number of tools out there that will show the exact state at a specific draw call.
build your own debugging state tracking
dump the OpenGL state of interest at the time of the draw. OpenGL provides getter methods for every bit of its state (or almost, I won't go into the dirtiest details here), You want to do that only for debugging purposes, Getters are not guaranteed to be efficient at all).
Related
I'm having trouble getting my texture to map to a quad using OpenGL and Qt. I've looked at several other SO threads, but a lot of the function calls have to be used slightly differently for me to compile (Qt Verison 4.8.6). Here's my relevant code, right now all that happens is a window is displayed with a black background, but nothing else.
void LoadGLTextures( const char * name )
{
QImage img;
if(!img.load("resources/Green_Dragon.bmp")){
std::cerr << "ERROR in loading image" << std::endl;
}
QImage t = QGLWidget::convertToGLFormat(img);
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits());
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glBindTexture( GL_TEXTURE_2D, 0 );
}
void GLWidget::initializeGL()
{
qglClearColor(qtBlack.dark());
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_MULTISAMPLE);
static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
cameraPos = 0;
glEnable(GL_TEXTURE_2D);
LoadGLTextures("resources/Green_Dragon.jpeg");
}
void GLWidget::paintGL()
{
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f);
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glShadeModel( GL_FLAT );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glColor3f(0.5, 0.5, 0);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f); glVertex2f(-0.5f, 0.5f); // vertex 1
glTexCoord2f(0.0f, 0.0f); glVertex2f(-0.5f, -0.5f); // vertex 2
glTexCoord2f(1.0f, 0.0f); glVertex2f(0.5f, -0.5f); // vertex 3
glTexCoord2f(1.0f, 1.0f); glVertex2f(0.5f, 0.5f); // vertex 4
glEnd();
glDisable(GL_TEXTURE_2D);
glFlush();
}
Looking at your comment, the answer is fairly clear now, sorry that I missed it in the question comments.
You are seeing a black screen because you are enabling depth testing, but you are not clearing the depth buffer between frames. Therefore, the previous frame's depth buffer values remain in place, and the depth tests fail for all subsequent frames (note that the default depth function is GL_LESS).
You may leave depth testing enabled. The correct solution is to clear your depth buffer in addition to your color buffer before each render. You have:
glClear( GL_COLOR_BUFFER_BIT );
But you need:
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
See also: glClear()
Removing glEnable(GL_DEPTH_TEST) solved this for me, in case anyone runs into a similar problem.
I've implemented shadow mapping using ARB extensions following this tutorial
http://www.paulsprojects.net/tutorials/smt/smt.html
I've modified the code to add another light source. I've created and initialized 2 more matrices (lightViewMatrix2 and lightProjectionMatrix2) and another shadowMap texture.
At step 3 of the tutorial, after binding the first shadowmap texture, I've binded the second one.
The result I get is that I see only the intersections between the 2 shadows produced by the 2 different light sources.
I've initialized all the matrices in the init function as shown in the tutorial, this is my display function.
void Display(void){
//First pass - from light's point of view
//Calculate & save matrices LIGHT 1
glPushMatrix();
glLoadIdentity();
gluLookAt( lightPosition[0], lightPosition[1], lightPosition[2],
0.0f, 0.0f , 0.0f,
0.0f, 1.0f, 0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix);
glPopMatrix();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(lightProjectionMatrix);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(lightViewMatrix);
//Use viewport the same size as the shadow map
glViewport(0, 0, shadowMapSize, shadowMapSize);
//Draw back faces into the shadow map
glCullFace(GL_FRONT);
//Disable color writes, and use flat shading for speed
glShadeModel(GL_FLAT);
glColorMask(0, 0, 0, 0);
//Draw the scene
DrawScene();
//Read the depth buffer into the shadow map texture
glBindTexture(GL_TEXTURE_2D, shadowMapTexture[0]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize);
//First pass - from light's point of view
//Calculate & save matrices LIGHT 2
glPushMatrix();
glLoadIdentity();
gluLookAt( lightPosition2[0], lightPosition2[1], lightPosition2[2],
0.0f, 0.0f , 0.0f,
0.0f, 1.0f, 0.0f);
glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix2);
glPopMatrix();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(lightProjectionMatrix2);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(lightViewMatrix2);
//Use viewport the same size as the shadow map
glViewport(0, 0, shadowMapSize, shadowMapSize);
//Draw the scene
DrawScene();
//Read the depth buffer into the shadow map texture
glBindTexture(GL_TEXTURE_2D, shadowMapTexture[1]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize);
//restore states
glCullFace(GL_BACK);
glShadeModel(GL_SMOOTH);
glColorMask(1, 1, 1, 1);
//2nd pass - Draw from camera's point of view
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(cameraProjectionMatrix);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(cameraViewMatrix);
glViewport(0, 0, windowWidth, windowHeight);
float white2[3]={0.2f,0.2f,0.2f};
//light to represent shadowed areas
glLightfv(GL_LIGHT1, GL_POSITION, VECTOR4D(lightPosition));
glLightfv(GL_LIGHT1, GL_AMBIENT, white2);
glLightfv(GL_LIGHT1, GL_DIFFUSE, white2);
glLightfv(GL_LIGHT1, GL_SPECULAR, black1);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
DrawScene();
//3rd pass
//Draw with bright light LIGHT1
glLightfv(GL_LIGHT1, GL_DIFFUSE, white1);
glLightfv(GL_LIGHT1, GL_SPECULAR, white1);
//Calculate texture matrix for projection
//This matrix takes us from eye space to the light's clip space
//It is postmultiplied by the inverse of the current view matrix when specifying texgen
static MATRIX4X4 biasMatrix(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f); //bias from [-1, 1] to [0, 1]
MATRIX4X4 textureMatrix=biasMatrix*lightProjectionMatrix*lightViewMatrix;
//Set up texture coordinate generation.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix.GetRow(0));
glEnable(GL_TEXTURE_GEN_S);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix.GetRow(1));
glEnable(GL_TEXTURE_GEN_T);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix.GetRow(2));
glEnable(GL_TEXTURE_GEN_R);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix.GetRow(3));
glEnable(GL_TEXTURE_GEN_Q);
//Bind & enable shadow map texture
glBindTexture(GL_TEXTURE_2D, shadowMapTexture[0]);
glEnable(GL_TEXTURE_2D);
//Enable shadow comparison
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
//Shadow comparison should be true (ie not in shadow) if r<=texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
//Shadow comparison should generate an INTENSITY result
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
//Set alpha test to discard false comparisons
glAlphaFunc(GL_GEQUAL, 0.99f);
glEnable(GL_ALPHA_TEST);
DrawScene();
//3rd pass
//Draw with bright light LIGHT2
MATRIX4X4 textureMatrix2=biasMatrix*lightProjectionMatrix2*lightViewMatrix2;
//Set up texture coordinate generation.
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix2.GetRow(0));
glEnable(GL_TEXTURE_GEN_S);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix2.GetRow(1));
glEnable(GL_TEXTURE_GEN_T);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix2.GetRow(2));
glEnable(GL_TEXTURE_GEN_R);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix2.GetRow(3));
glEnable(GL_TEXTURE_GEN_Q);
//Bind & enable shadow map texture
glBindTexture(GL_TEXTURE_2D, shadowMapTexture[1]);
glEnable(GL_TEXTURE_2D);
//Enable shadow comparison
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
//Shadow comparison should be true (ie not in shadow) if r<=texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
//Shadow comparison should generate an INTENSITY result
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
//Set alpha test to discard false comparisons
glAlphaFunc(GL_GEQUAL, 0.99f);
glEnable(GL_ALPHA_TEST);
DrawScene();
//Disable textures and texgen
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
//Restore other states
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
//Set matrices for ortho
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
//reset matrices
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glFinish();
glutSwapBuffers();}
What you are doing here is you are first generating the shadow map for the first light, then you are generating a shadow map for the second light at the same time doing comparisons with the first shadow map. As a result you end up with a shadow that is some kind of combination of the two.
You would need to generate your second shadow the same way you generate your first (shadow generation for each light should be independent of every other light) and then finally since you would need to use some multi-texturing to somehow do the same comparison check for each z-texture independently.
Consider using a shader-based approach as all these fixed-function calls are outdated and have no advantage over shaders. The best article I read about shadow mapping with many lights is "Massive Number of Shadow-Casting Lights with Layered Rendering" By Daniel Rákos. It presents a very efficient way of doing this.
I am attempting to draw a quadrilateral (square) on the screen. I inserted this into a pre-existing program that drew a cylinder. This is in an orthographic modelview matrix, and I am almost positive the clipping volume is correct (It's 200 in any direction from the origin). In the display function I'm using, I pushed a matrix, translated forward (0.0,0.0,-20.0), called quadriliteral, and then popped the matrix. Are the any common openGL settings people use that I'm unaware of that may make this not visible? Is there a way to get the current clipping volume and print it out in the console?
void quadrilateral()
{
glLoadIdentity();
glColor3f(0.5f,0.0f,0.8f);
glBegin(GL_QUADS);
glVertex3f(-10.0f,-10.0f,0.0f);
glVertex3f(-10.0f,10.0f,0.0f);
glVertex3f(10.0f,10.0f,0.0f);
glVertex3f(10.0f,-10.0f,0.0f);
glEnd();
}
//This is called from a main function elsewhere
void draw(void)
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Cylinder");
glutReshapeFunc(CChangeSize);
glutSpecialFunc(CSpecialKeys);
glutKeyboardFunc(Ckeyboard);
glutDisplayFunc(CRenderScene);
CSetupRC();
glPopMatrix();
}
void CSetupRC()
{
// Light values and coordinates
GLfloat ambientLight[] = {0.4f, 0.4f, 0.4f, 1.0f };
GLfloat diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f };
GLfloat specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
GLfloat lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
GLfloat specref[] = { 0.6f, 0.6f, 0.6f, 1.0f };
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glEnable(GL_CULL_FACE); // Do not calculate inside of solid object
glFrontFace(GL_CCW);
// Enable lighting
glEnable(GL_LIGHTING);
// Setup light 0
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
// Position and turn on the light
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);
// Enable color tracking
glEnable(GL_COLOR_MATERIAL);
// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// All materials hereafter have full specular reflectivity
// with a moderate shine
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,64);
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f );
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);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
}
// Called to draw scene
void CRenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Save the matrix state
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Rotate about x and y axes
glRotatef(CxRot, 1.0f, 0.0f, 0.0f);
glRotatef(CyRot, 0.0f, 1.0f, 0.0f);
// Draw the cylinder
cylinder();
glPopMatrix();
// CylinderTwo
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Rotate about x and y axes
glRotatef(CxRot, 1.0f, 0.0f, 0.0f);
glRotatef(CyRot, 0.0f, 1.0f, 0.0f);
// Draw the cylinder
glRotatef(120.0f, 1.0f, 1.0f, 1.0f);
cylinderTwo();
glPopMatrix();
// Random square
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(-30.0f,20.0f,10.0f);
quadrilateral();
glPopMatrix();
// Swap buffers
glutSwapBuffers();
}
It looks like your winding order is incorrect:
glEnable(GL_CULL_FACE);
this line means it will cull back faces.
glFrontFace(GL_CCW);
and this sets the front face to counter clockwise.
glVertex3f(-10.0f,-10.0f,0.0f);
glVertex3f(-10.0f,10.0f,0.0f);
glVertex3f(10.0f,10.0f,0.0f);
glVertex3f(10.0f,-10.0f,0.0f);
Here you have clockwise ordering of your vertices meaning you are drawing with the back to camera. either disable culling:
glDisable(GL_CULL_FACE);
make the front face clockwise:
glFrontFace(GL_CW);
or change the order of your vertices to a counter clockwise order.
Looks to me that your quad is wound backwards. You've enabled GL_CULL_FACE, which throws out any clockwise wound polygons, and your quad has a clockwise winding.
Either disable backface culling, or switch the order of your vertices to counter-clockwise.
I'm rendering textures on the two surfaces which actually have the same location and position.
In these kind of cases I want to display only one of the textures, while I get following
I.e. I want only the texture of first material to be displayed.
So I would like to know where I've to search for solution, should I play with the blending of the materials ?
This is a pretty old issue (z-fighting) as the card isn't sure which object to draw in front. The linked Wikipedia article has more examples of this.
To fix this, increase the depth buffer's accuracy (bit depth), reduce the depth of your view (distance far/near clip plane) or add a tiny offset so the coordinates are no longer exactly (or almost) the same. You could as well simply disable the depth buffer (or clear it) for rendering this (in which case whatever is rendered last will overlap everything else).
You mean you want to display few textures at one time? Use multi texturing then. Attach both textures to one Quad using:
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 0.0f);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 0.0f);
And play with glTexEnvi to combine them as you want. If you want to show only one of your textures then draw two quads with separate textures on each of them. And quad witch will be drawn later will be visible. Then if you want to turn from one to another, make separate -(void)'s for each of quad, with glClearColor before each quad drawing and then make button to call for example -(void)quad1 and button to call -(void)quad2.
Or just use depth buffer.
At your situation i would use multi texturing, because all buffers looked too hard for me all time.
I will show how would my code look like.
Code using multi texture:
glClear(GL_COLOR_BUFFER_BIT);
//Turn on blending and set glBlendFunc for your needs
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//Describing multitexturing
glClientActiveTexture(GL_TEXTURE0_ARB); //Activating texture on unit 0
glActiveTexture(GL_TEXTURE0_ARB); //Activating texture on unit 0
glBindTexture(GL_TEXTURE_2D, Texture1); //Bind texture on unit 0
glEnable(GL_TEXTURE_2D); //Enable GL_TEXTURE_2D to set it's glTexEnvi for your needs
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); //Edit glTexEnvi for your needs (link bellow code)
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE );
glClientActiveTexture(GL_TEXTURE1_ARB); //Activating texture on unit 1
glActiveTexture(GL_TEXTURE1_ARB); //Activating texture on unit 1
glBindTexture(GL_TEXTURE_2D, Texture2); //Bind texture on unit 0
glEnable(GL_TEXTURE_2D); //Enable GL_TEXTURE_2D to set it's glTexEnvi for your needs
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); //Edit glTexEnvi for your needs (link bellow code)
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
//Drawing quad with multi texture
glBegin(GL_QUADS);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 0.0f); //Texture on unit 0 coords
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 0.0f); //Texture on unit 1 coords
glVertex2f(0.0, 500);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 1.0f); //Texture on unit 0 coords
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 1.0f); //Texture on unit 1 coords
glVertex2f(0.0, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 1.0f); //Texture on unit 0 coords
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 1.0f); //Texture on unit 1 coords
glVertex2f(800, 0.0);
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 0.0f); //Texture on unit 0 coords
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 0.0f); //Texture on unit 1 coords
glVertex2f(800, 500);
glEnd();
//Disable GL_TEXTURE_2D. We don't need it anymore
glDisable(GL_TEXTURE_2D);
//Disable blending
glDisable(GL_BLEND);
//Flush everything
glFlush();
Code for using one quad for each texture
-(void) drawQuad1
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture1);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0, 500);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0, 0.0);
glTexCoord2f(1.0f, 1.0f); glVertex2f(800, 0.0);
glTexCoord2f(1.0f, 0.0f); glVertex2f(800, 500);
glEnd();
glDisable(GL_TEXTURE_2D)
glFlush();
}
-(void) drawQuad2
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture2);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0, 500);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0, 0.0);
glTexCoord2f(1.0f, 1.0f); glVertex2f(800, 0.0);
glTexCoord2f(1.0f, 0.0f); glVertex2f(800, 500);
glEnd();
glDisable(GL_TEXTURE_2D)
glFlush();
}
//and now when you want to draw `drawQuad1` you need to do `[self drawQuad1];`
//and where you want to draw `drawQuad2` you need to do `[self drawQuad2];`
Info about glTexEnvi here. Its just sample code. Fast written so could have mistakes. Sorry if i forgot something. Just i haven't been doing it for long time. Written it on Mac OS X, so if you are using other platform maby you will have to change few things (not opengl). And about depth buffer? I don't know how to use it. So I can't explain it for you. Sorry. Never used them.
To make my maze type game faster I decided to put my drawed ball inside a texture, because i have to draw it otherwise once for every room and I'm drawing it like a concave polygon using the stencil buffer, it takes more time than using a texture. The problem is, that I'm getting it inside a texture correctly from the back buffer when I'm rendering the third frame since the start of the game and my question is, why is it like so?
When I'm using a texture from the thirst frame, I'm having texture with solid white color, so it has nothing inside. When I'm using textures from the second frame, then I have only the black background of the desired texture and when I take the texture from the third frame, then I have desired texture. For frame count I use the static variable "done" inside the "drawTexture" function.
Copying from the first frame:
Copying from the second frame:
Copying from the third frame (desired outcome):
void DrawBall::drawTexture(float imageD) {
static int done = 0;
if (done < 3) {
drawToTexture(imageD);
done++;
}
glEnable(GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture);
glColor3f(1, 1, 1);
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0); glVertex3f (0.0, 0.0, -imageD);
glTexCoord2f (1.0, 0.0); glVertex3f (5.0, 0.0, -imageD);
glTexCoord2f (1.0, 1.0); glVertex3f (5.0, 5.0, -imageD);
glTexCoord2f (0.0, 1.0); glVertex3f (0.0, 5.0, -imageD);
glEnd ();
glDisable(GL_TEXTURE_2D);
}
void DrawBall::drawToTexture(float imageD) {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, (int*) viewport);
int textureWidth = 64;
int textureHeight = 64;
texture = genEmptyTexture(textureWidth, textureHeight);
glViewport(0, 0, textureWidth, textureHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
This function calculates the vertexes for the ball
inside a vector<vector<float>> variable "test"
*/
_calculateCircleVertexes(0.0f, 0.0f, -2.0f, 0.249f, &test, 20);
_displayBall(&test, 0.0f, 0.0f, 0.5f, -2.0f, &*smallBallColor);
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, textureWidth, textureHeight, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)viewport[2] / (GLfloat)viewport[3], 1.0f, imageD + 10.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
GLuint DrawBall::genEmptyTexture(unsigned int width, unsigned int height) {
GLuint txtIndex;
glGenTextures(1, &txtIndex);
glBindTexture(GL_TEXTURE_2D, txtIndex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
return txtIndex;
}
void DrawBall::_displayBall(vector<vector<GLfloat>> *vertexes, GLfloat x, GLfloat y
, GLfloat imageW, GLfloat imageD, color *color) {
glTranslatef(x, y, imageD);
glClearStencil(0);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NEVER, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glBegin(GL_POLYGON);
vector<vector<GLfloat>>::iterator it = vertexes->begin();
for (; it != vertexes->end(); it++) {
glVertex3f((*it)[0], (*it)[1], 0.0f);
}
glEnd();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glColor3f(color->r, color->g, color->b);
glBegin(GL_QUADS);
glVertex3f(-(imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), (imageW / 2.0f), 0.0f);
glVertex3f(-(imageW / 2.0f), (imageW / 2.0f), 0.0f);
glEnd();
glDisable(GL_STENCIL_TEST);
glTranslatef(x, y, -imageD);
}
You should not use the window framebuffer (which includes both back- and frontbuffer) for render to texture operations. It just breaks to easily (you've experienced it). Instead use a so called Framebuffer Object, with the texture as rendering target.
Well, Datenwolf, thank you for your suggestion, you are probably right but I just want to use the advanced stuff as less as possible and I found my mistakes. I didn't get the desired outcome before the second frame because I didn't have yet enabled stencil test. Before the first frame I didn't get the desired outcome because in the window creation Windows sends WM_SIZE message and I had the draw message inside it but at that time the OpenGL isn't set up properly yet.