CodingRays
CodingRays

Reputation: 109

JOGL OpenGL only rendering under weird conditions

I'm currently trying to get a very simple program to work. It just displays a white cross on a black background. The problem is that the rendering of my cross is only working under strange conditions. These are all the conditions i figured out thus far:

  1. The layout of the vertex shader position input has to be greater than 2
  2. Any call to glBindVertexArray(0) is causing the cross not to render even after calling glBindVertexArray(array)
  3. I have to call glUseProgram before every draw call

As you might see i have no idea anymore of what is acutally happening here. How do i fix this bug?

Here is the code:

int axesVBO;
int axesVAO;
int vert, frag;
int program;

@Override
public void display(GLAutoDrawable drawable) {
    System.out.println("Render");
    GL4 gl = drawable.getGL().getGL4();

    gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);

    gl.glBindVertexArray(axesVAO);

    gl.glUseProgram(program); //Doesnt work without

    gl.glDrawArrays(GL4.GL_LINES, 0, 2);
    gl.glDrawArrays(GL4.GL_LINES, 2, 2);
    gl.glBindVertexArray(0); //After this line the cross isn't renderd anymore
}

@Override
public void dispose(GLAutoDrawable drawable) {
    GL4 gl = drawable.getGL().getGL4();

    gl.glDeleteBuffers(1, IntBuffer.wrap(new int[]{axesVBO}));
    gl.glDeleteVertexArrays(1, IntBuffer.wrap(new int[]{axesVAO}));
    gl.glDeleteProgram(program);
    gl.glDeleteShader(vert);
    gl.glDeleteShader(frag);
}

@Override
public void init(GLAutoDrawable drawable) {
    System.out.println("Init");
    GL4 gl = drawable.getGL().getGL4();

    IntBuffer buffer = Buffers.newDirectIntBuffer(2);
    gl.glGenBuffers(1, buffer);
    axesVBO = buffer.get(0);

    vert = gl.glCreateShader(GL4.GL_VERTEX_SHADER);
    frag = gl.glCreateShader(GL4.GL_FRAGMENT_SHADER);

    gl.glShaderSource(vert, 1, new String[]{"#version 410\n in vec2 pos;void main() {gl_Position = vec4(pos, 0, 1);}"}, null);
    gl.glShaderSource(frag, 1, new String[]{"#version 410\n out vec4 FragColor;void main() {FragColor = vec4(1, 1, 1, 1);}"}, null);

    gl.glCompileShader(vert);
    gl.glCompileShader(frag);

    if(GLUtils.getShaderiv(gl, vert, GL4.GL_COMPILE_STATUS) == GL.GL_FALSE) {
        System.out.println("Vertex shader compilation failed:");
        System.out.println(GLUtils.getShaderInfoLog(gl, vert));
    } else {
        System.out.println("Vertex shader compilation sucessfull");
    }

    if(GLUtils.getShaderiv(gl, frag, GL4.GL_COMPILE_STATUS) == GL.GL_FALSE) {
        System.out.println("Fragment shader compilation failed:");
        System.out.println(GLUtils.getShaderInfoLog(gl, frag));
    } else {
        System.out.println("Fragment shader compilation sucessfull");
    }

    program = gl.glCreateProgram();

    gl.glAttachShader(program, vert);
    gl.glAttachShader(program, frag);

    gl.glBindAttribLocation(program, 2, "pos"); //Only works when location is > 2
    gl.glLinkProgram(program);

    if(GLUtils.getProgramiv(gl, program, GL4.GL_LINK_STATUS) == GL.GL_FALSE) {
        System.out.println("Program linking failed:");
        System.out.println(GLUtils.getProgramInfoLog(gl, program));
    } else {
        System.out.println("Program linking sucessfull");
    }

    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, axesVBO);
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, Float.BYTES * 8, FloatBuffer.wrap(new float[]{-1f, 0, 1f, 0, 0, 1f, 0, -1f}), GL4.GL_STATIC_DRAW);

    gl.glUseProgram(program);

    buffer.clear();
    gl.glGenVertexArrays(1, buffer);
    axesVAO = buffer.get();
    gl.glBindVertexArray(axesVAO);

    int pos = gl.glGetAttribLocation(program, "pos");
    gl.glEnableVertexAttribArray(pos);

    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, axesVBO);
    gl.glVertexAttribPointer(pos, 2, GL4.GL_FLOAT, false, 0, 0);
    //Commented out for testing reasons (doesnt work when active)
    //gl.glBindVertexArray(0);

    gl.glClearColor(0f, 0f, 0f, 1f);
}

Upvotes: 2

Views: 180

Answers (1)

elect
elect

Reputation: 7180

The conditions you figured out look strange. Anyway in general, having a clean and simple code helps a lot to avoid nasty bugs. Start clean and simple and then built it up :)

Few considerations:

  • don't use int for vbo and vao, use directly direct buffers
  • don't need to declare globally vert and frag if they are gonna be used only in the init, declare them locally in the method instead
  • prefer generating direct buffers using the jogl utility GLBuffers.newDirect*Buffer(...)
  • prefer, at least at the begin, to use the jogl utility (ShaderCode.create and ShaderProgram) to compile your shaders, it offloads you from work and potential bugs and includes a deeper check on any step during the whole shader creation (sometimes even too much, but nowadays shaders are so fast to compile it doesn't matter)
  • if you have ARB_explicit_attrib_location, you can check with gl4.isExtensionAvailable("GL_ARB_explicit_attrib_location");, use it everywhere you can, it will avoid a lot of potential bugs and overhead with any kind of location (such as glBindAttribLocation and glGetAttribLocation)
  • better to pass a direct buffer to glBufferData so that jogl doesn't have to create it by itself underneath and you can keep trace of it to deallocate it
  • keep the init clean and readable. You are mixing a lot of stuff together. For example you generate the vbo at the begin, then you create the program, then you upload data to the vbo.
  • it makes no sense gl.glUseProgram(program); in the init, unless your idea is to bind it and leave it bound. Anyway, normally, program is part of the initialization phase before a rendering call, so better to move it in the display().
  • prefer glClearBuffer to glClear
  • gl.glDrawArrays(GL4.GL_LINES, 0, 2); has no utility because you are passing zero as the number of vertices
  • if you need inspiration, take a look of this Hello Triangle

Upvotes: 1

Related Questions