[Solved] Problem with multiple VAOs not recording states

Started by rdeterre, October 10, 2013, 19:03:01

Previous topic - Next topic

rdeterre

Hi,

I'm not sure if my understanding of the way VAOs work is good enough. I'm trying to use two VAOs to each draw a model, and the vertices data gets mixed between the two. I've pasted a small program that demonstrates the issue below.

In this program, I generate the VAOs and two VBOs. Then, for each VAO I first bind the VAO, bind the VBO, fill the VBO with glBufferData, then link the VBO to the shader's attribute index with glVertexAttribPointer. In the render loop, I then successively bind each VAO and issue a draw call (glDrawArrays). The problem is that on screen, only the vertices data of the bound VBO during the last glVertexAttribPointer call are used. Worse, this data also gets used if the glBindVertexArray(0) is called just before the draw call.

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.FloatBuffer;
import java.util.Scanner;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

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

public class MainDisplay {
	public void start() {
		try {
			Display.setDisplayMode(new DisplayMode(400,300));
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(-1);
		}
		
		float[] triangle = {
				-.5f, -.5f, 0f,
				0.5f, -.5f, 0f,
				  0f, 0.5f, 0f
		};
		
		float[] square = {
				-.4f, -.4f, 0f,
				0.4f, -.4f, 0f,
				0.4f, 0.4f, 0f,
				-.4f, 0.4f, 0f
		};
		
		String[] attributes = {"position"};
		int shaderProgram = createShaderProgram("res/simple.vert",
				"res/simple.frag",
				attributes);
		
		int tVao = glGenBuffers();
		int sVao = glGenBuffers();
		
		glBindVertexArray(tVao);
		int tVbo = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, tVbo);
		FloatBuffer tBuffer = (FloatBuffer) BufferUtils
				.createFloatBuffer(triangle.length)
				.put(triangle)
				.flip();
		glBufferData(GL_ARRAY_BUFFER, tBuffer, GL_STATIC_DRAW);
		glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
		glEnableVertexAttribArray(0);
		glBindVertexArray(sVao);
		int sVbo = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, sVbo);
		FloatBuffer sBuffer = (FloatBuffer) BufferUtils
				.createFloatBuffer(square.length)
				.put(square)
				.flip();
		glBufferData(GL_ARRAY_BUFFER, sBuffer, GL_STATIC_DRAW);
		glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
		glEnableVertexAttribArray(0);
		glBindVertexArray(0);
		
		
		
		while (!Display.isCloseRequested()) {
			glClearColor(0.0f,0f,0f,1f);
			glClear(GL_COLOR_BUFFER_BIT);
			glUseProgram(shaderProgram);
			glBindVertexArray(tVao);
			glBindBuffer(GL_ARRAY_BUFFER, tVbo);
			glBindVertexArray(sVao);
			glDrawArrays(GL_QUADS, 0, 4);
			glBindVertexArray(0);
			glUseProgram(0);
			Display.update();
		}
		
		Display.destroy();
	}
	
	public static void main(String[] args) {
		MainDisplay display = new MainDisplay();
		display.start();
	}
	
	public static int createShaderProgram(String vertex, 
			String fragment, 
			String[] attributes) {
		int vertexShader = glCreateShader(GL_VERTEX_SHADER);
		String s = null; 
		String f = null;
		try {
			s = new Scanner(new File(vertex)).useDelimiter("\\Z").next();
			f = new Scanner(new File(fragment)).useDelimiter("\\Z").next();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		glShaderSource(vertexShader, s);
		glCompileShader(vertexShader);
		
		// Error check
		if (glGetShaderi(vertexShader, GL_COMPILE_STATUS) == GL_FALSE) {
			System.err.print("Failure in compiling vertex shader. Error log :\n"
					+ glGetShaderInfoLog(vertexShader, 
							glGetShaderi(vertexShader, GL_INFO_LOG_LENGTH)));
			System.exit(1);
		}
		
		int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragmentShader, f);
		glCompileShader(fragmentShader);
		
		// Error check
		if (glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE) {
			System.err.print("Failure in compiling fragment shader. Error log :\n"
					+ glGetShaderInfoLog(fragmentShader, 
							glGetShaderi(fragmentShader, GL_INFO_LOG_LENGTH)));
			System.exit(1);
		}
		
		int shaderProgram = glCreateProgram();
		glAttachShader(shaderProgram, vertexShader);
		glAttachShader(shaderProgram, fragmentShader);
		
		// Vertex attributes to shader mapping
		for (int i = 0; i < attributes.length; i++) {
			glBindAttribLocation(shaderProgram, i, attributes[i]);
		}
		
		glLinkProgram(shaderProgram);
		
		// Error check
		if (glGetProgrami(shaderProgram, GL_LINK_STATUS) == GL_FALSE) {
			System.err.println("Failure in linking program. Error log:\n"
					+ glGetProgramInfoLog(shaderProgram, 
							glGetProgrami(shaderProgram, GL_INFO_LOG_LENGTH)));
			System.exit(1);
		}
		
		glDetachShader(shaderProgram, vertexShader);
		glDetachShader(shaderProgram, fragmentShader);
		glDeleteShader(vertexShader);
		glDeleteShader(fragmentShader);
		
		return shaderProgram;
	}
}



With the shaders :

#version 130

in vec4 position;

void main()
{
	gl_Position = position;
}


and

#version 130

out vec4 outputColor;

void main()
{
	outputColor = vec4(1.0, 1.0, 1.0, 1.0);
}


What am I missing ?

Thanks

spasi

There are two problems in your code:

1) This:

int tVao = glGenBuffers();
int sVao = glGenBuffers();


should be:

int tVao = glGenVertexArrays();
int sVao = glGenVertexArrays();


2) This:

glBindVertexArray(tVao);
glBindBuffer(GL_ARRAY_BUFFER, tVbo);
glBindVertexArray(sVao);
glDrawArrays(GL_QUADS, 0, 4);


should be:

glBindVertexArray(tVao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(sVao);
glDrawArrays(GL_QUADS, 0, 4);


You should get the result you're looking for. Notice how you don't need to have an ARRAY_BUFFER bound when using VAO.

My recommendations:

1) Your code was obviously generating OpenGL errors. You should use Util.checkGLError() or -Dorg.lwjgl.util.Debug=true when developing new stuff. Or, even better, one of the OpenGL debugging extensions like AMD_debug_output, ARB_debug_output, etc, they provide much more useful info.

2) Don't use VAO. I know it's modern OpenGL and it was supposed to help cleanup code, but it turns out it's bad for performance across all platforms and implementations. The core profile requires it, so create one at the beginning, bind it, then forget it even exists.

rdeterre

Thanks spasi, that fixed the problem !

Thanks you also for the recommendations, I'll use them in the future.