今回はステンシルバッファについて
フォーマット
深度バッファのみのときは、DXGI_FORMAT_D32_FLOATを使っていた。
ステンシルバッファを使う場合は、DXGI_FORMAT_D24_UNORM_S8_UINTを使う。
Dの部分が深度バッファの精度で、ステンシルバッファに8ビット使ってしまうため、24に落ちる。
精度を落としたくなければDXGI_FORMAT_D32_FLOAT_S8X24_UINTというものもあるらしいけど、24ビット丸々無駄にするらしいし、4バイトの範囲に収まらないのでなんだか遅そう。
D3D12_RESOURCE_DESC1.Format
深度バッファのみのときは、DXGI_FORMAT_R32_TYPELESS
ステンシルバッファを使う場合は、DXGI_FORMAT_R24G8_TYPELESS
D3D12_CLEAR_VALUE.Format
深度バッファのみのときは、DXGI_FORMAT_D32_FLOAT
ステンシルバッファを使う場合は、DXGI_FORMAT_D24_UNORM_S8_UINT
CreatePlacedResource2.CastFormat
深度バッファのみのときは、
CastFormat[0]=DXGI_FORMAT_D32_FLOAT
CastFormat[1]=DXGI_FORMAT_R32_FLOAT
ステンシルバッファを使う場合は指定なし。
これがいまいち分からず、指定するとエラーになりCreateできない。
深度バッファの方は、指定する場合は両方指定しないとランタイムエラーになる。
指定なしにしたら動くので、下手に指定する必要がないかも。
D3D12_DEPTH_STENCIL_VIEW_DESC.Format
深度バッファのみのときは、DXGI_FORMAT_D32_FLOAT
ステンシルバッファを使う場合は、DXGI_FORMAT_D24_UNORM_S8_UINT
D3D12_GRAPHICS_PIPELINE_STATE_DESC.DSVFormat
深度バッファのみのときは、DXGI_FORMAT_D32_FLOAT
ステンシルバッファを使う場合は、DXGI_FORMAT_D24_UNORM_S8_UINT
D3D12_SHADER_RESOURCE_VIEW_DESC.Format
深度バッファのみのときは、DXGI_FORMAT_R32_FLOAT
ステンシルバッファを使う場合は、DXGI_FORMAT_R24_UNORM_X8_TYPELESS
ここを見るとPlaneSlice0にDXGI_FORMAT_R24_UNORM_X8_TYPELESS、1にDXGI_FORMAT_X24_TYPELESS_G8_UINTを指定する様に書かれている。
SRVでPlaneSliceを複数指定する方法がわからないけど、2つ指定するとそれぞれ深度バッファと、ステンシルバッファが参照できるのだろう。
今のところステンシルありのバッファをテクスチャ利用する予定はないので、必要が出てきたら調べることにする。
PSO
ステンシルバッファを使う場合は、DepthStencilState.StencilEnableをTRUEにする。
ステンシルバッファ書き込み
DepthStencilState.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK ;
DepthStencilState.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK ;
DepthStencilState.FrontFace = {
D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP_REPLACE,
D3D12_COMPARISON_FUNC_ALWAYS
} ;
DepthStencilState.BackFace = DepthStencilState.FrontFace ;
上記は描画した場所をOMSetStencilRefで設定した値で塗りつぶす場合の設定(D3D12_STENCIL_OP_REPLACE)
D3D12_STENCIL_OPは3つ設定できて、最初がステンシルテストに失敗した場合、次がステンシルテストは成功したけど、Zバッファのテストが失敗した場合、最後が両方のテストが成功した場合。
ステンシルバッファの書き込みだけで、描画は行わない場合BlendState.RenderTarget[i].RenderTargetWriteMaskも0にするといいらしいけど、そもそもレンダーターゲットを指定しなければいいんじゃないのか?
バッファ書き込みはやってないので分からず。
ステンシルテスト
DepthStencilState.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK ;
DepthStencilState.StencilWriteMask = 0 ;
DepthStencilState.FrontFace = {
D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP_KEEP,
D3D12_STENCIL_OP_KEEP,
D3D12_COMPARISON_FUNC_EQUAL
} ;
DepthStencilState.BackFace = DepthStencilState.FrontFace ;
上記は、OMSetStencilRefで設定した値と同じ箇所だけ描画する場合の設定。
ClearDepthStencilViewでD3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCILを指定して、深度バッファとステンシルバッファを初期化したあと、ClearDepthStencilViewの最後の引数に矩形を指定して、ステンシルバッファだけを10で初期化。OMSetStencilRefにも10を設定して描画してみると、こんな感じになった。
 |
| Hが欠けてる |
指定通りの動作になっているけど、デバッグレイヤには下記の警告が出続ける。
D3D12 WARNING: ID3D12CommandList::ClearDepthStencilView: The clear values do not match those passed to resource creation. The clear operation is typically slower as a result; but will still clear to the desired value. [ EXECUTION WARNING #821: CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE]
ステンシルバッファの書き換えにClearDepthStencilViewを利用したのがだめみたい。
矩形で指定範囲を書き換えたい時、わざわざシェーダを通さずClearDepthStencilViewで手軽にクリップ領域を指定できるかと思ったけど、この使い方はだめみたい。