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.
Per rappresentarla con il solo vertex buffer sono necessari 2 triangoli, quindi un array di 6 vertici.
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
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 i punti sono 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
ID3D10Buffer* indexBuffer;
short indices[6];
indices[0]=0;
indices[1]=1;
indices[2]=2;
indices[3]=3;
indices[4]=0;
indices[5]=2;
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = 2* indexCount;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D10_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.
device->IASetIndexBuffer( indexBuffer, format, offset );
Con questa istruzione si inserisce nel device 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
device->DrawIndexed( IndexCount, StartIndexLocation, BaseVertexLocation );
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.
I commenti sono disabilitati.