Configurazione delle 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, vedere tecniche avanzate di stencil.

Creare una risorsa Depth-Stencil

Creare il buffer depth-stencil usando una risorsa trama.

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 );

Crea stato Depth-Stencil

Lo stato depth-stencil indica alla fase di unione di 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) il test di profondità e stencil. Impostare DepthEnable su FALSE per disabilitare il 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à supera sempre l'operazione degli 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 visualizzazione.

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

Una matrice di visualizzazioni di destinazione di rendering può essere passata in ID3D11DeviceContext::OMSetRenderTargets, ma tutte queste visualizzazioni di destinazione di rendering corrispondono a una singola visualizzazione degli stencil di profondità. La matrice di destinazione di rendering in Direct3D 11 è una funzionalità che consente a un'applicazione di eseguire il rendering in 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 viene usato l'anti-aliasing 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 in tutte le dimensioni (larghezza e altezza e profondità per dimensioni 3D o matrice per i tipi di matrice).
  • Ogni destinazione di rendering può avere un formato di dati diverso.
  • Le maschere di scrittura controllano i dati scritti in una destinazione di rendering. Il controllo delle maschere di scrittura di output in una destinazione per rendering, a livello di componente, dei dati scritti nelle destinazioni di rendering.

Tecniche avanzate di stencil

La parte stencil del buffer depth-stencil può essere usata per la creazione di effetti di rendering, ad esempio composizione, decaling e struttura.

Compositing

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 occudere un'area della superficie di destinazione di rendering. Le informazioni 2D archiviate, ad esempio testo o bitmap, possono quindi essere scritte nell'area bloccata. In alternativa, l'applicazione può eseguire il rendering di primitive 3D aggiuntive nell'area mascherata dello stencil della superficie di destinazione del rendering. Può anche eseguire il rendering di un'intera scena.

I giochi spesso compositi più scene 3D insieme. Ad esempio, i giochi di guida visualizzano in genere uno specchio retrovisore. Il mirror contiene la visualizzazione della scena 3D dietro il driver. Si tratta essenzialmente di una seconda scena 3D composta con la visualizzazione avanti del driver.

Decaling

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 pneumatico e linee gialle a una strada, i contrassegni dovrebbero apparire direttamente sulla parte superiore della strada. Tuttavia, i valori z dei contrassegni e della strada sono gli stessi. 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 sembra scemare da frame a frame. Questo effetto è chiamato z-fighting o flimmering.

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

Per risolvere questo problema, è possibile usare la fusione di più trame.

Contorni e silhouette

È possibile usare il buffer degli stencil per effetti più astratti, ad esempio struttura e silhouetting.

Se l'applicazione esegue due passaggi di rendering, uno per generare la maschera stencil e il secondo 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 dello stencil dell'immagine con un colore a tinta unita, dando alla primitiva un aspetto in rilievo.

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

Two-Sided Stencil

I volumi shadow vengono usati per disegnare ombreggiature con il buffer degli stencil. L'applicazione calcola i volumi di ombreggiatura castati dalla geometria occlusione, calcolando i bordi della silhouette ed estrusendoli dalla luce in un set di volumi 3D. Questi volumi vengono quindi sottoposti a rendering due volte nel buffer degli stencil.

Il primo rendering disegna poligoni rivolti verso l'avanti e incrementa i valori del buffer degli stencil. Il secondo rendering disegna i poligoni back-facing del volume shadow e decrementa i valori del buffer degli stencil. In genere, tutti i valori incrementati e decrementati si annullano l'uno dall'altro. Tuttavia, il rendering della scena è già stato eseguito con la geometria normale, causando l'esito negativo del test z-buffer quando viene eseguito il rendering del volume shadow. I valori lasciati nel buffer degli stencil corrispondono ai pixel presenti nell'ombreggiatura. Questi contenuti rimanenti del buffer degli stencil vengono usati come maschera, per unire alfa un quad nero di grandi dimensioni e incorporato nella scena. Con il buffer degli stencil che funge da maschera, il risultato consiste nell'oscurare i pixel presenti nelle ombreggiature.

Ciò significa che la geometria dell'ombreggiatura viene disegnata due volte per sorgente di luce, quindi la pressione sulla velocità effettiva 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 ognuno dei triangoli front-fronte e l'altro per i triangoli rivolta verso il retro. In questo modo, viene disegnato solo un singolo passaggio per volume di ombreggiatura, per luce.

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

Lettura del buffer Depth-Stencil come trama

Un buffer depth-stencil inattivo può essere letto da uno shader come trama. Un'applicazione che legge un buffer depth-stencil come trama esegue il rendering in due passaggi, il primo passaggio scrive nel buffer depth-stencil e il secondo passaggio legge dal buffer. Ciò consente a uno shader di confrontare i valori di profondità o stencil scritti in precedenza nel buffer con il valore per il rendering del pixel in modo simultaneo. Il risultato del confronto può essere utilizzato 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 una risorsa Depth-Stencil risorsa .

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

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

    descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
    

Inoltre, è necessario creare una visualizzazione risorse shader per il buffer di profondità usando una struttura di D3D11_SHADER_RESOURCE_VIEW_DESC e ID3D11Device::CreateShaderResourceView. La visualizzazione risorse shader userà un formato tipizzato, ad esempio DXGI_FORMAT_R32_FLOAT equivalente al formato senza tipi specificato al momento della creazione della risorsa depth-stencil.

Nel primo rendering passare il buffer di profondità è associato come descritto nella sezione Associare Depth-Stencil Dati alla fase OM . Si noti che il formato passato a D3D11_DEPTH_STENCIL_VIEW_DESC. Il formato userà un formato tipizzato, 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 rendering passa la funzione ID3D11DeviceContext::OMSetRenderTargets viene usata per impostare la visualizzazione depth-stencil su NULL o su una risorsa depth-stencil diversa e la visualizzazione delle risorse dello 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.

Fase di fusione dell'output

Fasi della pipeline (Direct3D 10)