glColor coloring all textures - c++

I'm fairly new to OpenGL so maybe the answer will be obvious. I am currently trying to make a blue circle using GL_TRIANGLE_FAN in C++. My problem is that when I set the color using glColor4f, it sets all my other textures to have a blue color over them such as shown below (this is supposed to be silvery metal).
I draw the textures using the method shown below.
glLoadIdentity();
glTranslatef(x,y,0);
glBindTexture(GL_TEXTURE_2D, this->texture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0,0,0);
glTexCoord2f(1.0f, 0.0f); glVertex3f(width,0,0);
glTexCoord2f(1.0f, 1.0f); glVertex3f(width,height,0);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0,height,0);
glEnd();
I'm not sure whether I just have to clear a flag for it to work, but I've been stuck for a few days now.

After drawing your blue circle, you should set the color back to white (default value) using glColor4f(1.f, 1.f, 1.f, 1.f);. Please note that by default the texture gets modulated by the currently set color (blue in your case) and that's the reason why your silver material gets a bluish tone (final color = blue color * texture color).

Unbind the texture and set the color back to white after you're done drawing:
glLoadIdentity();
glTranslatef(x,y,0);
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, this->texture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0,0,0);
glTexCoord2f(1.0f, 0.0f); glVertex3f(width,0,0);
glTexCoord2f(1.0f, 1.0f); glVertex3f(width,height,0);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0,height,0);
glEnd();
glColor4f(1, 1, 1, 1);
glBindTexture(GL_TEXTURE_2D, 0);
And if you aren't rendering textures on the next object, disable texturing:
glDisable( GL_TEXTURE_2D );

When You have enabled glEnable(GL_COLOR_MATERIAL) and changed a color by glColor, then all your textures will be affected by this color. This is because by default the texture is displayed in modulate mode (glColor multiplied by texture colors).
If you don't have lighting enabled, to restore the original texture color is simple - just set glColor to white: glColor4f(1.0, 1.0, 1.0, 1.0).
The problem comes, when you have lighting enabled on your texture. Then, setting the color to white or changing texture mode to REPLACE doesn't help at all - your lighting effects will be removed! (which nobody seems to be noticing!) The reason for this is because with enabling GL_COLOR_MATERIAL by default you're getting behaviour, where glColor commands changes both Ambient and Diffuse colours at the same time - thus your ambient and diffuse material properties will be affected (lost). So all you have to do, to restore the material state (and thus lighting effects), which you had before applying glEnable(GL_COLOR_MATERIAL), is the following:
glDisable(GL_COLOR_MATERIAL); //disable color influence
GLfloat ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f }; //default material has this ambient color!
GLfloat diffuse[] = { 0.8f ,0.8f ,0.8f, 1.0f }; //default material has this diffuse color!
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); //restore default material ambient color
glMaterialfv(GL_FRONT, GL_AMBIENT, diffuse); //restore default material diffuse color
Please note, what are the default ambient and diffuse colors for default material! There is no pure white there!
This way, all the textures, that you use from this point will be drawn as intended (with the correct color and lighting effects).
Took me some time to find this stuff, so I suppose it's nice to mention it here.

Before binding a texture, you need to enable it. And normally, you should disabled it when you are done with it. Something like this :
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, this->texture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0,0,0);
glTexCoord2f(1.0f, 0.0f); glVertex3f(width,0,0);
glTexCoord2f(1.0f, 1.0f); glVertex3f(width,height,0);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0,height,0);
glEnd();
glDisable( GL_TEXTURE_2D );

Related

Adding a Light Source to 3D objects in OpenGL

I was wondering if anyone could help me figure out how to add a light source to my 3D objects. I have four objects that are rotating and I want the light source to be at a fixed position, and I want to be able to see lighting on the object.
I tried doing this (********):
//*******Initializing the light position
GLfloat pos[] = {-2,4,5,1};
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
//*******adding the light to the display method
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, pos);
// rectangle
glPushMatrix();
glTranslatef(0.0f, 2.5f, -8.0f);
glRotatef(angleRectangle, 0.0f, 1.0f, 0.0f);
drawRectangle();
glPopMatrix();
//small cylinder
glPushMatrix();
glTranslatef(0.0f, 2.0f, -8.0f);
glRotatef(90, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 0.0f, 1.0f);
drawCylinder(0.2, 0.7);
glPopMatrix();
//big cylinder
glPushMatrix();
glTranslatef(0.0f, 1.5f, -8.0f);
glRotatef(90, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 0.0f, 1.0f);
drawCylinder(0.7, 2.7);
glPopMatrix();
//pyramid
glPushMatrix();
glTranslatef(0.0f, -2.2f, -8.0f);
glRotatef(180, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 1.0f, 0.0f);
drawPyramid();
glPopMatrix();
glutSwapBuffers();
anglePyramid += k * 0.2f; //- is CW, + is CCW
angleRectangle += -k * 0.2f;
}
//******* Then i added these to the main method
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
However when I do this and I run the entire program, my objects turn gray, and at certain points in the rotation they turn white. And this isnt what I want. I want to keep my colorful objects, but I want to be able to see the light source on them.
Any help would be greatly appreciated. Also let me know if you need to see more of my code to figure out the issue. Thanks
When lighting (GL_LIGHTING) is enabled, then the color is taken from the material parameters (glMaterial).
If you still want to use the current color, the you have to enable GL_COLOR_MATERIAL
and to set the color material paramters (glColorMaterial):
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
See also Basic OpenGL Lighting.
But note, that drawing by glBegin/glEnd sequences, the fixed function pipeline matrix stack and fixed function pipeline per vertex light model, is deprecated since decades.
Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.

All texture colors affected by colored rectangle - OpenGL

I'm currently trying to color some rectangles to represent collision boxes for my game character. The issue is the color I'm trying to apply ONLY to the rectangles are being applied to my character and background textures as well. So if I draw a rect using the following code:
void DrawRect(v2f MinPoint, v2f MaxPoint)
{
glBegin(GL_QUADS);
glColor3f(1.0f, 0.0f, 0.0f); //Red color
glVertex2f(MaxPoint.x, MaxPoint.y);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(MinPoint.x, MaxPoint.y);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(MinPoint.x, MinPoint.y);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(MaxPoint.x, MinPoint.y);
glEnd();
glFlush();
}
Then right after draw my background texture:
void DrawBackground(ui32 TextureID, Drawable_Rect BackgroundImage, v2f MinUV, v2f MaxUV)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, TextureID);
glBegin(GL_QUADS);
glTexCoord2f(MinUV.x, MinUV.y);
glVertex2f(BackgroundImage.BottomLeft.x, BackgroundImage.BottomLeft.y);
glTexCoord2f(MaxUV.x, MinUV.y);
glVertex2f(BackgroundImage.BottomRight.x, BackgroundImage.BottomRight.y);
glTexCoord2f(MaxUV.x, MaxUV.y);
glVertex2f(BackgroundImage.TopRight.x, BackgroundImage.TopRight.y);
glTexCoord2f(MinUV.x, MaxUV.y);
glVertex2f(BackgroundImage.TopLeft.x, BackgroundImage.TopLeft.y);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
Then both my rectangle AND my background are red instead of just my rectangle. Why is the color being applied to both my rectangle and my texture?
If texturing is enabled, then by default the color of the texel is multiplied by the current color, because by default the texture environment mode (GL_TEXTURE_ENV_MODE) is GL_MODULATE. See glTexEnv.
This causes that the color of the texels of the texture is "mixed" by the last color which you have set by glColor3f:
Set a "white" color before you render the texture, to solve your issue:
glColor3f(1.0f, 1.0f, 1.0f);
Likewise you can change the environment mode to GL_REPLACE, instead:
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

OpenGL display textures correctly

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.

OpenGL - How do you scroll a texture?

I am creating a texture from a pango layout and mapping the texture to the screen using OpenGL and GLUT. I want to scroll the texture in the window. I'm not concerned with the controls to scroll, but how do I cause map the portion of the texture I want to see onto the screen? I assume I use glTranslate, but where do I apply it?
Thanks in advance.
Here is what I currently do:
glEnable(GL_TEXTURE_2D);
{
glBegin(GL_QUADS);
{
glTexCoord2f(0.0f, 0.0f); glVertex2f( 0.0f+x, 0.0f+y);
glTexCoord2f(1.0f, 0.0f); glVertex2f(_width+x, 0.0f+y);
glTexCoord2f(1.0f, 1.0f); glVertex2f(_width+x, _height+y);
glTexCoord2f(0.0f, 1.0f); glVertex2f( 0.0f+x, _height+y);
}
glEnd();
}
glFlush();
glDisable(GL_TEXTURE_2D);
Another way would be to use a texture matrix (matrix mode GL_TEXTURE) or do it in a shader.
Depends on how many vertices would have to be modified. If just a few it could be more performant but for many vertices a texture matrix/shader approach could be better. Note that built in matrix operations are deprecated, i.e. it now is recommended to use textures.
Scrolling in a shader would be easy: out.tex = in.tex + offset where offset could be a uniform which is set per frame or be calculated from other input.
Since your example uses immediate mode, I'll expand it with the texture matrix mode.
But please be aware that this is deprecated methodology.
glEnable(GL_TEXTURE_2D);
{
glMatrixMode(GL_TEXTURE);
glLoadIndentity();
glTranslatef(x,y,0);
glMatrixMode(GL_MODELVIEW);
glBegin(GL_QUADS);
{
glTexCoord2f(0.0f, 0.0f); glVertex2f( 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex2f(_width, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex2f(_width, _height);
glTexCoord2f(0.0f, 1.0f); glVertex2f( 0.0f, _height);
}
glEnd();
}
glFlush();
glDisable(GL_TEXTURE_2D);
Unless you also want to tile I would just modify the UV coordinates of the vertices you are outputting. Then you just change the coordinates you feed to glTexCoord2f to specify a crop.
There is also a nice example of texture transformations here http://potatoland.org/glart/week5/GLART_5_texture_samples.java (it's java but you can easily translate it to C)

Shadows via shadowmaps and other textures - how to combine? OpenGL

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).