Texturing a VBO?

Hey, I’m trying to put a texture on my vbo, anybody happen to help me out because I can’t get it working. I’ve been looking at many examples, googled. But I can’t seem to find why it wont work.


private void rebuildVBO(int preX, int preY, int preZ) {
		FloatBuffer vCoords = BufferUtils.createFloatBuffer(12 * 6 * size * size * size);
		FloatBuffer cCoords = BufferUtils.createFloatBuffer(16 * 6 * size * size * size);
		FloatBuffer tCoords = BufferUtils.createFloatBuffer(02 * 6 * size * size * size);
		
		faceCount = 0;
		for(int x = 0; x < size; x++) {
			for(int y = 0; y < size; y++) {
				for(int z = 0; z < size; z++) {
					Block block = blockMap[x][y][z];
					
					if(block.isVisible()) {
						boolean[] faces = {
							true, true, true, true, true, true
						};
						
						int fNum = Block.countFaces(faces);
						if(fNum > 0) {
							vCoords.put(block.getVerticies(preX + x, preY + y, preZ + z, faces));
							cCoords.put(block.getColors(faces));
							
							tCoords.put(new float[] { 0f, 1f, });
							tCoords.put(new float[] { 1f, 1f, });
							tCoords.put(new float[] { 0f, 0f, });
							
							tCoords.put(new float[] { 1f, 0f, });
							tCoords.put(new float[] { 0f, 0f, });
							tCoords.put(new float[] { 1f, 1f, });
							
							faceCount += fNum;
						}
					}
				}
			}
		}
		
		vCoords.flip();
		cCoords.flip();
		tCoords.flip();
		
		glBindBuffer(GL_ARRAY_BUFFER, vId);
		glBufferData(GL_ARRAY_BUFFER, vCoords, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		
		glBindBuffer(GL_ARRAY_BUFFER, cId);
		glBufferData(GL_ARRAY_BUFFER, cCoords, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		
		glBindBuffer(GL_ARRAY_BUFFER, tId);
		glBufferData(GL_ARRAY_BUFFER, tCoords, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}


public void render() {
		glBindBuffer(GL_ARRAY_BUFFER, vId);
		glVertexPointer(3, GL_FLOAT, 0, 0);
		
		glBindBuffer(GL_ARRAY_BUFFER, cId);
		glColorPointer(4, GL_FLOAT, 0, 0L);
		
		glBindBuffer(GL_ARRAY_BUFFER, tId);
		glTexCoordPointer(2, GL_FLOAT, 0, 0);
		
		// Not sure if this is neccesariy?
		//glBindBuffer(GL_ARRAY_BUFFER, 0);
		
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		
		glBindTexture(GL_TEXTURE_2D, tex.id);
		glDrawArrays(GL_QUADS, 0, 4 * faceCount);
		glBindTexture(GL_TEXTURE_2D, 0);
		
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	}

Any help appreciated

Steps how to debug things like this that don’t work:

  1. Make sure your texture is actually being loaded properly: render a triangle or a quad with immediate mode to make sure you are actually able to display texture properly;
  2. Make a VBO which contains triangle or quad without any colors, just vertices. Make sure its being rendered properly;
  3. Add color to the VBO;
  4. Add texturing to the VBO;

Following these steps you will gradually increase complexity in your code, so you will know if something doesn’t work along the way.

Just to point out the obvious:

At line 4:

FloatBuffer tCoords = BufferUtils.createFloatBuffer(02 * 6 * size * size * size);

02? :stuck_out_tongue:

Well, so I did that… somewhat and I’m not able to render the texture on my VBO. How? Well before binding the texture I added these 4 lines.


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_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Would someone please explain what this means?, Why di I need todo this? From what I understand I’m telling openGL the coordinates of the texture, but I thought I did that with this…


tCoords.put(new float[] { 0f, 1f, });
tCoords.put(new float[] { 1f, 1f, });
tCoords.put(new float[] { 0f, 0f, });
				
tCoords.put(new float[] { 1f, 0f, });
tCoords.put(new float[] { 0f, 0f, });
tCoords.put(new float[] { 1f, 1f, });

Also, My problem now is… it’s not rendered properly, take a look!

With the tCoords.put(…) you’re passing texture coordinates to openGL that define which part of the texture correlates to each vertex, where the top left corner is (0, 0) and the bottom right is (1, 1)
.

Each time you call glTexParameteri, you’re defining something about your texture.
GL_TEXTURE_MIN_FILTER means your specifying the minification filter (AKA how it reacts to be being scaled down), where GL_TEXTURE_MAG_FILTER filter defines how it is when it is magnified, or scaled up.
GL_LINEAR is what you’re specified the scaling filters to do. GL_LINEAR blurs each pixel into the next pixel, making it good for high-res things as it gets rid of any pixelation. What you should probably be using considering what you’re texture looks to be, is GL_NEAREST. This doesn’t do any blurring, and is good for lower-res stuff like pixel art and subsequently what you appear to be doing. Here is a good representation of GL_NEAREST v. GL_LINEAR

The second two lines effectively define what happens when you give texture coords (otherwise know as UV or ST) that are greater than one. GL_CLAMP_TO_EDGE means that the edge pixels will be repeated continuously, while the alternative GL_REPEAT means the texture will just repeat itself infinitely. In images:

I hope I have cleared things up a little for you :slight_smile:

Upon what I just said about UVs, looking at your code you bind one face of UV coords, and although it’s hard to know without seeing your code, the context implies that block.getVerticies() returns more than one face of vertex positions, but all exposed faces. However, every vertex position has to line up to a vertex, as shown with this diagram here:

http://www.real3dtutorials.com/images/img00017.png

Assuming I right in saying that block.getVerticies() returns all exposed faces, you would have to have a for loop around your UV coords like so:


if(fNum > 0) {
        vCoords.put(block.getVerticies(preX + x, preY + y, preZ + z, faces));
        cCoords.put(block.getColors(faces));
                     
+      for(int i =0; i < fNum i++)                
                tCoords.put(new float[] { 0f, 1f, });
                tCoords.put(new float[] { 1f, 1f, });
                tCoords.put(new float[] { 0f, 0f, });
                     
                tCoords.put(new float[] { 1f, 0f, });
                tCoords.put(new float[] { 0f, 0f, });
                tCoords.put(new float[] { 1f, 1f, });
+      }                     
        faceCount += fNum;
}

EDIT: when debugging openGL, a good idea is to have a method like this:


	public static void GLError(){
		int GLErr = GL11.glGetError();
		while(GLErr != 0){
			System.err.println("Error " + GLErr + ":");
			System.err.println(GLU.gluErrorString(GLErr));
			GLErr = GL11.glGetError();
		}
	}

This method GL11.glGetError() will return an non-zero number if there has been an issue.
while(GLErr != 0) will iterate until there are no more issues to be resolved.
GLU.gluErrorString(GLErr) will give greater insight into what the error is beyond just the error code.
NOTE: GLU.gluErrorString() requires that you have lwjgl_util.jar importing into your workspace.

Just to let you know @NegativeZero

[quote]When an error occurs, the error flag is set to the appropriate error code value. No other errors are recorded until glGetError is called, the error code is returned, and the flag is reset to GL_NO_ERROR.
[/quote]

Thank you, this really cleared things up. However I would have to say, I’ve read many tutorials and guides on this and i never understood the s & t cordinates was of the texture. I thought it was which corner the texture should bind to. However now when that’s cleared up I made a atlas texture and things works fine :smiley: almost.

When using one texture things work fine. but when trying to load a secondary texture the first stop’s to display? O.o’?


package voxel.util;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;

import javax.imageio.ImageIO;

import org.lwjgl.BufferUtils;

import static org.lwjgl.opengl.GL11.*;

public class Texture {
	
	private int id, width, height;
	private int textureFilter = GL_NEAREST;
	private int textureWrap = GL_REPEAT;
	
	private Texture(int id, int width, int height) {
		this.id = id;
		this.width = width;
		this.height = height;
	}
	
	public static Texture loadTexture(String location) {
		BufferedImage image = null;
		try {
			image = ImageIO.read(Texture.class.getClassLoader().getResourceAsStream(location));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		int[] pixels = new int[image.getWidth() * image.getHeight()];
		image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getHeight());
		
		ByteBuffer buffer = BufferUtils.createByteBuffer(pixels.length * 4);
		for(int y = 0; y < image.getHeight(); y++) {
			for(int x = 0; x < image.getWidth(); x++) {
				int pixel = pixels[y * image.getWidth() + x];
				
				buffer.put((byte) ((pixel >> 16) & 0xFF));
				buffer.put((byte) ((pixel >> 8) & 0xFF));
				buffer.put((byte) ((pixel) & 0xFF));
				buffer.put((byte) ((pixel >> 24) & 0xFF));
				
			}
		}
		
		buffer.flip();
		
		int id = glGenTextures();
		glBindTexture(GL_TEXTURE_2D, id);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		
		return new Texture(id, image.getWidth(), image.getHeight());
	}
	
	public void setTextureFilter(int textureFilter) {
		this.textureFilter = textureFilter;
	}
	public void setTextureWrap(int textureWrap) {
		this.textureWrap = textureWrap;
	}
	
	public int getTextureFilter() {
		return textureFilter;
	}
	public int getTextureWrap() {
		return textureWrap;
	}
	
	public void bind() {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, textureFilter);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, textureFilter);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, textureWrap);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, textureWrap);
		
		glBindTexture(GL_TEXTURE_2D, id);
	}
	
	public void unbind() {
		glBindTexture(GL_TEXTURE_2D, 0);
	}
	
	public void dispose() {
		glDeleteTextures(id);
	}
	
}


package voxel.game.world;

import voxel.game.Camera;
import voxel.util.Texture;

public class World {
	
	public static final int size = 8;
	
	private Chunk[][][] chunkMap = new Chunk[size][size][size];	
	private Texture terrain;
	
	public World() {
		init();
		genChunkMap();
	}
	
	public void init() {
		terrain = Texture.loadTexture("voxel/util/atlas.png");
		System.out.println("Terrain Texture loaded!");
	}
	
	public void genChunkMap() {
		for(int x = 0; x < size; x++) {
			for(int y = 0; y < size; y++) {
				for(int z = 0; z < size; z++) {
					chunkMap[x][y][z] = new Chunk(Chunk.size * x, Chunk.size * y, Chunk.size * z);
				}
			}
		}
		
		System.out.println("World generated!");
	}
	
	public void render(Camera camera) {
		camera.lookThrough();
		
		terrain.bind();
		for(int x = 0; x < size; x++) {
			for(int y = 0; y < size; y++) {
				for(int z = 0; z < size; z++) {
					
					//TODO Only render the chunks infront of you.
					
					chunkMap[x][y][z].render();
					
				}
			}
		}
		terrain.unbind();
	}
	
	public void dispose() {
		for(int x = 0; x < size; x++) {
			for(int y = 0; y < size; y++) {
				for(int z = 0; z < size; z++) {
					chunkMap[x][y][z].dispose();
				}
			}
		}
		
		terrain.dispose();
	}
}


package voxel.game.ui;

import voxel.game.ui.comp.Label;
import voxel.util.Texture;

public class Hud {
	
	private Texture font;
	private Label infoLabel;
	
	public Hud() {
		// When running this, all the blocks turn white!?
		font = Texture.loadTexture("voxel/util/atlas.png");
		
	}
	
	public void pollInputs(float deltaTime) {
	}
	
	public void render() {
		
	}
	
	public void dispose() {
		font.dispose();
	}
}

Not calling terrain.unbind(); resovles the problem. But why?

Without reading the whole thread:
Probably because it gets not (or not successfully) rebound when it is needed.

I’m sorry what? I don’t understand?
When binding it it doesn’t successfully do so?, Wouldn’t it give me an error? Would you care to explain, elaborate?

To be honest no idea. You seem to call “bind()”…
Maybe something with that method is wrong, if the texture’s id is not correctly stored before (for whatever reason) bind() would bind 0 - might not be the case here.

Leaving “unbind()” out is probably helpful because the texture gets bound when it gets generated and theres a problem with “bind()” doing nothing…

EDIT:
Did you try putting the lines with glTexParameteri(…) before glTexImage2D(…) in the initializer instead of the bind method?