Multiple VAO and VBO with JOGL

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Multiple VAO and VBO with JOGL

Chen norris
Hello everyone,

This is my very first post in here about JOGL so sorry in advance if I missed a step before posting in here.
The problem I'm facing deals with VAO/VBO comprehension. As an example, I'd like to render a square in very specific (and not optimized) way : I would like to render two triangles with two different VAOs. The structure of my code looks like this :

INIT :
  • creation of two VAOs (one for each triangle),
  • creation of three VBOs (position, color and index). As far as I understood, the number of VBOs to create doesn't rely on the number of VAOs that's why I don't need to create six VBOs but only as many VBOs as I have attributes (a VBO for the position, a VBO for the color and a VBO for the index, shared between all VAOs),
  • binding of the first VAO, then buffering the first triangle's attributes (3 positions, 3 colors and 3 indices),
  • binding of the second VAO, then buffering the second triangle's attributes (3 positions, 3 colors and 3 indices).
RENDERING :
  • binding of the first VAO, call to glDrawElement method, and unbinding the first VAO,
  • binding of the second VAO, call to glDrawElement method, and unbinding the second VAO.
My code for the init part is then the following :
// creation of two VAOs
int[] tempVertexArrayObject = new int[2];
gl3.glGenVertexArrays(2, tempVertexArrayObject, 0);
vaoId1 = tempVertexArrayObject[0];
vaoId2 = tempVertexArrayObject[1];

// creation of three VBOs
IntBuffer idArray = GLBuffers.newDirectIntBuffer(3);
gl3.glGenBuffers(3, idArray);
positionBufferId = idArray.get(0);
colorBufferId = idArray.get(1);
indexBufferId = idArray.get(2);

// binding and buffering the first VAO
gl3.glBindVertexArray(vaoId1);

// buffering positions
gl3.glBindBuffer(GL.GL_ARRAY_BUFFER, positionBufferId);
gl3.glBufferData(GL.GL_ARRAY_BUFFER, positionBuffer.capacity() * Buffers.SIZEOF_FLOAT, positionBuffer, GL.GL_STATIC_DRAW);
gl3.glEnableVertexAttribArray(positionHandler);
gl3.glVertexAttribPointer(positionHandler, 3, GL.GL_FLOAT, false, 0, 0);
gl3.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

// buffering colors
gl3.glBindBuffer(GL.GL_ARRAY_BUFFER, colorBufferId);
gl3.glBufferData(GL.GL_ARRAY_BUFFER, colorBuffer.capacity() * Buffers.SIZEOF_FLOAT, colorBuffer, GL.GL_STATIC_DRAW);
gl3.glEnableVertexAttribArray(colorHandler);
gl3.glVertexAttribPointer(colorHandler, 4, GL.GL_FLOAT, false, 0, 0);
gl3.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

// buffering indices
gl3.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
gl3.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Buffers.SIZEOF_INT, indexBuffer, GL.GL_STATIC_DRAW);

// binding and buffering the second VAO + buffering positions + ...
// same as before, but gl.glBindVertexArray(vaoId2) instead of gl.glBindVertexArray(vaoId1), and with other buffers
// that contain data for the other triangle
My code for the rendering part is the following :
// Drawing the first triangle
gl3.glBindVertexArray(vaoId1);
gl3.glDrawElements(GL3.GL_TRIANGLES, 3, GL3.GL_UNSIGNED_INT, 0);
gl3.glBindVertexArray(0);

// Drawing the second triangle
gl3.glBindVertexArray(vaoId2);
gl3.glDrawElements(GL3.GL_TRIANGLES, 3, GL3.GL_UNSIGNED_INT, 0);
gl3.glBindVertexArray(0);
Of course, I didn't put the part where I clear my background, I enable depth test, ...
My problem is that only the second triangle is drawn, as if buffering data when VAO #2 is binded buffers data for VAO #1. Another strange behavior I can see is that when I only call the Drawing the first triangle instructions, I can see my second triangle.

Any advice on something I misunderstood or on something I may do wrong ?

Thanks in advance for your help.
Reply | Threaded
Open this post in threaded view
|

Re: Multiple VAO and VBO with JOGL

gouessej
Administrator
Hey

Have you looked at Xerxes's example in the wiki?
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Multiple VAO and VBO with JOGL

Chen norris
Just had a look at this one :
https://wiki.jogamp.org/git/?p=jogl-demos.git;a=blob;f=src/demos/es2/RawGL2ES2demo.java;hb=HEAD

but I'm not sure that it's the example you were talking about because I didn't find any glBindVertexArray call inside the source code. I searched for other examples from Xerxes (through the wiki and through his website) but I didn't find any occurence of glBindVertexArray either...
Reply | Threaded
Open this post in threaded view
|

Re: Multiple VAO and VBO with JOGL

jmaasing
Hope this sample can help, it's been a few years since I ran it so you need to change the import lines from the 'javax...' to jogamp and so on but it will show how to bind a VAO and a VBO. It should be rather straight forward to extend to bind several VBOs to the same VAO.


/*
 DO WHAT THE F*CK YOU WANT TO PUBLIC LICENSE
 Version 2, December 2004

 Copyright (C) 2014 Johan Maasing

 Everyone is permitted to copy and distribute verbatim or modified
 copies of this license document, and changing it is allowed as long
 as the name is changed.

 DO WHAT THE F*CK YOU WANT TO PUBLIC LICENSE
 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

 0. You just DO WHAT THE F*CK YOU WANT TO.
 http://en.wikipedia.org/wiki/WTFPL
 */
package nu.zoom.corridors.client;

import com.jogamp.common.nio.Buffers;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.FloatBuffer;
import javax.media.nativewindow.WindowClosingProtocol;
import javax.media.opengl.DebugGL4;
import javax.media.opengl.GL;
import javax.media.opengl.GL4;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
import javax.media.opengl.TraceGL4;

/**
 *
 * @author Johan Maasing <johan@zoom.nu>
 */
public class TriangleSample {

	// http://www.opengl.org/wiki/Vertex_Specification
	final int[] vas = new int[1];
	final int[] vbos = new int[1];
	private int shaderPosition;

	private int flatColorShaderProgram = 0;
	private Animator animator;
	private GLWindow glWindow;
	private boolean windowDestroyed = false;

	private static final float[] two_triangles = new float[]{
		-1.0f, -1.0f, 0.1f,
		1.0f, 1.0f, 0.1f,
		0.0f, 1.0f, 0.1f, 
		1.0f, -1.0f, 0.7f,
		0.0f, 1.0f, 0.7f,
		-1.0f, 1.0f, 0.7f
	};

	private final String vertShader
			= "#version 410 core\n"
			+ "in vec3 position;\n"
			+ "out vec2 uv ;\n"
			+ "void main(void)\n"
			+ "{"
			+ "   uv = (position.xy + 1.0f)/2.0f;"
			+ "   gl_Position = vec4(position, 1.0f) ; \n"
			+ "}";

	private final String flatColorfragShader
			= "#version 410 core\n"
			+ "in vec2 uv;\n"
			+ "layout(location = 0) out vec4 fragColor ;\n"
			+ "void main(void)\n"
			+ "{"
			+ "   fragColor = vec4(gl_FragCoord.z,gl_FragCoord.z,gl_FragCoord.z, 1.0) ; \n"
			+ "}";

	public static void main(String[] args) throws Exception {
		TriangleSample app = new TriangleSample();
		app.run();
	}

	private void stop(String msg) {
		if (this.animator != null) {
			this.animator.stop();
		}
		if (this.glWindow != null) {
			this.windowDestroyed = true;
			this.glWindow.destroy();
		}
		System.out.println(msg);
	}

	private void run() throws Exception {
		final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL4));
		caps.setBackgroundOpaque(true);
		caps.setDoubleBuffered(true);
		caps.setDepthBits(8);
		caps.setSampleBuffers(false);
		this.glWindow = GLWindow.create(caps);
		this.glWindow.setTitle("FBO Test");
		this.glWindow.setSize(640, 480);
		this.glWindow.setUndecorated(false);
		this.glWindow.setPointerVisible(true);
		this.glWindow.setVisible(true);
		this.glWindow.setFullscreen(false);
		this.glWindow.setDefaultCloseOperation(WindowClosingProtocol.WindowClosingMode.DISPOSE_ON_CLOSE);
		this.glWindow.addWindowListener(new WindowAdapter() {
			@Override
			public void windowDestroyNotify(WindowEvent we) {
				if (!windowDestroyed) {
					stop("Window destroyed");
				}
			}
		});
		this.glWindow.addGLEventListener(new GLEventListener() {
			@Override
			public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
				GL gl = drawable.getGL();
				gl.glViewport(x, y, width, height);
			}

			@Override
			public void init(GLAutoDrawable drawable) {
				GL gl = drawable.getGL();
				if (gl.isGL4core()) {
					drawable.setGL(new TraceGL4(new DebugGL4(gl.getGL4()), System.out));
					GL4 gL4 = drawable.getGL().getGL4();
					try {
						TriangleSample.this.init(gL4);
					} catch (IOException ex) {
						stop(ex.getLocalizedMessage());
					}
				} else {
					stop("Not a GL4 core context");
				}
			}

			@Override
			public void dispose(GLAutoDrawable drawable) {
			}

			@Override
			public void display(GLAutoDrawable drawable) {
				GL4 gL4 = drawable.getGL().getGL4();
				TriangleSample.this.display(gL4);
			}
		});
		this.animator = new Animator(glWindow);
		this.animator.start();
	}

	private void init(GL4 gl) throws IOException {
		gl.glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
		gl.glClearDepthf(1.0f);
		gl.glEnable(GL4.GL_CULL_FACE);
		gl.glCullFace(GL4.GL_BACK);
		gl.glFrontFace(GL4.GL_CCW);
		gl.glEnable(GL4.GL_DEPTH_TEST);
        gl.glDepthFunc(GL4.GL_LEQUAL);
		
		// Compile and link the shader then query the shader for the location of the vertex input variable
		final ShaderCode vertexShader = compileShader(gl, vertShader, GL4.GL_VERTEX_SHADER);
		final ShaderCode flatColorFragmentShader = compileShader(gl, flatColorfragShader, GL4.GL_FRAGMENT_SHADER);
		this.flatColorShaderProgram = linkShader(gl, vertexShader, flatColorFragmentShader);
		this.shaderPosition = gl.glGetAttribLocation(this.flatColorShaderProgram, "position");
		
		// Create the mesh
		createBuffer(gl, shaderPosition, two_triangles, 3);
	}

	public ShaderCode compileShader(final GL4 gl4, final String source, final int shaderType) throws IOException {

		final String[][] sources = new String[1][1];
		sources[0] = new String[]{source};
		ShaderCode shaderCode = new ShaderCode(shaderType, sources.length, sources);
		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
		final boolean compiled = shaderCode.compile(gl4, System.err);
		if (!compiled) {
			System.err.println("Unable to compile " + source);
			System.exit(1);
		}
		return shaderCode;
	}

	private int linkShader(GL4 gl, final ShaderCode vertexShader, final ShaderCode textureFragmentShader) throws GLException {
		ShaderProgram program = new ShaderProgram();
		program.init(gl);
		program.add(vertexShader);
		program.add(textureFragmentShader);
		program.link(gl, System.out);

		final boolean validateProgram = program.validateProgram(gl, System.out);
		if (!validateProgram) {
			System.err.println("Unable to link shader");
			System.exit(1);
		}
		return program.program();
	}

	private void display(GL4 gl) {
		// Clear the default framebuffer
		gl.glBindFramebuffer(GL4.GL_DRAW_FRAMEBUFFER, 0);
		gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);

		gl.glUseProgram(this.flatColorShaderProgram);
		gl.glBindVertexArray(this.vas[0]);
		gl.glEnableVertexAttribArray(this.shaderPosition);
		gl.glDrawArrays(GL4.GL_TRIANGLES, 0, 6);
	}

	public void createBuffer(final GL4 gl, final int shaderAttribute, float[] values, final int valuesPerVertex) {
		gl.glGenVertexArrays(this.vas.length, this.vas, 0);
		gl.glBindVertexArray(this.vas[0]);
		gl.glGenBuffers(this.vbos.length, this.vbos, 0);
		gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, this.vbos[0]);
		FloatBuffer fbVertices = Buffers.newDirectFloatBuffer(values);
		final int bufferSizeInBytes = values.length * Buffers.SIZEOF_FLOAT;
		gl.glBufferData(GL4.GL_ARRAY_BUFFER, bufferSizeInBytes, fbVertices, GL4.GL_STATIC_DRAW);
		gl.glVertexAttribPointer(shaderAttribute, valuesPerVertex, GL4.GL_FLOAT, false, 0, 0);
	}
}
Reply | Threaded
Open this post in threaded view
|

Re: Multiple VAO and VBO with JOGL

Chen norris
Hi John, thanks a lot for your code.

I managed to change the import so that it uses the JOGL librairies and it works like a charm (pink background with 2 grey triangles).
Then I tried to change a bit the way it works so that it would run with 2 differents VAOs. The changes I made are the following :
private static final float[] first_triangle = new float[]{
    -1.0f, -1.0f, 0.1f,
    1.0f, 1.0f, 0.1f,
    0.0f, 1.0f, 0.1f
};
private static final float[] second_triangle = new float[]{
    1.0f, -1.0f, 0.7f,
    0.0f, 1.0f, 0.7f,
    -1.0f, 1.0f, 0.7f
};
Two triangles to render = two calls to createBuffer like this :
// Create the mesh
createBuffer(gl, shaderPosition, first_triangle, 3, 0);
createBuffer(gl, shaderPosition, second_triangle, 3, 1);
The final parameter I added to the createBuffer method is used to know what VAO must be binded :
public void createBuffer(final GL4 gl, final int shaderAttribute, float[] values, final int valuesPerVertex, int n) {
    if (!vasSet) {
        gl.glGenVertexArrays(this.vas.length, this.vas, 0);
        vasSet = true;
    }
    gl.glBindVertexArray(this.vas[n]);
    // ... and so on
A last modification is made in the display method, to render not anymore 1 but 2 VAOs :
gl.glUseProgram(this.flatColorShaderProgram);
gl.glBindVertexArray(this.vas[0]);
gl.glEnableVertexAttribArray(this.shaderPosition);
gl.glDrawArrays(GL4.GL_TRIANGLES, 0, 3);

gl.glBindVertexArray(this.vas[1]);
gl.glEnableVertexAttribArray(this.shaderPosition);
gl.glDrawArrays(GL4.GL_TRIANGLES, 0, 3);

So now, I think I have a good example on which I can rely on to understand why I couldn't render properly multiple VAOs.
Thank you so much, that thing was starting to drive me crazy...

Nice copyright, by the way ^^