Shakier
Shakier

Reputation: 7

glVertexAttribPointer doesn't seem to work, but no errors

I have been using LWJGL 3 and a tutorial at LearnOpenGL.com in order to create a game engine. However, after following the tutorial, I have discovered that the use of glVertexAttribPointer is not working. It works when uploading vertex positions and indices, but when I try to upload color and texture coordinates, nothing's happening, and I'm just getting a white box. I have attached the source code of the render engine, main class, and shaders:

public class Mesh {
    public float[] vertices;
    public float[] colors;
    public float[] textureCoords;
    public int[] indices;

    public Mesh(float[] vertices, float[] colors, float[] textureCoords, int[] indices) {
        this.vertices = vertices;
        this.colors = colors;
        this.textureCoords = textureCoords;
        this.indices = indices;
    }
}

public class MasterRenderer {
    private int vbo;
    private int vao;
    private int ebo;

    private Mesh mesh;

    private ShaderProgram program;

    public void Init(Mesh mesh) {
        this.mesh = mesh;

        program = new ShaderProgram();

        vao = GL30.glGenVertexArrays();

        vbo = GL20.glGenBuffers();
        ebo = GL20.glGenBuffers();
    }

    public void Render(Color clearColor) {
        // Clear Screen
        GL11.glClearColor(clearColor.getRed(), clearColor.getGreen(), clearColor.getBlue(), clearColor.getAlpha());
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

        // Bind vao
        GL30.glBindVertexArray(vao);

        // Bind Buffers
        GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo);
        GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.vertices, GL20.GL_STATIC_DRAW);

        GL20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, ebo);
        GL20.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.indices, GL20.GL_STATIC_DRAW);

        // Enable vertex attribPointers
        GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
        GL20.glEnableVertexAttribArray(0);

        // Handle Textures
        Texture texture = Utils.LoadTexture("resources//textures//test.png");

        // Uniforms


        // Use Program
        program.UseProgram();

        // Draw the shape
        GL20.glActiveTexture(GL20.GL_TEXTURE0);
        GL20.glBindTexture(GL20.GL_TEXTURE_2D, texture.getId());

        GL30.glBindVertexArray(vao);
        GL20.glDrawElements(GL20.GL_TRIANGLES, 6, GL20.GL_UNSIGNED_INT, 0);
    }
}

public class ShaderProgram {
    public int programID;

    public int vertexShaderID;
    public int fragmentShaderID;

    public ShaderProgram() {
        programID = GL20.glCreateProgram();

        try {
            CompileVertexShader(Utils.LoadResource("resources/shaders/default/defaultShader.vs"));
            CompileFragmentShader(Utils.LoadResource("resources/shaders/default/defaultShader.fs"));

            GL20.glAttachShader(programID, vertexShaderID);
            GL20.glAttachShader(programID, fragmentShaderID);

            if(GL20.glGetShaderi(vertexShaderID, GL20.GL_COMPILE_STATUS) == 0) {
                Logger.LogErrorClose("Error compiling vertex shader code: " + GL20.glGetShaderInfoLog(vertexShaderID, 1024));
            }

            if(GL20.glGetShaderi(fragmentShaderID, GL20.GL_COMPILE_STATUS) == 0) {
                Logger.LogErrorClose("Error compiling fragment shader code: " + GL20.glGetShaderInfoLog(fragmentShaderID, 1024));
            }

            GL20.glLinkProgram(programID);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void UseProgram() {
        GL20.glUseProgram(programID);
        GL20.glDeleteShader(vertexShaderID);
        GL20.glDeleteShader(fragmentShaderID);
    }

    public void CompileVertexShader(String shaderCode) {
        vertexShaderID = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);

        GL20.glShaderSource(vertexShaderID, shaderCode);
        GL20.glCompileShader(vertexShaderID);
    }

    public void CompileFragmentShader(String shaderCode) {
        fragmentShaderID = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);

        GL20.glShaderSource(fragmentShaderID, shaderCode);
        GL20.glCompileShader(fragmentShaderID);
    }
}

public class Texture {
    private int id;

    public Texture(int id){
        this.id = id;
    }

    public int getId(){
        return id;
    }
}

public class FoodFight {
    public static void main(String[] args) {
        Logger.LogMessage("Running on LWJGL Version: " + Version.getVersion());

        Window w = new Window();

        long window = w.CreateWindow(640, 360, "Food Fight");

        MasterRenderer renderer = new MasterRenderer();

        float[] vertices = {
                 0.5f,  0.5f, 0f,
                 0.5f, -0.5f, 0f,
                -0.5f, -0.5f, 0f,
                -0.5f,  0.5f, 0f
        };
        float[] colors = {
                1f, 0f, 0f,
                0f, 1f, 0f,
                0f, 0f, 1f,
                1f, 1f, 0f
        };
        float[] textureCoords = {
                 1f, 1f,
                 1f, 0f,
                 0f, 0f,
                 0f, 1f
        };
        int[] indices = {
            0, 1, 3,
            1, 2, 3
        };

        Mesh m = new Mesh(vertices, colors, textureCoords, indices);

        renderer.Init(m);

        while(!w.ShouldClose(window)) {
            Input.ProcessInput(window);

            renderer.Render(Color.black);

            w.HandleWindow(window);
        }

        w.DestroyWindow(window);
    }
}

Fragment:

#version 330 core

in vec3 color;
in vec2 texCoords;

out vec4 fragColor;

uniform sampler2D inputTexture;

void main() {
    fragColor = texture(inputTexture, texCoords) * vec4(color, 1.0);
}

Vertex:

#version 330 core

in vec3 aPos;
in vec3 aColor;
in vec2 aTexCoord;

out vec3 color;
out vec2 texCoord;

void main() {
    gl_Position = vec4(aPos, 1.0);
    color = aColor;
    texCoord = aTexCoord;
}

Upvotes: 1

Views: 975

Answers (1)

Rabbid76
Rabbid76

Reputation: 211278

Since you have separate arrays for the vertex coordinates, colors and texture coordinates, you have specify separat buffers for the attributes:

vbo_ver = GL20.glGenBuffers();
vbo_col = GL20.glGenBuffers();
vbo_tex = GL20.glGenBuffers();

Creates and initializes the buffer object's data store

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_ver);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.vertices, GL20.GL_STATIC_DRAW);

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_col);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.colors, GL20.GL_STATIC_DRAW);

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_tex);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.textureCoords, GL20.GL_STATIC_DRAW);

Specify the attribute indices, in the vertex shader by layout qualifiers:

#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

glVertexAttribPointer associates the buffer which is currently bound to the ARRAY_BUFFER target, to the specified attribute (index), in the state vector of the currently bound Vertex Array Object. (See Vertex Specification). Hence, the proper buffer and the VAO has to be bound before glVertexAttribPointer.
(The ELEMENT_ARRAY_BUFFER) is stated in the VAO, thus the VAO has to be bound before specifying the index buffer):

GL30.glBindVertexArray(vao);

GL20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL20.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.indices, GL20.GL_STATIC_DRAW);

GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_ver);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_col);
GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0);

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_tex);
GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, 0, 0);

Alternatively you can put the vertices and attributes to 1 array:

float[] attributes = {
//   x      y     z     r   g   b     u   v
     0.5f,  0.5f, 0f,   1f, 0f, 0f,   1f, 1f,  
     0.5f, -0.5f, 0f,   0f, 1f, 0f,   1f, 0f,
    -0.5f, -0.5f, 0f,   0f, 0f, 1f,   0f, 0f,
    -0.5f,  0.5f, 0f,   1f, 1f, 0f    0f, 1f
};
vbo = GL20.glGenBuffers();
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.attributes, GL20.GL_STATIC_DRAW);

The stride and the offset have to be specified in bates:

GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo);

int stride = 8 * 4; // the tuple size is 8 (x y z r g b u v), sizeof float is 4

GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, stride, 0);
GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, stride, 3*4);
GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, stride, 6*4);

Upvotes: 1

Related Questions