[Problem].Obj Model not loaded fully using VBO/VAO

Hello everyone :slight_smile:

Lately I am trying to make small game in java using lwjgl. I also try as much as I can to write my own code, since I want to learn java and openGL. So far most of code is mine - sometimes I have to copy others - I cannot reinvent the wheel…

Now on to the issue :
I am trying to import .obj models into my “engine/game” and so far I managed to load only part of it and the problem is that I cannot figure out why my whole model isn’t being rendered.

I made simple cube in Blender 2.72b - here is .obj

# Blender v2.72 (sub 0) OBJ File: ''
# www.blender.org
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
s off
f 1 2 3 4
f 5 8 7 6
f 1 5 6 2
f 2 6 7 3
f 3 7 8 4
f 5 1 4 8

And when I run the program I get only top and bottom face :

http://pokit.org/get/img/4fe6d14ce93f1da3aef980a729ee223c.png

My code for loading .obj is (NOTE : it probably looks noobish and “weird” - I am still learning :slight_smile: )

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import static org.lwjgl.opengl.ARBBufferObject.*;
import static org.lwjgl.opengl.ARBVertexBufferObject.*;
import com.jogamp.opengl.*;

import javax.swing.JOptionPane;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.*;
public class ObjectLoad {
	
	ByteBuffer inx;
	int indices[];
	float verts[];
	public int vaoID = 0;
	public int vboID = 0;
	public ObjectLoad(String objfolder, String objfile, int size)
	{
		 
		ArrayList<Float> verticesL = new ArrayList<Float>();
		ArrayList<Integer> indicesL = new ArrayList<Integer>();
		
		FileReader objectfile = null;
		try {
			objectfile = new FileReader(objfolder + "/" + objfile);
		} catch (FileNotFoundException e2) {
			System.out.println(" File not found !");
			JOptionPane.showMessageDialog(null,
				    "File not found.",
				    "Error - Failed to Load Object",
				    JOptionPane.ERROR_MESSAGE);
			e2.printStackTrace();
		}
		
		String line;
		
		
		try{
		BufferedReader br = new BufferedReader(objectfile);
		while( (line=br.readLine()) != null)
		{
			if( line.startsWith("v"))
			{
				String parts[] = line.split(" ");
				verticesL.add(Float.parseFloat(parts[1]));
				verticesL.add(Float.parseFloat(parts[2]));
				verticesL.add(Float.parseFloat(parts[3]));
			}
			if (line.startsWith("f"))
			{
				String parts[] = line.split(" ");
				indicesL.add(Integer.parseInt(parts[1]));
				indicesL.add(Integer.parseInt(parts[2]));
				indicesL.add(Integer.parseInt(parts[3]));
				indicesL.add(Integer.parseInt(parts[4]));
			}
		}
		}catch(FileNotFoundException e){
			e.printStackTrace();
			
		}catch( Exception e1)
		{
			e1.printStackTrace();
		
		}
		float[] verticesA = new float[verticesL.size()];
		int[] indicesA = new int[indicesL.size()];
		for(int i = 0;i < verticesL.size(); i++)
		verticesA[i] = verticesL.get(i);
		for(int i = 0;i < indicesL.size(); i++)
		indicesA[i] = indicesL.get(i);
		
		indices = indicesA;
		verts = verticesA;
		for(int i = 0;i < verts.length; i++)
			System.out.println(i + ". vertex : " + verts[i]);
		
		
		
		
		
	}
	public void setUP()
	{
	
		FloatBuffer vertexData = BufferUtils.createFloatBuffer(verts.length);
		vertexData.put(verts);
		vertexData.flip();
		
		vaoID = GL30.glGenVertexArrays();
		GL30.glBindVertexArray(vaoID);
		vboID = GL15.glGenBuffers();
	
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID );
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexData , GL15.GL_STATIC_DRAW);
		GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
		GL20.glEnableVertexAttribArray(0);
		inx = BufferUtils.createByteBuffer(indices.length);
      
        GL30.glBindVertexArray(0);
        
	}
	public void render()
	{
	
		GL30.glBindVertexArray(vaoID);
		GL20.glEnableVertexAttribArray(0);
	
		GL11.glDrawArrays(GL11.GL_QUADS, 0, 36);
		
		GL20.glDisableVertexAttribArray(0);
        GL30.glBindVertexArray(0);
        //GL11.glDrawElements(GL11.GL_QUADS, inx);
    	
		
	}
	public void cleanMemory()
	{
		GL20.glDisableVertexAttribArray(0);
		
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		GL15.glDeleteBuffers(vboID);
		
		GL30.glBindVertexArray(0);
		GL30.glDeleteVertexArrays(vaoID);
	}
}

If you need anything from “main” just tell me :slight_smile:
Any help is appreciated :slight_smile:
Thanks in advance :slight_smile:

you’re using [icode]glDrawArrays[/icode] but if you want to use the indices provided by the .obj, you need to use [icode]glDrawElements[/icode] (which means it’s also required to setup the ELEMENT_ARRAY_BUFFER).

if you do not want to use the indices, you need to convert the vertex-data into a sequence which allows [icode]glDrawArrays[/icode] to draw all faces.

Thank you for your replay :slight_smile:

Is it easier to set up for

glDrawElements

or to convert vertex-data( and if so, how ) ?

i think it’s easier just to convert the data - no fiddling to get the element_array to work :wink:

to collapse the indices+vertex data into “pure” vertex data we could do something like …

  • compute the result number of vertices :

from the .obj file i see 6 quad-faces (lines starting with f). 6 * 4 (corners) = 24 vertices total. also, the .obj file shows only 8 vertices. 8 / 4 = 2. that’s why we see only two quad-faces drawn.

  • setup a bytebuffer for 24 vertices. 24 * 3 (3d-vectors) = 72 floats. each float takes 4 bytes. 72 * 4 = 288 bytes. that’s the total required memory we need.

  • fill the bytebuffer with vertices :

in pseudo code that would look like :


ByteBuffer vertexData = ... // allocate direct-buffer with 288 bytes.

// assuming we want to use glDrawArrays with GL_QUADS.

for ( quad : quads )
{
  // a quad is defined by the 4 numbers next to the lines starting with f

  int index_a = quad.a;
  int index_b = quad.b;
  int index_c = quad.c;
  int index_d = quad.d;

  // each index points to a vertex as defined by the 3 floats next to the lines starting with v
  // reading the .obj v-lines, first line = index 0, 2nd line = index 1, etc.

  // ! that is not matching the .obj spec as the first index is 1, not 0.
  // subtract 1, assuming quad-indices are processed as they came in.

  vec3 a = vertices[index_a - 1];
  vec3 b = vertices[index_b - 1];
  vec3 c = vertices[index_c - 1];
  vec3 d = vertices[index_d - 1];

  // write those 4 vertices to the bytebuffer

  vertexData.putFloat(a.x);
  vertexData.putFloat(a.y);
  vertexData.putFloat(a.z);

  vertexData.putFloat(b.x);
  vertexData.putFloat(b.y);
  vertexData.putFloat(b.z);

  vertexData.putFloat(c.x);
  vertexData.putFloat(c.y);
  vertexData.putFloat(c.z);

  vertexData.putFloat(d.x);
  vertexData.putFloat(d.y);
  vertexData.putFloat(d.z);
}

// the buffer should have zero remaining() now. if not, there was an error.

vertexData.flip();

upload( vertexData, VBO_id );


converting to glDrawArrays with GL_TRIANGLES or GL_POINTS etc, would require an different conversion.

(disclaimer : there is at least one bug sitting somewhere ;))

o/

Thank you for replay and for the code ! I wouldn’t be able to do that by myself - I just don’t have enough knowledge…

I kinda get idea how to do it for GL_TRIANGLES.
I don’t have time now to test your idea - but I will give it a shot sometimes next week. I think it should work :slight_smile:

If not, you’ll probably see another post from me :smiley:

Thank you one more time !

Cheers :smiley:

I managed to implement your solution. The problem now is that it doesn’t render the model.

Here is the changed part of the code

try{
		BufferedReader br = new BufferedReader(objectfile);
		while( (line=br.readLine()) != null)
		{
			
			if( line.startsWith("v"))
			{
				String parts[] = line.split(" ");
				verticesL.add(new Vector3f(Float.parseFloat(parts[1]),Float.parseFloat(parts[2]), Float.parseFloat(parts[3])));
			}
			System.out.println(verticesL.size() * 36);
			inx = BufferUtils.createByteBuffer(verticesL.size() * 36);
			if (line.startsWith("f"))
			{
				String parts[] = line.split(" ");
				if ( parts.length == 4)
				{
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[1]) - 1)).getX());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[1]) - 1)).getY());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[1]) - 1)).getZ());
					
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[2]) - 1)).getX());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[2]) - 1)).getY());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[2]) - 1)).getZ());
					
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[3]) - 1)).getX());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[3]) - 1)).getY());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[3]) - 1)).getZ());
					
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[4]) - 1)).getX());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[4]) - 1)).getY());
					inx.putFloat((float) verticesL.get((Integer.parseInt(parts[4]) - 1)).getZ());
				}
				inx.flip();	
			}
			
				

		}
		}catch(FileNotFoundException e){
			e.printStackTrace();
			
		}catch( Exception e1)
		{
			e1.printStackTrace();
		
		}
	
		
		
		
		
		
	}
	public void setUP()
	{
	
		
		vaoID = GL30.glGenVertexArrays();
		GL30.glBindVertexArray(vaoID);
		vboID = GL15.glGenBuffers();
	
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID );
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, inx , GL15.GL_STATIC_DRAW);
		GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
		GL20.glEnableVertexAttribArray(0);
		
      
        GL30.glBindVertexArray(0);
        
	}
	public void render()
	{
	
		GL30.glBindVertexArray(vaoID);
		GL20.glEnableVertexAttribArray(0);
	
		//GL11.glDrawArrays(GL11.GL_QUADS, 0, 36);
		GL11.glDrawElements(GL11.GL_QUADS, inx);
		GL20.glDisableVertexAttribArray(0);
        GL30.glBindVertexArray(0);
        //
    	
		
	}
	public void cleanMemory()
	{
		GL20.glDisableVertexAttribArray(0);
		
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		GL15.glDeleteBuffers(vboID);
		
		GL30.glBindVertexArray(0);
		GL30.glDeleteVertexArrays(vaoID);
	}

oh in that case you just need glDrawArrays, like in your first code-snip. the file-parse looks good to me :slight_smile:

If I use glDrawArrays I get a crash

http://pokit.org/get/img/e9c5c9375fb4eb97ce741fc0927a0df1.png