0
\$\begingroup\$

I am working on a voxel game engine using OpenGL binding for JVM languages (scala is my case) - LWJGL 3 for OpenGL version 4.5 . Currently I'm stuck with chunk rendering (32*32*32 blocks). To render any object I firstly give it an unique ID, treating similar objects, like simple blocks, as one with different transformations, create one VAO data thing in initialization stage and after all preparation is done, I render a whole chunk looping through each block, passing its data to the shader and then calling drawElements with appropriate offset, taken from ID. This way fps drops from 3000(with 3 axis lines and a huge grid object rendered separately) to 1-2. So how should I correctly render a chunk ?

I used https://sites.google.com/site/letsmakeavoxelengine/home/basic-block-rendering tutorial as reference.

Fps dropping code:

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

EDIT: for those who are interested, instanced arrays helped me a lot ! Link for a tut: http://learnopengl.com/#!Advanced-OpenGL/Instancing

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

The way you are rendering voxels is extremely ineffective. For each cube you have to do calculations, set uniforms, and worst of all bind textures(This is usually a very expensive operation)

Typically effective voxel rendering involves multiple techniques to speed up rendering:

  • Rendering in chunks: You split your world into neatly sized proportions, which makes it easier to cull and to generate/regenerate.
  • VBO: You render each chunk as a single VBO to utilize least possible API calls.
  • You render only the blocks that are "facing air"(Don't render the blocks that are completely surrounded and have no visible faces.) to reduce polygon count. The most commonly used algorithm for this, is called "Marching cubes". wiki
  • To further reduce rendered polygons, you could use frustum culling, so you would only render the chunks that are in your viewport.(Thanks to @Kaarez to pointing this out)
  • Texture atlas: you don't bind a new texture for each cube, but create a huge texture which contains all of your voxel textures and just change the voxel texture coordinates to match the correct texture's location on the atlas.

The site you referenced also has these and other techniques in its tutorial section, so you should probably reduce your world size so you get a testable FPS and start implementing these optimizations.

Also you should measure performance not in FPS but in frame time: The time needed to rendered a single frame. FPS is not good, because it is not linear.

\$\endgroup\$
4
  • \$\begingroup\$ ok, then how do i pass extra properties of each of my voxels to the shader, like smoothness, material, etc ? And how to i translate the blocks ? \$\endgroup\$
    – Russoul
    Commented Jul 7, 2015 at 10:04
  • 1
    \$\begingroup\$ You only translate individual chunks to their position. Inside that each cube has its location "baked" into the VBO. Smoothness and material are usually the same for all voxels, but if you want you could create a material index property for your vertices and that would choose from a set of predefined/uniform block materials in your shader. \$\endgroup\$
    – akaltar
    Commented Jul 7, 2015 at 10:15
  • \$\begingroup\$ The technique where you only render visible faces is called frustum culling, not marching cubes. \$\endgroup\$
    – KaareZ
    Commented Jul 7, 2015 at 10:21
  • 1
    \$\begingroup\$ @Kaarez Yes, frustum culling is used too, but that usually only accounts for chunks that are "behind your back", while marching cubes(or something similar) transform voxels to show only faces that are visible(you don't render the rock that is buried underground, you don't even generate vertices for it.) \$\endgroup\$
    – akaltar
    Commented Jul 7, 2015 at 10:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .