Hot questions for Using Lightweight Java Game Library in vbo

Question:

Here is my code:

import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;

import java.io.File;
import java.nio.*;
import java.util.Scanner;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL31.*;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.opengl.GL33.*;
import static org.lwjgl.opengl.GL40.*;
import static org.lwjgl.opengl.GL41.*;
import static org.lwjgl.opengl.GL42.*;
import static org.lwjgl.opengl.GL43.*;
import static org.lwjgl.opengl.GL44.*;
import static org.lwjgl.opengl.GL45.*;
import static org.lwjgl.opengl.GL46.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;

public class Test {

  public static void main(String[] args) {

    if (!glfwInit()) {
      System.out.println("GLFW not init.");
      return;
    }

    glfwDefaultWindowHints();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    long window = glfwCreateWindow(500, 500, "Window", NULL, NULL);
    if (window == NULL) {
      System.out.println("Window not create.");
      return;
    }

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);
    glfwShowWindow(window);

    GL.createCapabilities();

    Utilities.printGLInfo();

    int vert=glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vert, Utilities.loadStrFromFile("Shaders/shader.vert"));
    glCompileShader(vert);
    if(glGetShaderi(vert, GL_COMPILE_STATUS)==GL_FALSE) {
      System.out.println("Vertex shader compilation error:\n"+glGetShaderInfoLog(vert));
    }
    int frag=glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frag, Utilities.loadStrFromFile("Shaders/shader.frag"));
    glCompileShader(frag);
    if(glGetShaderi(frag, GL_COMPILE_STATUS)==GL_FALSE) {
      System.out.println("Fragment shader compilation error:\n"+glGetShaderInfoLog(frag));
    }

    int prog=glCreateProgram();
    glAttachShader(prog, vert);
    glAttachShader(prog, frag);
    glLinkProgram(prog);

    float[]vboData=new float[] {
        0,0,0,
        1,0,0,
        0,1,0
    };

    int vao=glGenVertexArrays();
    int vbo=glGenBuffers();


    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER,vbo);
    glBufferData(GL_ARRAY_BUFFER, FloatBuffer.wrap(vboData), GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 3*Float.BYTES, 0);

    glBindVertexArray(0);


    System.out.println("prog="+prog+",vert="+vert+",frag="+frag);
    System.out.println("vao="+vao+",vbo="+vbo);

    while (!glfwWindowShouldClose(window)) {
      glClearColor(1, 1, 1, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      glUseProgram(prog);

      glBindVertexArray(vao);
//      glDrawElements(GL_TRIANGLES, indices);
      glDrawArrays(GL_TRIANGLES, 0, 3);
      glBindVertexArray(0);

      glUseProgram(0);

      glfwSwapBuffers(window);
      glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();

  }

}

And here is what it prints:

Version       : 4.1 ATI-1.66.31
Vendor        : ATI Technologies Inc.
Renderer      : AMD Radeon Pro 560 OpenGL Engine
GLSL version  : 4.10
Major version : 4
Minor version : 1
prog=3,vert=1,frag=2
vao=1,vbo=1

So it is generated the shaders and vao/vbos correctly.

Vertex shader:

#version 410 core

layout (location = 0) in vec3 inPos;

out vec4 outPos;

void main(){
    outPos=vec4(inPos,1.0);
}

Fragment shader:

#version 410 core

out vec4 fragColor;

void main(){
    fragColor=vec4(0.0,0.0,0.0,1.0);
}

I am on macOS High Sierra Version 10.13.4.

Graphics:

Radeon Pro 560 4096 MB
Intel HD Graphics 630 1536 MB

It displays a white window with correct width, height and title. I think that the problem is with my glVertexAttribPointer call, and I have heard something called "buffer flipping" that may be nesecarry.

EDIT:

In response to some of the comments, with this vertex shader:

#version 410 core

layout (location = 0) in vec3 inPos;

void main(){
    gl_Position=vec4(inPos,1.0);
}

Nothing changes.


Answer:

You have to write to gl_Position in the vertex shader. The homogeneous coordinate which is written to gl_Position is used for primitive assembly. You can't specify your own "output" variable, as you can do it in the fragment shader. The output variables in the Vertex Shader are varying variables, which are passed to the next section of the pipeline.

#version 410 core

layout (location = 0) in vec3 inPos;

void main()
{
    gl_Position = vec4(inPos, 1.0);
}

See GLSL - The OpenGL Shading Language 4.6; 7.1.1. Vertex Shader Special Variables; page 131

The variable gl_Position is intended for writing the homogeneous vertex position. It can be written at any time during shader execution. This value will be used by primitive assembly, clipping, culling, and other fixed functionality operations, if present, that operate on primitives after vertex processing has occurred. Its value is undefined after the vertex processing stage if the vertex shader executable does not write gl_Position.


Further you have to flip() the buffer after the data were transferred to the buffer. See alos:

  • Java: FloatBuffer to OpenGL - wrap() vs. allocate() vs. BufferUtils.createBuffer()
  • Converting C++ OpenGl to Java(LWJGL), glBufferData()
  • LWJGL3: Overloaded glBufferData methods

float[]vboData=new float[] { 0,0,0,  1,0,0,  0,1,0 };

FloatBuffer buf = BufferUtils.createFloatBuffer(vboData.length);
buf.put(vboData).flip();

glBufferData(GL_ARRAY_BUFFER, buf, GL_STATIC_DRAW);

Explanation:

put(vboData) transfers the the data to the buffer, beginning at the current position (which is the start of the buffer in this case). The buffer position is incremented by the size of the data. So the new buffer position is at the end of the new data.

flip() sets the limit (length) of the buffer to the current position and then the position is set to zero.

When you pass the buffer data to glBufferData, the a pointer to the data at the current position of the buffer is retrieved.

Question:

I am trying to render two triangles on the screen at once, using two different VBOs so that I can add textures later (to my understanding, if you want to add different textures, you must make two VBOs?). I have tried using a combination of VAOs (both examples) and VAOs and IBOs (1st example).

Edit: As Stackoverflow doesn't recognise the tag, I'd like to clarify that IBO stands for Index Buffer Object

In both cases, I get a blank red screen.

I have previously managed to draw four triangles onto the screen using only one VBO and one IBO, but no VAO, putting all of the vertices into the one VBO, however I feel I need to learn how to draw multiple VBOs, as having everything in one VBO will become cumbersome and inefficient as greater numbers of objects are added.

I have already consulted other related questions as well as several tutorials, but have failed to find the information I am looking for in them (the tutorials tending to only describe drawing one item)

https://learnopengl.com/Getting-started/OpenGL

https://www.lwjgl.org/guide

OpenGL - VAO, VBO, IBO, glDrawElements not displaying

What is the role of glBindVertexArrays vs glBindBuffer and what is their relationship?

Textured triangles with OpenGL using VBO/IBO

Here is my source code:

Render loop

private void setupLoop() {
        GL.createCapabilities();
        debugProc = GLUtil.setupDebugMessageCallback();

        // Set the clear color
        glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

        while (!glfwWindowShouldClose(window)) {
            Engine.makeAndDrawBuffersForTwoTriangles();

            renderLoop();
        }
    }

    private void renderLoop() {
        // Run the rendering loop until the user has attempted to close
        // the window or has pressed the ESCAPE key.
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        float aspect = (float) width / height;
        glLoadIdentity();
        glOrtho(-aspect, aspect, -1, 1, -1, 1);

        glfwSwapBuffers(window); // swap the color buffers

        // Poll for window events.
        glfwPollEvents();
    }

Defining my vertices and declaring my ids

static int vbo_left;
static int vao_left;
static int ibo_left;
static float left_vertices[] = { -0.5f, 0f, -0.25f, 0.5f, 0f, 0f };
static int left_indices[] = { 0, 1, 2, 3, 4, 5 };

static int vbo_right;
static int vao_right;
static int ibo_right;
static float right_vertices[] = { 0f, 0f, 0.25f, -0.5f, 0.5f, 0f };
static int right_indices[] = { 0, 1, 2, 3, 4, 5 };

1st Engine class

public static void makeAndDrawBuffersForTwoTriangles() {
    // VBO
    vbo_left = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
    glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);
    // IBO
    ibo_left = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_left);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
            (IntBuffer) BufferUtils.createIntBuffer(left_indices.length).put(left_indices).flip(), GL_STATIC_DRAW);
    glVertexPointer(2, GL_FLOAT, 0, 0L);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    // VAO
    vao_left = glGenVertexArrays();
    glBindVertexArray(vao_left);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
    glBindVertexArray(0);

    // VBO
    vbo_right = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo_right);
    glBufferData(GL_ARRAY_BUFFER, right_vertices, GL_STATIC_DRAW);
    // IBO
    ibo_right = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_right);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
            (IntBuffer) BufferUtils.createIntBuffer(right_indices.length).put(right_indices).flip(),
            GL_STATIC_DRAW);
    glVertexPointer(2, GL_FLOAT, 0, 0L);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    // VAO
    vao_right = glGenVertexArrays();
    glBindVertexArray(vao_right);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_right);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
    glBindVertexArray(0);

    // Unbind all
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // Draw elements
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_left);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
    glDrawElements(GL_TRIANGLES, left_indices.length, GL_UNSIGNED_INT, 0L);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_right);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_right);
    glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
    glDrawElements(GL_TRIANGLES, right_indices.length, GL_UNSIGNED_INT, 0L);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    /*
    // Draw Arrays
    glBindVertexArray(vao_left);
    glDrawArrays(GL_TRIANGLES, 0, left_indices.length);
    glBindVertexArray(vao_right);
    glDrawArrays(GL_TRIANGLES, 0, right_indices.length);
    glBindVertexArray(0);
    */

2nd Engine class

    public static void makeAndDrawBuffersForTwoTriangles() {
        vbo_left = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
        glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);

        vao_left = glGenVertexArrays();
        glBindVertexArray(vao_left);
        glBindBuffer(GL_ARRAY_BUFFER, vao_left);
        glVertexAttribPointer(vao_left, 2, GL_FLOAT, false, 2, 0);
        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        vbo_left = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
        glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);

        vao_left = glGenVertexArrays();
        glBindVertexArray(vao_left);
        glBindBuffer(GL_ARRAY_BUFFER, vao_left);
        glVertexAttribPointer(vao_left, 2, GL_FLOAT, false, 2, 0);
        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(vao_left);
        glDrawArrays(GL_TRIANGLES, 0, left_vertices.length);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(vao_right);
        glDrawArrays(GL_TRIANGLES, 0, right_vertices.length);

    }

Answer:

The Index buffers binding is stated in the Vertex Array Object. Invoking glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); breaks the binding of the index buffer to the VAO. You have to delete glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);. Furthermore, the vertex specification is stored in the VAO, so the VAO has to be bound, before the array of generic vertex attribute data is specified and the index buffer is bound:

// VBO
vbo_left = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

// IBO
ibo_left = glGenBuffers();

// VAO
vao_left = glGenVertexArrays();
glBindVertexArray(vao_left);

// IBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_left);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
    (IntBuffer) BufferUtils.createIntBuffer(left_indices.length).put(left_indices).flip(), GL_STATIC_DRAW);

// vertex specification
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);

Note, in compare to the index buffer, the array buffer binding is a global state. Each attribute which is stated in the VAOs state vector may refer to a different ARRAY_BUFFER. This reference is stored when glVertexAttribPointer (respectively glVertexPointer) is called. Then the buffer which is currently bound to the target ARRAY_BUFFER is associated to the attribute and the name (value) of the object is stored in the state vector of the VAO. But the index buffer is a state of the VAO. When a buffer is bound to the target ELEMENT_ARRAY_BUFFER, then this buffer is associated to the vertex array object which is currently bound.

Question:

I am making a 3D game that has a player with the follow cam. Before I started using real models I used the cube and I rendered it using displaylist and it everything moved fine. However, now that I am importing full 3D models with many more vertices, I looked into VBOs. I have a full structure setup for my VBOs and I can see the model drawn initially but it is drawn at the center of the game world. When I move the player, the model doesn't translate as it should. The model doesn't move its position.

Here is the code that I used initially to draw the player as a rectangle (which works):

public static void drawRectPrism(float centerx, float centery, float centerz, float length, float height, float width, float rx, float ry, float rz)
{
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    {
        glTranslatef(centerx, centery, centerz);
        glRotatef(rx, 1, 0, 0);
        glRotatef(ry, 0, 1, 0);
        glRotatef(rz, 0, 0, 1);
        glTranslatef(-centerx, -centery, -centerz);
        glTranslatef(-length/2f, -height/2f, -width/2f);


        glBegin(GL_QUADS);
        {
            glColor3f(1.0f, 0, 0);
            glVertex3f(centerx, centery, centerz);
            glVertex3f(centerx + length, centery, centerz);
            glVertex3f(centerx + length, centery + height, centerz);
            glVertex3f(centerx, centery + height, centerz);

            glColor3f(0, 1.0f, 0);
            glVertex3f(centerx, centery, centerz + width);
            glVertex3f(centerx + length, centery, centerz + width);
            glVertex3f(centerx + length, centery + height, centerz + width);
            glVertex3f(centerx, centery + height, centerz + width);

            glColor3f(0, 0, 1.0f);
            glVertex3f(centerx, centery, centerz);
            glVertex3f(centerx, centery + height, centerz);
            glVertex3f(centerx, centery + height, centerz + width);
            glVertex3f(centerx, centery, centerz + width);          

            glColor3f(0, 1.0f, 1.0f);
            glVertex3f(centerx + length, centery, centerz);
            glVertex3f(centerx + length, centery + height, centerz);
            glVertex3f(centerx + length, centery + height, centerz + width);
            glVertex3f(centerx + length, centery, centerz + width); 

            glColor3f(1.0f, 1.0f, 0);
            glVertex3f(centerx, centery, centerz);
            glVertex3f(centerx + length, centery, centerz);
            glVertex3f(centerx + length, centery, centerz + width);
            glVertex3f(centerx, centery, centerz + width);

            glColor3f(1.0f, 0, 1.0f);
            glVertex3f(centerx, centery + height, centerz);
            glVertex3f(centerx + length, centery + height, centerz);
            glVertex3f(centerx + length, centery + height, centerz + width);
            glVertex3f(centerx, centery + height, centerz + width);         
        }
        glEnd();
    }
    glPopMatrix();
}   

I tried a couple of different ways somewhere better than others and probably implemented terrible programming structure, but I figured it should still work.

First attempt: to adapt the rectangle code to load my vertices and models instead of specific rectangle verticies:

public void translate(float x, float y, float z, float rx, float ry, float rz)
{

        File f = new File("graveDigga.obj");
        try{
            m = OBJLoader.loadModel(f);
        }
        catch(FileNotFoundException e)
        {
            e.printStackTrace();
            Display.destroy();
            System.exit(1);
        }
        catch(IOException e)
        {
            e.printStackTrace();
            Display.destroy();
            System.exit(1);
        }
        displayListChar = glGenLists(1);
        glNewList(displayListChar, GL_COMPILE);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        {
            glTranslatef(x, y, z);
            glRotatef(rx, 1, 0, 0);
            glRotatef(ry, 0, 1, 0);
            glRotatef(rz, 0, 0, 1);
            //glTranslatef(-x, -y, -z);
            //glTranslatef(-length/2f, -height/2f, -width/2f);
            glBegin(GL_TRIANGLES);
            for(Face face : m.faces)
            {
                Vector2f t1 = m.textures.get((int) face.textures.x - 1);
                glTexCoord2f(t1.x +x ,1-(t1.y +y ));
                Vector3f n1 = m.normals.get((int) face.normal.x-1);
                glNormal3f(n1.x +x ,n1.y+y,n1.z +z);
                Vector3f v1 = m.vertices.get((int) face.vertex.x-1);
                glVertex3f(v1.x +x,v1.y+y,v1.z+z);
                Vector2f t2 = m.textures.get((int) face.textures.y - 1);
                glTexCoord2f(t2.x +x, 1 - (t2.y+y ));
                Vector3f n2 = m.normals.get((int) face.normal.y-1);
                glNormal3f(n2.x+x,n2.y+y ,n2.z+z);
                Vector3f v2 = m.vertices.get((int) face.vertex.y-1);
                glVertex3f(v2.x+x,v2.y+y ,v2.z+z);
                Vector2f t3 = m.textures.get((int) face.textures.z - 1);
                glTexCoord2f(t3.x +x, 1 - (t3.y +y));
                Vector3f n3 = m.normals.get((int) face.normal.z-1);
                glNormal3f(n3.x+x,n3.y+y,n3.z +z);
                Vector3f v3 = m.vertices.get((int) face.vertex.z-1);
                glVertex3f(v3.x+x,v3.y+y,v3.z +z);

            }
            glEnd();
        }
        glPopMatrix();

    //}
    //glPopMatrix();
    build();
}

I next tried to display model by creating a VBO from this data and call a rander method in my game loop. Before calling render I would run through the code to attempt to translate the position of VBO but nothing was happening.

glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            {
                //glLoadIdentity();
                glTranslatef(x,y,z);
                glRotatef(rx, 1, 0, 0);
                glRotatef(ry, 0, 1, 0);
                glRotatef(rz, 0, 0, 1);
                glTranslatef(-x,-y,-z);
                glDrawArrays(GL_TRIANGLES, 0, m.faces.size() * 3);

}

I am not sure if I should be using shaders for this or not, but part of me is questioning why it is hard to move a 3D model in world space? Is there a messy way that is easier to implement for a temporary basis?


Answer:

Considering you're a new person with 1 rep, have an upvote. Nicely written question :).

I am not sure if I should be using shaders for this or not, but part of me is questioning why it is hard to move a 3D model in world space? Is there a messy way that is easier to implement for a temporary basis?

A simple glTranslatef() call should suffice to move an object, and simple glRotatef() call will rotate the object.

For example, using glRotatef(90, 1, 0, 0) returns this result: Wheras without the line, the grass is not rotated at all:

Same with the ship. Using glRotatef(40, -1, 0, 0) returns this result: Wheras without the line it just returns flat:

Obviously that is just the pitch. glRotatef(AmountToRotate, PITCH, YAW, ROLL) can roll the ship onto its side, or rotate the ship around.

Enough about rotation.

For rendering the grass, I just use this:

public void render(){
    Main.TerrainDemo.shader.start();
    glPushMatrix();
    glDisable(GL_LIGHTING);
    glTranslatef(location.x * TerrainDemo.scale, location.y, location.z * TerrainDemo.scale);
    TexturedModel texturedModel = TerrainDemo.texModel;
    RawModel model = texturedModel.getRawModel();
    GL30.glBindVertexArray(model.getVaoID());
    GL20.glEnableVertexAttribArray(0);
    GL20.glEnableVertexAttribArray(1);
    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getID());
    glScalef(10f, 10f, 10f);
    glColor4f(0, 0, 0, 0.5f);
    glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
    GL20.glDisableVertexAttribArray(0);
    GL20.glDisableVertexAttribArray(1);
    GL30.glBindVertexArray(0);
    glEnable(GL_LIGHTING);
    glPopMatrix();
    Main.TerrainDemo.shader.stop();
}

To cut through code which you will probably not recognize/understand, I am basically just saying that glTranslatef(location.x * TerrainDemo.scale, location.y, location.z * TerrainDemo.scale) is the only thing that is setting the location. After translating, I simple set the scale (the size), and then draw it.

Wheras if I remove the glTranslatef() line, all the grass will just render in the same location:

So to answer your question: use something like this (Psuedocode)

PUSH MATRIX HERE (glPushMatrix) SO TO NOT SAVE THE CURRENT TRANSLATION
USE GLTRANSLATEF ON LOCATION OF CURRENT OBJECT
RENDER/DRAW OBJECT
POP THE MATRIX

Unfortunately, looking through your code I could'nt find the specific issue that is actually causing it not to draw, meaning I cannot just say "Have xxx code and it will work", but I hope that it helped on how to move/rotate an object.

I am using VBOs just like you are for rendering the grass, ship, and trees (though I use a display list for terrain because I am lazy). My skype is joehot200 if you wish to discuss anything further.

Question:

Ive been playing around with open GL for a while now and i got to the point that i can draw 3d shapes, My shapes and vertices and indices are definitely right and my shape was getting messed up. I am now wanting to redo my drawing. I used to only use VBO with no VAO and just bind and draw them. This worked but im suspicious of this being my bug. So i started using VAO's and i dont see anything that is wrong with my code and i still cant get it to draw my white square(no shaders just like the wiki tutorials).

My code for initializing the window is here:

private void initWindow() {
    //Makes sure window can work
    if (!glfwInit()) {
        throw new IllegalStateException("Failed to Initialize GLFW!");
    }

    //Create window object and set its hints
    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);

    this.windowRef = glfwCreateWindow(width, height, name, NULL, NULL);

    if (windowRef == 0) {
        throw new IllegalStateException("Failed to create Window!");
    }

    GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    glfwSetWindowPos(windowRef, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);

    // Make the OpenGL context current
    glfwMakeContextCurrent(windowRef);
    // Enable v-sync
    glfwSwapInterval(1);

    //Make GL capabilites for window
    GL.createCapabilities();
    glfwShowWindow(windowRef);
}

my code for initializing my buffers and objects is here

public void loadGL() {
    float[] vertex = {
        0f, 0f, 0f, //0
        0.5f, 0, 0, //1
        0.5f, 0, 0.5f, //2
        0f, 0f, 0.5f, //3
        0f, 0.5f, 0f, //4
        0.5f, 0.5f, 0, //5
        0.5f, 0.5f, 0.5f,//6
        0f, 0.5f, 0.5f//7
    };

    int[] index = {
        0, 1, 2, //0
        0, 2, 3, //1
        0, 3, 4, //2
        3, 7, 4,//3
        0, 4, 1,//4
        1, 5, 4,//5
        1, 5, 2,//6
        2, 6, 5,//7
        2, 3, 6,//8
        3, 7, 6,//9
        4, 5, 7,//10
        5, 6, 7//11
    };
    size = 12*3;

    indicesBuff = BufferUtils.createIntBuffer(index.length);
    vertBuff = BufferUtils.createFloatBuffer(vertex.length);
    indicesBuff.put(index);
    vertBuff.put(vertex);
    indicesBuff.flip();
    vertBuff.flip();

    vao = glGenVertexArrays();
    glBindVertexArray(vao);

    vboID = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, vertBuff, GL_STATIC_DRAW);
    GL20.glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    ibo = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuff, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

}

and finally my main loop is here, it is called after the window init:

    private void mainLoop() {
    loadGL();
    glClearColor(0.5f, 0.5f, 0.5f, 1);
    while (!glfwWindowShouldClose(windowRef)) {

        //Render Stuff here
        //TODO: later skip this block if nothing has changed
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear 
the framebuffer

        glBindVertexArray(vao);
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

        glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

//            glBegin(GL_QUADS);
//            glVertex3f(-0.5f, -0.5f, 0);
//            glVertex3f(-0.5f, 0.5f, 0);
//            glVertex3f(0.5f, -0.5f, 0);
//            glVertex3f(0.5f, 0.5f, 0);
//            glEnd();

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glDisableVertexAttribArray(0);
        glBindVertexArray(0);

        glfwSwapBuffers(windowRef);
        glfwPollEvents();
    }
}

btw drawing it with glBegin and so works but its not efficient for what i want to do.


Answer:

The modern way of rendering in OpenGL, would be to use a Shader program.

If you don't use a shader program, than you have to define the array of vertex data using the deprected way by glVertexPointer and you have to enable the client-side capability for vertex coordinates by glEnableClientState( GL_VERTEX_ARRAY ):

vao = glGenVertexArrays();
glBindVertexArray(vao);

vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vertBuff, GL_STATIC_DRAW);
GL20.glVertexPointer(3, GL_FLOAT, 0, 0);  // <--------------
glBindBuffer(GL_ARRAY_BUFFER, 0);

 glBindVertexArray(vao);
 glEnableClientState( GL_VERTEX_ARRAY );   // <--------------
 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

 glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 glDisableClientState( GL_VERTEX_ARRAY ); // <---------------
 glBindVertexArray(0);

Further note, that the state of the client-side capability (or vertex attribute array) and the reference to the index (element) buffer is stored in the Vertex Array Objects state vector. So it is sufficient to enable the vertex coordinates, when the vertex array object is specified and to bid the index buffer when the vertex array object is bound. The enabling and disabling of the vertex coordinates and binding of the index buffer, when drawing the geometry, can be omitted:

vao = glGenVertexArrays();
glBindVertexArray(vao);

vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vertBuff, GL_STATIC_DRAW);
GL20.glVertexPointer(3, GL_FLOAT, 0, 0);    // <--------------
glEnableClientState( GL_VERTEX_ARRAY );     // <--------------
glBindBuffer(GL_ARRAY_BUFFER, 0);

ibo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuff, GL_STATIC_DRAW);
// skip glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);

glBindVertexArray(vao);

glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

glBindVertexArray(0);

Question:

I am writing a modern openGL model loader, and am running into some issues using shader attribute locations other than 0. I can get the position attribute into the shader, but not the values needed for Blinn-Phong shading (bound in the program to locations: Ks-3, Ka-4, Kd-5). Here is the code I am using to load and render the OBJ models:

public class Model{
private List<Vector3f> vertices=new ArrayList<>();
private List<Vector3f> normals=new ArrayList<>();

private ArrayList<Integer> vaos=new ArrayList<>();
private float[] faces=new float[fvaoSize];
private float[] ks=new float[kvaoSize];
private float[] ka=new float[kvaoSize];
private float[] kd=new float[kvaoSize];
private int currentPlace=0,kcurrentPlace=0;
private static final int fvaoSize=glGetInteger(GL12.GL_MAX_ELEMENTS_VERTICES)-(glGetInteger(GL12.GL_MAX_ELEMENTS_VERTICES)%12);
private static final int kvaoSize=(fvaoSize/4)*3;
private int facesd=0;
private HashMap<String,Material> materials=new HashMap<>();

@SuppressWarnings("unused")
private int plainFaceVAO=0,texFaceVAO=0,normalsFaceVAO=0,normalsTexVAO=0;
@SuppressWarnings("unused")
private int faceOffset=0,
        texOffset=0,texTexture=0,texCoords=0,
        normalOffset=0,normalCoords=0,
        normalTexOffset=0,normalTexNormalCoords,normalTexTexCoords,normalTexTexture=0;
@SuppressWarnings("unused")
private Shader faceShader=null,texShader=null,normalsShader=null,normalTexShader=null;
private Material currMtl=null;

public Model(File f,Shader faceShader,Shader texShader,Shader normalsShader,Shader normalTexShader){
    loadModelData(f);
    this.faceShader=faceShader;
    this.texShader=texShader;
    this.normalsShader=normalsShader;
    this.normalTexShader=normalTexShader;
    faceOffset=glGetUniformLocation(faceShader.getID(),"trans");
    texOffset=glGetUniformLocation(texShader.getID(),"trans");
    texTexture=glGetAttribLocation(texShader.getID(),"tex");
    texCoords=glGetAttribLocation(texShader.getID(),"texCoords");
    normalOffset=glGetUniformLocation(normalsShader.getID(),"trans");
    normalCoords=glGetAttribLocation(normalsShader.getID(),"normalsCoords");
}
@SuppressWarnings("null")
private void loadModelData(File f){
    try(BufferedReader br=new BufferedReader(new FileReader(f))){
        String line="";
        while((line=br.readLine())!=null){
            String[] words=line.split(" ");
            //System.out.println(line);
            if(line.startsWith("#"))
                continue;
            switch(words[0]){
                case OBJ_VERTEX:
                    vertices.add(new Vector3f(parseFloat(words[1]),parseFloat(words[2]),-parseFloat(words[3])));
                    break;
                case OBJ_VERTEX_NORMAL:
                    normals.add(new Vector3f(parseFloat(words[1]),parseFloat(words[2]),-parseFloat(words[3])));
                    break;
                case OBJ_FACE:
                    facesd++;
                    FaceType cft=null;
                    int slashCount=0;
                    for(char c:words[1].toCharArray()){
                        if(c=='/')
                            slashCount++;
                    }

                    if(slashCount==0){
                        cft=FaceType.COORDSONLY;
                    }else if(slashCount==1){
                        cft=FaceType.TEXTURE;
                    }else if(slashCount==2){
                        if(words[0].contains("//")){
                            cft=FaceType.NORMALS;
                        }else{
                            cft=FaceType.NORMALS_AND_TEXTURE;
                        }
                    }
                    switch(cft){
                        case COORDSONLY:
                            Vector3f pos1=vertices.get(Integer.parseInt(words[1])-1);
                            Vector3f pos2=vertices.get(Integer.parseInt(words[2])-1);
                            Vector3f pos3=vertices.get(Integer.parseInt(words[3])-1);
                            Vec3 Ks=(currMtl.getKs()!=null?currMtl.getKs():new Vec3(1));
                            Vec3 Ka=(currMtl.getKa()!=null?currMtl.getKa():new Vec3(1));
                            Vec3 Kd=(currMtl.getKd()!=null?currMtl.getKd():new Vec3(1));
                            float[] temp=new float[]
                                {
                                    pos1.x,pos1.y,pos1.z,1.0f,
                                    pos2.x,pos2.y,pos2.z,1.0f,
                                    pos3.x,pos3.y,pos3.z,1.0f
                                };
                            for(int i=0;i<12;i++){
                                faces[currentPlace+i]=temp[i];
                            }
                            float[] ktemp=new float[]
                                {
                                    Ks.x,Ks.y,Ks.z,
                                    Ks.x,Ks.y,Ks.z,
                                    Ks.x,Ks.y,Ks.z
                                };
                            for(int i=0;i<9;i++){
                                ks[kcurrentPlace+i]=ktemp[i];
                            }
                            ktemp=new float[]
                                {
                                    Ka.x,Ka.y,Ka.z,
                                    Ka.x,Ka.y,Ka.z,
                                    Ka.x,Ka.y,Ka.z
                                };
                            for(int i=0;i<9;i++){
                                ka[kcurrentPlace+i]=ktemp[i];
                            }
                            ktemp=new float[]
                                {
                                    Kd.x,Kd.y,Kd.z,
                                    Kd.x,Kd.y,Kd.z,
                                    Kd.x,Kd.y,Kd.z
                                };
                            for(int i=0;i<9;i++){
                                kd[kcurrentPlace+i]=ktemp[i];
                            }
                            kcurrentPlace+=9;
                            currentPlace+=12;
                            if(currentPlace==fvaoSize){


                                int fvbo=glGenBuffers();
                                FloatBuffer vertexPositionsBuffer=BufferUtils.createFloatBuffer(fvaoSize);
                                vertexPositionsBuffer.put(faces);
                                vertexPositionsBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, fvbo);
                                glBufferData(GL_ARRAY_BUFFER, vertexPositionsBuffer, GL_STATIC_DRAW);

                                int ksvbo=glGenBuffers();
                                FloatBuffer ksBuffer=BufferUtils.createFloatBuffer(kvaoSize);
                                ksBuffer.put(ks);
                                ksBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
                                glBufferData(GL_ARRAY_BUFFER, ksBuffer, GL_STATIC_DRAW);

                                int kavbo=glGenBuffers();
                                FloatBuffer kaBuffer=BufferUtils.createFloatBuffer(kvaoSize);
                                kaBuffer.put(ka);
                                kaBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, kavbo);
                                glBufferData(GL_ARRAY_BUFFER, kaBuffer, GL_STATIC_DRAW);

                                int kdvbo=glGenBuffers();
                                FloatBuffer kdBuffer=BufferUtils.createFloatBuffer(kvaoSize);
                                kdBuffer.put(kd);
                                kdBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
                                glBufferData(GL_ARRAY_BUFFER, kdBuffer, GL_STATIC_DRAW);

                                int vao = glGenVertexArrays();
                                glBindVertexArray(vao);

                                glBindBuffer(GL_ARRAY_BUFFER, fvbo);
                                glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);

                                glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
                                glVertexAttribPointer(3, 3, GL_FLOAT, false, 0, 0);

                                glBindBuffer(GL_ARRAY_BUFFER, kavbo);
                                glVertexAttribPointer(4, 3, GL_FLOAT, false, 0, 0);

                                glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
                                glVertexAttribPointer(5, 3, GL_FLOAT, false, 0, 0);

                                glEnableVertexAttribArray(0);
                                glEnableVertexAttribArray(3);
                                glEnableVertexAttribArray(4);
                                glEnableVertexAttribArray(5);

                                glBindVertexArray(0);

                                glDeleteBuffers(fvbo);
                                glDeleteBuffers(ksvbo);
                                glDeleteBuffers(kavbo);
                                glDeleteBuffers(kdvbo);
                                ksBuffer=null;
                                kaBuffer=null;
                                kdBuffer=null;
                                vertexPositionsBuffer=null;
                                vaos.add(vao);

                                glBindBuffer(GL_ARRAY_BUFFER, 0);
                                currentPlace=0;
                                kcurrentPlace=0;
                                faces=new float[fvaoSize];
                                ks=new float[kvaoSize];
                                ka=new float[kvaoSize];
                                kd=new float[kvaoSize];
                            }
                            break;
                        case NORMALS:
                            throw new RuntimeException("File is unsupported.");
                        case NORMALS_AND_TEXTURE:
                            throw new RuntimeException("File is unsupported.");
                        case TEXTURE:
                            throw new RuntimeException("File is unsupported.");
                        default:
                            throw new RuntimeException("File is unsupported.");
                    }

                    break;
                case OBJ_MTLLIB:
                    materials=MTLLibLoader.loadMTLLib(f.toPath().getParent()+"/"+words[1]);
                    break;
                case OBJ_USEMTL:
                    System.out.println("Using Material "+words[1]+": Exists in hmap: "+materials.containsKey(words[1]));
                    currMtl=materials.get(words[1]);
                    break;
                default:
                    break;
            }
        }
        int fvbo=glGenBuffers();
        FloatBuffer vertexPositionsBuffer=BufferUtils.createFloatBuffer(fvaoSize);
        vertexPositionsBuffer.put(faces);
        vertexPositionsBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, fvbo);
        glBufferData(GL_ARRAY_BUFFER, vertexPositionsBuffer, GL_STATIC_DRAW);

        int ksvbo=glGenBuffers();
        FloatBuffer ksBuffer=BufferUtils.createFloatBuffer(kvaoSize);
        ksBuffer.put(ks);
        ksBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
        glBufferData(GL_ARRAY_BUFFER, ksBuffer, GL_STATIC_DRAW);

        int kavbo=glGenBuffers();
        FloatBuffer kaBuffer=BufferUtils.createFloatBuffer(kvaoSize);
        kaBuffer.put(ka);
        kaBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, kavbo);
        glBufferData(GL_ARRAY_BUFFER, kaBuffer, GL_STATIC_DRAW);

        int kdvbo=glGenBuffers();
        FloatBuffer kdBuffer=BufferUtils.createFloatBuffer(kvaoSize);
        kdBuffer.put(kd);
        kdBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
        glBufferData(GL_ARRAY_BUFFER, kdBuffer, GL_STATIC_DRAW);

        int vao = glGenVertexArrays();
        glBindVertexArray(vao);

        glBindBuffer(GL_ARRAY_BUFFER, fvbo);
        glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
        glVertexAttribPointer(3, 3, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, kavbo);
        glVertexAttribPointer(4, 3, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
        glVertexAttribPointer(5, 3, GL_FLOAT, false, 0, 0);

        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(3);
        glEnableVertexAttribArray(4);
        glEnableVertexAttribArray(5);

        glBindVertexArray(0);

        glDeleteBuffers(fvbo);
        glDeleteBuffers(ksvbo);
        glDeleteBuffers(kavbo);
        glDeleteBuffers(kdvbo);
        ksBuffer=null;
        kaBuffer=null;
        kdBuffer=null;
        vertexPositionsBuffer=null;
        vaos.add(vao);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }catch(FileNotFoundException e){
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch(IOException e){
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("Object \""+f.getName().substring(0,f.getName().lastIndexOf("."))+"\" loaded, has "+facesd+" faces");
}
public void drawModel(Camera c,Vec3 offset){
    //System.err.format("rendering model, %d vaos\n",vaos.size());
    //Matrix4f modelMat=RenderMatrixHelper.getModelMatrix(offset,new Vec3(0));

    faceShader.useShader();
    c.useCameraView();
    glUniform4f(faceOffset,offset.x,offset.y,offset.z,0f);
    for(Integer i:vaos){
        glBindVertexArray(i);
        glDrawArrays(GL_TRIANGLES, 0, fvaoSize/4);
    }
    Shader.stopShader();
    glBindVertexArray(0);
}
public int getNumFaces(){
    return facesd;
}
private enum FaceType{
    COORDSONLY,
    TEXTURE,
    NORMALS,
    NORMALS_AND_TEXTURE,
}

}

I think I have correctly bound the K-VBO's to the correct location, but the shader is rendering them as black. Here is the vertex shader code:

#version 330

in vec4 position;
in vec3 normals;
in vec2 texCoords;


uniform vec4 trans;

uniform mat4 view;
uniform mat4 projection;
uniform mat4 model;

void main()
{
    gl_Position = projection*view* (position+trans);//-camera_position;
}

The fragment shader outputs black if the Kd has a value of (0,0,0), white otherwise. In my code, I have checked and know that Kd is (.64,.64,.64) And the fragment shader:

#version 330
out vec4 outputColor;

in vec3 Ks;
in vec3 Ka;
in vec3 Kd;

uniform mat4 view;
uniform mat4 projection;

void main()
{   
    if(Kd==vec3(0f)){
        outputColor=vec4(0f);
    }else{
        outputColor=vec4(1f);
    }

}

I can't find the issue, but if anyone could it would be a great help. Thanks!


Answer:

I didn't look at your code in full detail, but there seems to be a basic misunderstanding about how vertex attributes work. In the vertex shader, you have these attributes, which look fine:

in vec4 position;
in vec3 normals;
in vec2 texCoords;

But then in the fragment shader, you have these definitions:

in vec3 Ks;
in vec3 Ka;
in vec3 Kd;

Based on the code, it looks like you're planning to use these as vertex attributes. This will not work. You can't feed vertex attributes directly into the fragment shader. They need to be in variables in the vertex shader. If you need the (interpolated) values in the fragment shader, you need to pass them from vertex shader to fragment shader using out variables in the vertex shader, and in variables in the fragment shader.

If you do error checking, I'm surprised that your shader program even links. in variables in the fragment shader (at least as long as they are used in the code) need to have matching out variables in the vertex shader, which you do not have e.g. for Kd.

Of course if your material properties are constant at least for a single object, you could also make them uniforms instead of attributes.

One other aspect to watch out for once you have the more basic problems addressed is the location of the attributes. You have values 3, 4 and 5 hardwired for the material attributes. You will need to use calls like glGetAttribLocation(), glSetAttribLocation(), or location qualifiers in the shader code, to ensure that the locations you use for calls like glVertexAttribPointer() match up with the attribute locations in the shader program.

Question:

I am trying to port a ClickTeam Fusion game to Java using LWJGL. I decided to simply use pixel measurements as everything in this game is done using PNG files, even animations (Yes, really). And I have heard of the function called glOrtho() which is supposed to let you set how things are drawn in OpenGL.

While I managed to get this working with functions like glVertexf(), those functions including glOrtho() are deprecated and if I am correct completely removed in OpenGL 3.1. So, I am using the modern way of doing it which is using VBO's, Indices, Shaders, etc. Is there any way to accomplish glOrtho()'s effect using a VBO?

If you need me to, I can upload the current code I have here as well; just leave a comment and I will update the post with the current code I have.


Answer:

For OpenGL >= 3.1 you need to define your own matrices. There are some libs that defined them for you. GLM, to name a famous one.

glOrtho matrix defintion can be found here: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml

glOrtho is not an "effect", but a way to project things onto the screen. Ortho refers to "orthogonal", which means "no perspective".

Question:

I want to store three float values and two byte-values in an interleaved OpenGL vbo. Unfortunately, the rendered data is obviously not correct. When I rendered the same data with two different VBOs, all worked fine, so I don't assume that there is a problem with my shaders.

/*
 * 20^3 blocks per chunk, 6 faces per block, 3 vertices per face
 * max. every second face can be visible
 */
private static final int MAX_FLOAT_AMOUNT = 20 * 20 * 20 * 6 * 3 / 2;

/*
 * 20^3 blocks per chunk, 6 faces per block, 2 bytes per face
 * max. every second face can be visible
 */
private static final int MAX_BYTE_AMOUNT = 20 * 20 * 20 * 6 * 2 / 2;

private int dataVboIndex;

protected int vaoId;
protected int indicesCount;

protected boolean isInitialized = false;


public static ByteBuffer dataFloatBuffer = BufferUtils.createByteBuffer(4 * MAX_FLOAT_AMOUNT + MAX_BYTE_AMOUNT);

DefaultChunkVao(int indiciesVboId) {
    init();
}

DefaultChunkVao(boolean initialize) {
    if(initialize) init();
}

private void init() {
    isInitialized = true;

    // bind vao
    vaoId = glGenVertexArrays();
    glBindVertexArray(vaoId);

    //create vbo
    dataVboIndex = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, dataVboIndex);

    dataFloatBuffer.clear();
    dataFloatBuffer.position(4 * MAX_FLOAT_AMOUNT + MAX_BYTE_AMOUNT);
    dataFloatBuffer.flip();

    // allocate memory
    glBufferData(GL_ARRAY_BUFFER, dataFloatBuffer, GL_STREAM_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4 + 2, 0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4);
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4 + 1);

    // unbind vao
    glBindVertexArray(0);
}

public void updateData(float[] data) {
    if(!isInitialized) init();

    dataFloatBuffer.clear();
    for(int counter = 0; counter < data.length; counter+=0) {
        dataFloatBuffer.putFloat(data[counter++]);
        dataFloatBuffer.putFloat(data[counter++]);
        dataFloatBuffer.putFloat(data[counter++]);

        dataFloatBuffer.put((byte) data[counter++]);
        dataFloatBuffer.put((byte) data[counter++]);
    }
    dataFloatBuffer.flip();

    glBindBuffer(GL_ARRAY_BUFFER, dataVboIndex);
    glBufferSubData(GL_ARRAY_BUFFER, 0, dataFloatBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    this.indicesCount = data.length / 5;
}

The MAX_FLOAT_AMOUNT and the MAX_BYTE_AMOUNT constants contains the amount of floats resp. bytes per VBO. Am I right in assuming that I have to multiply the amount of floats with 4 when I determine the capacity of the ByteBuffer since every float has 4 bytes?

And what did I make wrong that I the my byte values are always 0 in the shader?


EDIT: I was able to reproduce the issue with a simpler example. Here I want to store the position and two bytes in the VBO. In the fragment shader I check if the byte1 value is passed correctly. If so, the shader renders the shape green, else blue. Unfortunately, my shape is rendered blue, hence I assume that the byte1 value is not passed correctly.

vertexShader

#version 400 core

in vec3 position;
in int byte1;
in int byte2;

flat out int p_byte1;
flat out int p_byte2;

void main(void) {

    gl_Position = vec4(position, 1);

    p_byte1 = byte1;
    p_byte2 = byte2;
}

fragmentShader:

#version 400 core

flat in int p_byte1;
flat in int p_byte2;

out vec3 out_color;

void main(void) {
    if(p_byte1 == 45) {
        out_color = vec3(0, 1, 0);
    } else out_color = vec3(0, 0, 1);

}

creating the VAO:

vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
final int vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);

float[] data = {0, 0, 0, 20f, 20f, 1, 1, 1, 20f, 20f, 1, 0, 1, 20f, 20f, 0, 1, 1, 20f, 20f};
ByteBuffer dataBuffer = BufferUtils.createByteBuffer(4 * (3 * 4) + 1 * (2 * 4));
for(int counter = 0; counter < data.length; counter+=0) {
dataBuffer.putFloat(data[counter++]);
dataBuffer.putFloat(data[counter++]);
dataBuffer.putFloat(data[counter++]);

dataBuffer.put((byte) data[counter++]);
dataBuffer.put((byte) data[counter++]);
}
dataBuffer.flip();

glBufferData(GL_ARRAY_BUFFER, dataBuffer, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4 + 2, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4 + 1);

glBindVertexArray(0);

Answer:

I was able to find the solution to my question. It is necessary to use glVertexAttribIPointer instead of glVertexAttribPointer for integer data types.

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4 + 2, 0);
glEnableVertexAttribArray(1);
glVertexAttribIPointer(1, 1, GL_UNSIGNED_BYTE, 3 * 4 + 2, 3 * 4);
glEnableVertexAttribArray(2);
glVertexAttribIPointer(2, 1, GL_UNSIGNED_BYTE, 3 * 4 + 2, 3 * 4 + 1);

Question:

I've recently found out that using immediate mode when rendering is a big no-no.

So I started looking up on VBO's and VAO's and if I understand correctly, VBO's are objects/buffers which containts data like position, color and so on.

You then put the VBO's in a VAO and render everything in the VAO?

All of this is very new and strange to me, so I was wondering on HOW I would use it, for example, how would a Sprite/Texture class look like, and am I able to modify things like textures once I've started rendering?

I've googled around but haven't found anything I've been able to grasp.

Thank you in advance!


Answer:

Even though the question is quite wierd formulated, I think I get what you want(correct me if I don't)

You have to think of a VAO as a list. In this list, there are a number of attributes, for example positions, texture coordinates, etc(up to 16). Each attribute is stored as an array(VBO). This array is filled with all data of one attribute(e.g. all vertex-positions). The function glVertexAttribPointer describes the properties of one VBO, like the size of one vertex, data type, etc.

On the other hand, there are Uniform variables. These variables are loaded before the draw-call into a slot specified in the shader. These variables stay constant for the whole mesh and are used for values, which stay the same for all vertices(projection, view, etc.). These variables can also be of the datatype Sampler, which represents a texture.

For more detailed information I suggest you read through some samples/tutorials.