Calling DrawPrimitive Heaps

Started by
3 comments, last by BMW 10 years, 9 months ago

Hi all,

In my voxel engine similar to Minecraft, I draw each side of each block separately, like this:


for(unsigned int i = 0; i < BLOCKS_PER_CHUNK; i++)
{
	if(blocks[i].type == BLOCKTYPE_AIR)
		continue;

	if(blocks[i].BackFaceVisible)
	{
		g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 4, 2);
	}
	if(blocks[i].FrontFaceVisible)
	{
		g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK), 2);
	}
	if(blocks[i].LeftFaceVisible)
	{
		g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 8, 2);
	}
	if(blocks[i].RightFaceVisible)
	{
		g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 12, 2);
	}
	if(blocks[i].TopFaceVisible)
	{
		g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 16, 2);
	}
	if(blocks[i].BottomFaceVisible)
	{
		g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 20, 2);
	}
}

Is it a bad idea to call DrawPrimitive so much like this? Should I use an index buffer and just make one call to DrawIndexedPrimitive?

Advertisement

Yes, it's a very bad idea.

You should render the whole scene with the minimum possible calls to DrawPrimitive. That is, render various cubes at once if possible otherwise performance will degrade very fast.

Reducing DrawPrimitive calls by grouping geometry/materials is called batching. You should find lots of info by google for "geometry batching" and similar terms.

Ok, I will see if I can render an entire chunk using one DrawPrimitive() call. That should help.

You might be much happier doing a DIP call for each block type, so you don't have to mess up to much with shader parameters.

Doing a whole chunk per-DIP is excessive in my opinion and the issues involved in managing the multiple textures have to be carefully considered.

edit: oh, I see you're using a texture atlas from the other thread. No problem then, go ahead!

Previously "Krohm"

You might be much happier doing a DIP call for each block type, so you don't have to mess up to much with shader parameters.

Doing a whole chunk per-DIP is excessive in my opinion and the issues involved in managing the multiple textures have to be carefully considered.

edit: oh, I see you're using a texture atlas from the other thread. No problem then, go ahead!

WOW WOWOWOWOWOWOWOWOWOWOWOW

Using the inferior method as discussed earlier (heaps of draw primitive calls) = 62FPS.

Using new method - 1 DIP call per chunk = 320FPS. THATS IT, THREE HUNDRED AND TWENTY FRAMES PER SECOND. (Considering my laptop has integrated graphics, NOT TOO FOUL!!!!)

THIS IS THE BEST DAY OF MY LIFE.

THANK YOU EVERYONE.

I love game development.

EDIT: Is updating the entire index buffer for the chunk every time a block changes a good idea? It seems to run ok.

This is how I update index buffer:


void Chunk::UpdateIndices()
{
	void* IB = NULL;

	unsigned int* pIBEntry = NULL;

	PrimitiveCount = 0;

	if(g_pIB->Lock(0, BLOCKS_PER_CHUNK * INDICES_PER_BLOCK * 4, &IB, D3DLOCK_DISCARD) != D3D_OK)
		return;

	pIBEntry = (unsigned int*)IB;

	for(unsigned int i = 0; i < BLOCKS_PER_CHUNK; i++)
	{
		if(blocks[i].type == BLOCKTYPE_AIR)
			continue;

		if(blocks[i].FrontFaceVisible)
		{
			*pIBEntry = i * VERTICES_PER_BLOCK;
			*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 1;
			*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 2;
			*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 1;
			*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 3;
			*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 2;
			pIBEntry += 6;
			PrimitiveCount += 2;
		}
		if(blocks[i].BackFaceVisible)
		{
			*pIBEntry = i * VERTICES_PER_BLOCK + 4;
			*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 4 + 1;
			*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 4 + 2;
			*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 4 + 1;
			*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 4 + 3;
			*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 4 + 2;
			pIBEntry += 6;
			PrimitiveCount += 2;
		}
		if(blocks[i].LeftFaceVisible)
		{
			*pIBEntry = i * VERTICES_PER_BLOCK + 8;
			*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 8 + 1;
			*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 8 + 2;
			*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 8 + 1;
			*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 8 + 3;
			*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 8 + 2;
			pIBEntry += 6;
			PrimitiveCount += 2;
		}
		if(blocks[i].RightFaceVisible)
		{
			*pIBEntry = i * VERTICES_PER_BLOCK + 12;
			*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 12 + 1;
			*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 12 + 2;
			*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 12 + 1;
			*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 12 + 3;
			*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 12 + 2;
			pIBEntry += 6;
			PrimitiveCount += 2;
		}
		if(blocks[i].TopFaceVisible)
		{
			*pIBEntry = i * VERTICES_PER_BLOCK + 16;
			*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 16 + 1;
			*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 16 + 2;
			*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 16 + 1;
			*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 16 + 3;
			*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 16 + 2;
			pIBEntry += 6;
			PrimitiveCount += 2;
		}
		if(blocks[i].BottomFaceVisible)
		{
			*pIBEntry = i * VERTICES_PER_BLOCK + 20;
			*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 20 + 1;
			*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 20 + 2;
			*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 20 + 1;
			*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 20 + 3;
			*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 20 + 2;
			pIBEntry += 6;
			PrimitiveCount += 2;
		}
	}

	g_pIB->Unlock();
}

This topic is closed to new replies.

Advertisement