java - JOGL OpenGL 只在奇怪的条件下渲染

标签 java opengl jogl

我目前正在尝试让一个非常简单的程序运行。它只是在黑色背景上显示一个白色十字。问题是我的十字架的渲染只在奇怪的条件下工作。这些是我到目前为止发现的所有条件:

  1. 顶点着色器位置输入的布局必须大于2
  2. 任何对 glBindVertexArray(0) 的调用都会导致十字即使在调用 glBindVertexArray(array) 之后也不会呈现
  3. 我必须在每次绘制调用之前调用 glUseProgram

如您所见,我对这里实际发生的事情一无所知。我该如何修复这个错误?

代码如下:

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);
}

最佳答案

您计算出的条件看起来很奇怪。无论如何,总的来说,拥有干净简单的代码有助于避免讨厌的错误。从干净简单开始,然后构建它:)

一些注意事项:

  • 不要对vbo和vao使用int,直接使用direct buffers
  • 不需要全局声明 vertfrag 如果它们只在 init 中使用,在局部声明它们方法代替
  • 更喜欢使用 jogl 实用程序生成直接缓冲区 GLBuffers.newDirect*Buffer(...)
  • 至少在开始时,更喜欢使用 jogl 实用程序(ShaderCode.createShaderProgram)来编译您的着色器,它可以减轻您的工作负担和潜在的错误并包括对整个着色器创建过程中任何步骤的更深入检查(有时甚至太多,但如今着色器编译速度如此之快,这无关紧要)
  • 如果你有 ARB_explicit_attrib_location ,你可以用 gl4.isExtensionAvailable("GL_ARB_explicit_attrib_location"); 检查,尽可能在任何地方使用它,它将避免很多潜在的错误和任何类型的开销(例如 glBindAttribLocation glGetAttribLocation)
  • 最好将一个直接缓冲区传递给 glBufferData,这样 jogl 就不必在下面自己创建它,您可以跟踪它以释放它
  • 保持 init 干净且可读。你把很多东西混合在一起。例如,您在开始时生成 vbo,然后创建程序,然后将数据上传到 vbo。
  • gl.glUseProgram(program);init 中是没有意义的,除非你的想法是绑定(bind)它并让它保持绑定(bind)状态。无论如何,通常情况下,程序是渲染调用之前的初始化阶段的一部分,因此最好将其移动到 display() 中。
  • 更喜欢 glClearBuffer 而不是 glClear
  • gl.glDrawArrays(GL4.GL_LINES, 0, 2); 没有任何用处,因为您传递的顶点数为零
  • 如果你需要灵感,看看这个Hello Triangle

关于java - JOGL OpenGL 只在奇怪的条件下渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36705057/

相关文章:

java - 如何在 JOGL 中正确使用光照?

java - 绘图 : eg. Graphics.drawRect 或 Rectangle.draw 之间的差异

delphi - 将 OpenGL 场景保存到 TBitmap - glReadPixels 返回空数据?

java - 如果用户调整框架大小,如何扩展/收缩 glcanvas (Jogl)?

OpenGL/JOGL : Multiple triangle fans in a vertex array

java - JOGL 在调用 openGL 的绑定(bind) c 实现之前是否编码任何数据?

java - 哈希表原始类型

java - 如何将 python 套接字中的值存储在 double 值中?

java - Class.getResource 和 ClassLoader.getSystemResource : is there a reason to prefer one to another?

java - 我可以在我的 Java 应用程序中使用 OpenGL 吗?如果是,如何?