Direct3D Vertexbuffers & Indexbuffers

Voordat je aan deze tutorial begint is het belangrijk dat je alle voorgaande direct3d tutorials hebt gelezen.

Ik heb besloten ook wat direct3d kennis te delen in de vorm van tutorials. De eerste zal gaan over indexbuffers. In het kort: arrays die direct3d aangeven welke vertices moeten worden verbonden om driehoeken (ookwel triangles of faces of polygonen of indices) genoemd te maken. Het voordeel hiervan boven het niet gebruiken van een indexbuffer is dat je op deze manier 1 vertex meerdere keren kan gebruiken. Dit scheelt geheugen, en bij sommige videokaarten gaat dit ook sneller. Voor triangles moeten we ook (net als bij vertices) een struct definieren:

		struct sFace
		{
		  unsigned short v0, v1, v2;
		}; 
		

v0, v1 en v2 zijn hier een index in een vertexbuffer. Faces worden in direct3d 'counter-clockwise' gedefinieerd, in tegenstelling tot opengl. Een face heeft altijd 2 kanten. Een voorkant en een achterkant. De voorkant is de kant waarbij, als je er naar 'kijkt', de vertices tegen de richting van de wijzers klok in gedefinieerd zijn. Dit moet echt met een plaatje verduidelijkt worden.

Een face gezien van de voorkant Een face gezien van de achterkant


Hm, ik hoop dat 't helpt. Direct3D tekent alleen de faces die, nadat alle transformaties zijn toegepast, met hun voorkant naar het 'scherm' gericht zijn1. Je snapt natuurlijk dat dit wordt gedaan om performance redenen. Voor de duidelijkheid nog een voorbeeld van een definitie van een face:

 CUSTOMVERTEX cvVertices[4]; cvVertices[0] = {-1.0f, -1.0f, 0.5f, 0xffff0000,}; //
		x, y,z, colour cvVertices[1] = { 1.0f, -1.0f,
		0.5f, 0xffff0000,}; cvVertices[2]  = {-1.0f, 1.0f, 0.5f,
		0xffff0000,}; cvVertices[3] = {  1.0f, 1.0f, 0.5f, 0xffff0000,};
		
		//..
				
		sFace indexb[2];
		indexb[0].v0 = 0;
		indexb[0].v1 = 1;
		indexb[0].v2 = 2;

		indexb[1].v0 = 1;
		indexb[1].v1 = 3;
		indexb[1].v2 = 2;
		

Oke, we moeten nu ook een direct3d interface hebben net zoals voor bijna alless in direct3d.

		IDirect3DIndexBuffer9* g_pIndexBuffer;
		
		//..
		
		// Create indexbuffer in device
		if (FAILED(g_pd3ddevice->CreateIndexBuffer
					(
						sizeof(sFace) * 2, 
						D3DUSAGE_WRITEONLY,
						D3DFMT_INDEX16,
						D3DPOOL_DEFAULT, 
						&g_pIndexBuffer
					))) 
		{
			return E_FAIL;
		};

De 1e parameter geeft de grootte van de buffer aan, in dit geval 3x een face. De 2e parameter is de usage, deze kan je het beste op writeonly zetten, aangezien we er toch alleen in gaan schrijven. D3DPOOL_DEFAULT geeft aan dat we de vertex buffer op de best geschikte plaats gebruiken. In de inmiddels 5e parameter komt het geheugenadres van de buffer.

		void* pFaces;
		// get pointer to index buffer and lock it
		if(FAILED(g_pIndexBuffer->Lock(0, 0, (void**)&pIndices, 0)))
		{
			return E_FAIL;
		}
		// copy stored faces in index buffer
		
		memcpy(pFaces, indexb, sizeof(sFace)*2);
		
		// unlock
		
		g_pIndexBuffer->Unlock();		
		
		

Dit werkt vrijwel hetzelfde als het locken van een vertexbuffer. (zie D3D Weergeven)

Tot zover hebben we alleen nog dingen aan ons programma toegevoegd, maar nu gaan we ook dingen veranderen, namelijk de renderloop. Op de plaats waar we eerst deze functie aanroepten:

		g_pd3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, 1);

Komt nu dit te staan:

		// setting the indexbuffer that should be used to construct the triangles		
		g_pd3ddevice->SetIndices(g_pIndexBuffer, 0);
		
		g_pd3ddevice->DrawIndexedPrimitive(
							D3DPT_TRIANGLELIST, 
							0, 
							4,	// Number of vertices in our vertexbuffer
							0, 
							2	// Number of faces in our indexbuffer
						  );
		
		

Zoals je ziet gebruiken we nu DrawIndexedPrimitive dat natuurlijk aangeeft dat we een indexbuffer gebruiken, in plaats van 3-tallen vertices achter elkaar in 1 vertexbuffer, zoals DrawPrimitive werkt.

Tot zover de indexbuffer tutorial. Voor vragen of opmerkingen of klachten, wat dan ook, mail: apesonline@hotmail.com of voeg dat adres toe bij M$N messenger.


  1. Je kunt Direct3D ook zo instellen dat het ook de achterkant van de faces tekent doormiddel van een renderstate. Dat zal ik later nog bespreken.