Search code examples
javaopengllwjglopengl-3

OpenGL Triange demo shows blank window


I've started my learning of LWJGL3 and OpenGL 3.2+ with a triangle demo. The program seems to run well and I'm not getting any OpenGL errors, but the triangle does not show up on screen.

I've looked through some of the similar questions on here, and the identified problem with many of them were a missing VAO or bad triangle coordinates or shaders, but I've checked those in my code. VAO is created, bound and vertex attributes are assigned. The triangle coordinates should actually make a triangle, and my shaders say they've compiled and linked properly. I'm at a loss to what I've missed here.

Here is my code. Everything is in this one file (triangle vertex data, OpenGL object IDs, and shader source code at the bottom), save for LWJGL itself and the com.hackoeur.jglm library, which I'm using for my matrices:

package net.part1kl;

import com.hackoeur.jglm.Mat4;
import com.hackoeur.jglm.Matrices;
import org.lwjgl.Version;
import org.lwjgl.glfw.*;
import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.opengl.GL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.opengl.GL30C.*;
import static org.lwjgl.system.MemoryUtil.*;


public class Demo {

    public static void main(String[] args) {
        init();
        loop();
        dispose();
    }

    private static long window;

    private static void init(){
        /* Initialize GLFW */
        System.out.println(Version.getVersion());
        glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err));
        if (!glfwInit()) throw new IllegalStateException("GLFW Init Failed");

        /* Set window hints and create window */
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        window = glfwCreateWindow(600, 600, "Demo", NULL, NULL);
        if ( window == NULL) { glfwTerminate(); throw new RuntimeException("Window Creation Failed"); }

        /* Other window setup */
        glfwSetWindowPos(window, 200, 200);
        glfwMakeContextCurrent(window);
        GL.createCapabilities();
        glfwSwapInterval(1);
        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, true);
        });
        glfwShowWindow(window);

        /* Create and bind VAO */
        vao = glGenVertexArrays();
        glBindVertexArray(vao);

        /* Create, bind, and populate VBO */
        vbo = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        FloatBuffer verts = memAllocFloat(vertices.length);
        for (float val : vertices) verts.put(val);
        verts.flip();
        glBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW);
        memFree(verts);

        /* Create Vertex Shader */
        vShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vShader, vertexSource);
        glCompileShader(vShader);
        if (glGetShaderi(vShader, GL_COMPILE_STATUS) != GL_TRUE) throw new RuntimeException(glGetShaderInfoLog(vShader));

        /* Create Fragment Shader */
        fShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fShader, fragmentSource);
        glCompileShader(fShader);
        if (glGetShaderi(fShader, GL_COMPILE_STATUS) != GL_TRUE) throw new RuntimeException(glGetShaderInfoLog(fShader));

        /* Create Shader Program */
        program = glCreateProgram();
        glAttachShader(program, vShader);
        glAttachShader(program, fShader);
        glBindFragDataLocation(program, 0, "fragColor");
        glLinkProgram(program);
        if (glGetProgrami(program, GL_LINK_STATUS) != GL_TRUE) throw new RuntimeException(glGetProgramInfoLog(program));
        glUseProgram(program);

        /* Set pointer for vertex position information */
        int pAttr = glGetAttribLocation(program, "position");
        glEnableVertexAttribArray(pAttr);
        glVertexAttribPointer(pAttr, 3, GL_FLOAT, false, 6 * Float.BYTES, 0);

        /* Set pointer for vertex color information */
        int cAttr = glGetAttribLocation(program, "color");
        glEnableVertexAttribArray(cAttr);
        glVertexAttribPointer(cAttr, 3, GL_FLOAT, false, 6 * Float.BYTES, 3 * Float.BYTES);

        /* Create and set model uniform. Using com.hackoeur.jglm v1.0.0 for matrices. */
        Mat4 model = new Mat4();
        int uModel = glGetUniformLocation(program, "model");
        glUniformMatrix4fv(uModel, false, (FloatBuffer)model.getBuffer().flip());

        /* Create and set view uniform */
        Mat4 view = new Mat4();
        int uView = glGetUniformLocation(program, "view");
        glUniformMatrix4fv(uView, false, (FloatBuffer)view.getBuffer().flip());

        /* Get window size ratio for projection */
        IntBuffer width = memAllocInt(1);
        IntBuffer height = memAllocInt(1);
        GLFW.glfwGetFramebufferSize(window, width, height);
        float ratio = width.get() / (float) height.get();
        memFree(width); memFree(height);

        /* Create and set projection uniform */
        Mat4 projection = Matrices.ortho(-ratio, ratio, -1f, 1f, -1f, 1f);
        int uProjection = glGetUniformLocation(program, "projection");
        glUniformMatrix4fv(uProjection, false, (FloatBuffer)projection.getBuffer().flip());
    }

    private static void loop(){
        double lastTime = glfwGetTime();
        double time = lastTime;
        while(!glfwWindowShouldClose(window)){
            double delta = (float) (time - lastTime);

            glClear(GL_COLOR_BUFFER_BIT);

            glBindVertexArray(vao);
            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glUseProgram(program);


            glDrawArrays(GL_TRIANGLES, 0, 3);

            glfwSwapBuffers(window);
            glfwPollEvents();

            glCheck();

            lastTime = time;
            time = glfwGetTime();
        }
    }

    private static void dispose(){
        glDeleteVertexArrays(vao);
        glDeleteBuffers(vbo);
        glDeleteShader(vShader);
        glDeleteShader(fShader);
        glDeleteProgram(program);

        glfwDestroyWindow(window);
    }

    private static void print(String message) { System.out.println(message); }

    private static void err(String message) { System.err.println(message); }

    private static int glCheckCounter = 0;

    private static void glCheck() {
        int val = glGetError();
        if (val==0) print("GL Error Check "+glCheckCounter+" no error.");
        else err("GL Error Check "+glCheckCounter+" returned error "+val);
        glCheckCounter++;
    }


    private static int vao, vbo, vShader, fShader, program;
    private static final float[] vertices = {
            -0.6f,   -0.4f,   0f,   1f,   0f,   0f,
             0.6f,   -0.4f,   0f,   0f,   1f,   0f,
               0f,    0.6f,   0f,   0f,   0f,   1f
    };
    private static final CharSequence vertexSource
            = "#version 150 core\n"
            + "\n"
            + "in vec3 position;\n"
            + "in vec3 color;\n"
            + "\n"
            + "out vec3 vertexColor;\n"
            + "\n"
            + "uniform mat4 model;\n"
            + "uniform mat4 view;\n"
            + "uniform mat4 projection;\n"
            + "\n"
            + "void main() {\n"
            + "    vertexColor = color;\n"
            + "    mat4 mvp = projection * view * model;\n"
            + "    gl_Position = mvp * vec4(position, 1.0);\n"
            + "}";
    private static final CharSequence fragmentSource
            = "#version 150 core\n"
            + "\n"
            + "in vec3 vertexColor;\n"
            + "\n"
            + "out vec4 fragColor;\n"
            + "\n"
            + "void main() {\n"
            + "    fragColor = vec4(vertexColor, 1.0);\n"
            + "}";
}

This is the output I get from running this program:

3.3.1 build 7
GL Error Check 0 no error.
GL Error Check 1 no error.
GL Error Check 2 no error.
GL Error Check 3 no error.
GL Error Check 4 no error.
GL Error Check 5 no error.
GL Error Check 6 no error.
GL Error Check 7 no error.

The "GL Error Check # no error." keeps going for as long as the program runs, I've cut it off at 8 loops. It's never brought up an OpenGL error.


Solution

  • The problem appears to be with the way the Mat4 object creates the buffer. This is the source code my IDE decompiled for com.hackoeur.jglm.Mat4.getBuffer():

        public FloatBuffer getBuffer() {
            FloatBuffer buffer = this.allocateFloatBuffer();
            int startPos = buffer.position();
            buffer.put(this.m00).put(this.m01).put(this.m02).put(this.m03);
            buffer.put(this.m10).put(this.m11).put(this.m12).put(this.m13);
            buffer.put(this.m20).put(this.m21).put(this.m22).put(this.m23);
            buffer.put(this.m30).put(this.m31).put(this.m32).put(this.m33);
            buffer.position(startPos);
            return buffer;
        }
    

    I'm not 100% sure what the problem with it is or whether I was just using it wrong, but when I went back to the source code of the tutorial I was initially following by SilverTiger and used the Matrix4f object there, the triangle showed up. Source code for silvertiger.tutorial.lwjgl.math.Matrix4f.toBuffer():

        public void toBuffer(FloatBuffer buffer) {
            buffer.put(m00).put(m10).put(m20).put(m30);
            buffer.put(m01).put(m11).put(m21).put(m31);
            buffer.put(m02).put(m12).put(m22).put(m32);
            buffer.put(m03).put(m13).put(m23).put(m33);
            buffer.flip();
        }