OpenGL 如何渲染具有多个对象的基于体素的世界场景

OpenGL How to render a voxel based world scene with many objects

我正在使用针对 JVM 语言的 OpenGL 绑定开发体素游戏引擎(scala 是我的例子)- LWJGL 3 for OpenGL version 4.5。目前我坚持使用块渲染(32*32*32 块)。为了渲染任何对象,我首先给它一个唯一的 ID,将类似的对象(如简单的块)视为具有不同转换的对象,在初始化阶段创建一个 VAO 数据事物,在完成所有准备后,我渲染整个块循环遍历每个块,将其数据传递给着色器,然后使用取自 ID 的适当偏移量调用 drawElements。这样 fps 从 3000(3 条轴线和一个巨大的网格对象单独渲染)下降到 1-2。那么我应该如何正确渲染块?

我参考了basic-block-rendering教程。

Fps 下降代码:

def render(shader:Shader): Unit ={
for(x <- 0 until SIZE) {
  for (y <- 0 until SIZE) {
    for (z <- 0 until SIZE) {
      val obj = blocks(x)(y)(z)
      if(obj != null){
        val M = obj.getTransformationMatrix() * Matrix4F.matrixTRANSLATION(obj.getPosition())
        shader.setUniformMat4f("M", M)
        shader.setUniformMat4f("MI", M.inverse())
        shader.setUniformBool("lightInteraction", obj.lightInteraction)
        shader.setUniform1f("smoothness", obj.smoothness)
        shader.setUniform3f("matD", obj.matDiffuse)
        shader.setUniform3f("matS", obj.matSpecular)
        GL13.glActiveTexture(GL13.GL_TEXTURE0); // Texture unit 0
        glBindTexture(GL_TEXTURE_2D, obj.getTextureID())

        Shader.full.setUniform1i("tex", 0)
        RenderRegistry.getRenderManager().render(obj.getID, obj.getRenderType())
      }
    }
  }
}
}

您当前的代码正在尝试每帧执行 32768 (32*32*32) 次矩阵乘法、求逆、统一上传和纹理状态更改。通常,这些都是昂贵的操作,并且很可能并非块中的每个对象都需要它们。幸运的是,优化的方法很少。

分组依据texture/material

很可能有些对象共享相同的着色器参数和纹理。绑定这些值然后绘制共享它们的所有对象应该会恢复一些性能。

实例化渲染

我不会过多地讨论这个问题,因为有一个关于该主题的优秀教程 here。假设您所有的体素都使用相同的几何体并且大部分是静态的,您可以将变换矩阵上传到缓冲区并上传顶点对象 一次。这样做的好处部分取决于您的图形驱动程序,但对于大型体素场景,它可能是值得的。

将矩阵运算移至 GPU

这是次要的,但如果您不想为实例化而烦恼,您至少可以节省一些矩阵运算的周期。不要上传 M.inverse() 而是在 GPU 上调用 inverse(M)。还可以考虑上传体素位置并作为制服单独变换并在 GPU 上执行 transform*position