\\ Home : Articoli : Stampa
Index Buffer
Di robydx (del 28/02/2010 @ 10:41:33, in Direct3D11, linkato 1811 volte)

Con i vertex buffer tutta la descrizione geometrica è contenuta sotto forma di array di strutture in un buffer.

Questo presenta un grosso svantaggio. Osservate questa immagine.

http://www.notjustcode.it/public/Indexbuffer_D6F1/1_thumb.jpg

Per rappresentarla con il solo vertex buffer sono necessari 2 triangoli, quindi un array di 6 vertici.

http://www.notjustcode.it/public/Indexbuffer_D6F1/2_thumb1.jpg

Due di questi però sono in effetti dei duplicati. Nell'immagine del vertex buffer potete vedere che i vertici 0 e 4, come quelli 2 e 5 sono identici. Questo è uno spreco di memoria. Se ad esempio i vertici avessero contenuto posizione XYZ e coordinate texture UV sarebbero stati sprecati 5 float per vertice, un totale di 40byte su una oggetto di 120 byte, il 33%. All'aumentare della complessità aumenta lo spreco di memoria ma soprattutto aumentano i vertici da processare. Il vertex shader viene eseguito 1 volta per ogni vertice ed in questo modo sarebbe eseguito più volte del necessario.

Per questo esistono gli index buffer

http://www.notjustcode.it/public/Indexbuffer_D6F1/3_thumb1.jpg

Nei rendering indicizzati il vertex buffer contiene vertici senza duplicati, disposti senza un ordine. L'indexbuffer conterrà invece l'ordine con cui tali vertici devono essere presi per formare triangoli. Sono sufficienti valori short (2 byte) per indicizzare oggetti con 65000 vertici, ma potrete utilizzare anche interi (4byte) ed indicizzare oltre 4 miliardi di vertici. Nel nostro caso quindi avremo un array di 6 short, 12 byte ma ne risparmieremo 40 ed avremo 2 vertici in meno da far processare al vertex shader.

Per figure molto più complesse il vantaggio diventa esponenziale. Un cubo ad esempio ha 12 triangoli, 36 vertici. Con i vertex buffer occuperebbero 

36 * 5 float = 720 byte.

Ma, dato che in realtà solo 8 vertici sono unici avremo un vertex buffer di soli

8 x 5 float = 40 byte

ed un indexbuffer di 36 indici, quindi soli 72 byte.

Un cubo indicizzato occuperà solo 112 byte contro 720 e dovrà processare solo 8 vertici anzichè 36. Numeri che in una scena complessa fanno la differenza. Mediamente risparmierete almeno il 30%.

Un indexbuffer si crea esattamente come un vertex buffer

ID3D11Buffer* indexBuffer;

short indices[6];
indices[0]=0;

indices[1]=1;

indices[2]=2;

indices[3]=3;

indices[4]=0;

indices[5]=2;

D3D11_BUFFER_DESC bd;
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = 2* indexCount;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
InitData.pSysMem = data;
HRESULT hr=device->CreateBuffer( &bd, &initData, &indexBuffer);

Le proprietà sono le stesse del vertex buffer, l'unica differenza è che si deve indicare come bind il fatto che sia un indexbuffer.

deviceContext->IASetIndexBuffer( indexBuffer, format, offset );

Con questa istruzione si inserisce nel deviceContext il buffer. Occorre passare il buffer, il format (che sarà o DXGI_FORMAT_R16_UINT nel caso di short o DXGI_FORMAT_R32_UINT per gli interi) e l'offset ossia il punto in byte da dove leggere, utile per poter variare il triangolo di inizio ma solitamente impostato a zero.

Per renderizzare si usa l'istruzione

deviceContext->DrawIndexed( IndexCountStartIndexLocationBaseVertexLocation );

Dove indexCount è il numero di indici( e quindi di triangoli) da renderizzare, mentre startIndex e BaseVertex location sono i punti nel vertex e index buffer dove iniziare a prendere i dati, solitamente impostati a zero.

Vi lascio ai demo che contengono una struttura che sarà base per i futuri tutorial. Sono state incluse 2 funzionalità:

La prima è il caricamento da obj, un formato 3D testuale ormai standard. Utilizzando la classe fornita negli esempi potrete caricare un modello 3D pronto da essere usato. La versione .Net è stata creata dal sottoscritto mentre quella C++ da una libreria open source trovata in rete (approfitto per fare i ringraziamenti all’autore che mi ha fatto risparmiare tantissimo tempo tra sviluppo e test).

Il secondo regalo è una classe per la gestione dei font. Dato che in Direct3D11 non esiste più un’interfaccia dedicata alla scrittura di testo ho provveduto personalmente a creare una semplice alternativa interamente in shader (in pratica avete una texture con i caratteri già pronti e lo shader processerà la stringa che gli passerete).

 

Demo CPP

Demo .Net