使用glDrawArrays,绘图工作正常,但使用glDrawElements失败

时间:2015-06-10 12:33:04

标签: java scala opengl

我的着色器工作正常,我可以使用glDrawArrays进行绘制,但是很难让glDrawElements工作。我已经在lwjgl函数调用与标准openGL不同的地方添加了注释。代码:

import org.lwjgl.Sys
import org.lwjgl.glfw._
import org.lwjgl.opengl._
import java.nio.ByteBuffer
import java.nio.FloatBuffer
import  org.lwjgl.glfw.Callbacks._
import  org.lwjgl.glfw.GLFW._
import  org.lwjgl.opengl.GL11._
import  org.lwjgl.opengl.GL15._
import  org.lwjgl.opengl.GL20._
import  org.lwjgl.opengl.GL30._
import  org.lwjgl.system.MemoryUtil._
import  org.lwjgl.BufferUtils._
import hands._
import javafx.scene.shape.CullFace


class Test {

    val vertex_positions:  Array[Float] = Array(
     -1.0f, -1.0f, 0.0f,  
     1.0f, -1.0f, 0.0f,
     -1.0f, 1.0f, 0.0f
    )

    val vertex_indices: Array[Int] = Array(
      0, 1, 2    
    )

    // We need to strongly reference callback instances.
    val errorCallback: GLFWErrorCallback = Callbacks.errorCallbackPrint();
    val keyCallback: GLFWKeyCallback = new GLFWKeyCallback() {
      @Override
      def invoke(window: Long , key: Int, scancode: Int , action: Int , mods: Int) {
        if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
          glfwSetWindowShouldClose(window, GL_TRUE) // We will detect this in our rendering loop
      }
    }

    val WIDTH = 800
    val HEIGHT = 600 

    def run(): Unit = {
            System.out.println("Hello LWJGL " + Sys.getVersion() + "!")  

            try {

                val vertBuffer = hands.createFlippedBuffer(vertex_positions)
                val indexBuffer = hands.createFlippedBuffer(vertex_indices)

                // Setup an error callback. The default implementation
                // will print the error message in System.err.
                glfwSetErrorCallback(errorCallback)

                // Initialize GLFW. Most GLFW functions will not work before doing this.
                if ( glfwInit() != GL_TRUE )
                    throw new IllegalStateException("Unable to initialize GLFW")

                // Configure our window
                glfwDefaultWindowHints() // optional, the current window hints are already the default
                glfwWindowHint(GLFW_VISIBLE, GL_FALSE) // the window will stay hidden after creation
                glfwWindowHint(GLFW_RESIZABLE, GL_TRUE) // the window will be resizable
                glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
                glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
                glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)

                // Create the window
                val window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL)
                if ( window == NULL )
                    throw new RuntimeException("Failed to create the GLFW window")

                // Setup a key callback. It will be called every time a key is pressed, repeated or released.        
                glfwSetKeyCallback(window, keyCallback)

                // Get the resolution of the primary monitor
                val vidmode: ByteBuffer = glfwGetVideoMode(glfwGetPrimaryMonitor())
                // Center our window
                glfwSetWindowPos(
                        window,
                        (GLFWvidmode.width(vidmode) - WIDTH) / 2,
                        (GLFWvidmode.height(vidmode) - HEIGHT) / 2)

                // Make the OpenGL context current
                glfwMakeContextCurrent(window)
                // Enable v-sync
                glfwSwapInterval(1)

                // Make the window visible
                glfwShowWindow(window)

                // This line is critical for LWJGL's interoperation with GLFW's
                // OpenGL context, or any context that is managed externally.
                // LWJGL detects the context that is current in the current thread,
                // creates the ContextCapabilities instance and makes the OpenGL
                // bindings available for use.
                GLContext.createFromCurrent()

                //create shader, and use it as program
                val shader = new Shader()
                glUseProgram(shader.program)

                val vao = glGenVertexArrays()
                glBindVertexArray(vao)

                val vbo = glGenBuffers()
                glBindBuffer(GL_ARRAY_BUFFER, vbo)
                //http://javadoc.lwjgl.org/org/lwjgl/opengl/GL15.html#glBufferData%28int,%20java.nio.FloatBuffer,%20int%29
                glBufferData(GL_ARRAY_BUFFER,  vertBuffer, GL_STATIC_DRAW)

                //this function accepts false instead of GL_FALSE
                glVertexAttribPointer(0, 3, GL_FLOAT, false , 0, 0)
                glEnableVertexAttribArray(0)

                val ebo = glGenBuffers()
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
                //http://javadoc.lwjgl.org/org/lwjgl/opengl/GL15.html#glBufferData%28int,%20java.nio.ShortBuffer,%20int%29
                glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW)


                // Set the clear color
                glClearColor(0, 0, 0.4f, 1)
                // Run the rendering loop until the user has attempted to close
                // the window or has pressed the ESCAPE key.
                //glfwWindowShouldClose produces a GL_FALSE, instead of a boolean value
                while ( glfwWindowShouldClose(window) == GL_FALSE ) {

                glClear(GL_COLOR_BUFFER_BIT) // clear the framebuffer

                glBindVertexArray(vao)
                glEnableVertexAttribArray(0)

                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)

                //http://javadoc.lwjgl.org/org/lwjgl/opengl/GL11.html#glDrawElements%28int,%20java.nio.ShortBuffer%29
                glDrawElements(GL_TRIANGLES, indexBuffer)
                //glDrawArrays(GL_TRIANGLES, 0, 9)

                glfwSwapBuffers(window); // swap the color buffers

                // Poll for window events. The key callback above will only be
                // invoked during this call.
                glfwPollEvents();
            }

            // Release window and window callbacks            
            glfwDestroyWindow(window)
            keyCallback.release()
        } finally {
            // Terminate GLFW and release the GLFWerrorfun
            glfwTerminate()
            errorCallback.release()
        }
    }

}

object main{

      def main( args: Array[String] ) = {
          new Test().run();
      }
    }

1 个答案:

答案 0 :(得分:0)

glDrawElements()有两种变体在定义和使用最后一个参数方面有很大不同:

  1. 一个人需要"数据"作为论点。参数的确切类型取决于语言绑定,但它通常类似于C / C ++中的指针,Java中的缓冲区等。

  2. 将一个整数偏移作为参数。

  3. 如果缓冲区当前绑定到GL_ELEMENT_ARRAY_BUFFER,则使用选项2。作为最后一个参数给出的整数是相对于绑定缓冲区起始的偏移量(以字节为单位)。

    如果没有缓冲区绑定到GL_ELEMENT_ARRAY_BUFFER,则使用选项1。在这种情况下,最后一个参数直接指定索引数据。

    您的代码中的问题是您要将两者混合在一起。您有一个缓冲区绑定,因此您需要使用选项2.但是您使用选项1.您的案例中的正确调用将是:

    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0)
    

    请注意, count (第二个参数)以顶点为单位给出,而 offset (最后一个参数)以字节为单位给出。由于您正在使用整个缓冲区,并且偏移量为0,因此这里没有任何区别。但它经常出错。

    在像C / C ++这样的弱类型语言中,实际上只有一个glDrawElements()调用,并且选项2的偏移量被强制转换为指针。如果您错误地使用选项1中的调用而不是OpenGL错误,这也是导致崩溃的原因。根据规范C / C ++绑定的规范,只有一个调用,所以没有调用"错误"在这种情况下的切入点。它们只是更强类型语言的不同入口点。