OpenGL glDrawElements

Hello guys, first post here hopefully I can find some help.

I am fairly new to opengl but I like it so far. I wrote a .obj parser and it works great if I use gl_drawArrays() which works great but if I use gl_drawElements() its all funky… I get the feeling I am doing something incorrectly but I hope that someone here can help me figure out what i’m doing.

Here is my parser and vbo setup code so far.


private void parseData(String data){
			String[] lines = data.split("
");
			for (int i = 0; i < lines.length; i++) {
				String l = lines[i];
				if(l.startsWith("#")){
					continue;
				}
				
				if(l.startsWith("v ")){
					String[] verts = l.split("[ ]");
					parseVertex(l, verts);
					numberOfVertexAttributes++;
					continue;
				}
				
				if(l.startsWith("vn ")){
					String[] normals = l.split("[ ]");
					parseNormals(l, normals);
					numberOfNormalAttributes++;
					continue;
				}
	
				if(l.startsWith("vt ")){
					//String[] texture = l.split("[ ]+");
					//nothing for now					
					continue;
				}
				
				if(l.startsWith("f ")){
					String[] faces = l.split("[ ]+");
					parseFaces(l, faces);
					faceIndex++;
					if(faceIndex % 2 == 0)
						numberOfFaces++;
					continue;
				}
				}
			}
		
		private String load(int id){
			String data = "";
			try {
			    InputStream is = context.getResources().openRawResource(id);
				
				BufferedReader reader = new BufferedReader(new InputStreamReader(is));
				StringBuffer b = new StringBuffer();
				String l = reader.readLine();
					while(l != null){
						b.append(l);
						b.append("
");
						l = reader.readLine();
					}
				data = b.toString();
				reader.close();
				}catch(Exception ex){
					Log.d("model loader load data", "exception "+ex);
				}
			return data;
			}
			
		
			private void parseVertex(String l, String[] vert){
				String[] v = l.split("[ ]");
				vertices.add(new vec3(Float.parseFloat(v[1]), Float.parseFloat(v[2]), Float.parseFloat(v[3])));
			}
			
			private void parseNormals(String l, String[] normal){
				String[] n = l.split("[ ]");
				normals.add(new vec3(Float.parseFloat(n[1]), Float.parseFloat(n[2]), Float.parseFloat(n[3])));
			}
			
			private void parseFaces(String s, String[] index){
				String[] fi = s.split("[ ]");
				
				String[] a = fi[1].split("[/]");		
				String[] b = fi[2].split("[/]");
				String[] c = fi[3].split("[/]");				
						
				indices.add(new vec3(Integer.parseInt(a[0]), Integer.parseInt(b[0]), Integer.parseInt(c[0])));
				faces.add(new face(Integer.parseInt(a[0]), Integer.parseInt(b[0]), Integer.parseInt(c[0]), Integer.parseInt(a[2])));
				numberOfVertices+=3;
				numberOfFacesAttributes++;
			}
			
	private class vec3{
		float x, y, z;
		
		public vec3(float x, float y, float z){
			this.x = x;
			this.y = y;
			this.z = z;
		}
				
		@SuppressWarnings("unused")
		public String printout(){
			return "x "+this.x+" y "+this.y+" z "+this.z;
		}
	}
	
	private class face{
		int[] data;
		
		public face(int v1, int v2, int v3, int n1){
			data = new int[6];
			data[0] = v1;
			data[1] = v2;
			data[2] = v3;
			
			data[3] = n1;
		}
		
	}	

here is how i setup my vbo



vertexArray = new float[numberOfFacesAttributes*9];
		normalArray = new float[numberOfFacesAttributes*9];
		indexArray =  new short[numberOfFacesAttributes*3];
		
		int va = 0;
		int ia = 0;
		int na = 0;
		//System.out.println(numberOfFacesAttributes);
		for(int i = 0; i < numberOfFacesAttributes; i++){
			
			vertexArray[va++] = vertices.get((faces.get(i).data[0]-1)).x;
			vertexArray[va++] = vertices.get((faces.get(i).data[0]-1)).y;
			vertexArray[va++] = vertices.get((faces.get(i).data[0]-1)).z;
			
			vertexArray[va++] = vertices.get((faces.get(i).data[1]-1)).x;
			vertexArray[va++] = vertices.get((faces.get(i).data[1]-1)).y;
			vertexArray[va++] = vertices.get((faces.get(i).data[1]-1)).z;
			
			vertexArray[va++] = vertices.get((faces.get(i).data[2]-1)).x;
			vertexArray[va++] = vertices.get((faces.get(i).data[2]-1)).y;
			vertexArray[va++] = vertices.get((faces.get(i).data[2]-1)).z;
			
			
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).x;
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).y;
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).z;
			
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).x;
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).y;
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).z;
			
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).x;
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).y;
			normalArray[na++] = normals.get((faces.get(i).data[3]-1)).z;
		
			
			indexArray[ia++] = (short) (faces.get(i).data[0]);
			indexArray[ia++] = (short) (faces.get(i).data[1]);
			indexArray[ia++] = (short) (faces.get(i).data[2]);
		}


if I use gl_drawArrays() and use the vertex arrays I get a nice drawing, if i use gl_drawElements i get really terrible rendering.
See videos below, i really appreciate you guys help.

cube rendered with gl_drawarrays() : obj model loader0 - YouTube
same model drawn gl_drawelements() : obj model loader a0 - YouTube

monkey with per fragment lighting gl_drawarrays() : monkey - YouTube
same monkey no lighting gl_drawelements() : obj model loader a1 - YouTube

Verify your indices. Make sure they start at 0.

Post your code on how you bound the data (glBufferData) and when you call you call glDrawElements. I’ve had problems where I’ve passed in the wrong values in the arguments.

V-man i indeed start the indexing at zero

mrmoo


private FloatBuffer vertsBuffer;
private ShortBuffer indicesBuffer;

l = new OBJLoader(c);
l.load(R.raw.cu);
verts = l.vertexArray; 
index = l.indexArray;
number = l.numVertices;

vertsBuffer = ByteBuffer.allocateDirect(verts.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
		vertsBuffer.put(verts).position(0);
		
		indicesBuffer = ByteBuffer.allocateDirect(index.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer();
		indicesBuffer.put(index).position(0);

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		
		GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		final float eyeX = 0.0f;
		final float eyeY = 0.0f;
		final float eyeZ = 0.0f;
		final float centerX = 0.0f;
		final float centerY = 0.0f;
		final float centerZ = -1.0f;
		final float upX = 0.0f;
		final float upY = 1.0f;
		final float upZ = 0.0f;
		Matrix.setLookAtM(viewMatrix, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
		Matrix.translateM(viewMatrix, 0, 0.0f, 0.0f, -4.0f);
		
	
		
		vShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
		GLES20.glShaderSource(vShader, vCode);
		GLES20.glCompileShader(vShader);
		
		fShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
		GLES20.glShaderSource(fShader, fCode);
		GLES20.glCompileShader(fShader);
		
		sProgram = GLES20.glCreateProgram();
		GLES20.glAttachShader(sProgram, vShader);
		GLES20.glAttachShader(sProgram, fShader);
		GLES20.glLinkProgram(sProgram);
		
	}
public void onSurfaceChanged(GL10 gl, int width, int height) {
		GLES20.glViewport(0, 0, width, height);
		
		final float ratio = (float)width/height;
		final float left = -ratio;
		final float right = ratio;
		final float bottom = -1.0f;
		final float top = 1.0f;
		final float near = 1.0f;
		final float far = 100.0f;
		Matrix.frustumM(projMatrix, 0, left, right, bottom, top, near, far);
	}

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
	    GLES20.glUseProgram(sProgram);
		
	    
	    long time = SystemClock.uptimeMillis() % 10000L;
        float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
        
	    
	    Matrix.setIdentityM(modelMatrix, 0);
	    Matrix.rotateM(modelMatrix, 0, angleInDegrees, 0.0f, 1.0f, 0.0f);
	    
	    vertsBuffer.position(0);
		GLES20.glEnableVertexAttribArray(GLES20.glGetAttribLocation(sProgram, "aPos"));
		GLES20.glVertexAttribPointer(GLES20.glGetAttribLocation(sProgram, "aPos"), 3, GLES20.GL_FLOAT, false, 0, vertsBuffer);
		
		GLES20.glVertexAttrib4f(GLES20.glGetAttribLocation(sProgram, "aCol"), 1.0f, 1.0f, 0.0f, 1.0f);
		
		Matrix.multiplyMM(modViewProjMatrix, 0, viewMatrix, 0, modelMatrix, 0);
		Matrix.multiplyMM(modViewProjMatrix, 0, projMatrix, 0, modViewProjMatrix, 0);
		
		GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(sProgram, "uMVPMat"), 1, false, modViewProjMatrix, 0);
		
		//GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 0, number);
		GLES20.glDrawElements(GLES20.GL_LINE_LOOP, number, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);

private final String vCode = 
			 "uniform mat4 uMVPMat;              
"
			+"uniform mat4 uMVMat;               
"
			+"attribute vec3 aPos;        
"
			+"attribute vec4 aCol;       
"
			+"varying vec4 vCol;         
"
			+"void main(){               
"
			+" vCol = aCol;              
"
			+" gl_Position = uMVPMat * vec4(aPos, 1.0); 
"
			+"}                          
";
	
	private final String fCode =
			"precision mediump float;    
"
			+"varying vec4 vCol;         
"
			+"void main(){               
"
			+"gl_FragColor = vCol;       
"
			+"}                          
";
		
	}


As this is OpenGL ES, I don’t know all the idiosyncrasies but I do see something that might be the problem. When you call glDrawElements, the second arg (count) needs to be the number of indices, not the number of vertices.