0
votes

I programming with C++ + SDL2 + GLEW + Opengl 4.1 a small voxel game a little bit like Minecraft.

I am trying to optimize the voxel rendering where I can.

I slide the world into chunks and this chunks into blocks.

Each chunk contains 16x16x16 blocks.

Now if a edit a chunk(remove/place a block) I rebuild the complete chunk and the neighbor chunk and upload it with vao's and vbo's to the graphic card.

Now to minimize the vertex data I have to transfer from the cpu to the gpu I use geometry shaders.

First of all, is that a good idea?

I mean every frame the geometry shader has to calculate the primitive for each voxel face.

However, I programmed the vertex shader so, that I only have to pass one vertex for each block face.

To make that possible I used a vec4.

The first 3 elements(x, y, z) I used for the block position and the 4. Element (w) I used to indicate in which direction the face is showing.

0 means back, 1 means front, 2 means left, 3 means right, 4 means bottom, 5 means top.

Please ignore the UV and the normal for now.

Further more I upload GLbyte's instead of GLfloat's.

Is that a good idea?

What would be a better/faster way?

    #version 410 

    uniform mat4 un_Combined; 

    layout(points) in; 
    layout(triangle_strip, max_vertices = 4) out; 

    in vec2 ge_UV[]; 

    out vec2 fr_UV; 
    out vec3 fr_Normal; 

    void main() 
    { 

        vec4 o = gl_in[0].gl_Position.xyzw; 

        if(o.w == 0) 
        { 
            gl_Position = un_Combined * vec4(o.x, o.y, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y + 1, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y + 1, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, -1); 
            EmitVertex(); 
        } 
        else 
        if(o.w == 1) 
        { 
            gl_Position = un_Combined * vec4(o.x + 1, o.y, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y + 1, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y + 1, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 
        } 
        else 
        if(o.w == 2) 
        { 
            gl_Position = un_Combined * vec4(o.x, o.y, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y + 1, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y + 1, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(-1, 0, 0); 
            EmitVertex(); 
        } 
        else 
        if(o.w == 3) 
        { 
            gl_Position = un_Combined * vec4(o.x + 1, o.y, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y + 1, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y + 1, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(1, 0, 0); 
            EmitVertex(); 
        } 
        else 
        if(o.w == 4) 
        { 
            gl_Position = un_Combined * vec4(o.x + 1, o.y, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, -1, 0); 
            EmitVertex(); 
        } 
        else 
        { 
            gl_Position = un_Combined * vec4(o.x, o.y + 1, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y + 1, o.z + 1, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x, o.y + 1, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 0, 1); 
            EmitVertex(); 

            gl_Position = un_Combined * vec4(o.x + 1, o.y + 1, o.z, 1); 
            fr_UV = vec2(0, 0); 
            fr_Normal = vec3(0, 1, 0); 
            EmitVertex(); 
        } 

        EndPrimitive(); 
    }
1
Too bad you're not using 4.3, then you could run compute shaders to generate the chunks.Dietrich Epp
Thanks, I didn't knew the "compute shader" it seems to be another good approach.Michael Buschmann

1 Answers

3
votes

You can test yourself, but in general, the geometry shader will slow things down rather than speed things up. From what I understand, AMD GPUs have a special case for geometry shaders which always output exactly 4 vertexes (true in this case) and the Intel GPUs can have fast geometry shaders relative to other GPUs, but in general, without the fixed output size optimization, the different geometry shaders will have to be synchronized. So, you may be hitting the fast cases here on some or many or most implementations, but you would have to test.

Consider that the vertex data might not be very large anyway: say, 8 bytes per vertex, or 32 bytes per face. You can even reuse the same index buffer for all chunks (e.g. 0, 1, 2, 3, 0xffff, 4, 5, 6, 7, 0xffff, …). This transforms the problem into a very traditional time-vs-space tradeoff. You can either spend more time in the geometry shader or spend more space storing the full vertex data. Is your program running into memory limits? Or are you running into computation limits? Test.

Note that your geometry shader could be written branchless. Instead of using if/else, you can just use an array to store the basis vectors for the output of faces in each direction.