Voxel - a start

I don’t know how much you know about (vertex & fragment) shader but you might want to look into setting positions via a shader uniform rather than modifying the vertex data itself (which is much more expensive). Since you’re already useing OpenGL 3.1+ (VBOs) you might as well use shaders as well - if you are not using them already.

The loop would look something like that:

  1. use shader program (glUseProgram) and upload the uniform offset (glUseUniform)
  2. render the vbo
  3. get the next vbo and continue

Of course this only works as described if all vertices share the same offset which should be the case with chunks.

Don’t you mean OpenGL 2.1? Pretty sure vbos and shaders are standard in that.
But I agree completely, shaders are the way forward. I used to try and find “smart” ways of doing things without using shaders but it’s just pointless. It’s inefficient for you and your computer. Shaders are just simple. As soon as I read the first tutorial, I realized that and cursed for all the time I’d wasted avoiding them.

Hi,

My gfx card in my macbook pro supports up to 2.1.

I’m familiar with shaders in DirectX.

Just would like to do this without shaders first, so was asking the question, how do you store all the geometry i.e.chunk in one display list and then render that?

Thanks

Hi,

Ok, I’ve done the following to put a whole chunk into a display list:


// Create a chunk and store in display list
private void createChunkVoxel() {
		chunkList = glGenLists(1);  // this hard coded value will need changing as some point
		glNewList(chunkList, GL_COMPILE);
		createDisplayList();
		glEndList();
	}

private void createDisplayList() {

		
			Chunk c = ChunkManager.getInsance().GetChunk(0);
	
			for (int x = 0; x < c.CHUNK_SIZE; x++) {
				for (int y = 0; y < c.CHUNK_SIZE; y++) {
					for (int z = 0; z < c.CHUNK_SIZE; z++) {
						GL11.glPushMatrix();
						
						glTranslatef(x,y,z);
                                                // Only create block if it is active
                                                if(c.GetBlock(x,y,z).isActive())
						    renderCube();
						GL11.glPopMatrix();
					}
				}
			}
		
	}

private void renderCube() {

		//GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
		glBegin(GL11.GL_QUADS);
			glColor3f(0.0f, 1.0f, 0.0f);
			glVertex3f(1.0f, 1.0f, -1.0f);
			glVertex3f(-1.0f, 1.0f, -1.0f);
			glVertex3f(-1.0f, 1.0f, 1.0f);
			glVertex3f(1.0f, 1.0f, 1.0f);
			
			glColor3f(0.0f, 0.4f, 0.0f);
			glVertex3f(1.0f, -1.0f, 1.0f);
			glVertex3f(-1.0f, -1.0f, 1.0f);
			glVertex3f(-1.0f, -1.0f, -1.0f);
			glVertex3f(1.0f, -1.0f, -1.0f);
			
			glColor3f(0.0f, 0.8f, 0.0f);
			glVertex3f(1.0f, 1.0f, 1.0f);
			glVertex3f(-1.0f, 1.0f, 1.0f);
			glVertex3f(-1.0f, -1.0f, 1.0f);
			glVertex3f(1.0f, -1.0f, 1.0f);
			
			glColor3f(0.0f, 0.7f, 0.0f);
			glVertex3f(1.0f, -1.0f, -1.0f);
			glVertex3f(-1.0f, -1.0f, -1.0f);
			glVertex3f(-1.0f, 1.0f, -1.0f);
			glVertex3f(1.0f, 1.0f, -1.0f);
			
			glColor3f(0.0f, 0.6f, 0.0f);
			glVertex3f(-1.0f, 1.0f, 1.0f);
			glVertex3f(-1.0f, 1.0f, -1.0f);
			glVertex3f(-1.0f, -1.0f, -1.0f);
			glVertex3f(-1.0f, -1.0f, 1.0f);
			
			glColor3f(0.0f, 0.5f, 0.0f);
			glVertex3f(1.0f, 1.0f, -1.0f);
			glVertex3f(1.0f, 1.0f, 1.0f);
			glVertex3f(1.0f, -1.0f, 1.0f);
			glVertex3f(1.0f, -1.0f, -1.0f);
		glEnd();
	}

And then in my update I just call:


glCallList(chunkList);

This does the whole chunk in one go, does this seem correct?
Before I was create a display list just for one cube, not a whole chunk, now just have one call to
draw a chunk, not 4096 (which is 4096 glTranslatef calls too!).

I guess I need to have an array of display lists for each chunk? How many display lists
can you have? PS - I’m doing it this way before eventually moving onto VBO’s, want to walk
before I can run, and hey, Notch used display lists :slight_smile:

Thanks

Hi there!

How about using no glTranslate’s at all?
It’s very easy!

Modified Code:


// Vertex Offset Variables
private int tx = 0;
private int ty = 0;
private int tz = 0;

// Create a chunk and store in display list
private void createChunkVoxel() {
      chunkList = glGenLists(1);  // this hard coded value will need changing as some point
      glNewList(chunkList, GL_COMPILE);
      createDisplayList();
      glEndList();
   }

private void createDisplayList() {

      
         Chunk c = ChunkManager.getInsance().GetChunk(0);
   
         for (int x = 0; x < c.CHUNK_SIZE; x++) {
            for (int y = 0; y < c.CHUNK_SIZE; y++) {
               for (int z = 0; z < c.CHUNK_SIZE; z++) {
                   // Only create block if it is active
                   if(c.GetBlock(x,y,z).isActive()){
                       
                       // Since your blocks are 2³ Units big, we have to multiply the coordinates by the blocks size.
                       tx = x * 2;
                       ty = y * 2;
                       tz = z * 2;
                       
                       // Render the Cube
                       renderCube();
                   }
               }
            }
         }
      
   }

private void renderCube() {

      //GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
      glBegin(GL11.GL_QUADS);
         glColor3f(0.0f, 1.0f, 0.0f);
         off_glVertex3f(1.0f, 1.0f, -1.0f);
         off_glVertex3f(-1.0f, 1.0f, -1.0f);
         off_glVertex3f(-1.0f, 1.0f, 1.0f);
         off_glVertex3f(1.0f, 1.0f, 1.0f);
         
         glColor3f(0.0f, 0.4f, 0.0f);
         off_glVertex3f(1.0f, -1.0f, 1.0f);
         off_glVertex3f(-1.0f, -1.0f, 1.0f);
         off_glVertex3f(-1.0f, -1.0f, -1.0f);
         off_glVertex3f(1.0f, -1.0f, -1.0f);
         
         glColor3f(0.0f, 0.8f, 0.0f);
         off_glVertex3f(1.0f, 1.0f, 1.0f);
         off_glVertex3f(-1.0f, 1.0f, 1.0f);
         off_glVertex3f(-1.0f, -1.0f, 1.0f);
         off_glVertex3f(1.0f, -1.0f, 1.0f);
         
         glColor3f(0.0f, 0.7f, 0.0f);
         off_glVertex3f(1.0f, -1.0f, -1.0f);
         off_glVertex3f(-1.0f, -1.0f, -1.0f);
         off_glVertex3f(-1.0f, 1.0f, -1.0f);
         off_glVertex3f(1.0f, 1.0f, -1.0f);
         
         glColor3f(0.0f, 0.6f, 0.0f);
         off_glVertex3f(-1.0f, 1.0f, 1.0f);
         off_glVertex3f(-1.0f, 1.0f, -1.0f);
         off_glVertex3f(-1.0f, -1.0f, -1.0f);
         off_glVertex3f(-1.0f, -1.0f, 1.0f);
         
         glColor3f(0.0f, 0.5f, 0.0f);
         off_glVertex3f(1.0f, 1.0f, -1.0f);
         off_glVertex3f(1.0f, 1.0f, 1.0f);
         off_glVertex3f(1.0f, -1.0f, 1.0f);
         off_glVertex3f(1.0f, -1.0f, -1.0f);
      glEnd();
   }

// Draw a vertex with a offset.
private void off_glVertex3f(float x,float y,float z){
         glVertex3f(tx+x,ty+y,tz+z);
}

You could also move the glBegin/glEnd’s out of the renderBlock Method into the createDisplayList Method, wich would give you even more performance.

  • Longor1996

Cool :slight_smile:

Thanks again, really appreciate your help.

This is what I’ve got in createDisplayList now:


private void createDisplayList() {

		for(int chunkAmount = 0; chunkAmount < 1;/*chunkManager.GetChunkCount(); */chunkAmount++)
		{
			Chunk c = ChunkManager.getInsance().GetChunk(0);
	
			for (int x = 0; x < c.CHUNK_SIZE; x++) {
				for (int y = 0; y < c.CHUNK_SIZE; y++) {
					for (int z = 0; z < c.CHUNK_SIZE; z++) {
						GL11.glPushMatrix();						
						glTranslatef(x,y,z);
						if(c.GetBlock(x,y,z).IsActive())
						{
							
							glBegin(GL11.GL_QUADS);
							renderCube();
							glEnd();
						}
						GL11.glPopMatrix();
					}
				}
			}
		}
	}

This look ok?

The offsets on the vertices is obvious now :wink:

Just need introduce another variable for the chunk offset :slight_smile:

Steve

Quick update, added offset which is basically chunk number we are up to, also
draws the correct chunk.


private void createDisplayList(int chunkNumber) {

		tx = 0; ty = 0; tz = 0;

			Chunk c = ChunkManager.getInsance().GetChunk(chunkNumber);  
	
			for (int x = 0; x < Chunk.CHUNK_SIZE; x++) {
				for (int y = 0; y < Chunk.CHUNK_SIZE; y++) {
					for (int z = 0; z < Chunk.CHUNK_SIZE; z++) {
						GL11.glPushMatrix();						
					
						if(c.GetBlock(x,y,z).IsActive())
						{
							tx = ((chunkNumber * Chunk.CHUNK_SIZE) << 1) + (x << 1);
		                    ty = y << 1;
		                    tz = z << 1;
							glBegin(GL11.GL_QUADS);
							   renderCube();
							glEnd();
						}
						GL11.glPopMatrix();
					}
				}
			}
	}

Hi again,

Just wondering, when I get height from simplex noise, if it is zero I set it to one so at least a block is drawn - thus we have floor, is this correct?

Regards,
Steve

You should add a number to that height instead. For example, have a default ground area of 10 blocks of height.

so height + 10 should be your end height.

Cheers Argo, so height of 10 blocks instead of 1 then when height is 0? Would doing that
now screw up my array - i.e. arrayIndexOutOfBounds possibly? Or are you saying draw
a ground area separately?

Link to what I have so far:

Does that look ok? Just rendering the same chunk, and a sphere.

Created a ChunkManager Singleton now which takes care of rendering the chunks.

Modified my chunk class to take in offsets for chunk position:


private void createChunkList() {

		tx = 0; ty = 0; tz = 0;

		for (int x = 0; x < Chunk.CHUNK_SIZE; x++) {
			for (int y = 0; y < Chunk.CHUNK_SIZE; y++) {
				for (int z = 0; z < Chunk.CHUNK_SIZE; z++) {
					if(GetBlock(x,y,z).IsActive())
					{
						tx = ((xOffset * Chunk.CHUNK_SIZE) << 1) + (x << 1);
	                    ty = ((yOffset * Chunk.CHUNK_SIZE) << 1) + (y << 1);
	                    tz = ((zOffset * Chunk.CHUNK_SIZE) << 1) + (z << 1);

						glBegin(GL11.GL_QUADS);
						   renderBlock();
						glEnd();
					}
				}
			}
		}
	}


Simple matter to add a chunk to the world now:

Example:


ChunkManager.getInstance().AddChunk(ChunkType.ChunkType_Land,3,0,3);
ChunkManager.getInstance().AddChunk(ChunkType.ChunkType_Sphere,2,2,2);

An another note, what is best way of drawing block trees and display a wired cube around my chunks for debug purposes?

Also, I’m using display lists to render each chunk, anyways of speeding things up even when using display lists?

First time using OpenGL and I must say, it is great and the people on this forum are awesome!

Thanks,
Steve

Hi,

Added optimisation so we only draw blocks that aren’t hidden by there neighbours, this saves drawing
a lot of unwanted blocks!


	private int createChunkList() {

		tx = 0; ty = 0; tz = 0;
		int iHidden = 0;
		int iBlockCount = 0;

		boolean bDefault = true;
		for (int x = 0; x < Chunk.CHUNK_SIZE; x++) {
			for (int y = 0; y < Chunk.CHUNK_SIZE; y++) {
				for (int z = 0; z < Chunk.CHUNK_SIZE; z++) {
					if(!GetBlock(x,y,z).IsActive())  // 
					{
						continue;
					}
					bLeft = bDefault;
					if(x > 0)
					{
						bLeft = Blocks[x-1][y][z].IsActive();
					} else bLeft = false;
					bRight = bDefault;
					if(x < Chunk.CHUNK_SIZE - 1)
					{
						bRight = Blocks[x+1][y][z].IsActive();
					} else bRight = false;
					bAbove = bDefault;
					if(y > 0)
					{
						bAbove = Blocks[x][y-1][z].IsActive();
					} else bAbove = false;
					bBelow = bDefault;
					if(y < Chunk.CHUNK_SIZE - 1)
					{
						bBelow = Blocks[x][y+1][z].IsActive();
					} else bBelow = false;
					bFront = bDefault;
					if(z > 0)
					{
						bFront = Blocks[x][y][z-1].IsActive();
					} else bFront = false;
					bBack = bDefault;
					if(z < Chunk.CHUNK_SIZE - 1)
					{
						bBack = Blocks[x][y][z+1].IsActive();
					} else bBack = false;
					
					boolean bResult = bLeft & bRight & bAbove &
							          bBelow & bFront & bBack;
					
					if(!bResult) // Block is not hidden by neighbouring blocks
					{
						tx = ((xOffset * Chunk.CHUNK_SIZE) << 1) + (x << 1);
	                    ty = ((yOffset * Chunk.CHUNK_SIZE) << 1) + (y << 1);
	                    tz = ((zOffset * Chunk.CHUNK_SIZE) << 1) + (z << 1);

						glBegin(GL11.GL_QUADS);
						   renderBlock();
						glEnd();
						iBlockCount++;   // total of blocks that can be seen
					}
					else
						iHidden++;   // amount of blocks that are surrounded
				}
			}
		}
		System.out.println("Block amount hidden by neighbours:" + iHidden +
				" and Block total rendered:" + iBlockCount);
		return iBlockCount;

	}

Next will be to add some FrustumCulling.

Anybody any tips on when to set blocks to certain types…i.e.dirt, grass…would this be dependant
on the height value?

Thanks

Hi,

I am wanting to cull chunks of my voxels (those that don’t appear in the view frustum).

I was wondering, am I correct or completely wrong in saying that I cull on a per chunk basis, not per block as my geometry is already at the GPU?

Also, is it correct to use an Octree structure when frustum culling in a voxel engine? Any tips?

Thanks,
Steve

merged :clue:

Ooops, sorry about that.
::slight_smile:

Hi, would you be able to show a picture of your game/rendering. I’m doing the same thing and I’m interested how yours is looking. Much of your post is interesting and relevant to mine also.

Will keep popping back to see how it’s going.

Hi,

No probs, here is a small video of it:


http://www.youtube.com/watch?v=zlBbj4kzkY8

Did you first use display lists, should I switch to VBO’s? Mine is still display lists, running
on my Macbook pro which only has the intel HD gfx 3000 video card, guess this isn’t
very good?

Thanks

That’s looking good, I like the lighting and the skybox. Thanks for posting that. I started with immediate mode. And I’m trying VBO but its quite a learning curve. Though it does draw much faster for me.

Looks like an interesting project, will keep checking on ur progress.

Thanks,

Display lists seem to be performing fine for me, I’ve put some stuff into VBO’s and tested, doesn’t seem too bad to do, although it looks like it depends on the version of OpenGL you are using with some of the methods as they do change a lot?!

Think if I put in frustum culling, will need to partition the space up, octree comes to mind, have you implemented one in your project?

Thanks

Hi

My space is partitioned into 16^3 chunks. But no frustum culling or octree. I’m still struggling with the VBO’s at the moment! Then I think I’ll look at terrain generation next!

Hi,

What do you mean by your space is partitioned into 16^3 chunks? I guess you mean
you re using chunks of 16x16x16, this is the same as me.

What would be needed is to use an octree structure to partition the world into smaller spaces, thus when doing frustum culling there isn’t as many checks to do - I can’t really see the point of doing frustum culling without space partitioning unless somebody tells me otherwise?

I’m also doing neighbouring checks on the blocks so blocks that are hidden by other blocks aren’t rendered.

Cheers