[LWJGL] Attributes and VBO

Hello !

I am confused about the way I should transfer attributes values to a Vertex Shader using buffers. In the shader I defined this:

// The vertex position
attribute vec3 Vertex;
// The normal
attribute vec3 Normal;
// The color
attribute vec3 Color;
// The bones index attributes
attribute vec2 Index;
// The bones weight for each indexed bone
attribute vec2 Weight;

in java I use this code to render (the 3D model may dynamically update):

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexID);
        if (faces == null)
        { faces = faces(resolution);
          size = 3*faces.size();
          int bufferSize = size*VSIZE;
          if (vbuf == null || vbuf.capacity() < bufferSize) vbuf = BufferUtils.createFloatBuffer(bufferSize);
          if (colors) for (Triangle3D f : faces) f.loadrgb(vbuf); else for (Triangle3D f : faces) f.load(vbuf);
          System.out.println(size+" points loaded in buffers.");
          vbuf.flip();
          GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vbuf, GL15.GL_DYNAMIC_DRAW);
        }
        //GL11.glVertexPointer(3, GL11.GL_FLOAT, VSIZE, VOF);
        //GL11.glNormalPointer(GL11.GL_FLOAT, VSIZE, NOF);
        //GL11.glColorPointer(3, GL11.GL_FLOAT, VSIZE, COF);
        GL20.glVertexAttribPointer(VERTEX, 3, GL11.GL_FLOAT, false, VSIZE, VOF);
        GL20.glVertexAttribPointer(NORMAL, 3, GL11.GL_FLOAT, false, VSIZE, NOF);
        GL20.glVertexAttribPointer(COLOR,  3, GL11.GL_FLOAT, false, VSIZE, COF);
        GL20.glVertexAttribPointer(INDEX,  2, GL11.GL_FLOAT, false, VSIZE, IOF);
        GL20.glVertexAttribPointer(WEIGHT, 2, GL11.GL_FLOAT, false, VSIZE, WOF);
        GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, size);

As you can see I tried different methods (commented) and I read here and there that there is old and modern ways to do this, but I still don’t know what is the modern and best solution ! All I get with this code for now is nothing rendered !

I know how to use vbo buffers correctly with the default openGL vertex shader variables, I also know how to use attributes without vbo, for example with GL20.glVertexAttrib2f(weight, a, b), but I don’t understand how to do both !

OpenGL version?

I did not use anything post version 2.0 for now.

You are doing everything right so far, given that your VOF, NOF, COF, etc… are the byte offsets into the buffer currently bound to GL_ARRAY_BUFFER at which the first vertex will have its attribute value for that attribute and given that VSIZE is the total size of a vertex in bytes (containing all vertex attributes).
But that seems to be the case with you.
Next is what VERTEX, NORMAL, COLOR, INDEX and WEIGHT are supposed to be. These are the generic vertex attribute indexes of your vertex attributes in the vertex shader.
Before linking a shader program, you must assign those vertex attributes to specific generic vertex attribute indexes via GL20.glBindAttribLocation(program, index, “vertexAttributeName”). This must be done before linking the shader program via GL20.glLinkProgram(program).
If you don’t assign the generic vertex attribute indexes manually via GL20.glBindAttribLocation(), you can query them after a successful shader program link via GL20.glGetAttribLocation(program, “vertexAttributeName”) and use that return value as the argument to the first parameter of GL20.glVertexAttribPointer().
Next, make sure that the generic vertex attributes are actually enabled.
You must do this with GL20.glEnableVertexAttribArray(index).
Since you are using OpenGL 2.0, as you said, you don’t need to worry about VAOs now.

EDIT:

As for your question about what the most modern and best solution is: there is none.

It simply depends on which version of OpenGL you are targeting. No one using Direct3D would ask “what is the best way to do vertex specification?” because he or she would get as answer: “are you targeting Direct3D 7, 8, 9, 10, 11 or 12?”
There are so many different ways now to setup the vertex specification in an OpenGL program, that it makes me really cry tears of joy and relief when looking at Vulkan, because there is ONLY ONE way to do that there.

If you would ask me for the absolute most recent and very latest way to do vertex specification, I’d say in OpenGL 4.5 there is GL45.glVertexArrayVertexBuffer() to bind a VBO within a named VAO to a vertex buffer binding point.
Alternatively you can use OpenGL 4.3’s glBindVertexBuffer which binds a number of VBOs to a vertex buffer binding points and store that state inside the currently bound VAO.
Then you need to use GL43.glVertexAttribFormat() which specifies the format/layout of the vertex data separetely from binding the buffer to any buffer point (so it separates GL20.glVertexAttribPointer() into that and GL45.glVertexArrayVertexBuffer() or GL43.glBindVertexBuffer()).
Then you must use GL43.glVertexAttribBinding() to bind the generic vertex attribute of a shader to a buffer binding point which you previously bound a VBO to using glVertexArrayVertexBuffer or glBindVertexBuffer.
Oh and what is a buffer binding point now? It is a new indirection to replace/retire the old named buffer binding points like GL_ARRAY_BUFFER and have simple integers for them instead, which we are now able to associate format/layout properties with.

You see, it is really is a mess with the latest OpenGL and there are sooo many different ways. :slight_smile:
I’d stick with OpenGL 2.0 if you have no reason to upgrade.

I think Kai is a little too much dramatic and critic :stuck_out_tongue:

In modern OpenGL there is only one way to setup vertices, it is called Vertex Array Binding, VAB or ARB_vertex_attrib_binding

This include all the following calls:

    void BindVertexBuffer(uint bindingindex, uint buffer, intptr offset, 
                          sizei stride);
    void VertexAttribFormat(uint attribindex, int size, enum type, 
                            boolean normalized, uint relativeoffset);

    void VertexAttribBinding(uint attribindex, uint bindingindex);

that, in case of of Direct State Access is available, simply add the Array part in the function name and the VAO name as first argument:

    void VertexArrayVertexBuffer(uint vaobj, uint bindingindex, uint buffer,
                                 intptr offset, sizei stride);

    void VertexArrayAttribFormat(uint vaobj, uint attribindex, int size,
                                 enum type, boolean normalized,
                                 uint relativeoffset);

    void VertexArrayAttribBinding(uint vaobj, uint attribindex,
                                  uint bindingindex);

It’s not a mess, there are no so many ways, all the functions belong to the same unique VAB extension. There are no other ways.

It’s important to study, learn and understand what belongs to what in order to avoid confusion and misunderstanding.

VAB decreases the cpu overhead and alleviates the need to switch VAOs.

With the previous glVertexAttribPointer you were merging, with one call, two separate concepts, the vertex attribute and the vertex binding. This was fine but limitating, because you had to switch VAO for each mesh, or calling again glVertexAttribPointer if you were not using VAO.
VAB separates these two concepts and this is open new possibilities, because now if two meshes share the same vertex format, it’s just enough to call glBindVertexBuffer and bind the buffer of the second mesh on the same binding index of the first mesh.

This means, for you:


        GL20.glVertexAttribPointer(VERTEX, 3, GL11.GL_FLOAT, false, VSIZE, VOF);
        GL20.glVertexAttribPointer(NORMAL, 3, GL11.GL_FLOAT, false, VSIZE, NOF);
        GL20.glVertexAttribPointer(COLOR,  3, GL11.GL_FLOAT, false, VSIZE, COF);
        GL20.glVertexAttribPointer(INDEX,  2, GL11.GL_FLOAT, false, VSIZE, IOF);
        GL20.glVertexAttribPointer(WEIGHT, 2, GL11.GL_FLOAT, false, VSIZE, WOF);

becomes in the init (I do here only for the VERTEX, you have to do this for each one of your attributes):


glVertexAttribFormat(VERTEX, // attribute index
                     3,  // size
                     GL_FLOAT,  // type
                     false, // normalised
                     VOF); // offset

glVertexAttribBinding(VERTEX, // attribute index
                      bindingIndex); // binding index

Now the format of the VERTEX (and all the others) attribute is bound at bindingIndex.

What remains to do in the rendering process is now simply make pointing this bindingIndex to the buffer/stream where we want to fetch data from:


                    glBindVertexBuffer(
                            bindingIndex, // binding index
                            vboVertexID, //vbo
                            0, // offset
                            VSIZE); // stride

Great explanation! :slight_smile:
Yes, I was trying to be too dramatic to get people to move to Vulkan with LWJGL3 :stuck_out_tongue:

However, if you took whole “OpenGL” without saying “this is OpenGL 4.3” then there are countless ways to do vertex specification. There’s no denying about that. :smiley:

  • immediate mode (either with GL11 fixed attributes, or GL20 generic vertex attributes)
  • client-side vertex arrays (also either with fixed or generic attributes)
  • server-side vertex buffer objects with client-side bind/enable state (fixed or generic attributes)
  • server-side VBOs with server-side bind/enable state (VAO) (again either fixed or generic attributes)
  • server-side VBOs with explicit/decoupled format specification (GL 4.3)
  • and all that again with Direct State Access via extension or in GL 4.5
  • and on top of that the numerous ways to connect vertex specification to the rest of the pipeline via fixed-function or shaders

So, the confusion that people have about which method to use in OpenGL is justified and explainable, because there has never been an API break with OpenGL, and GL11 methods work in GL45 just as well and versions get smeared together. So, when people find tutorials/guides/codesamples of OpenGL, those things usually do not mention the explicit GL version which they are using. Or saying, they are using GL 4.3 whereas what they actually do is using GL 2.0.
That’s the problem.

I know, you evil man :smiley:

Yeah, but one should think about it in terms of extension. Because each extension may have different way to be applied.

This is totally deprecated and should be avoid at all costs. Most software can’t use it and emulates it.

This is old and it will get deprecated soon.

Current.

So, when if you ask for modern OpenGL, you have one extension, VAB, applied in two ways, based on the fact you also want to get advantage of DSA or not. Essentially then two ways.

Sure, but I didn’t mean that they have no confusion. I mean that the confusion comes from the fact that they do not know the OpenGL ecosystem is and works and not from OpenGL being unclear.

That’s the point.

New features get implemented, usually, via third extensions and then, after some time and discussion they may be added inside core profile.
This is the case of DSA, when it has been initially available as external extension through EXT_direct_state_access and then brought to core through ARB_direct_state_access.
You should know this, you know that there is the VAB extension that can interacts with both DSA EXT and DSA core, because DSA EXT came out first, but since it made to core, you should use this one.

OpenGL is ~25 years old and has evolved a lot, althought it starts showing some limitations. There has been a break on 3.3 (and there should be another one).

You can access last years methods and (in some way) 90’ years methods, this is, again, a double edge sword, you can have a great range of compatibility, but also a lot of confusion if you don’t learn and stop at the very few tutorials you find on the first page of google.

If the tutorial doesn’t help by stating which OpenGL version and extensions is using, the problem is the tutorial, not the API.

If you use GL 1.1 methods mixed with GL 4.5, this is totally silly and, again, the problem is just you, not the API. :wink:

Ps: you is impersonal :stuck_out_tongue:

Alright, thank you for those infos !

I totally agree that it is very hard to find good documents on the web about openGL and its different versions, tutorials or examples.

I finally managed to render the model as I wanted. But I had to remove the attributes I used for the vertex position, normal and color and use the default GLSL variables instead. So I have now only this in the vertex shader:

// The bones index attributes
attribute vec2 Index;
// The bones weight for each indexed bone
attribute vec2 Weight;

Before the rendering loop I use this (I commented the lines when I tried to use attributes for everything vertex related in the previous version):

      GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
      GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
      GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);

I get the 2 attributes indexes after binding the shaderProgram this way:

      INDEX  = shaderProgram.getAttributeLocation("Index");
      WEIGHT = shaderProgram.getAttributeLocation("Weight");

and enable the attributes this way:

      GL20.glEnableVertexAttribArray(INDEX);
      GL20.glEnableVertexAttribArray(WEIGHT);

So I render the model with this in the loop:

        // Bind the vertex buffer
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexID);
        if (faces == null)
        { faces = faces(resolution);
          size = 3*faces.size();
          int bufferSize = size*VSIZE;
          if (vbuf == null || vbuf.capacity() < bufferSize) vbuf = BufferUtils.createFloatBuffer(bufferSize);
          if (colors) for (Triangle3D f : faces) f.loadrgb(vbuf); else for (Triangle3D f : faces) f.load(vbuf);
          System.out.println(size+" points loaded in buffers.");
          vbuf.flip();
          GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vbuf, GL15.GL_DYNAMIC_DRAW);
        }
        GL11.glVertexPointer(3, GL11.GL_FLOAT, VSIZE, VOF);
        GL11.glNormalPointer(GL11.GL_FLOAT, VSIZE, NOF);
        GL11.glColorPointer(3, GL11.GL_FLOAT, VSIZE, COF);
        GL20.glVertexAttribPointer(INDEX,  2, GL11.GL_FLOAT, false, VSIZE, IOF);
        GL20.glVertexAttribPointer(WEIGHT, 2, GL11.GL_FLOAT, false, VSIZE, WOF);
        GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, size);

When I previously removed GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); and used the attribute vec3 Vertex instead the model was not rendered at all! I still don’t understand clearly why… If you have any advice on what I could do better in this code, tell me!

Also, what is Vulkan exactly? :slight_smile:
Oh and I should may be start using LWJGL3, last time I checked it, it did not include any math utils classes for matrices and vectors, I was pissed and thought I should check it later when it would be less brutal!

You should use JOML with LWJGL3 for matrices and vectors. Its unlikely that LWJGL3 will add math util classes of its own.

You are using deprecated OpenGL, Egraynn, you should upgrade your code, but if this is quite big, it is better for you to start from a simple program and build up

Ok, so, what is deprecated exactly, is it GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); ?

Is it the usage of gl_Vertex, gl_Normal and gl_Color in vertex shader ?

What upgrade should I do ? I am just learning for the moment, I don’t have a very big code to handle, so I really want to upgrade! If you have a link with code example that just does what I try to do (buffering meshes with skeleton animation support) or simply know what should replace the deprecated code, please tell me :slight_smile:

LWJGL Util features matices and vector structures.

LWJGL Util is deprecated and is not available since LWJGL3. Instead we highly recommend you to switch to JOML, which also gives you great performance.

I puked a little looking at their matrix4f class set up on github. I am now going to, since I only use Matrix4f and Vector4f from LWJGL Util, create my own classes.

maybe once you have your improved math methods written you can submit a pull request to joml

Structure of code.

Exactly

You see, programmable pipeline it means you decide what the data will represent. OpenGL doesn’t need to know if a vec3 is a color, a position or a normal. Because this will be determined by you and how you will use them. For OpenGL what matters is only declaring the format, the binding, offset, strides, locations and so on, nothing else.

That’s the spirit, you are on the right way Egraynn :smiley:

I wrote a little Hello Triangle. It uses jogl, but don’t worry, jogl and lwjgl are at 95% 1 to 1 replaceable.

You can grab this lwjgl Hello Triangle and add my init() and reshape() ad the begin of the loop() before the while cycle. And my render() inside the while cycle.

You can copy most of the code. I am gonna expand it with a wiki step by step. Anyway for the moment just copy and skip for example the initDebug(). You can add debug like Spasi says here, but it’s not mandatory to get it running.

Few tips, use a Semantic class like this one and reference buffers and whatever with something like this. It highly decreases the error possibility and increases your code readability.

If you have any dubt, don’t hesitate to ask :wink:

Thanks you for the code !

I just checked the supported version of openGL on this computer (I work on several computers of very different capacities and ages, this one is among the oldest!) with

System.out.println("OpenGL version: " + GL11.glGetString(GL11.GL_VERSION));

the result:
3.2.9606 Compatibility Profile Context

Also, I ran the HelloWorld example in your second link with LWJGL 3.0.0b build 64, it does not seem to deal with triangles but displays a red-filled window :slight_smile:
In your Hello Triangle source I see you use a GL4 object, I suppose it would correspond to the GL40 class in lwjgl. So on the computer I currently use I guess it will not work!

I am still trying to understand what is happening in my previous code…
One thing is clear now; when I use ONLY attributes, GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, size); renders absolutely nothing, and when I use at least one predefined shader entry like gl_Vertex, with the GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); everything is rendered, custom attributes included.

Any idea why?

Do this:


GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexID);
GL20.glVertexAttribPointer(VERTEX, 3, GL11.GL_FLOAT, false, VSIZE, VOF);
GL20.glEnableVertexAttribArray(VERTEX); // <--- this is important!

and use that “Vertex” attribute in your vertex shader, instead of gl_Vertex.
DO NOT USE any invocations of GL11.glEnableClientState() ANYWHERE in your code. :slight_smile:
Use generic vertex attributes for everything.

I did it, I used GL20.glEnableVertexAttribArray(VERTEX); but it was before the binding of the VBO. So I tried to put the lines in the same order you suggested, but still nothing renders at all…