Sign in to follow this  
ATGardner23

trouble with material/textures

Recommended Posts

I have put on the materials as read from the mtl file, and the models look alright (some of them, at least..). The thing is that the last material gets smeared over my textures somehow. After drawing the car, I should draw the road, and it has a texture. When I use the materials, the road gets the color of the car wheels - probably the last material used. why is that? should I disable the material somehow?

Share this post


Link to post
Share on other sites
You just replied to your own question :)

A simple way of handling with these kind of problems is making a 'clear' function that calls the proper glDisable(...) calls for each of the glEnable(...) calls you use in your program and call that before setting up the state for a new object. This my not be the best option from a performance point of view, but it does make state cleaning easy. More efficient ways of state management require you to track the states yourself.

Tom

Share this post


Link to post
Share on other sites
yeah, well...
what do I have to disable then? I never did an glEnable(GL_MATERIAL) or anything like that, and my textures are set to GL_DECAL, so how come the materials cover them?

Share this post


Link to post
Share on other sites
If you don't want any colors or lighting effects on the road and only want to see the texture, make sure you use:
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
This ensures that any color values are overwritten.
If you do want lighting effects, use:
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
and specify proper material values for the road as well.

Tom

Share this post


Link to post
Share on other sites
I must be doing something wrong...
I just changed the GL_DECAL to GL_REPLACE, and I still get an all black road.
It's probably not it.. I edited the mtl file so that the last used material will be bright yellow.. the model gets it, but the road gets all black.
and when I just comment out the line that causes the four glMaterialf calls (ambient, diffuse, specular, shininess), the road gets the texture alright.
what am I missing here?

Share this post


Link to post
Share on other sites
I disabled lighting for the engite scene, and nothing changed (excpet that the model now looks like a 2d blob).
This texture thing is weird - the sideways of the road are getting the proper texture alright. just not the middle polygon.

Share this post


Link to post
Share on other sites
First I load and bind the texture:

void Road::GetTexture(const char *texFileName)
{
texImage = NULL;

FREE_IMAGE_FORMAT format = FreeImage_GetFileType(texFileName);
if (format == FIF_UNKNOWN)
{
format = FreeImage_GetFIFFromFilename(texFileName);
if ((format == FIF_UNKNOWN) || (!FreeImage_FIFSupportsReading(format)))
return;
}

texImage = FreeImage_Load(format, texFileName, NULL);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

BYTE *pixels = FreeImage_GetBits(texImage);
int texWidth = FreeImage_GetWidth(texImage);
int texHeight = FreeImage_GetHeight(texImage);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
}

loading the image, and reading it's pixel array.

here is the method that draws the road

void Road::Draw()
{
GLfloat wall_diffuse[] = {1, 0.3, 0.5, 1.0};

glPushAttrib(GL_CURRENT_BIT);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glBegin(GL_QUADS);
{
glTexCoord2f(0.0, time); glVertex3f(-shoulderWidth, 0, length);
glTexCoord2f(1.0, time); glVertex3f(shoulderWidth, 0, length);
glTexCoord2f(1.0, time + ratio); glVertex3f(shoulderWidth, 0, -length);
glTexCoord2f(0.0, time + ratio); glVertex3f(-shoulderWidth, 0, -length);
}

glEnd();

glBindTexture(GL_TEXTURE_2D, 0);
glPopAttrib();
time += speed;
if (time == 1024)
time = 0;

for(unsigned int i = 0; i < models.size(); ++i)
models[i]->Draw();
}

the shoulderWidth and length just define the road, a simple quad polygon around (0,0,0) on the XZ plane.
After the road is done with, I draw all the models (one, at the moment...) on it.
The models are drawn using display lists, which are being compiled when they are loaded from files.
here is the creation of the display list:

displayList = glGenLists(1);
glNewList(displayList, GL_COMPILE);
glPushMatrix();
boundingBox.Normalize();
glBegin(GL_TRIANGLES);
{
for (unsigned int i = 0; i < triangles.size(); ++i)
{
if (currentMaterial != triangles[i].material)
{
currentMaterial = triangles[i].material;
currentMaterial->Set();
}

for (unsigned int j = 0; j < 3; ++j)
{
normal = normals[triangles[i].normal[j]].v;
vertex = vertices[triangles[i].vertex[j]].v;
glNormal3fv(normal);
glVertex3fv(vertex);
}
}
}

glEnd();
glPopMatrix();
glEndList();

just a simple loop. whenever the triangles array calls for a change of material, I change it, and set it (just a call to the 4 material mehotds). The rest is just going over all the vertex of each triangle, creating it's normal and vertex.
if I comment the line with currentMaterial->Set(); I get the road texture working fine.

Another newbie question, while I am at it - in order to create a decent interactive frame rate, what should I do? right now I am just using my display function as the glutIdleFunc, so it keeps refreshing the screen whenever it can. is that the way to do it, or is there another way?
And about creating the movement - should I just get the Draw method of every Model I've got to run the display list, and then update some local variable to change the current location? or should I seperate the drawing from the moving ( - before each call do a glTranslatef call, but updating the local x,y,z values at a different location)?

Share this post


Link to post
Share on other sites
Allthough this will probably not solve your problem, I'm missing a glEnable(GL_TEXTURE_2D); at the start of your road::Draw() and a glDisable(GL_TEXTURE_2D); at the end of that same function.

I don't understand why currentMaterial->Set() had an effect on the road, because you did not add the code for the Set() function. However, if it contains a glDisable(GL_TEXTURE_2D); that would explain your problem.

On the other issues; my glutIdle() always looks like this:
void idle(void)
{
glutPostRedisplay();
}
You could do some variable upkeep here, but as a rule I only use glut* calls and no gl* calls in idle. gl* calls should be in your glutDisplay function. This only to get nicer code, it will not make much of a performance difference compared to your approach. Performance is normally determined by whatever you do in the rendering loop (and by your program logics if you perform complex calculations such as object culling, game a.i., etc.).

About the movement; as it's just a matter of design, this is all up to you. I use my own Scene Graph API where each object has Translation, Rotation and Scaling functions that togeter form the TRS-transform matrix for a particular object. Then I load the TRS matrix before drawing the object. This might be overkill for a smaller program. I would definately store the position and orientation inside the object, because they are properties of that object.

Tom

Share this post


Link to post
Share on other sites
my material->set() func is just

glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);

I had the GL_TEXTURE2D enabled globally. I now moved it to before the road drawing, and disabled it afterwards. Nothing changed really.

Thanks for the info about the idle. I just now found the glutTimerFunc, and tried using it to maintain a minimum 30fps rate. I am not sure how to use it exactly - I just call a function

void timer(int i)
{
glutPostRedisplay();
}

ignoring the "i" value. Anyway, it doesn't work.. I think I will stick to the glutIdleFunc idea.

Share this post


Link to post
Share on other sites
As I said, I didn't really believe the glEnable(GL_TEXTURE_2D) would solve anything. Your problem is weird alright. Could you add a screenshot showing the problem? I'm going offline now, but maybe someone else will recognize the problem.

About the glutTimerFunc(); I never use it because it doesn't scale to slower computers. Anyway, if I remember correctly how it works, you have to set it again after each call. So, changing your timer callback to
void timer(int i)
{
glutPostRedisplay();
glutTimerFunc(TIMER_TIME, timer, i);
}
should do the trick.

Tom

Share this post


Link to post
Share on other sites
Since you don't seem to be changing the material state before you render the road, the previous state is propagating forward ( OpenGL is a state machine afterall ). You need to set the roads material before rendering it - if you don't want the road to be lit, then just specify an ambient term, and put the rest at zero.

Share this post


Link to post
Share on other sites
well, I added those lines to the beginning of my Road::Draw method:

GLfloat road_ambient[] = {1, 1, 1, 1.0};
GLfloat road_diffuse[] = {0, 0, 0, 1.0};
GLfloat road_specular[] = {0, 0, 0, 1.0};

glMaterialfv(GL_FRONT, GL_AMBIENT, road_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, road_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, road_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 100);

and nothing changed at all, except now the model looks like a blob, when I don't put on it's material settings (commenting out the material->set() call).
I tried ul two pics to my uni server, but it seems to be down at the moment

Share this post


Link to post
Share on other sites
Quote:
Original post by ATGardner23
well, I added those lines to the beginning of my Road::Draw method:

GLfloat road_ambient[] = {1, 1, 1, 1.0};
GLfloat road_diffuse[] = {0, 0, 0, 1.0};
GLfloat road_specular[] = {0, 0, 0, 1.0};

glMaterialfv(GL_FRONT, GL_AMBIENT, road_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, road_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, road_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 100);

and nothing changed at all, except now the model looks like a blob, when I don't put on it's material settings (commenting out the material->set() call).
I tried ul two pics to my uni server, but it seems to be down at the moment


The models need their materials, so don't comment out their material->set() function. Is there perhaps a stray glColour() somewhere thats screwing things up? It shouldn't matter if you have lighting enabled ( and the material isn't tracking the colour ), but try it out anyway. Do you actually have a light with an ambient term?

Share this post


Link to post
Share on other sites
The thing is that when I comment out the material->set() method, the road's texture re-appear... of course I need it un-commented. I want the car to have materials. I also tried commenting each of the 4 material->set() method lines. Each line alone causes this mess. only when ALL four are commented (or the call to the method itself), do I get the road's texture.

About the light, here are the lines setting it up:

GLfloat light_ambient[] = {0.5, 0.5, 0.5, 1};
GLfloat light_position[] = {0.0, 10.0, 10.0, 1.0};

glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);

And another thing - I have two more textured squares in my scene - the two roadsides. Their texture appears alright when I enable the car's material. it only effects the road's texture.

Share this post


Link to post
Share on other sites
So you want lighting to affect the road, right? I noticed that you aren't setting normals when you render the road so that would make lighting on it "mess up" but I don't know if that's your only problem because commenting out glMaterial calls wouldn't fix that.

EDIT: And just to make sure, are you checking for OpenGL errors? If not you should be.

Share this post


Link to post
Share on other sites
I do not need lights for the road. Only texture. That's why I don't have the road's normals set up.

About checking for errors - The functions that are giving me hard times are returning voids.. should I try glGetError after each one? What should I look for?

Share this post


Link to post
Share on other sites
Quote:
Original post by ATGardner23
I do not need lights for the road. Only texture. That's why I don't have the road's normals set up.


Ah... Well, then you should do a glDisable( GL_LIGHTING ) before you render the road.

Share this post


Link to post
Share on other sites
Well, I disabled the lighting. Still the road doesn't appear when I set the car's material.
And without disabling the lighting it's all the same.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this