Search code examples
javaopengllwjgl

Undestanding OpenGL fundamentals


Greetings fellow OpenGL enthusiasts!

  • First of all I use LWJGL 2, so it's Java code below.
  • Second. I want to say that I googled every single question I will be asking in this post. The main problem is that answers differ from each other so I can't build a concrete undestanding of things that is happening in my code below.
  • Third. I just started learning OpenGL and I'm also not at all experiences in Java. So if you have any suggestion besides explanations of my question feel free to criticize/advise. Besides doing OpenGL with C++ :)

Now let's begin.

public class Loader {
public void createVAO(int[] indices) {
    int vaoID = glGenVertexArrays();

    glBindVertexArray(vaoID);
    createIndicesVBO(indices);
    glEnableVertexAttribArray(0);
}

public void createVBO(float[] vertices) {
    int vboID = glGenBuffers(); 
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    FloatBuffer buffer = makeByteBufferFromArrayOfFloats(vertices);
    glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 0,0);
}

public void createIndicesVBO(int[] indices) {
    int vboID = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
    IntBuffer buffer = makeByteBufferFromArrayOfInts(indices);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
}

public void pleaseDraw(float[] vertices, int[] indices) {
    glClearColor(0, 0, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT,0);

}
public void cleanUp() {
    glDeleteBuffers(0);
    glDeleteVertexArrays(0);
}
public FloatBuffer makeByteBufferFromArrayOfFloats(float[] vertices) {

    FloatBuffer FloatByteBuffer = BufferUtils.createFloatBuffer(vertices.length);
    FloatByteBuffer.put(vertices);
    FloatByteBuffer.flip();
    return FloatByteBuffer;
}

public IntBuffer makeByteBufferFromArrayOfInts(int[] array) {

    IntBuffer IntByteBuffer = BufferUtils.createIntBuffer(array.length);
    IntByteBuffer.put(array);
    IntByteBuffer.flip();
    return IntByteBuffer;
}
}

Note - This code is working and outputs a blue window with a black quad in the middle. Questions:

  1. glBindBuffer(GL_ARRAY_BUFFER, vboID); I don't understand clearly what does GL_Array Buffer even means. As far as I can get it just shows to OpenGL current state that this VBO will store Array data at some point. But from the function below I can guess that it is not just a type of data but it is like a container for a data and this is only that can be active for a current state. Am I getting it right? Or am I missing something?
  2. glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW); Again this GL_Array_Thing. And it seems this funtion puts a data into GPU or It puts current VBO into VAO? I'm not sure.
  3. glVertexAttribPointer(0, 3, GL_FLOAT, false, 0,0); So VAO consist of attributes and here we show to OpenGL how to read our 0 attrib. Correct me if I'm wrong.
  4. If I got how attribs in VAO works correctly I assume I can change this lines glEnableVertexAttribArray(0); and glVertexAttribPointer(0, 3, GL_FLOAT, false, 0,0); to glEnableVertexAttribArray(1); and glVertexAttribPointer(1, 3, GL_FLOAT, false, 0,0);. Nothing should change in final render, but in reality black quad is not appearing. Can't figure out why.
  5. I use indices to Draw a quad. But how in the world does OpenGL understand how to read the data I provide, because I did not specify how to use it. I only imagine this line help me to do it glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT,0);

There are a lot of extra questions but they either appears because of my lack of understanding about questions that I described above. Please help me to make out this mess in my head about fundamentals of OpenGL. For those who were able to read or even answer to this post - Thanks a lot!


Solution

  • glBindBuffer(GL_ARRAY_BUFFER, vboID);
    

    Means: I have several VBOs. Select (for next usage) the one identified by vboID. The mode GL_ARRAY_BUFFER is for raw (bytes) data.

    glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW); //Notice I added "size" for C++. LWJGL doesn't need it.
    

    Means: Fill currently bound array_buffer (with "glBindBuffer") with size bytes; take them from buffer (an address in CPU RAM). My intention (GL_STATIC_DRAW) is that the GPU reads many times the data, not to modify it.

    glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, 0,0); // "stride" added
    

    The GPU reads from one or several VBOs. For example the VBO may consists of x,y,z coords (3 floats) followed by R,G,B,A color-components (4 bytes) and repeat the sequence for other vertices.
    glVertexAttribPointer establish the relation between VBO and the attributes needed. In the example: the first attribute (0) needs 3 values of type GL_FLOAT which are not(false) normalized (not in [0.0, 1.0] range). The next sequence for this attribute is stride bytes far (using 0 means attributes are tightly packed). The last 0.0 is the offset in the VBO for the first attribute.

    The color may be read as another attribute, from the same VBO or not. The "name" for this attribute may be 1, because 0 is already used for coordinates. So it needs its own glVertexAttribPointer call.

    The attribute identifiers were chosen by the GPU. Since OpenGL >=3.3 (which I strongly advise to use) you better choose them (by "location = 0" stuff in the shaders)

    A VAO contains the buffers bindings and the attributes bindings. Each time you need to render the data from some VBOs you don't need to use again the glBindBuffer and glVertexAttribPointer required. Just use glBindVertexArray instead.

    "Indexing rendering" means that you use two VBOs: one for coordinates and the other for indices. (Other VBOs may also be used for other attributes). The VBO with indices tells the GPU the "sequences" order from the first VBO (and the other VBOs). These allows to read the same vertex several times without repeating its attributes. Notice that a triangulation shares the same vertex among several triangles. You can avoid sending to GPU repeated data.