Condividi tramite


Configurazione della funzionalità di Depth-Stencil

Questa sezione illustra i passaggi per configurare il buffer depth-stencil e lo stato depth-stencil per la fase di unione dell'output.

Dopo aver appreso come usare il buffer depth-stencil e lo stato depth-stencil corrispondente, fare riferimento a tecniche avanzate di stencil.

Creare una risorsa Depth-Stencil

Creare il buffer di profondità-stencil usando una risorsa texture.

ID3D11Texture2D* pDepthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = backBufferSurfaceDesc.Width;
descDepth.Height = backBufferSurfaceDesc.Height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = pDeviceSettings->d3d11.AutoDepthStencilFormat;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );

Creare lo stato Depth-Stencil

Lo stato depth-stencil indica alla fase di fusione dell'output come eseguire il test depth-stencil . Il test depth-stencil determina se deve essere disegnato o meno un determinato pixel.

D3D11_DEPTH_STENCIL_DESC dsDesc;

// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;

// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;

// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// Create depth stencil state
ID3D11DepthStencilState * pDSState;
pd3dDevice->CreateDepthStencilState(&dsDesc, &pDSState);

DepthEnable e StencilEnable abilitano (e disabilitano) i test di profondità e stencil. Impostare DepthEnable su FALSE per disabilitare i test di profondità e impedire la scrittura nel buffer di profondità. Impostare StencilEnable su FALSE per disabilitare i test degli stencil e impedire la scrittura nel buffer degli stencil (quando DepthEnable è FALSE e StencilEnable è TRUE, il test di profondità passa sempre nell'operazione di stencil).

DepthEnable influisce solo sulla fase di unione dell'output: non influisce sul ritaglio, la distorsione della profondità o il blocco dei valori prima che i dati vengano inseriti in un pixel shader.

Associare i dati Depth-Stencil alla fase OM

Associare lo stato depth-stencil.

// Bind depth stencil state
pDevice->OMSetDepthStencilState(pDSState, 1);

Associare la risorsa depth-stencil usando una vista.

D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;

// Create the depth stencil view
ID3D11DepthStencilView* pDSV;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, // Depth stencil texture
                                         &descDSV, // Depth stencil desc
                                         &pDSV );  // [out] Depth stencil view

// Bind the depth stencil view
pd3dDeviceContext->OMSetRenderTargets( 1,          // One rendertarget view
                                &pRTV,      // Render target view, created earlier
                                pDSV );     // Depth stencil view for the render target

È possibile passare una serie di viste di destinazione di rendering in ID3D11DeviceContext::OMSetRenderTargets; tuttavia, tutte queste viste di destinazione di rendering corrisponderanno a una singola vista stencil di profondità. La matrice di destinazione di rendering in Direct3D 11 è una funzionalità che consente a un'applicazione di eseguire il rendering su più destinazioni di rendering contemporaneamente a livello primitivo. Le matrici di destinazione di rendering offrono prestazioni migliori rispetto all'impostazione individuale delle destinazioni di rendering con più chiamate a ID3D11DeviceContext::OMSetRenderTargets (essenzialmente il metodo usato in Direct3D 9).

Le destinazioni di rendering devono essere tutte dello stesso tipo di risorsa. Se si usa l'antialiasing multisample, tutte le destinazioni di rendering associate e i buffer di profondità devono avere gli stessi conteggi di campioni.

Quando un buffer viene usato come destinazione di rendering, i test depth-stencil e più destinazioni di rendering non sono supportati.

  • Fino a 8 destinazioni di rendering possono essere associate contemporaneamente.
  • Tutte le destinazioni di rendering devono avere le stesse dimensioni (larghezza, altezza e profondità per 3D o dimensione dell'array per i tipi Array).
  • Ogni destinazione di rendering può avere un formato di dati diverso.
  • Le maschere di scrittura controllano i dati scritti in un target di rendering. Il controllo delle maschere di scrittura dell'output determina, per ogni destinazione di rendering e per ogni componente, quali dati vengono scritti nelle destinazioni di rendering.

Tecniche avanzate di stencil

La parte dello stencil del buffer "depth-stencil" può essere usata per creare effetti di rendering come il compositing, il decaling e l'elaborazione del contorno.

Composizione visiva

L'applicazione può usare il buffer degli stencil per comporre immagini 2D o 3D in una scena 3D. Una maschera nel buffer degli stencil viene usata per occludere un'area della superficie di destinazione del rendering. Le informazioni 2D archiviate, ad esempio testo o bitmap, possono quindi essere scritte nell'area occlusa. In alternativa, l'applicazione può eseguire il rendering di primitive 3D aggiuntive nell'area mascherata da stencil della superficie di destinazione di rendering. Può anche eseguire il rendering di un'intera scena.

I giochi spesso compongono più scene 3D. Ad esempio, i giochi di guida in genere visualizzano uno specchietto retrovisore. Lo specchio contiene la vista della scena 3D dietro il guidatore. Si tratta essenzialmente di una seconda scena 3D composta con la visualizzazione frontale del conducente.

Applicazione di decalcomanie

Le applicazioni Direct3D usano il decaling per controllare quali pixel di una particolare immagine primitiva vengono disegnati nella superficie di destinazione del rendering. Le applicazioni applicano decals alle immagini delle primitive per consentire il rendering corretto dei poligoni coplanari.

Ad esempio, quando si applicano segni di pneumatici e linee gialle a una strada, i contrassegni dovrebbero apparire direttamente sopra la strada. Tuttavia, i valori z dei contrassegni e della strada sono uguali. Pertanto, il buffer di profondità potrebbe non produrre una separazione pulita tra i due. È possibile eseguire il rendering di alcuni pixel nella primitiva posteriore sopra la primitiva anteriore e viceversa. L'immagine risultante appare scintillante dalla cornice alla cornice. Questo effetto è chiamato z-fighting o scintillio.

Per risolvere questo problema, usare uno stencil per mascherare la sezione della primitiva posteriore in cui verrà visualizzato il decal. Disattivare il buffer z ed eseguire il rendering dell'immagine della primitiva anteriore nell'area mascherata della superficie di destinazione di rendering.

La combinazione di più texture può essere usata per risolvere questo problema.

Contorni e silhouette

È possibile usare il buffer degli stencil per creare effetti più astratti, come la contornatura e la silhouettatura.

Se l'applicazione esegue due passaggi di rendering, uno per generare la maschera stencil e la seconda per applicare la maschera stencil all'immagine, ma con le primitive leggermente più piccole al secondo passaggio, l'immagine risultante conterrà solo il contorno della primitiva. L'applicazione può quindi riempire l'area mascherata da stencil dell'immagine con un colore a tinta unita, dando alla primitiva un aspetto in rilievo.

Se la maschera stencil ha la stessa dimensione e forma della primitiva di cui si esegue il rendering, l'immagine risultante contiene un foro in cui dovrebbe trovarsi la primitiva. L'applicazione può quindi riempire il buco di nero per produrre una silhouette della forma primitiva.

Two-Sided Stencil

I "Shadow Volumes" vengono usati per disegnare ombreggiature con lo stencil buffer. L'applicazione calcola i volumi d'ombra proiettati dalla geometria dell'occultamento, calcolando i bordi della silhouette ed estrudendoli lontano dalla luce in un insieme di volumi 3D. Questi volumi vengono quindi renderizzati due volte nel buffer degli stencil.

Il primo rendering disegna poligoni frontali e incrementa i valori del buffer stencil. Il secondo rendering disegna i poligoni rivolti verso l'indietro del volume d'ombra e decrementa i valori del buffer stencil. In genere, tutti i valori incrementati e decrementati si annullano a vicenda. Tuttavia, la scena era già stata renderizzata con una geometria normale, causando il fallimento del test z-buffer quando viene eseguito il rendering del volume delle ombre. I valori lasciati nel buffer degli stencil corrispondono ai pixel presenti nell'ombreggiatura. Questi rimanenti contenuti del buffer degli stencil vengono usati come maschera, per fondere con l'alfa un ampio quad nero che copre tutta la scena. Usando il buffer stencil come maschera, il risultato è l'oscuramento dei pixel che si trovano nelle ombre.

Ciò significa che la geometria delle ombre viene disegnata due volte per sorgente luminosa, mettendo così sotto pressione la larghezza di banda dei vertici della GPU. La funzionalità stencil a due lati è stata progettata per attenuare questa situazione. In questo approccio, sono disponibili due set di stato stencil (denominati di seguito), uno per i triangoli rivolti in avanti e l'altro per i triangoli rivolti all'indietro. In questo modo, viene disegnato un unico passaggio per volume d'ombra, per luce.

Un esempio di implementazione dello stencil a due lati è disponibile nell'esempio di ShadowVolume10.

Lettura del buffer Depth-Stencil come texture

Un buffer depth-stencil inattivo può essere letto da uno shader come texture. Un'applicazione che legge un buffer depth-stencil come texture esegue il rendering in due passaggi: il primo passaggio scrive nel buffer depth-stencil, mentre il secondo passaggio legge dal buffer. Ciò consente a uno shader di confrontare i valori di profondità o stencil precedentemente scritti nel buffer con il valore del pixel attualmente in fase di rendering. Il risultato del confronto può essere usato per creare effetti come il mapping delle ombre o le particelle morbide in un sistema di particelle.

Per creare un buffer depth-stencil che può essere usato sia come risorsa depth-stencil che come risorsa shader è necessario apportare alcune modifiche al codice di esempio nella sezione Creare un Depth-Stencil risorsa.

  • La risorsa depth-stencil deve avere un formato senza tipi, ad esempio DXGI_FORMAT_R32_TYPELESS.

    descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
    
  • La risorsa depth-stencil deve usare sia i flag di associazione D3D10_BIND_DEPTH_STENCIL che D3D10_BIND_SHADER_RESOURCE.

    descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
    

È inoltre necessario creare una visualizzazione delle risorse shader per il buffer di profondità usando una struttura D3D11_SHADER_RESOURCE_VIEW_DESC e ID3D11Device::CreateShaderResourceView. La visualizzazione delle risorse dello shader userà un formato tipizzato, come DXGI_FORMAT_R32_FLOAT, equivalente al formato tipeless specificato al momento della creazione della risorsa depth-stencil.

Nel primo passaggio di rendering, il buffer di profondità è collegato come descritto nella sezione Bind Depth-Stencil Data to the OM Stage. Si noti che il formato passato a D3D11_DEPTH_STENCIL_VIEW_DESCutilizzerà un formato tipizzato, come ad esempio DXGI_FORMAT_D32_FLOAT. Dopo il primo passaggio del rendering, il buffer di profondità conterrà i valori di profondità per la scena.

Nel secondo passaggio di rendering la funzione ID3D11DeviceContext::OMSetRenderTargets viene usata per impostare la visualizzazione depth-stencil su NULL o una risorsa depth-stencil diversa e la visualizzazione risorse shader viene passata allo shader usando ID3D11EffectShaderResourceVariable::SetResource. Ciò consente allo shader di cercare i valori di profondità calcolati nel primo passaggio di rendering. Si noti che è necessario applicare una trasformazione per recuperare i valori di profondità se il punto di visualizzazione del primo passaggio di rendering è diverso dal secondo passaggio di rendering. Ad esempio, se viene usata una tecnica di mapping delle ombreggiature, il primo passaggio di rendering sarà dal punto di vista di una sorgente di luce mentre il secondo passaggio di rendering passerà dal punto di vista del visualizzatore.

Output-Merger fase

Fasi della pipeline (Direct3D 10)