Using VBO 3d Models makes strange triangles at wrong places

Started by Sumec99, March 31, 2014, 18:05:24

Previous topic - Next topic

Sumec99

Hi Everyone,
I've written(well, I've got the code from a tutorial) a few classes to load my own 3d models in .obj format into my programm ...
each single face of the model is a triangle
At first i thought everything would work perfect, but when I load more than just one model, there are triangles between vertices of the model where they shall NOT be...
I use vbos to display my models ...
I've tried changes and googled around for about a week but I haven't got any solution ...

Here's my code of all classes:
OBJLoader:
package the_wormhole;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.lwjgl.util.vector.Vector3f;

public class OBJLoader {
	public static Model loadModel(File f) throws FileNotFoundException, IOException{
		BufferedReader reader = new BufferedReader(new FileReader(f));
		
		Model m = new Model();
		String line;
		while((line = reader.readLine()) != null){
			if(line.startsWith("v ")){
				float x = Float.valueOf(line.split(" ")[1]);
				float y = Float.valueOf(line.split(" ")[2]);
				float z = Float.valueOf(line.split(" ")[3]);
				
				m.vertices.add(new Vector3f(x, y, z));
			}else if(line.startsWith("vn ")){
				float x = Float.valueOf(line.split(" ")[1]);
				float y = Float.valueOf(line.split(" ")[2]);
				float z = Float.valueOf(line.split(" ")[3]);
				
				m.normals.add(new Vector3f(x, y, z));
			}else if(line.startsWith("f ")){
				Vector3f vertexIndices = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[0]),
						Float.valueOf(line.split(" ")[2].split("/")[0]),
						Float.valueOf(line.split(" ")[3].split("/")[0]));
				Vector3f normalIndices = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[2]),
						Float.valueOf(line.split(" ")[2].split("/")[2]),
						Float.valueOf(line.split(" ")[3].split("/")[2]));
				m.faces.add(new Face(vertexIndices, normalIndices));
			}
		}
		reader.close();
		
		return m;
	}
}

Model:
package the_wormhole;

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

import java.nio.FloatBuffer;
import java.util.ArrayList;

import org.lwjgl.BufferUtils;
import org.lwjgl.util.vector.Vector3f;

public class Model {
	public ArrayList<Vector3f> vertices = new ArrayList<Vector3f>();
	public ArrayList<Vector3f> normals = new ArrayList<Vector3f>();
	public ArrayList<Face> faces = new ArrayList<Face>();

	private FloatBuffer verticesBuffer;
	private FloatBuffer normalsBuffer;

	private int verticesVBO;
	private int normalsVBO;

	private int nrVertices = 0;
	
	public float x = 0, y = 0, z = 0;

	public static final int X_AXIS = 0, Y_AXIS = 1, Z_AXIS = 2;
	
	public boolean isPlainFloor = false;

	public Model() {
		glEnable(GL_COLOR_MATERIAL);

		verticesVBO = glGenBuffers();
		normalsVBO = glGenBuffers();
				
		x = 0;
		y = 0;
		z = 0;
	}

	public ArrayList<Vector3f> getVertices() {
		return vertices;
	}

	public ArrayList<Vector3f> getNormals() {
		return normals;
	}

	public ArrayList<Face> getFaces() {
		return faces;
	}

	public void prepare() {
		this.nrVertices = 0;

		verticesBuffer = BufferUtils.createFloatBuffer(faces.size() * 9);
		for (int i = 0; i < faces.size(); i++) {
			Face f = faces.get(i);
			Vector3f v1 = vertices.get((int) (f.getVertexIndices()[0] - 1));
			verticesBuffer.put(new float[] { v1.x, v1.y, v1.z });
			Vector3f v2 = vertices.get((int) (f.getVertexIndices()[1] - 1));
			verticesBuffer.put(new float[] { v2.x, v2.y, v2.z });
			Vector3f v3 = vertices.get((int) (f.getVertexIndices()[2] - 1));
			verticesBuffer.put(new float[] { v3.x, v3.y, v3.z });
			nrVertices += 3;
		}
		System.out.println(faces.size() * 9);
		verticesBuffer.flip();
		glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
		glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		normalsBuffer = BufferUtils.createFloatBuffer(faces.size() * 9);
		for (int i = 0; i < faces.size(); i++) {
			Face f = faces.get(i);
			Vector3f v1 = normals.get((int) (f.getNormalIndices()[0] - 1));
			normalsBuffer.put(new float[] { v1.x, v1.y, v1.z });
			Vector3f v2 = normals.get((int) (f.getNormalIndices()[1] - 1));
			normalsBuffer.put(new float[] { v2.x, v2.y, v2.z });
			Vector3f v3 = normals.get((int) (f.getNormalIndices()[2] - 1));
			normalsBuffer.put(new float[] { v3.x, v3.y, v3.z });
		}
		normalsBuffer.flip();
		glBindBuffer(GL_ARRAY_BUFFER, normalsVBO);
		glBufferData(GL_ARRAY_BUFFER, normalsBuffer, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}

	public void draw() {
		if(verticesBuffer == null)
			throw new IllegalStateException("prepare() not called yet");
		
		glMaterialf(GL_FRONT, GL_SHININESS, 128f);

		glBindBuffer(GL_ARRAY_BUFFER, normalsVBO);
		glNormalPointer(GL_FLOAT, 0, 0);

		glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
		glVertexPointer(3, GL_FLOAT, 0, 0);

		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_NORMAL_ARRAY);

		glDrawArrays(GL_TRIANGLES, 0, nrVertices);

		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_NORMAL_ARRAY);
		
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}

	public void move(int axis, float distance) {
		if(verticesBuffer == null)
			throw new IllegalStateException("prepare() not called yet");
				
		switch (axis) {
		case X_AXIS:
			for(int i = 0 ; i < vertices.size() ; i ++){
				Vector3f v = vertices.get(i);
				v.x += distance;
				x = v.x;
			}
			
			break;
		case Y_AXIS:
			for(int i = 0 ; i < vertices.size() ; i ++){
				Vector3f v = vertices.get(i);
				v.y += distance;
				y = v.y;
			}
			
			break;
		case Z_AXIS:
			for(int i = 0 ; i < vertices.size() ; i ++){
				Vector3f v = vertices.get(i);
				v.z += distance;
				z = v.z;
			}
			
			break;
		default:
			break;
		}
		
		verticesBuffer = BufferUtils.createFloatBuffer(faces.size() * 9);
		for (int i = 0; i < faces.size(); i++) {
			Face f = faces.get(i);
			Vector3f v1 = vertices.get((int) (f.getVertexIndices()[0] - 1));
			verticesBuffer.put(new float[] { v1.x, v1.y, v1.z });
			Vector3f v2 = vertices.get((int) (f.getVertexIndices()[1] - 1));
			verticesBuffer.put(new float[] { v2.x, v2.y, v2.z });
			Vector3f v3 = vertices.get((int) (f.getVertexIndices()[2] - 1));
			verticesBuffer.put(new float[] { v3.x, v3.y, v3.z });

			nrVertices += 3;
		}
		verticesBuffer.flip();
		glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
		glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}

	public void cleanUp() {
		glDeleteBuffers(verticesVBO);
		glDeleteBuffers(normalsVBO);
	}
}

Main Class:
package the_wormhole;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.FloatBuffer;

import org.lwjgl.*;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.*;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;

public class WormholeMain {
	
	private float rotationX;
	private float translationX;
	private float translationY;
	private float translationZ;
	private float rotationY;
	private Vector3 walk;
	private FloatBuffer fb2 = BufferUtils.createFloatBuffer(4);
	private ShaderManager shaderManager;
	Model m1, m2, m3, m4, m5, m6;
	
	public WormholeMain() {
		fb2.put(new float[] { -2, -2, 0, 0});
		fb2.flip();
		
		setUpDisplay();
		setUp3dWorld();
		
		walk = new Vector3(0, 0, -1);
		wormhole = new Wormhole();
		
		shaderManager = new ShaderManager();
		shaderManager.loadShader(GL_VERTEX_SHADER, "shaders/vertexShader.sh");
		shaderManager.loadShader(GL_FRAGMENT_SHADER, "shaders/fragmentShader.sh");
		shaderManager.prepareProgram();
		
		m1 = loadModelAndPrepare("res/right_up_floor.obj", 0, 0);
		m2 = loadModelAndPrepare("res/right_up_floor.obj", 2, 0);
		m3 = loadModelAndPrepare("res/right_up_floor.obj", -2, 0);
		m4 = loadModelAndPrepare("res/right_up_floor.obj", 0, 2);
		m5 = loadModelAndPrepare("res/right_up_floor.obj", 2, 2);
		m6 = loadModelAndPrepare("res/right_up_floor.obj", -2, 2);
		
		mainLoop();
		cleanUp();
	}
	
	private void cleanUp() {
		wormhole.cleanUp();
		Display.destroy();
	}
	
	long thisFrame = System.currentTimeMillis(), lastFrame = System.currentTimeMillis();
	float frametime;

	private void mainLoop() {
		lastFrame = System.currentTimeMillis();
		while(!Display.isCloseRequested()){
			thisFrame = System.currentTimeMillis();
			frametime = (thisFrame - lastFrame) / 1000f;
			lastFrame = thisFrame;
			
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glClearColor(0.8f, 0.8f, 0.8f, 1);
			
			glLight(GL_LIGHT0, GL_POSITION, fb2);
			
			applyCamera();
			
			shaderManager.useProgram();
			m1.draw();
			shaderManager.useProgram0();
			shaderManager.useProgram();
			m2.draw();
			shaderManager.useProgram0();
			shaderManager.useProgram();
			m3.draw();
			shaderManager.useProgram0();
			shaderManager.useProgram();
			m4.draw();
			shaderManager.useProgram0();
			shaderManager.useProgram();
			m5.draw();
			shaderManager.useProgram0();
			shaderManager.useProgram();
			m6.draw();
			shaderManager.useProgram0();
			
			Display.update();
			Display.sync(60);
		}
	}

	private void setUp3dWorld() {
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(30, 800f/600f, 0.001f, 100);
		glMatrixMode(GL_MODELVIEW);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_TRIANGLE_FAN);
		glEnable(GL_DEPTH_TEST);
		glShadeModel(GL_SMOOTH);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		
		FloatBuffer fb1 = BufferUtils.createFloatBuffer(4);
		fb1.put(new float[] { 0.05f, 0.05f, 0.05f, 1 });
		fb1.flip();
		
		glLightModel(GL_LIGHT_MODEL_AMBIENT, fb1);
		glLight(GL_LIGHT0, GL_POSITION, fb2);
		
		glRotatef(-25f, 0, 1, 0);
		glRotatef(30f, 1, 0, 0);
		glTranslatef(-1.5f, -2.1f, -0.55f);
	}

	private void setUpDisplay() {
		try {
			Display.setDisplayMode(new DisplayMode(800, 600));
			Display.setTitle("The Wormhole");
			Display.setVSyncEnabled(true);
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		new WormholeMain();
	}
	
	private Model loadModelAndPrepare(String path, float xdistance, float zdistance){
		Model m = null;
		try {
			m = OBJLoader.loadModel(new File(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return m;
		} catch (IOException e) {
			e.printStackTrace();
			return m;
		}
		m.prepare();
		m.move(Model.X_AXIS, xdistance);
		m.move(Model.Z_AXIS, zdistance);
		if(path.equals("res/plain_floor.obj"))
			m.isPlainFloor = true;
		return m;
	}
}


Thanks for your help ...  ;D ;D

Oebele

Pics or it didn't happen ;-)

Just a wild guess: shouldn't you be using indexed drawing?

Sumec99

I'm sorry but I don't understand  the first sentence "Pics or it didn't happen" of your answer because English isn't my first language ... Sorry for that
And , what is indexed drawing ?

Oebele

With "Pics or it didn't happen" I meant to say: "please post some pictures, so we can actually see what is wrong".

for indexed drawing, look at this page: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/ or this one:

Sumec99

Ok, thanks for the description ...
2 screenshots are attached

matanui159

May I see the .obj file? I believe I have an idea...

You store your vertices in an array which (because of java) starts at zero. So when the face requests vertex 1 it is requesting (according to your code) the second vertex. But the .obj file might be starting at one so when a face requests vertex 1 it wants the first vertex but your code is giving it the second vertex.

Also how did you show a working version if it is not working?
ALGORITHM
A word used by programmers when they do not want to explain what they did.

WEE :)

matanui159

Actually nevermind... I just realised you are already subtracting one from it so it should work unless your .obj file starts at zero (to find out search it using your text editor for a 0/ or a /0). Try another model like the Utah teapot of Stanford bunny and post the results because your current model ( whatever it is) doesn't really like anything and it is hard to tell what is going on...
ALGORITHM
A word used by programmers when they do not want to explain what they did.

WEE :)

Sumec99

The matter ifs , if I just want to display Model, everything is fine, but if there are 2 or 3 models (or more) it's messed up
(Sorry that I have not written these days, I just haven't seen the new answer after 2 weeks)