Search code examples
javaopenglglsllwjglglfw

LWJGL VAO/VBO not displaying


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.


Solution

  • 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:

    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.