notJustCode.it
 
\\ Home : Articoli
Output Stream
Di robydx (del 30/08/2007 @ 20:45:54, in Direct3D10, linkato 3362 volte)

L’Output Stream è una delle nuove funzionalità di DirectX10, che insieme al Geometry Shader permette di trasportare la gestione dei vertici dalla CPU alla GPU.

L’Output Stream è l’equivalente del Rendering su Texture applicato però al vertex buffer. Quando si utilizza un Output Stream i vertici invece di essere mandati al pixel shader vengono inviati in questo buffer che provvede a conservare questi dati. Successivamente si potrà usare l’Output Stream come una normale mesh contenente tutto ciò che ci abbiamo renderizzato sopra.

L’utilizzo di questa tecnologia permette di accelerare il rendering in modo veramente incredibile.

Facciamo un esempio.

Immaginiamo di creare una scena in cui dobbiamo assemblare molti oggetti diversi tra loro ma che quasi sempre rimarranno immobili. Normalmente renderizzeremo ad ogni frame tutti gli oggetti, con pesanti impatti sulle prestazioni. Ricordo infatti che renderizzare 1000 oggetti da 100 poligoni è immensamente più pesante rispetto a renderizzare 1 oggetto da 100000 poligoni.

L’istancing non ci può aiutare, visto che si limita a creare copie di un solo oggetto, di conseguenza quello che si faceva era creare un’unica mesh contenente tutti i poligoni delle mesh che componevano la scena (tecnica nota come Batching).

Ogni modifica alla scena prevedeva la modifica dei buffer usando la CPU, processo molto più lento.

L’output stream invece lavora usando l’accellerazione hardware permettendoci di fondere più mesh con la stessa velocità con cui le renderizzeremmo.

In ogni momento potremo svuotare il buffer e ricominciare da capo, sempre considerando che la velocità dell’operazione sarà comunque elevatissima (più veloce di un rendering normale in quanto non viene processato alcun pixel shader).

Altro esempio sono i rendering multipass. Capita infatti che una scena durante un frame debba essere processata più volte (ombre, zonly, riflessioni). Ogni volta si deve quindi eseguire il vertex shader ed il geometry shader. Con gli output stream si fa una volta e si conserva il risultato per tutti i passaggi successivi.

Passiamo ora ad illustrare in pratica la tecnologia.

ID3D10Buffer *buffer;

D3D10_BUFFER_DESC bufferDesc =

{

bufferSize,

D3D10_USAGE_DEFAULT,

D3D10_BIND_VERTEX_BUFFER | D3D10_BIND_STREAM_OUTPUT,

0,

0

};

HRESULT hr = device-> CreateBuffer( &bufferDesc, NULL, & buffer );

Il buffer per l’output stream è creato utilizzando come Bind i flags VERTEX_BUFFER e STREAM_OUTPUT. Occorre poi passare una dimensione (variabile bufferSize), misurata in byte. Questa sarà la dimensione massima da destinare ai vertici. Per fare un calcolo, se vogliamo conservare 1000 triangoli con vertice da 32byte (posizione, normale e coordinata texture ad esempio), la dimensione sarà 32 x 3 x 1000= 96000 byte.

La dimensione sarà un tetto oltre il quale DirectX impedirà il rendering (senza tuttavia creare errori).

L’attivazione dell’output stream è molto simile a quella di un render target

UINT offset[]={0};

ID3D10Buffer* temp[1];

temp[0]= buffer;

device-> SOSetTargets( 1, temp, offset );

notate che è possibile passare fino a 4 output stream contemporaneamente, valorizzabili come volete.

Da questo momento non renderizzerete più a video, ma sul buffer. Nel momento in cui inserirete lo stream questo verrà anche svuotato dei precedenti rendering.

Al termine usate questo codice per tornare allo stato originario

UINT offset[]={ 0};

ID3D10Buffer* temp[1];

temp[0]=NULL;

device-> SOSetTargets( 1, temp, offset );

In questo momento il buffer è riempito con quello che avete restituito dal geometry shader. Per il rendering si procede in questo modo

UINT offset[]={0};

UINT strideSize[]={stride};

ID3D10Buffer* temp[]={buffer};

device->IASetInputLayout(layout);

device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

device->IASetVertexBuffers(0,1,temp,strideSize,offset);

device->DrawAuto();

Si utilizza come un normale vertex buffer ad eccezione dell’istruzione DrawAuto. Questa provedderà a stampare tutto il buffer fino alla fine senza dovervi preoccupare di nulla (non potete sapere infatti quanti vertici ci sono dentro).

Ora passiamo allo shader che deve essere un po’ diverso. Innanzittutto non dovete usare pixel shader, solo la geometria verrà esportata. Il vertex ed il geometry shader saranno assolutamente normali (ovviamente dovrete ragionare nell’ottica che ciò che renderizzate non va a video ma su un buffer da usare come mesh). Non dovrete neanche usare le semantiche di sistema (ad esempio SV_POSITION). Il geometry shader (obbligatorio) sarà compilato con l’istruzione ConstructGSWithSO. Qui andrete a specificare il geometry shader da usare e la semantica di ciò che esporterete (nel mio caso POSITION, NORMAL, TEXCOORD).

Questo sarà anche l’input layout da utilizzare quando userete il buffer per il rendering.

Ricordate anche di disabilitare il depth buffer.

DepthStencilState DisableDepth

{

DepthEnable = FALSE;

DepthWriteMask = ZERO;

};

GeometryShader gsS = ConstructGSWithSO( CompileShader( gs_4_0, GS_OUT() ), "POSITION.xyz; NORMAL.xyz; TEXCOORD.xy" );

technique10 Render

{

pass P1

{

SetVertexShader( CompileShader( vs_4_0, VS_OUT() ));

SetGeometryShader(gsS);

SetPixelShader( NULL );

SetDepthStencilState( DisableDepth, 0 );

}

}

Usate sempre l’output stream quando

  1. La stessa scena viene renderizzata più volte in un frame quando cambiano pochi parametri (esempio solo la view matrix)
  2. La scena è composta da tanti oggetti che possono essere fusi insieme
  3. Avete una scena a cui dovete solo aggiungere o eliminare ogni tanto delle parti

Nel demo qui sotto ho implementato una sorta di Snake 3D (ovviamente senza logica di gioco). Ogni secondo aggiungo un blocco alla testa del “serpente” nella direzione desiderata in modo che io abbiamo una buffer contenente tutti i blocchi da mandare in rendering con una sola istruzione. Nell’esempio uso 2 output stream. Ogni volta che aggiungo un blocco attivo uno dei due stream, e sopra ci renderizzo l’altro che contiene tutti i blocchi fino a quel momento, ed il nuovo blocco.

Demo

Articolo Articolo  Storico Storico Stampa Stampa
I commenti sono disabilitati.
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché."

Albert Einstein


Cerca per parola chiave
 

Titolo
Articoli (4)
C++ (4)
Direct3D10 (30)
Direct3D11 (20)
DirectX9 (82)
DotNet (10)
English (9)
FanGames (22)
ManagedDX11 (2)
Materiale Utile (4)
News (39)
Shader Library (12)
SharpDX (1)
Software (25)
Tecnologia (19)
Varie (9)

Gli interventi più cliccati

Ultimi commenti:
If you wish to retai...
23/05/2013 @ 13:07:45
Di chanel outlet
You deficit of self-...
23/05/2013 @ 13:07:13
Di cartier watches uk
Reinforce your own l...
23/05/2013 @ 13:06:37
Di replica watches
Whenever you"re shiv...
23/05/2013 @ 13:06:11
Di swiss replica watches
It's likely you have...
23/05/2013 @ 13:05:02
Di chanel handbags
Cheap automobile ins...
23/05/2013 @ 13:04:28
Di replica watches

Titolo
Con quale tecnologia state realizzando o avete intenzione di realizzare i vostri progetti?

 DirectX11
 DirectX10
 DirectX9
 XNA
 DirectX8 o Precedenti
 OpenGL
 Motori grafici già pronti
 Altro

Titolo
Umorismo (17)

Le fotografie più cliccate



Ci sono 291 persone collegate
Sono state visualizzate  pagine

03/12/2024 @ 21:53:07
script eseguito in 42 ms