LWJGL - OpenGL 不渲染

LWJGL - OpenGL not rendering

预计以下 LWJGL 代码会在屏幕中央呈现一个蓝色正方形。相反,我得到一个空白的白色屏幕。好像渲染根本不工作,或者我在屏幕外渲染。

我完全是 OpenGL 和 LWJGL 的菜鸟,所以我力不从心。 我经历了一切,但似乎无法找到任何可能与代码有关的错误。

OpenGLTest.scala

package com.summerbulb.lwjgl

import game.graphics.VertexArray
import game.input.KeyboardInput
import org.lwjgl.glfw.GLFW._
import org.lwjgl.glfw.GLFWVidMode
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL11._
import org.lwjgl.opengl.GL20._
import org.lwjgl.system.MemoryUtil.NULL

import scala.collection.mutable


class OpenGLTest() extends Runnable {
  val width: Int = 1280
  val height: Int = 720

  var isRunning = false

  var window: Long = 0L

  val vertices = Array[Float](
    -0.5f, -0.5f, -0.5f,
    -0.5f, 0.5f, -0.5f,
    0.5f, 0.5f, -0.5f,
    0.5f, -0.5f, -0.5f
  )

  val indices = Array[Byte](
    0, 1, 2,
    2, 3, 0

  )

  val textureCoordinates = Array[Float](
    0, 1,
    0, 0,
    1, 0,
    1, 1
  )

  val vertShader =
    "#version 400 core\n" +
    "\n" +
    "layout (location = 0) in vec4 position;\n" +
    "layout (location = 1) in vec2 tc;\n" +
    "\n" +
//    "uniform mat4 pr_matrix;\n" +
    "\n" +
    "void main()\n" +
    "{\n" +
    "    gl_Position = position;\n" +
    "}"

  val fragShader =
    "#version 400 core\n" +
    "\n" +
    "layout (location = 0) out vec4 color;\n" +
    "\n" +
    "void main()\n" +
    "{\n" +
    "    color = vec4(0.2, 0.3, 0.8, 1.0);\n" +
    "}"

  lazy val background = new VertexArray(vertices, indices, textureCoordinates)
  lazy val shaderProgramId = createShaderProgram(vertShader, fragShader)

  val cache = mutable.Map[String, Int]()

  def getUniform(name: String) = {

    if (cache.contains(name))
      cache(name)
    else {

      val location = glGetUniformLocation(shaderProgramId, name)
      if (location == -1) {
        System.err.println("Could not find uniform variable '" + name + "'!")
      } else {
        cache.put(name, location)
      }
      location
    }
  }

  def start() = {
    isRunning = true
    val thread = new Thread(this, "OpenGlTest")
    thread.start()
  }

  def init(): Unit = {
    if (!glfwInit()) {
      throw new Exception("Unable to initialize GLFW")
    }

    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE)
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)

    window = glfwCreateWindow(width, height, "OpenGlTest", NULL, NULL)

    if (window == null) {
      throw new Exception("Could not create window.")
    }

    val vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor())

    glfwSetWindowPos(window, (GLFWVidMode.WIDTH - width) / 2, (GLFWVidMode.HEIGHT - height) / 2)

    glfwSetKeyCallback(window, new KeyboardInput())

    glfwMakeContextCurrent(window)
    glfwShowWindow(window)
    GL.createCapabilities()


    glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
    glEnable(GL_DEPTH_TEST | GL_DEPTH_BUFFER_BIT)
    println("OpenGL: " + glGetString(GL_VERSION))
  }

  override def run(): Unit = {
    init()
    while (isRunning) {
      update()
      render()

      if (glfwWindowShouldClose(window))
        isRunning = false
    }
  }

  def update(): Unit = {
    glfwPollEvents()


    // ESC closes the window
    if (KeyboardInput.keys(GLFW_KEY_ESCAPE)) {
      isRunning = false
    }
  }

  def render(): Unit = {
    glClear(GL_COLOR_BUFFER_BIT)

    glUseProgram(shaderProgramId)
    background.render()
    glUseProgram(0)

    glfwSwapBuffers(window)

  }

  def createShaderProgram(vert: String, frag: String): Int = {
    val program:Int = glCreateProgram()
    val vertID = glCreateShader(GL_VERTEX_SHADER)
    val fragID = glCreateShader(GL_FRAGMENT_SHADER)

    glShaderSource(vertID, vert)
    glShaderSource(fragID, frag)

    glCompileShader(vertID)
    if (glGetShaderi(vertID, GL_COMPILE_STATUS) != GL_TRUE) {
      val infoLog = glGetShaderInfoLog(vertID)
      throw new Exception("Failed to compile vertex shader.\nDetails:\n" + infoLog)
    }

    glCompileShader(fragID)
    if (glGetShaderi(fragID, GL_COMPILE_STATUS) != GL_TRUE) {
      val infoLog = glGetShaderInfoLog(fragID)
      throw new Exception("Failed to compile fragment shader.\nDetails:\n" + infoLog)
    }

    glAttachShader(program, vertID)
    glAttachShader(program, fragID)
    glLinkProgram(program)


    glValidateProgram(program)

    glDeleteShader(vertID)
    glDeleteShader(fragID)

    val error = glGetError()
    if (error != GL_NO_ERROR) {
      println(error)
      System.exit(200)
    }

    program
  }

}

object OpenGLTest {
  def main(args: Array[String]): Unit = {
    new OpenGLTest().start()
  }
}

VertexArray.scala

package game.graphics

import java.nio.{ByteBuffer, ByteOrder, FloatBuffer, IntBuffer}

import org.lwjgl.opengl.GL11._
import org.lwjgl.opengl.GL15._
import org.lwjgl.opengl.GL20._
import org.lwjgl.opengl.GL30._

class VertexArray(vertices: Array[Float], indices: Array[Byte], textureCoordinates: Array[Float]) {

  val count = indices.length

  val vao = glGenVertexArrays()
  glBindVertexArray(vao)

  val vbo = glGenBuffers()
  glBindBuffer(GL_ARRAY_BUFFER, vbo)
//  val verticesBuffer = BufferUtils.createFloatBuffer(vertices.length)
//  verticesBuffer.put(vertices).flip()
  glBufferData(GL_ARRAY_BUFFER, createFloatBuffer(vertices) , GL_STATIC_DRAW)
  glVertexAttribPointer(Shader.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0)
  glEnableVertexAttribArray(Shader.VERTEX_ATTRIB)


  val tbo = glGenBuffers()
  glBindBuffer(GL_ARRAY_BUFFER, tbo)
//  val texCoordBuffer = BufferUtils.createFloatBuffer(textureCoordinates.length)
//  texCoordBuffer.put(textureCoordinates).flip()
  glBufferData(GL_ARRAY_BUFFER, createFloatBuffer(textureCoordinates), GL_STATIC_DRAW)
  glVertexAttribPointer(Shader.TCOORD_ATTRIB , 2, GL_FLOAT, false, 0, 0)
  glEnableVertexAttribArray(Shader.TCOORD_ATTRIB)


  val ibo = glGenBuffers()
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
//  private val indicesBuffer: ByteBuffer = BufferUtils.createByteBuffer(indices.length)
//  indicesBuffer.put(indices).flip()
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, createByteBuffer(indices), GL_STATIC_DRAW )

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
  glBindBuffer(GL_ARRAY_BUFFER, 0)
  glBindVertexArray(0)

  def bind() = {
    glBindVertexArray(vao)
    glEnableVertexAttribArray(Shader.VERTEX_ATTRIB)
    glEnableVertexAttribArray(Shader.TCOORD_ATTRIB)

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
  }

  def unbind() = {
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
    glBindVertexArray(0)
  }

  def draw() = {
    glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0)
  }


  def render() = {
    bind()
    draw()
  }


  def createByteBuffer(array: Array[Byte]): ByteBuffer = {
    val result = ByteBuffer.allocateDirect(array.length).order(ByteOrder.nativeOrder)
    result.put(array).flip
    result
  }

  def createFloatBuffer(array: Array[Float]): FloatBuffer = {
    val result = ByteBuffer.allocateDirect(array.length << 2).order(ByteOrder.nativeOrder).asFloatBuffer
    result.put(array).flip
    result
  }

  def createIntBuffer(array: Array[Int]): IntBuffer = {
    val result = ByteBuffer.allocateDirect(array.length << 2).order(ByteOrder.nativeOrder).asIntBuffer
    result.put(array).flip
    result
  }
}

的来电
glEnable(GL_DEPTH_TEST | GL_DEPTH_BUFFER_BIT)

将导致 INVALID_ENUM 错误。 glEnable 的参数必须是单个枚举器常量。该参数不是位掩码,其中值可以通过 |.

连接
glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
glEnable(GL_DEPTH_TEST)

如果要清除缓冲区,则必须调用 glClearglClear 的参数是一个位掩码,表示要清除的缓冲区:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)