共用方式為


設定 Depth-Stencil 功能

本節涵蓋設定深度模板緩衝區和深度模板狀態的步驟,用於輸出合併階段。

一旦您知道如何使用深度樣板緩衝區和對應的深度樣板狀態,請參閱 進階樣板技術

建立 Depth-Stencil 資源

使用紋理資源建立深度樣板緩衝區。

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

建立 Depth-Stencil 狀態

深度樣板狀態會告訴輸出合併階段如何執行 深度樣板測試。 深度模板測試會判斷是否應該繪製特定的像素。

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 和 StencilEnable 啟用和停用深度和模板測試。 將 DepthEnable 設定為 FALSE 停用深度測試,並防止寫入深度緩衝區。 將 StencilEnable 設定為 FALSE 以停用模版測試,並防止寫入模版緩衝區(當 DepthEnable 為 FALSE 且 StencilEnable 為 TRUE時,深度測試在模版操作中始終通過)。

DepthEnable 只會影響輸出合併階段,並不會影響在數據輸入到圖元著色器之前的值裁剪、深度偏移或夾緊。

將 Depth-Stencil 數據綁定至 OM 階段

系結深度-模板狀態。

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

使用視圖綁定深度模板資源。

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

可能會將多個轉譯目標檢視傳遞到 ID3D11DeviceContext::OMSetRenderTargets,但所有這些轉譯目標檢視都會對應至單一深度模板檢視。 Direct3D 11 中的轉譯目標陣列是一項功能,可讓應用程式在基本層級同時轉譯至多個轉譯目標。 轉譯目標陣列相較於在 Direct3D 9 中透過多個呼叫 ID3D11DeviceContext::OMSetRenderTargets 來個別設定轉譯目標,能提高效能。

轉譯目標必須全部是相同的資源類型。 如果使用多重采樣抗鋸齒,所有綁定的渲染目標和深度緩衝區都必須具有相同的採樣數。

當緩衝區被用作渲染目標時,不支援深度模板測試和多重渲染目標。

  • 可以同時綁定多達8個渲染目標。
  • 所有渲染目標在所有維度中必須具有相同的大小(寬度、高度,3D的深度或陣列型態的大小)。
  • 每個轉譯目標可能有不同的數據格式。
  • 寫入遮罩可控制哪些數據會寫入轉譯目標。 輸出寫入遮罩可在每個轉譯目標及每個元件層級控制哪些數據會寫入轉譯目標。

進階模板技術

深度模板緩衝區的模板部分可用於建立呈現效果,例如組合、貼花和輪廓。

合成

您的應用程式可以使用樣板緩衝區,將 2D 或 3D 影像複合到 3D 場景。 樣板緩衝區中的遮罩可用來遮蔽轉譯目標表面的區域。 已儲存的 2D 資訊,例如文字或點陣圖,可以將其寫入遮蔽區域。 或者,您的應用程式可以將額外的 3D 基本類型轉譯至轉譯目標介面的樣板遮罩區域。 它甚至可以轉譯整個場景。

遊戲通常會將多個 3D 場景組合在一起。 例如,駕駛遊戲通常會顯示後視鏡。 鏡子包含駕駛者後方 3D 場景的視圖。 它基本上是第二個 3D 場景,與駕駛員的前方視野混合。

貼花

Direct3D 應用程式會使用貼圖技術來控制特定基本影像的圖元如何繪製到繪圖目標表面。 應用程式會將貼圖套用至基本圖元的影像,以確保共面多邊形能夠正確渲染。

例如,將輪胎標記和黃色線條套用至道路時,標記應該直接出現在道路頂端。 不過,標記和道路的 z 值相同。 因此,深度緩衝區可能不會產生兩者之間的乾淨分隔。 後端基本類型中的某些圖元可能會呈現在前端基本類型之上,反之亦然。 產生的影像會在每一個畫框之間閃閃發光。 這種效果稱為 Z 軸重疊或閃爍現象。

若要解決此問題,請使用樣板來遮罩上一個貼圖出現的後基元區段。 關閉 z-緩衝,在渲染目標表面的遮罩區域呈現前景圖元的影像。

多個紋理混合可用來解決此問題。

外框和剪影

您可以使用樣板緩衝區來取得更抽象的效果,例如描邊和剪影。

如果您的應用程式執行兩個渲染通道——第一個用於生成樣板遮罩,第二個用於將樣板遮罩應用到影像,但在第二次通道中,基本圖元略小一些——則生成的影像將僅包含基本圖元的輪廓。 然後,應用程式可以使用純色填滿影像的樣板遮罩區域,讓圖形原件呈現浮雕的效果。

如果樣板遮罩的大小和形狀與您呈現的基本類型相同,則產生的影像會包含基本類型應為的洞。 然後,您的應用程式可以使用黑色填滿洞,以產生基本類型的剪影。

Two-Sided 樣板

陰影體積被用來使用模板緩衝區繪製陰影。 應用程式經由計算遮擋幾何的剪影邊緣,並將其向遠離光源的方向拉伸成一組 3D 體積來計算陰影體積。 然後,這些磁碟區會轉譯成樣板緩衝區兩次。

第一次渲染會繪製正向多邊形,並遞增樣板緩衝區值。 第二次渲染會繪製陰影體積的背面多邊形,並遞減模板緩衝區的值。 通常情況下,所有遞增和遞減的值會互相抵消。然而,場景已經以正常的幾何形狀呈現,這導致在渲染陰影體積時,某些像素未通過 z 緩衝區測試。 樣板緩衝區中保留的值對應於陰影中的像素。 這些剩餘的樣板緩衝區內容會作為遮罩,將大型全覆蓋的黑色四邊形以 Alpha 混合的方式融入場景中。 使用樣板緩衝區作為遮罩,結果是將陰影中的像素變暗。

這表示每個光源會繪製陰影幾何兩次,因此對 GPU 的頂點輸送量施加壓力。 雙面樣板功能的設計是為了減輕這種情況。 在此方法中,有兩組樣板狀態(如下所示),一組分別針對正面三角形,另一組用於反向三角形。 如此一來,針對每個光源,每個陰影體積只會繪製單一通道。

您可以在 shadowVolume10 範例中找到雙面樣板實作的範例。

將 Depth-Stencil 緩衝區讀取為紋理

著色器可以將非作用的深度模板緩衝區作為紋理來讀取。 應用程式透過兩次運算來呈現,其中第一次運算將資料寫入深度模板緩衝區,而第二次運算則從該緩衝區讀取資料。 這可讓著色器比較先前寫入緩衝區的深度或樣板值,與當前渲染中的像素值相比較。 比較的結果可用來在粒子系統中建立效果,例如陰影映射或軟粒子。

要建立一個可以作為深度樣板資源和著色器資源使用的深度樣板緩衝區,您需要在 建立 Depth-Stencil 資源 區段中對範例代碼進行一些變更。

  • 深度樣板資源必須具有無類型格式,例如DXGI_FORMAT_R32_TYPELESS。

    descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
    
  • 深度模板資源必須使用D3D10_BIND_DEPTH_STENCIL和D3D10_BIND_SHADER_RESOURCE綁定標誌。

    descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
    

此外,您必須使用 D3D11_SHADER_RESOURCE_VIEW_DESC 結構和 ID3D11Device::CreateShaderResourceView,為深度緩衝區建立著色器資源檢視。 著色器資源檢視會使用具類型的格式,例如 DXGI_FORMAT_R32_FLOAT,相當於建立深度樣板資源時所指定的無類型格式。

在第一個渲染通道中,深度緩衝區會被綁定,如 將數據綁定至 OM 階段 Depth-Stencil 一節中所述。 請注意,傳遞至 D3D11_DEPTH_STENCIL_VIEW_DESC的格式.Format 將會使用具類型的格式,例如 DXGI_FORMAT_D32_FLOAT。 第一次渲染通過後,深度緩衝區將包含場景的深度值。

在第二個轉譯中,會使用 ID3D11DeviceContext::OMSetRenderTargets 函式,將深度樣板檢視設定為 NULL 或不同的深度樣板資源,而著色器資源檢視會使用 ID3D11EffectShaderResourceVariable::SetResource傳遞至著色器。 這可讓著色器查閱第一個轉譯階段中計算的深度值。 請注意,如果第一個轉譯階段的觀點與第二個轉譯階段不同,則必須套用轉換來擷取深度值。 例如,如果使用陰影對應技術時,第一個轉譯階段會從光源的角度,而第二個轉譯階段會從查看器的角度。

Output-Merger 階段

管線階段 (Direct3D 10)