I am trying to establish some basic functionality using VBO and VAO setups, but it is so hard to find good examples and tutorials. They either use poor practices, don’t use all elements (i.e. just vertex and color or just vertex and shaders), or are using old methods to implement. I want to use the best up to date methods but can’t seem to pull it all together.
Here is my basic logical setup:
I have a class that initializes everything, then runs the main rendering loop. Once done, it destroys used resources then quits.
I have a class that contains all of the functions used in creating my OpenGL window such as setting options like fog or lighting.
These two run together and function quite well, so they are not the subject of this post.
I have a class that contains 2 main functions along with everything needed to support said two functions:
initialize()
- This class contains a static initializer() that creates a new instance of itself and passes in critical variables
- This class contains a HashMap that keeps track of all instances and allows me to call all of their draw() when needed
- This class constructor contains methods to load and parse a Blender.obj file
- This class parses data into appropriate buffers giving me Vertex, Texture coord, Normal, and Index buffers ready made
- This class then creates the VAO/VBO/IBOs (code to follow)
draw() - This method sets up environment for drawing this object, draws it, then cleans up after itself (code to follow)
The logic of all of this is so that I can initialize a copy of this class for each object I want to draw to the 3D world. It would load the data from external files, and this class would contain all the functions needed to draw the object using vertex, normal, texture coordinates, color (tinting), lighting, etc…
The data in an .obj file is stored in a method that makes an interleaved indexed VAO look like the best option. Just in case that isn’t a real thing, let me explain
The data for each vertex is stored in the .obj file in numbered order - insert directly into vertexBuffer
The data for each normal is stored in the .obj file in numbered order - insert directly into normalBuffer
The data for each texture is stored in the .obj file in numbered order - insert directly into textureBuffer
The data for each face is stored in the .obj file in numbered order - insert directly into indexBuffer in order: v, t, n, v, t, n, v, t, n,
So the data is stored in separate VBOs but the indexes are interleaved.
However I can’t get OpenGL to understand this as easily as I do. how do I do this?
Here is my initialization code for a simple triangle: (reading from external file removed for clarity)
Data:
[spoiler]
vBuffer = BufferUtils.createFloatBuffer(1 /*faces*/
*3 /*vertexes per face*/
*3 /*floats per vertex*/);
vBuffer.put(new float[]{-0.1f, -0.1f, 0f});
vBuffer.put(new float[]{+0.1f, -0.1f, 0f});
vBuffer.put(new float[]{+0.0f, +0.1f, 0f});
vBuffer.flip();
tBuffer = BufferUtils.createFloatBuffer(1 /*faces*/
*3 /*coords per face*/
*2 /*floats per coord*/);
tBuffer.put(new float[]{-0.1f, -0.1f});
tBuffer.put(new float[]{+0.1f, -0.1f});
tBuffer.put(new float[]{+0.0f, +0.1f});
tBuffer.flip();
nBuffer = BufferUtils.createFloatBuffer(1 /*faces*/
*1 /*normal per face*/
*3 /*floats per normal*/);
nBuffer.put(new float[]{0.0f, 0.0f, 1f});// Straight towards camera
nBuffer.flip();
iBuffer = BufferUtils.createFloatBuffer(1 /*faces*/
*3 /*index per face*/
*3 /*int per index*/);
iBuffer.put(new int[]{1,1,1}); // vertex, texCoord, normal index
iBuffer.put(new int[]{2,2,1});
iBuffer.put(new int[]{3,3,1});
iBuffer.flip();
[/spoiler]
Bindings:
[spoiler]
// Generate VAO Container for model
vaoHandle = glGenVertexArrays();
glBindVertexArray(vaoHandle);
// Generate Vertex Buffer Object
vHandle = glGenBuffers();//<editor-fold defaultstate="collapsed" desc="Vertex">
// Bind vertexes to Handle
glBindBuffer(GL_ARRAY_BUFFER, vHandle);
glBufferData(GL_ARRAY_BUFFER, vBuffer, GL_STATIC_DRAW);
// Put the VBO in the attributes list at index 0
glVertexAttribPointer(0, // Attribute Position Counter/Pointer - Must match layout in shader?
3, // Size of each item
GL_FLOAT, // Format of each item
false, // Normalized?
3, // Stride
0); // Array Buffer Offset
// Deselect (bind to 0) the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO
//</editor-fold>
// Generate Texture Buffer Object
tHandle = glGenBuffers();//<editor-fold defaultstate="collapsed" desc="Texture">
// Bind vertexes to Handle
glBindBuffer(GL_ARRAY_BUFFER, tHandle);
glBufferData(GL_ARRAY_BUFFER, tBuffer, GL_STATIC_DRAW);
// Put the VBO in the attributes list at index 3
glVertexAttribPointer(1, 3, GL_FLOAT, false, 3, 1);
// Deselect (bind to 0) the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO
//</editor-fold>
// Generate Normal Buffer Object
nHandle = glGenBuffers();//<editor-fold defaultstate="collapsed" desc="Normal">
// Bind vertexes to Handle
glBindBuffer(GL_ARRAY_BUFFER, nHandle);
glBufferData(GL_ARRAY_BUFFER, nBuffer, GL_STATIC_DRAW);
// Put the VBO in the attributes list at index 2
glVertexAttribPointer(2, 3, GL_FLOAT, false, 3, 2);
// Deselect (bind to 0) the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO
//</editor-fold>
// Generate Index Buffer Object
iHandle = glGenBuffers();//<editor-fold defaultstate="collapsed" desc="Index">
// Bind vertexes to Handle
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iBuffer, GL_STATIC_DRAW);
// Put the VBO in the attributes list at index 4
glVertexAttribPointer(3, 3, GL_INT, false, 3, 0);
// Deselect (bind to 0) the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO
//</editor-fold>
// Deselect (bind to 0) the VAO
glBindVertexArray(0);
[/spoiler]
Here is my draw code so far for the object:
[spoiler]
glUseProgram(shaderProgram);
// Bind chosen VAO and Enable it
GL30.glBindVertexArray(vaoHandle);
GL20.glEnableVertexAttribArray(0); // Vertex
GL20.glEnableVertexAttribArray(1); // Texture
GL20.glEnableVertexAttribArray(2); // Normal
GL20.glEnableVertexAttribArray(3); // Index
glDrawElements(GL_TRIANGLES, // type
indexCount, // count of indexes groups (currently 3)
GL_INT, // format of data
0); // offset?
// Put everything back to default (deselect)
GL20.glDisableVertexAttribArray(0); // Vertex
GL20.glDisableVertexAttribArray(1); // Texture
GL20.glDisableVertexAttribArray(2); // Normal
GL20.glDisableVertexAttribArray(3); // Index
GL30.glBindVertexArray(0);
glUseProgram(0);
[/spoiler]
I know there is some stuff here for shaders, but that isn’t the main focus of this post, however if you want to elaborate on that too, be my guest. If not answered here, I will make another post about the shaders side later.