\\ Home : Articoli : Stampa
Primitive
Di robydx (del 06/02/2010 @ 16:15:19, in Direct3D11, linkato 1860 volte)

Direct3D è un renderizzatore di triangoli. L’evoluzione ha portato alla possibilità di aumentarne sempre più la flessibilità, dai formati fissati di Direct3D7 fino alla completa flessibilità raggiunta con Direct3D9 ed in particolare con la versione 10.

I triangoli vengono raccolti all’interno di buffer di memoria chiamati Vertex Buffer che vengono ordinati o secondo l’ordine all’interno dello stesso o tramite un ordine inserito in un secondo buffer (Index Buffer).

Un vertice può essere una qualsiasi struttura e per questo occorre far in modo che lo Shader legga correttamente il dato. Questa informazione va creata in apposito oggetto: l’input layout.

Prendiamo una struttura definita nel codice C++

Struct Vertex

{

float x; float y; float z;

float nx; float ny; float nz;

float tu; float tv;

};

E l’ equivalente struttura nel codice shader;

struct VertexHLSL

{

float3 pos:POSITION;

float3 nrm:NORMAL;

float2 tex:TEXCOORD;

};

Ora creiamo un layout che descriva come i dati della prima vengono mappati nella seconda.

D3D11_INPUT_ELEMENT_DESC desc[] = {

{ "POSITION", 0,DXGI_FORMAT_R32G32B32_FLOAT , 0, 0,D3D11_INPUT_PER_VERTEX_DATA , 0 },

{ " NORMAL ", 0,DXGI_FORMAT_R32G32B32_FLOAT , 0, 12,D3D11_INPUT_PER_VERTEX_DATA , 0 },

{ " TEXCOORD ", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,D3D11_INPUT_PER_VERTEX_DATA , 0 },

};

La struttura inputLayoutDesc indica il formato di ogni componente del vertice, la semantica e la posizione nel buffer dell’elemento. Tramite questa struttura lo shader saprà quali elementi andare a prendere. Non è infatti importante l’ordine, l’importante è che ogni valore nello shader sappia in quale punto della struttura leggere.

L’oggetto dedicato a contenere tale informazione è

ID3D11InputLayout* layout;

device->CreateInputLayout(desc, count,bytecode,bytecodeSize,&layout);

Count indica il numero di InputElement presenti. Il parametro bytecode è il codice compilato del Vertex Shader. In questo modo la struttura viene confrontata con lo shader generando un errore se non corretto. BytecodeSize è invece la dimensione.

Una cosa molto utile è sapere che un elemento composto da 2 o 3 float nel vertex buffer può essere passato ad un float4 in uno shader. Se quindi carichiamo la posizione XYZ può essere inserita in un float4. I valori mancanti verranno riempiti con 0 nel caso della Y o della Z e 1 nel caso di W (il quarto elemento).

Ora defininiamo un array di vertici. Il minimo elemento renderizzabile è 1 triangolo, quindi 3 vertici

ID3D11Buffer* vertexBuffer;

D3D11_BUFFER_DESC bd;

bd.Usage = D3D11_USAGE_DEFAULT;

bd.ByteWidth = 32 * 3;

bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;

bd.CPUAccessFlags = 0;

bd.MiscFlags = 0;

VERTEX vertices[3];

…..qui va valorizzato il nostro array

D3D11_SUBRESOURCE_DATA data;

data.pSysMem=vertices;

device->CreateBuffer(&bd,&data,&vertexBuffer);

In questo modo abbiamo creato il nostro vertexBuffer e riempito.

Ora possiamo finalmente renderizzarlo. Passiamo al DeviceContext il vertexBuffer, l’inputLayout, gli shaders, i constantBuffer ed eseguiamo il metodo Draw.

context->IASetInputLayout(layout);

context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

UINT strides[]={32};

UINT offsets[]={0};

ID3D11Buffer* buffers[]= { vertexBuffer };

manager->context->IASetVertexBuffers(0,1,buffers,strides,offsets);

context->Draw(3,0);

Stride dà la dimensione di ogni vertice, offset la posizione da cui iniziare a leggere (per iniziare a leggere da punti diversi del buffer ad esempio). Vengono passati come array in quanto è possibile utilizzare più buffer contemporaneamente.

La topologia indica come sono organizzati i vertici. TriangleList indica che ogni 3 vertici viene chiuso un triangolo. Esistono altre topologie che permettono di risparmiare triangoli (esempio triangleStrip crea il ogni triangolo usando i 2 vertici precedenti). Osservate l’immagine sottostante.

I punti di adiancency indicano punti esterni al triangolo ma adiacenti allo stesso (il geometry shader ha bisogno di sapere quali sono i triangoli ad esso adiacenti).

Vi lascio agli esempi in cui renderizzeremo 1 triangolo.

Demo CPP

Demo .Net