Multiple textures in objects using the same shader

hello,

i´m still learning the basics of the glsl, so i´m a bit confused when you have to pass a variable to the shader it self, in this case i want to load like 2 textures and using the same program (vertex and pixel shader) attach 1 texture to a cube and the other one to the floor, i don´t know if that´s possible or not, do i have to compile a diferent shader program to attach a texture to each object?!

//Function for loading the textures


// Using auxDIBImageLoad's Own Error-Handler!
int LoadGLTextures(){												// Load Bitmaps And Convert To Textures
	
	bool status=true;													// Status Indicator
	AUX_RGBImageRec *Image=NULL;									// Create Storage Space For The Texture
	char *alpha=NULL;
	GLuint	texture[3];
	
	// Load The Tile-Bitmap For Base-Texture
	if (Image=auxDIBImageLoad("Data/crate.bmp")) {											
	
		// Storage For 3 Textures
						
		glGenTextures(3, texture);									// Create Three Textures
	
		// Create MipMapped Texture
		glActiveTexture(GL_TEXTURE0_ARB);
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, Image->data);
		glClientActiveTextureARB(GL_TEXTURE0_ARB);

	
	}
	else status=false;

		if (Image) {													// If Texture Exists
		if (Image->data) delete Image->data;						// If Texture Image Exists
		delete Image;
		Image=NULL;
	}
	

	// Load The Tile-Bitmap For Base-Texture
	if (Image=auxDIBImageLoad("Data/leaf.bmp")) {											


		glActiveTexture(GL_TEXTURE1_ARB);
		glBindTexture(GL_TEXTURE_2D, texture[1]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, Image->data);
		glClientActiveTextureARB(GL_TEXTURE1_ARB);
		
	}
	else status=false;

	if (Image) {													// If Texture Exists
		if (Image->data) delete Image->data;						// If Texture Image Exists
		delete Image;
		Image=NULL;
	}


	return status;

}



// Ser Up Cube And Floor
// Cube -> texture[0] Floor ->texture[1]



void doCube (void) {
	int i;


	glPushMatrix();

	glTranslatef(0, 0, 5);
	//glScalef(1,1,1);

	glBegin(GL_QUADS);
	
	// Front Face
		glNormal3f( 0.0f, 0.0f, +1.0f);
		for (i=0; i<4; i++) {
			
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i],data[5*i+1]);

	
			glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
		}
		// Back Face
		glNormal3f( 0.0f, 0.0f,-1.0f);
		for (i=4; i<8; i++) {
			
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i],data[5*i+1]);

			
		
			glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
		}
		// Top Face
		glNormal3f( 0.0f, 1.0f, 0.0f);
		for (i=8; i<12; i++) {
			
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i],data[5*i+1]);
			
			
		
			glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
		}
		// Bottom Face
		glNormal3f( 0.0f,-1.0f, 0.0f);
		for (i=12; i<16; i++) {
			
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i],data[5*i+1]);
			
		
			glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
		}
		// Right face
		glNormal3f( 1.0f, 0.0f, 0.0f);
		for (i=16; i<20; i++) {
		
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i],data[5*i+1]);
			
			
			glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
		}
		// Left Face
		glNormal3f(-1.0f, 0.0f, 0.0f);
		for (i=20; i<24; i++) {
		
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5*i],data[5*i+1]);

		
			glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
		}
	glEnd();
	
	glPopMatrix();
}



void floor(){

	glPushMatrix();
	glRotatef(90,1,0,0);
	glBegin(GL_POLYGON);
	glNormal3f(0,1,0);

	glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[0],data[1]);	glVertex3f(-25,0,-25);
	glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5],data[6]);	glVertex3f(25,0,-25);
	
	glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[10],data[11]);glVertex3f(25,0,25);
	glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[15],data[16]);glVertex3f(-25,0,25);
		
			
	glEnd();
	glPopMatrix();


}


//Set Shaders Function


void setShaders() {

	char *vs = NULL,*fs = NULL,*fs2 = NULL;

	v = glCreateShader(GL_VERTEX_SHADER);
	f = glCreateShader(GL_FRAGMENT_SHADER);
	f2 = glCreateShader(GL_FRAGMENT_SHADER);


	vs = textFileRead("shade/textureSimple.vert");
	fs = textFileRead("shade/textureSimple.frag");

	const char * vv = vs;
	const char * ff = fs;

	glShaderSource(v, 1, &vv,NULL);
	glShaderSource(f, 1, &ff,NULL);

	free(vs);free(fs);

	glCompileShader(v);
	glCompileShader(f);

	
	E.printShaderInfoLog(v);
	E.printShaderInfoLog(f);
	E.printShaderInfoLog(f2);

	p = glCreateProgram();
	glAttachShader(p,v);
	glAttachShader(p,f);

	glLinkProgram(p);
	E.printProgramInfoLog(p);
	glUseProgram(p);

}


//Draw Objects And attach the textures to each object
//Ser uniform location for each texture
//to pass to fragment shader
//(tex,0) and (tex,1)



       tex = glGetUniformLocation(p,"texture[0]");
       glUniform1iARB(tex,0);
		
		doCube();	

	tex = glGetUniformLocation(p,"texture[1]");
        glUniform1iARB(tex,1);
		floor();


//Vertex Shader


void main()
{

	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = ftransform();
} 

//Fragment Shader
//Receive -> uniform name variable:tex location: 0 and 1


uniform sampler2D tex;

void main()
{
	vec4 color = texture2D(tex,gl_TexCoord[0].st);
	gl_FragColor = color;
}


Now the problem is that the cube gets the 1st texture and the floor gets black wich probably means that it can´t find the 2nd texture on the right address or extension, could someone help me out?

I have not read through all your code but to answer your question…

You need two uniform 'sampler2D’s in your fragment shader to be able to access two textures in the same shader at the same time…

i.e:

uniform sampler2D texture0;
uniform sampler2D texture1;

You then use the name of the sampler2D with the required integer ID of the texture unit to identify it from your main code…

Roughly based on what you have above…

tex = glGetUniformLocation(p,“texture0”);
glUniform1iARB(tex,0);

tex = glGetUniformLocation(p,“texture1”);
glUniform1iARB(tex,1);

texture0 is texture Unit 0, and texture1 is texture Unit 1.

You then refer to them individually in your fragment shader…

texture2D(texture0,gl_TexCoord[0].st);
texture2D(texture1,gl_TexCoord[1].st);

From what it sounds like you are trying to do though I am not sure this will work as you expect. A texture is bound to a texture unit, not geometry.
So you are going to have to do something in your shaders to decide what is being drawn with some other variable, or something in your geometry it can identify, which is not really a good idea when there are simpler solutions available to you.

Alternatively you need to switch the setting of the one Uniform ‘tex’ location between 0 and 1 to refer to the different texture units depending on what geometry you are drawing.

Or bind a different texture to the same texture unit each time you draw either the walls or the floor.

GOT it many thanks for the help , now i can continue my shading EHEHEHHE, just another nobie question, can i change shaders while the same program run or do i have to recompile (the vertez and pixel shaders) all over again?

Best Regards

no need to reply, i have found the way

You can bind and unbind shaders as much as you like.

So you can have many shaders in one program, and turn them on and off as you wish. Typically people have a lot of shaders they compile and link at run time during the setup phase, and then bind and unbind as they require each different shaders functionality.

More adventurous programmers have multipart shaders made from small component text files that get appended to each other into one shader file at run time and then get compiled, linked and bound by OpenGL.

So you can delete shaders and then re-load / re-build / re-link them on the fly in your program. But the actual shader code is compiled, linked and interpreted by the OpenGL drivers from the text files in your program bundle, so you can’t really change them once they are active.

Is that what you mean?

A really good set of tutorials online are the LightHouse 3D tutorials.
They are easy to find on Google.

Other than that I would recommend The Orange Book.
http://www.3dshaders.com/

too late! :wink:

thanks for your time, now i know what i´m doing, yes that was what i was looking for,keeping the same program and just linking and unlink diferent shaders, at the mean time also, diferent objects in the scene will attached to the diferent shaders, i just got the book from amazon,i´m just waiting for it to arrive at my place so i can undo all my questions , and get started with the real thing :slight_smile:

sampler array are not supported even if I think the GLSL specification didn’t state on this … At least GLSL 1.2 specification.

However a way to do it is to use texture array but two sampler are good too in most cases.