Konfigurieren Depth-Stencil Funktionalität

In diesem Abschnitt werden die Schritte zum Einrichten des Tiefenschablonenpuffers und des Tiefenschablonenzustands für die Ausgabe-Merger-Phase behandelt.

Wenn Sie wissen, wie Sie den Tiefenschablonenpuffer und den entsprechenden Tiefenschablonenzustand verwenden, lesen Sie erweiterte Schablonentechniken.

Erstellen einer Depth-Stencil-Ressource

Erstellen Sie den Tiefenschablonenpuffer mithilfe einer Texturressource.

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

Erstellen Depth-Stencil Zustands

Der Tiefenschablonenzustand teilt der Ausgabe-Merger-Phase mit, wie der Tiefenschablonentest ausgeführt werden soll. Der Tiefenschablonentest bestimmt, ob ein bestimmtes Pixel gezeichnet werden soll.

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 und StencilEnable aktivieren (und deaktivieren) Tiefen- und Schablonentests. Legen Sie DepthEnable auf FALSE fest, um tiefentests zu deaktivieren und das Schreiben in den Tiefenpuffer zu verhindern. Legen Sie StencilEnable auf FALSE fest, um schablonentests zu deaktivieren und das Schreiben in den Schablonenpuffer zu verhindern (wenn DepthEnable false und StencilEnable TRUE ist, besteht der Tiefentest immer im Schablonenvorgang).

DepthEnable wirkt sich nur auf die Ausgabe-Merger-Phase aus. Es wirkt sich nicht auf das Ausschneiden, die Tiefenverzerrung oder das Klemmen von Werten aus, bevor die Daten in einen Pixel-Shader eingegeben werden.

Binden Depth-Stencil Daten an die OM-Phase

Binden Sie den Tiefenschablonenzustand.

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

Binden Sie die Tiefenschablonenressource mithilfe einer Ansicht.

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

Ein Array von Renderzielsichten kann an ID3D11DeviceContext::OMSetRenderTargets übergeben werden, aber alle diese Renderzielansichten entsprechen einer einzelnen Tiefenschablonenansicht. Das Renderzielarray in Direct3D 11 ist ein Feature, mit dem eine Anwendung gleichzeitig auf mehrere Renderziele auf primitiver Ebene rendern kann. Renderzielarrays bieten eine höhere Leistung gegenüber dem individuellen Festlegen von Renderzielen mit mehreren Aufrufen von ID3D11DeviceContext::OMSetRenderTargets (im Wesentlichen die in Direct3D 9 verwendete Methode).

Renderziele müssen alle denselben Ressourcentyp aufweisen. Wenn Multisample-Antialiasing verwendet wird, müssen alle gebundenen Renderziele und Tiefenpuffer die gleiche Stichprobenanzahl aufweisen.

Wenn ein Puffer als Renderziel verwendet wird, werden Tiefenschablonentests und mehrere Renderziele nicht unterstützt.

  • Es können bis zu 8 Renderziele gleichzeitig gebunden werden.
  • Alle Renderziele müssen in allen Dimensionen (Breite und Höhe und Tiefe für 3D oder Arraygröße für *Arraytypen) die gleiche Größe aufweisen.
  • Jedes Renderziel kann ein anderes Datenformat aufweisen.
  • Schreibmasken steuern, welche Daten in ein Renderziel geschrieben werden. Das Ausgabeschreibsteuerelement maskiert pro Renderziel pro Komponente, welche Daten in die Renderziele geschrieben werden.

Erweiterte Schablonentechniken

Der Schablonenteil des Tiefenschablonenpuffers kann zum Erstellen von Renderingeffekten wie Compositing, Decaling und Outlining verwendet werden.

Compositing

Ihre Anwendung kann den Schablonenpuffer verwenden, um zusammengesetzte 2D- oder 3D-Bilder in einer 3D-Szene zu erstellen. Eine Maske im Schablonenpuffer wird verwendet, um einen Bereich der Renderingzieloberfläche zu verschließen. Gespeicherte 2D-Informationen, z. B. Text oder Bitmaps, können dann in den verschließten Bereich geschrieben werden. Alternativ kann Ihre Anwendung zusätzliche 3D-Grundtypen im schablonenmaskierten Bereich der Renderingzieloberfläche rendern. Es kann sogar eine ganze Szene rendern.

Spiele kombinieren häufig mehrere 3D-Szenen. Für instance zeigen Fahrspiele in der Regel eine rückwärtige Spiegel an. Die Spiegel enthält die Ansicht der 3D-Szene hinter dem Treiber. Es handelt sich im Wesentlichen um eine zweite 3D-Szene, die mit der Vorwärtssicht des Fahrers kombiniert ist.

Abkalierung

Direct3D-Anwendungen verwenden Decaling, um zu steuern, welche Pixel aus einem bestimmten primitiven Bild auf die Renderingzieloberfläche gezeichnet werden. Anwendungen wenden Decals auf die Bilder von Primitiven an, damit coplanare Polygone ordnungsgemäß gerendert werden können.

Für instance sollten die Markierungen beim Anbringen von Reifenspuren und gelben Linien auf einer Fahrbahn direkt auf der Straße angezeigt werden. Die z-Werte der Markierungen und der Straße sind jedoch identisch. Daher erzeugt der Tiefenpuffer möglicherweise keine sauber Trennung zwischen den beiden. Einige Pixel im hinteren Grundtyp können oben auf dem Frontgrundiv gerendert werden und umgekehrt. Das resultierende Bild scheint von Frame zu Frame zu schimmern. Dieser Effekt wird als Z-Fighting oder Flimmering bezeichnet.

Um dieses Problem zu beheben, verwenden Sie eine Schablone, um den Abschnitt des hinteren Grundtyps zu maskieren, in dem das Decal angezeigt wird. Deaktivieren Sie die Z-Pufferung, und rendern Sie das Bild des Frontgrundivs in den maskierten Bereich der Renderzieloberfläche.

Mehrere Texturmischungen können verwendet werden, um dieses Problem zu lösen.

Konturen und Silhouetten

Sie können den Schablonenpuffer für abstraktere Effekte verwenden, z. B. Das Skizzieren und Das Silhouetting.

Wenn Ihre Anwendung zwei Renderdurchläufe ausführt – einen, um die Schablonenmaske zu generieren, und zweitens, um die Schablonenmaske auf das Bild anzuwenden, aber die Grundelemente im zweiten Durchlauf etwas kleiner sind , enthält das resultierende Bild nur die Umrisse des Grundtyps. Die Anwendung kann dann den schablonenmaskierten Bereich des Bilds mit einer Vollfarbe füllen, sodass das Primitive ein geprägtes Aussehen erhält.

Wenn die Schablonenmaske die gleiche Größe und Form hat wie das Primitive, das Sie rendern, enthält das resultierende Bild eine Lücke, an der sich das Grundelement befinden soll. Ihre Anwendung kann das Loch dann mit Schwarz füllen, um eine Silhouette des Primitiven zu erzeugen.

Two-Sided Schablone

Schattenvolumes werden zum Zeichnen von Schatten mit dem Schablonenpuffer verwendet. Die Anwendung berechnet die Schattenvolumina, die durch Verschließen der Geometrie, durch Berechnung der Silhouettenränder und extrudiert sie aus dem Licht in eine Reihe von 3D-Volumes. Diese Volumes werden dann zweimal in den Schablonenpuffer gerendert.

Das erste Rendern zeichnet nach vorne ausgerichtete Polygone und erhöht die Schablonenpufferwerte. Das zweite Rendern zeichnet die nach hinten gerichteten Polygone des Schattenvolumens und dekrementiert die Schablonenpufferwerte. Normalerweise heben sich alle inkrementierten und dekrementierten Werte gegenseitig ab. Die Szene wurde jedoch bereits mit normaler Geometrie gerendert, sodass einige Pixel beim Z-Puffertest fehlschlagen, wenn das Schattenvolumen gerendert wird. Werte, die im Schablonenpuffer verbleiben, entsprechen Pixeln, die sich im Schatten befinden. Diese verbleibenden Schablonenpufferinhalte werden als Maske verwendet, um ein großes, allumfassendes schwarzes Quad in die Szene zu überblenden. Wenn der Schablonenpuffer als Maske fungiert, wird das Ergebnis dazu führen, dass Die Pixel, die sich in den Schatten befinden, abdunkle.

Dies bedeutet, dass die Schattengeometrie zweimal pro Lichtquelle gezeichnet wird, wodurch der Vertexdurchsatz der GPU belastet wird. Die zweiseitige Schablonenfunktion wurde entwickelt, um diese Situation zu entschärfen. Bei diesem Ansatz gibt es zwei Sätze des Schablonenzustands (benannt unten), jeweils einen Satz für die nach vorne gerichteten Dreiecke und die andere für die nach hinten gerichteten Dreiecke. Auf diese Weise wird nur ein einzelner Durchgang pro Schattenvolumen und Licht gezeichnet.

Ein Beispiel für eine zweiseitige Schablonenimplementierung finden Sie im ShadowVolume10-Beispiel.

Lesen des Depth-Stencil Puffers als Textur

Ein inaktiver Tiefenschablonenpuffer kann von einem Shader als Textur gelesen werden. Eine Anwendung, die einen Tiefenschablonenpuffer als Textur in zwei Durchläufen rendert, der erste Durchlauf schreibt in den Tiefenschablonenpuffer und der zweite Durchlauf liest aus dem Puffer. Dadurch kann ein Shader Tiefen- oder Schablonenwerte, die zuvor in den Puffer geschrieben wurden, mit dem Wert für das gerenderte Pixel vergleichen. Das Ergebnis des Vergleichs kann verwendet werden, um Effekte wie Schattenkartierung oder weiche Partikel in einem Partikelsystem zu erzeugen.

Um einen Tiefenschablonenpuffer zu erstellen, der sowohl als Tiefenschablonenressource als auch als Shaderressource verwendet werden kann, müssen einige Änderungen am Beispielcode im Abschnitt Erstellen einer Depth-Stencil-Ressource vorgenommen werden.

  • Die Tiefenschablonenressource muss über ein typloses Format wie DXGI_FORMAT_R32_TYPELESS verfügen.

    descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
    
  • Die Tiefenschablonenressource muss sowohl die D3D10_BIND_DEPTH_STENCIL- als auch D3D10_BIND_SHADER_RESOURCE-Bindungsflags verwenden.

    descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
    

Darüber hinaus muss eine Shaderressourcensicht für den Tiefenpuffer mit einer D3D11_SHADER_RESOURCE_VIEW_DESC-Struktur und ID3D11Device::CreateShaderResourceView erstellt werden. Die Shaderressourcenansicht verwendet ein typisiertes Format, z . B. DXGI_FORMAT_R32_FLOAT , das dem typlosen Format entspricht, das beim Erstellen der Tiefenschablonenressource angegeben wurde.

Im ersten Renderdurchlauf ist der Tiefenpuffer wie im Abschnitt Binden Depth-Stencil Daten an die OM-Phase beschrieben gebunden. Beachten Sie, dass das Format an D3D11_DEPTH_STENCIL_VIEW_DESC übergeben wurde. Format verwendet ein typisiertes Format wie DXGI_FORMAT_D32_FLOAT. Nach dem ersten Renderdurchlauf enthält der Tiefenpuffer die Tiefenwerte für die Szene.

Im zweiten Renderdurchlauf wird die ID3D11DeviceContext::OMSetRenderTargets-Funktion verwendet, um die Tiefenschablonenansicht auf NULL oder eine andere Tiefenschablonenressource festzulegen, und die Shaderressourcenansicht wird mithilfe von ID3D11EffectShaderResourceVariable::SetResource an den Shader übergeben. Dadurch kann der Shader die im ersten Renderingdurchlauf berechneten Tiefenwerte nachschlagen. Beachten Sie, dass eine Transformation angewendet werden muss, um Tiefenwerte abzurufen, wenn sich der Standpunkt des ersten Renderdurchgangs vom zweiten Renderdurchlauf unterscheidet. Wenn beispielsweise ein Schattenzuordnungsverfahren verwendet wird, erfolgt der erste Renderdurchlauf aus der Perspektive einer Lichtquelle, während der zweite Renderdurchlauf aus der Perspektive des Betrachters erfolgt.

Output-Merger-Phase

Pipelinephasen (Direct3D 10)