LWJGL wiki上的示例代码因GL_INVALID_OPERATION而失败

时间:2014-11-18 05:00:27

标签: java opengl lwjgl

我只是复制粘贴了来自this tutorial的LWJGL维基上的代码,为了您的方便,我现在将其粘贴在这里。

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.*;
import org.lwjgl.util.glu.GLU;

import java.nio.FloatBuffer;

public class TheQuadExampleDrawArrays {
  // Entry point for the application
  public static void main(String[] args) {
    new TheQuadExampleDrawArrays();
  }

  // Setup variables
  private final String WINDOW_TITLE = "The Quad: glDrawArrays";
  private final int WIDTH = 320;
  private final int HEIGHT = 240;
  // Quad variables
  private int vaoId = 0;
  private int vboId = 0;
  private int vertexCount = 0;

  public TheQuadExampleDrawArrays() {
    // Initialize OpenGL (Display)
    this.setupOpenGL();

    this.setupQuad();

    while (!Display.isCloseRequested()) {
      // Do a single loop (logic/render)
      this.loopCycle();

      // Force a maximum FPS of about 60
      Display.sync(60);
      // Let the CPU synchronize with the GPU if GPU is tagging behind
      Display.update();
    }

    // Destroy OpenGL (Display)
    this.destroyOpenGL();
  }

  public void setupOpenGL() {
    // Setup an OpenGL context with API version 3.2
    try {
      PixelFormat pixelFormat = new PixelFormat();
      ContextAttribs contextAtrributes = new ContextAttribs(3, 2)
        .withForwardCompatible(true)
        .withProfileCore(true);

      Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
      Display.setTitle(WINDOW_TITLE);
      Display.create(pixelFormat, contextAtrributes);

      GL11.glViewport(0, 0, WIDTH, HEIGHT);
    } catch (LWJGLException e) {
      e.printStackTrace();
      System.exit(-1);
    }

    // Setup an XNA like background color
    GL11.glClearColor(0.4f, 0.6f, 0.9f, 0f);

    // Map the internal OpenGL coordinate system to the entire screen
    GL11.glViewport(0, 0, WIDTH, HEIGHT);

    this.exitOnGLError("Error in setupOpenGL");
  }

  public void setupQuad() {
    // OpenGL expects vertices to be defined counter clockwise by default
    float[] vertices = {
      // Left bottom triangle
      -0.5f, 0.5f, 0f,
      -0.5f, -0.5f, 0f,
      0.5f, -0.5f, 0f,
      // Right top triangle
      0.5f, -0.5f, 0f,
      0.5f, 0.5f, 0f,
      -0.5f, 0.5f, 0f
    };
    // Sending data to OpenGL requires the usage of (flipped) byte buffers
    FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
    verticesBuffer.put(vertices);
    verticesBuffer.flip();

    vertexCount = 6;

    // Create a new Vertex Array Object in memory and select it (bind)
    // A VAO can have up to 16 attributes (VBO's) assigned to it by default
    vaoId = GL30.glGenVertexArrays();
    GL30.glBindVertexArray(vaoId);

    // Create a new Vertex Buffer Object in memory and select it (bind)
    // A VBO is a collection of Vectors which in this case resemble the location of each vertex.
    vboId = GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer, GL15.GL_STATIC_DRAW);
    // Put the VBO in the attributes list at index 0
    GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
    // Deselect (bind to 0) the VBO
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

    // Deselect (bind to 0) the VAO
    GL30.glBindVertexArray(0);

    this.exitOnGLError("Error in setupQuad");
  }

  public void loopCycle() {
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

    // Bind to the VAO that has all the information about the quad vertices
    GL30.glBindVertexArray(vaoId);
    GL20.glEnableVertexAttribArray(0);

    // Draw the vertices
    GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, vertexCount);
    /**
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     * I found that the GL_INVALID_OPERATION flag was being raised here,
     * at the call to glDrawArrays().
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     */

    // Put everything back to default (deselect)
    GL20.glDisableVertexAttribArray(0);
    GL30.glBindVertexArray(0);

    this.exitOnGLError("Error in loopCycle");
  }

  public void destroyOpenGL() {
    // Disable the VBO index from the VAO attributes list
    GL20.glDisableVertexAttribArray(0);

    // Delete the VBO
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    GL15.glDeleteBuffers(vboId);

    // Delete the VAO
    GL30.glBindVertexArray(0);
    GL30.glDeleteVertexArrays(vaoId);

    Display.destroy();
  }

  public void exitOnGLError(String errorMessage) {
    int errorValue = GL11.glGetError();

    if (errorValue != GL11.GL_NO_ERROR) {
      String errorString = GLU.gluErrorString(errorValue);
      System.err.println("ERROR - " + errorMessage + ": " + errorString);

      if (Display.isCreated()) Display.destroy();
      System.exit(-1);
    }
  }
}

当我运行它时,它抛出了一个错误

ERROR - Error in loopCycle: Invalid operation

我将其缩小到glDrawArrays()方法中对loopCycle()的调用,然后点击谷歌找出可能意味着什么,并发现this SO question,其中列出了整整可能的原因(为方便起见,这里列出)。

    如果将非零缓冲区对象名称绑定到已启用的数组或GL_INVALID_OPERATION绑定并且当前映射了缓冲区对象的数据存储,则会生成
  1. GL_DRAW_INDIRECT_BUFFER

  2. 如果在执行GL_INVALID_OPERATION和相应的glDrawArrays之间执行glBegin,则会生成
  3. glEnd

  4. GL_INVALID_OPERATION将由glDrawArraysglDrawElements生成,如果当前程序对象中的任何两个活动采样器具有不同类型,但引用相同的纹理图像单元。

  5. 如果几何着色器处于活动状态且模式与当前安装的程序对象中几何着色器的输入基元类型不兼容,则会生成
  6. GL_INVALID_OPERATION

  7. 如果模式为GL_INVALID_OPERATION并且没有曲面细分控件着色器处于活动状态,则会生成
  8. GL_PATCHES

  9. 如果将基元的顶点记录到用于变换反馈目的的缓冲区对象,则会生成
  10. GL_INVALID_OPERATION,这将导致超出任何缓冲区对象大小的限制,或超出结束位置偏移+ size - 1,由glBindBufferRange设置。

  11. GL_INVALID_OPERATIONglDrawArrays()生成,如果没有几何着色器,则转换反馈处于活动状态且模式不是允许的模式之一。

  12. GL_INVALID_OPERATIONglDrawArrays()生成,如果存在几何着色器,则变换反馈处于活动状态,并且几何着色器的输出基本类型与变换反馈primitiveMode不匹配。

  13. 如果绑定的着色器程序无效,则会生成
  14. GL_INVALID_OPERATION

  15. 如果正在使用变换反馈,则生成
  16. GL_INVALID_OPERATION,并且绑定到变换反馈绑定点的缓冲区也绑定到数组缓冲区绑定点。

  17. 这些对我来说没有任何意义,经过相当长的时间阅读它们之后,我就无法找到这段代码的错误。如果有人比我更了解这个,请指出GL_INVALID_OPERATION旗帜被提出的原因吗?

1 个答案:

答案 0 :(得分:2)

项目9.看起来您没有绑定着色器程序。

您正在使用核心配置文件创建上下文:

  ContextAttribs contextAtrributes = new ContextAttribs(3, 2)
    .withForwardCompatible(true)
    .withProfileCore(true);

使用核心配置文件,您需要提供着色器程序。您通常会在GLSL中至少编写一个顶点和一个片段着色器,然后使用以下调用来构建和绑定着色器程序:

glCreateShader
glShaderSource
glCompileShader
glCreateProgram
glAttachShader
glLinkProgram
glUseProgram