(Ending Discussion to other Thread) How do Vbo Textures work?

So, I know I just had a post with 40 replies, but I want to clarify one thing.

I got VBO’s to work. I got them to render a texture and move, but I don’t know exactly how to set a different texture for each object.

I’m assuming that with VBO’s, you want to use a sprite sheet for animations and what not (switch Texture Coordinates), but what about a completely different texture for each object? I think I got it all working ok up to this point, but it’s being weird.

So I have an “Abstract Creature” Class which just has default stuff for every creature.

public void initVBO()
	{
		
		glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
		
		vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
        vertexData.put(new float[]{x, y, x + width, y, x + width, y + height, x, y + height});
        vertexData.flip();
        
        textureData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
        textureData.put(new float[]{0, 1, 1, 1, 1, 0, 0, 0});
        textureData.flip();

        vboVertexHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        
        vboTexCoordHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboTexCoordHandle);
        glBufferData(GL_ARRAY_BUFFER, textureData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
	}
	public void updateVBOCoords()
	{
		vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
        vertexData.put(new float[]{x, y, x + width, y, x + width, y + height, x, y + height});
        vertexData.flip();
        
        vboVertexHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
	}
	public void updateVBO()
	{
		
		 updateVBOCoords();
		
		 GL11.glColor3f(0.5f,0.5f,1.0f);
		 
         glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
         glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);
         
         glBindBuffer(GL_ARRAY_BUFFER, vboTexCoordHandle);
         glTexCoordPointer(vertexSize, GL_FLOAT, 0, 0L);

         glEnableClientState(GL_VERTEX_ARRAY);
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
         
         glDrawArrays(GL_QUADS, 0, amountOfVertices);
         
         glDisableClientState(GL_VERTEX_ARRAY);
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	}

As you can see, this is all of the code regarding creating/rendering the VBO. At the moment, I just draw it every frame through this code:

	public void drawCreature()
	{
		getInput();
		currentWeapon.draw();
		
		if (hasinit == false)
		{
			setTexture("PNG", "Enemy.png");
			initVBO();
			hasinit = true;
		}
		updateVBO();
	}

setTexture just uses slick to get a texture in my source file and sets it to a local variable within my “Tile” Class. The Abstract Creature Class Inherits the Tile class. So, whenever I create a new creature, I just copy the drawCreature method, and change the setTexture to the correct image.

The problem I’m having is… everything is staying as the Enemy Picture. This wasn’t happening before in immediate mode, so I feel like it’s once again something that I don’t understand with VBO’s. I never create the VBO until drawCreature, so I don’t know why it always uses the Enemy picture.

If anyone has better advice for how I go about Textures in VBO’s, let me know.

To be clear, this is for a 2D Side Scoller Game, and I’m using OpenGL 2. I don’t even have spritesheets at the moment, I just want to be able to set the textures according to each creature I create. (So Enemy1 may have a Enemy1.png… and so on)

When I comment this line out:

glBindTexture(GL_TEXTURE_2D, texture.getTextureID());

It still renders the Enemy.png. So that just confuses me :confused:

Well you’re commenting out

glBindTexture(GL_TEXTURE_2D, texture.getTextureID());

but you still have a setTexture() method that I assume does a binding, so of course you’re going to still have that texture bound. As for why every VBO has the enemy texture is because you’re never changing the bound texture so openGL just uses your last bound texture.

Now, if you want to have each object render with a different texture it’ll depend on how you’re objects are rendered. If you have one object in each VBO then it’s as simple as binding another texture before drawing the VBO. If however you’re packing multiple objects into your VBO you’ll need to send a texture list to your shader and index into that list to pull the correct texture.

This is setTexture btw.

	public void setTexture(String type, String dir)
	{
		try
		{
            // load texture from PNG file
            texture = TextureLoader.getTexture(type, ResourceLoader.getResourceAsStream(dir));
        }
		catch (IOException e)
		{
            e.printStackTrace();
        }
    }

I’m not binding here, but yolo I might as well.

Ok I just added it so it binds in setTexture instead of what I had. It still renders the Enemy.png.

Also setTexture updates what texture is stored… and

glBindTexture(GL_TEXTURE_2D, texture.getTextureID());

is just like texture.bind() I would assume right?

So in a sense, the texture should be updated? As for my rendering of the vbo… I have a mthod here:

	public void draw()
	{	
		if(this.isLiving() == true)
		{
			this.drawCreature();
		}
	}

and that runs every frame in my level class.

I mean, there’s only so much that I can change here lol. Is it something in VBO’s like the first texture attacked to it is the only one ever? But even then I don’t get why this would be an issue.

Edit: Each object has one texture, that’s all I want. If I add animations later, I’ll make it a spritesheet or something.

The texture that will be drawn is the texture that is bound at the time you call glDrawArrays(). So…


glBindTexture(GL_TEXTURE_2D, texture.getTextureID());

Put this line somewhere in your updateVBO() method (confusingly named method by the way when what it does is draw the contents of the VBO) BEFORE the call to glDrawArrays().

OK, so if each object has only one texture and you have only one object per VBO then you’ll do something like this every draw call:

//enable shader

glActiveTexture(GL_TEXTURE0 + texture.id);//Tell openGL which texture bind position you're using for the next texture you bind
glBindTexture(GL_TEXTURE_2D, texture.id);//Bind the texture

//set uniforms
//set attributes
//draw
//disable attributes
//disable shader

If you forget to set the active texture then you’ll always be using the same bind position, which is fine, unless you’re only binding the texture during initialization, in which case you’ll never bind a different texture so the last texture you bind will always be drawn at that bind position.

You sure? I’m using OpenGL 2 and it says glActiveTexture(int) isn’t a method. :confused: I googled it, and it said that was for OpenGL 4.

Edit:

I googled the method and someone said that the code for it was this

void glActiveTexture(GLenum textureUnit)
{
    currentTextureUnit = GL_TEXTURE0 - textureUnit;
}

It’s been around since at least 2.0, I thought earlier, but my reference doesn’t say so.

https://www.opengl.org/sdk/docs/man/html/glActiveTexture.xhtml

FYI, you don’t have to use active texture, you must call glBindTexture() every frame - unless you have one for your entire project, but and you might as well set it up so that you can set active textures for when you start multi-texturing with normal maps and such.

glActiveTexture is OpenGL 1.3, actually.
And the code you posted, is a) wrong: if any it should be textureUnit - GL_TEXTURE0, and b) this is - if anything - driver code, which you cannot just emulate or implement yourself in Java (where should the variable ‘currentTextureUnit’ come from?), as it changes the OpenGL state and affects other OpenGL functions, such as glBindTexture.

Oh, I have to call it every frame? :confused: I’ll go try it, but when I did that before (with immediate mode), it caused mad frame lag and was unplayable.

Ok so it works fine now, I get what I did wrong. I just needed to bind the texture every frame I guess :/. It’s running fine for what I’m rendering, but I need to try with projectiles and everything. I just made it so I only “set” the texture once, and just bind it every frame.

Thanks for all the help :).

@Therobodavo: I can tell you right now glBindTexture() will not be a point of contention for cpu cycles, it is one of the fastest openGL calls. All it does is grab a pointer and say here’s the texture to use.

Make sure to watch out for rebuilding textures every frame, you don’t want to do that. Calls like this will get you into trouble if you do them every frame (don’t mind the gl. prefix):


gl.glGenTextures(1, texture.m_id, 0);
		gl.glBindTexture(GL.GL_TEXTURE_2D, texture.m_id[0]);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, wrap_func);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, wrap_func);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
		gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, texture.m_bytes_per_pixel, texture.m_width, texture.m_height, 
						0, texture.m_type, GL.GL_UNSIGNED_BYTE, texture.m_image_data);
		gl.glGenerateMipmap(GL.GL_TEXTURE_2D);