Home Page Twitter Facebook Feed RSS
NotJustCode
Apri

Vertex Buffer 1548 Visite) DirectX 12

DirectX lavora essenzialmente con buffer di memoria. Le schede video devono solo sapere cosa fare con ognuno.

Il primo buffer é il Vertex Buffer, contenente i vertici che comporranno i triangoli del nostro modello. Nel precedente tutorial abbiamo creato una pipeline per gestire vertici contenenti posizione e colore.

Creiamo quindi una struttura per rappresentare questo tipo di vertice.

struct Vertex

{

public Vector3 position;

public Vector4 color;

};

Quindi popoliamo un array con 3 punti a formare un triangolo.

 

Vertex[] triangleVertices = new Vertex[]

{

new Vertex() {position=new Vector3(0.0f, 0.25f , 0.0f ),color=new Vector4(1.0f, 0.0f, 0.0f, 1.0f ) },

new Vertex() {position=new Vector3(0.25f, -0.25f , 0.0f),color=new Vector4(0.0f, 1.0f, 0.0f, 1.0f) },

new Vertex() {position=new Vector3(-0.25f, -0.25f , 0.0f),color=new Vector4(0.0f, 0.0f, 1.0f, 1.0f ) },

};

ora creiamo un buffer per contenere questo dato.

Resource vertexBuffer = device.CreateCommittedResource(new HeapProperties(HeapType.Upload), HeapFlags.None, ResourceDescription.Buffer(vertexBufferSize), ResourceStates.GenericRead);

In Direct3D12 qualsiasi buffer é una risorsa di tipo committed. Sarà il Device a crearlo impostando il tipo di Heap (nel nostro caso Upload che indica che andremo dalla cpu alla gpu), lo stato (GenericRead, quindi lettura) e, tramite la struttura ResourceDescription, tutte le caratteristiche. Questa struttura é comune per ogni tipologia di risorse quindi ci sono metodi per impostarla velocemente in base al tipo.

 Il metodo Buffer crea la struttura corretta passandogli la sola dimensione in byte per contenere tutti i dati. Il conto é semplice: la nostra struttura ha 2 vettori, uno da 3 e uno da 4, quindi 7 x 4 (dimensione del float) x 3 (numero di vertici) = 84

C'è comunque un utility in SharpDX per calcolare il tutto.

int vertexBufferSize = Utilities.SizeOf(triangleVertices);

Creato il buffer possiamo scriverci sopra i dati

IntPtr pVertexDataBegin = vertexBuffer.Map(0);

Utilities.Write(pVertexDataBegin, triangleVertices, 0, triangleVertices.Length);

vertexBuffer.Unmap(0);

I metodi map e unmap bloccano la risorsa in una posizione di memoria nella cpu dandoci un puntatore IntPtr. Questo contiene l'indirizzo di memoria da cui partire per leggere e scrivere.

Ora che la risorsa é creata e popolata dobbiamo creare un oggetto che descriva il buffer per aiutare Direct3D.

VertexBufferView vertexBufferView = new VertexBufferView();

vertexBufferView.BufferLocation = vertexBuffer.GPUVirtualAddress;

vertexBufferView.StrideInBytes = Utilities.SizeOf<Vertex>();

vertexBufferView.SizeInBytes = vertexBufferSize;

Il vertexBufferView rappresenta una vista su un vertex buffer. Sarà questo ciò che useremo. Notare i parametri richiesti: l'indirizzo di memoria del buffer, la dimensione di ogni vertice e la dimensione totale del buffer.

Già qui si può fare un ragionamento del potenziale di Direct3D12: possiamo creare più Viste su ogni buffer!

Basterà posizionare correttamente la posizione del buffer, lo stride, e possiamo salvare tutti gli oggetti in un unico buffer.

Ora possiamo utilizzare il buffer nella command list per disegnarlo:

commandList.PrimitiveTopology = PrimitiveTopology.TriangleList;

commandList.SetVertexBuffer(0, vertexBufferView);

commandList.DrawInstanced(3, 1, 0, 0);

Basta impostare il tipo di vertice, caricare il buffer tramite la vista e lanciare il draw.

Se avete impostato correttamente la pipeline state object verrà eseguito il rendering dell'oggetto seguendo gli Shader che abbiamo creato.

Questo completa il demo Hello Triangle scaricabile dal mio repository personale (link) .