Texturing a VBO model

Started by fiendfan1, May 16, 2013, 00:27:33

Previous topic - Next topic

fiendfan1

I cannot get Textures to work with VBOs I can texture fine using direct mode, but VBOs created from .obj files will not work!

Heres the code I use to create the VBO:
public static Object[][] createVBO(Model model) 
{
	int vboVertexHandle = glGenBuffers();
	int vboNormalHandle = glGenBuffers();
	int vboTexHandle = glGenBuffers();
		
	FloatBuffer vertices = reserveData(model.faces.size() * 9);
	FloatBuffer normals = reserveData(model.faces.size() * 9);
	FloatBuffer textCoords = reserveData(model.faces.size() * 9);
		
	for (Face face : model.faces)
	{
		vertices.put(asFloats(face.points[0]));
		vertices.put(asFloats(face.points[1]));
		vertices.put(asFloats(face.points[2]));
			
		normals.put(asFloats(face.normals[0]));
		normals.put(asFloats(face.normals[1]));
		normals.put(asFloats(face.normals[2]));
			
		textCoords.put(asFloats(face.textureCoords[0]));
	        textCoords.put(asFloats(face.textureCoords[1]));
		textCoords.put(asFloats(face.textureCoords[2]));
	}
	vertices.flip();
	normals.flip();
	textCoords.flip();
		
        //// These things are not necessary, but I do them becasue it  makes it easier for me. ////
	glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
	glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
	glVertexPointer(3, GL_FLOAT, 0, 0L);
		
	glBindBuffer(GL_ARRAY_BUFFER, vboNormalHandle);
	glBufferData(GL_ARRAY_BUFFER, normals, GL_STATIC_DRAW);
	glNormalPointer(GL_FLOAT, 0, 0L);
		
	glBindBuffer(GL_ARRAY_BUFFER, vboTexHandle);
        glBufferData(GL_ARRAY_BUFFER, textCoords, GL_STATIC_DRAW);
	glTexCoordPointer(3, GL_FLOAT, 0, 0L);
		
	glBindBuffer(GL_ARRAY_BUFFER, 0);

        ///// End Unnecessary code /////
	return new Object[][]{{vboVertexHandle, vertices}, {vboNormalHandle, normals}, {vboTexHandle, textCoords}};
}

private static FloatBuffer reserveData(int size) 
{
	return BufferUtils.createFloatBuffer(size);
}


And to call the VBO I use the following.
Model m = cur.model;

//Move the object
glTranslatef(cur.position.x, cur.position.y, cur.position.z);

//Set the shininess
glMaterialf(GL_FRONT, GL_SHININESS, m.shininess);

//Set the color
glColor3f(cur.color[0], cur.color[1], cur.color[2]);

//Use the model's shader
glUseProgram(m.shader);

//Bind the current model's texture
glBindTexture(GL_TEXTURE_2D, m.texture.getTextureID());
//Bind it again because... idk, its not working!
m.texture.bind();

//// Set Data for Vertices ////
glBindBuffer(GL_ARRAY_BUFFER, m.vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, m.vertex, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, 0L);

//// Set Data for Normals ////
glBindBuffer(GL_ARRAY_BUFFER, m.vboNormalHandle);
glBufferData(GL_ARRAY_BUFFER, m.normal, GL_STATIC_DRAW);
glNormalPointer(GL_FLOAT, 0, 0L);

//// Set Data for Texture Coordinates ////
glBindBuffer(GL_ARRAY_BUFFER, m.vboTexHandle);
glBufferData(GL_ARRAY_BUFFER, m.text, GL_STATIC_DRAW);
glTexCoordPointer(3, GL_FLOAT, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

//"Turn on" All Necessary client states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
{

	//Actually Draw the object
	glDrawArrays(GL_TRIANGLES, 0, m.faces.size() * 3);

}
//"Turn off" All Necessary client states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);


//Resets the array buffer, shader, texture, and color
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
cur.model.texture.release();
glBindTexture(GL_TEXTURE_2D, 0);
glColor4f(1, 1, 1, 1);

glLoadIdentity();


Using slick_util.jar for texture stuff.

My image's dimensions are powers of 2, no weird naming, and I already called glEnable(GL_TEXTURE_2D)

quew8

So what actually is your problem, the models are just showing as black or what?
I notice you are using shaders to render the models which means you don't need to enable GL_TEXTURE_2D, since you don't know this, I'm going to go ahead and assume it's your shaders that are not supporting texturing. Check out the LWJGL wiki: http://www.lwjgl.org/wiki/index.php?title=Main_Page, there are two tutorials there, in the legacy section there is "multi-texturing in GLSL" (also includes mono-texturing) or if you're an OpenGL 3.0+ man, there is "the quad textured," although you'd probably have to read the previous "the quad xxx"s

fiendfan1

Quote from: quew8 on May 16, 2013, 17:57:30
So what actually is your problem, the models are just showing as black or what?
I notice you are using shaders to render the models which means you don't need to enable GL_TEXTURE_2D, since you don't know this, I'm going to go ahead and assume it's your shaders that are not supporting texturing. Check out the LWJGL wiki: http://www.lwjgl.org/wiki/index.php?title=Main_Page, there are two tutorials there, in the legacy section there is "multi-texturing in GLSL" (also includes mono-texturing) or if you're an OpenGL 3.0+ man, there is "the quad textured," although you'd probably have to read the previous "the quad xxx"s
Thanks so much (again), I didn't even know you had to deal with texture coords after sending them to OpenGL.
I'm checking out the following pages on LWJGL Wiki:
http://lwjgl.org/wiki/index.php?title=The_Quad_textured
http://www.lwjgl.org/wiki/index.php?title=GLSL_Tutorial:_Texturing
http://lwjgl.org/wiki/index.php?title=Multi-Texturing_with_GLSL

quew8

Not a problem, the wiki is a great resource for beginners (please don't take offence, you may have lots of experience not using texture based shaders) you should take a look what is there. For the record that second tutorial, I wrote. Yay. It's nice to know that is actually helping people.

fiendfan1

Quote from: quew8 on May 17, 2013, 16:58:27
Not a problem, the wiki is a great resource for beginners (please don't take offence, you may have lots of experience not using texture based shaders) you should take a look what is there. For the record that second tutorial, I wrote. Yay. It's nice to know that is actually helping people.
The tutorials were great and really helpful, but I still can't get it to work. If I only use the texture2D to modify the gl_FragColor, It comes out black. If I use the texture2D and all the light stuff (see vertex shader below), It comes out white no matter what color material I have set.

Heres the Java code:
glTranslatef(cur.position.x, cur.position.y, cur.position.z);

							//Scale the object using the scale variable
							//glScalef(cur.model.scale, cur.model.scale, cur.model.scale);

							//Set the shininess
							glMaterialf(GL_FRONT, GL_SHININESS, m.shininess);

							//Set the color
							glColor3f(cur.color[0], cur.color[1], cur.color[2]);

							//Use the model's shader
							glUseProgram(m.shader);

							if(m.texture!=null)
							{
								GL13.glActiveTexture(GL13.GL_TEXTURE0);
								
								glBindTexture(GL_TEXTURE_2D, m.texture.getTextureID());
								//Bind it again because... idk, its not working!
								m.texture.bind();
								
								//Find the "memory address" of texture_diffuse uniform in shader
								int loc = glGetUniformLocation(m.shader, "texture1");
								
								//Pass the 0 value to the sampler meaning it is to use texture unit 0.
								glUniform1i(loc, 0);
							}

							//// Set Data for Vertices ////
							glBindBuffer(GL_ARRAY_BUFFER, m.vboVertexHandle);
							glBufferData(GL_ARRAY_BUFFER, m.vertex, GL_STATIC_DRAW);
							glVertexPointer(3, GL_FLOAT, 0, 0L);

							//// Set Data for Normals ////
							glBindBuffer(GL_ARRAY_BUFFER, m.vboNormalHandle);
							glBufferData(GL_ARRAY_BUFFER, m.normal, GL_STATIC_DRAW);
							glNormalPointer(GL_FLOAT, 0, 0L);

							//// Set Data for Texture Coordinates ////
							glBindBuffer(GL_ARRAY_BUFFER, m.vboTexHandle);
							glBufferData(GL_ARRAY_BUFFER, m.text, GL_STATIC_DRAW);
							glTexCoordPointer(3, GL_FLOAT, 0, 0);

							//Unbind Buffer for VBO
							glBindBuffer(GL_ARRAY_BUFFER, 0);

							//"Turn on" All Necessary client states
							glEnableClientState(GL_VERTEX_ARRAY);
							glEnableClientState(GL_TEXTURE_COORD_ARRAY);
							glEnableClientState(GL_NORMAL_ARRAY);
							{

								//Actually Draw the object
								glDrawArrays(GL_TRIANGLES, 0, m.faces.size() * 3);

							}
							//"Turn off" All Necessary client states
							glDisableClientState(GL_VERTEX_ARRAY);
							glDisableClientState(GL_TEXTURE_COORD_ARRAY);
							glDisableClientState(GL_NORMAL_ARRAY);

						//Resets the array buffer, shader, texture, and color
						glBindBuffer(GL_ARRAY_BUFFER, 0);
						glUseProgram(0);
						cur.model.texture.release();
						glBindTexture(GL_TEXTURE_2D, 0);
						glColor4f(1, 1, 1, 1);

						glLoadIdentity();


The vertex shader:

#version 120

varying vec3 varyingColour;

void main() {
	vec3 vertexPosition = (gl_ModelViewMatrix * gl_Vertex).xyz;

	vec3 lightDirection = normalize(gl_LightSource[0].position.xyz - vertexPosition);

	vec3 surfaceNormal  = (gl_NormalMatrix * gl_Normal).xyz;

	float diffuseLightIntensity = max(0, dot(surfaceNormal, lightDirection));
	
	varyingColour.rgb = diffuseLightIntensity * gl_FrontMaterial.diffuse.rgb;
	
	varyingColour += gl_LightModel.ambient.rgb;

	vec3 reflectionDirection = normalize(reflect(-lightDirection, surfaceNormal));

	float specular = max(0.0, dot(surfaceNormal, reflectionDirection));

	if (diffuseLightIntensity != 0) 
       {
		float fspecular = pow(specular, gl_FrontMaterial.shininess);

		varyingColour.rgb += vec3(fspecular, fspecular, fspecular);
	}

	gl_TexCoord[0] = gl_MultiTexCoord0;

    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}


fragment shader:

#version 120

// Per-vertex Phong lighting model

uniform sampler2D texture1;

varying vec3 varyingColour;

void main() 
{
    gl_FragColor = texture2D(texture1, gl_TexCoord[0].st);
    
    // Turns the varying color into a 4D color and stores in the built-in output gl_FragColor.
    //gl_FragColor += vec4(varyingColour, 1);
}

quew8

QuoteglTexCoordPointer(3, GL_FLOAT, 0, 0);

This should be 2 components right?

fiendfan1

Quote from: quew8 on May 18, 2013, 12:16:55
QuoteglTexCoordPointer(3, GL_FLOAT, 0, 0);

This should be 2 components right?

True. Fixed that and.... still not working... same problem.

fiendfan1

Other shaders work fine, it's just when I use anything with textures that it goes black.

For testing purposes, I'm just giving default texture coords to each face on the model.

f.textureCoords = new Vector2f[]
					{
					new Vector2f(0, 0),
					new Vector2f(1, 0),
					new Vector2f(1, 1)
					};


this data is then placed in a FloatBuffer using the code in the first post.

Basically this:
FloatBuffer textCoords = reserveData(model.faces.size() * 9);

for (Face face : model.faces)
{
       textCoords.put(asFloats(face.textureCoords[0]));
       textCoords.put(asFloats(face.textureCoords[1]));
       textCoords.put(asFloats(face.textureCoords[2]));
}
textCoords.flip();


Would that cause any problems?


Or are there any things that are supposed to be enabled? I have
GL_RESCALE_NORMAL
GL_DEPTH_TEST
GL_LIGHTING
GL_CULL_FACE (GL_BACK)
GL_COLOR_MATERIAL
GL_BLEND (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
GL_SMOOTH shadeModel
GL_PERSPECTIVE_CORRECTION_HINT is set to GL_NICEST

Is there anything that should not be enabled?

Sorry for the long questions, but I've been trying to solve this for about 4 months now and I can't figure it out.


quew8

I could find absolutely none of the code you have posted here in the github rep. I'm amazed anything is being drawn at all. Are you aware that you do not call Display.update in the loop? As far as I can see that is a big no no. The one thing I did notice though is that you seem to be calling flip on your buffers quite a lot. The problem with flip is that it sets the limit of the buffer to the previous position. So if the position is 0 then suddenly your buffer will not be read at all when sending it up to OpenGL but doesn't produce errors in java. Try printing out the position and limit of the texture coord buffer immediately before galling glBufferData, see what it says but that's just an idea.

I also noticed in the code posted here
QuoteFloatBuffer textCoords = reserveData(model.faces.size() * 9);
Should be * 6. But I don't see how that would cause this, I'm just saying.

fiendfan1

Quote from: quew8 on May 18, 2013, 23:59:39
I could find absolutely none of the code you have posted here in the github rep. I'm amazed anything is being drawn at all. Are you aware that you do not call Display.update in the loop? As far as I can see that is a big no no. The one thing I did notice though is that you seem to be calling flip on your buffers quite a lot. The problem with flip is that it sets the limit of the buffer to the previous position. So if the position is 0 then suddenly your buffer will not be read at all when sending it up to OpenGL but doesn't produce errors in java. Try printing out the position and limit of the texture coord buffer immediately before galling glBufferData, see what it says but that's just an idea.

I also noticed in the code posted here
QuoteFloatBuffer textCoords = reserveData(model.faces.size() * 9);
Should be * 6. But I don't see how that would cause this, I'm just saying.

Sorry I guess I forgot to mention the World class. Its update method is one that draws everything, calls Display.update(), ect.

I checked the position and limit of the texture coordinate FloatBuffer before glBufferData is called, and the position was 0 and the limit was 417996, which sounds right, unless I'm wrong. And as far as I know, I only flipped the buffer once... maybe I'm wrong.

I fixed the data reserve stuff, thanks for letting me know.

quew8

Near the end of your world update call there is
Quotecur.model.texture.release();
. This is destroying the texture, I looked it up and it's an interface but presumably the implementation would call glDeleteTextures. This means that next time you bind the texture, it is like you are simply binding a non-texture.

Your whole rendering code is wrong though. The idea of vbos is that you send the data to OpenGL when you create them, then each frame all you have to do is setup the pointers and call the draw functions. You are resending the data every frame which would be intensely slow I should imagine.

fiendfan1

Quote from: quew8 on May 19, 2013, 10:18:59
Near the end of your world update call there is
Quotecur.model.texture.release();
. This is destroying the texture, I looked it up and it's an interface but presumably the implementation would call glDeleteTextures. This means that next time you bind the texture, it is like you are simply binding a non-texture.

This was the problem. Not only was I calling this every update, but I called it immediately after loading the texture, which is kind of not good. I thought this method just allowed other textures to take its place of something. Thanks so much for all of your help. I can't thank you enough.