Unity2021からRenderTextureDescriptorにDepthStencilFormatというパラメータが追加されていた
補足:この記事ではUnity2022.3.21のC#コードを参照しています
RenderTextureDescriptor.depthStencilFormat
いつのタイミングからか、RenderTextureDescriptorにDepthStencilFormatという変数が追加された。ドキュメントではUnity2021.2から変数の説明が追加されている。
/// <summary>
/// <para>The desired format of the depth/stencil buffer.</para>
/// </summary>
public GraphicsFormat depthStencilFormat { get; set; }
その名の通りdepth/stencil bufferのFormatを設定するパラメータ。
既に存在しているstencilFormatとの違いは?
Stencil bufferはDepth bufferの中に埋め込まれており、Stencilを設定するということは、Stencil + Depthを設定する必要があるということになる(参考)。
そのため、stencilFormat単体でStencilのFormatを指定することは難しく、DepthとStencil両方を設定するFormatで決定するほうが良い、ということだと思われる。stencilFormatの説明書きにも似たようなことが書かれている。
This property does not specify the format of the stencil buffer, which is constrained by the depth buffer format specified in RenderTexture.depth.
このプロパティ(stencilFormat)は、ステンシル バッファーの形式を指定しません。ステンシル バッファーは、RenderTexture. Depth で指定された深度バッファー形式によって制限されます。
それに伴いdepthBufferBitsのgetter, setterも処理が変わり、depthBufferBitsのsetterに関しては、内部的にはdepthStencilFormatの値も変更されている。また、変更する際にはRenderTexture.GetDepthStencilFormatLegacy
が呼ばれるようになる。
Unityのどこで使用している?
URPだとUniversalRendererの_CameraDepthTexture
をAllocするために必要なRenderTextureDescriptorを定義するときに指定している。ただ、場合によってFormatが違うようで、
#if UNITY_SWITCH || UNITY_ANDROID
const GraphicsFormatk_DepthStencilFormat= GraphicsFormat.D24_UNorm_S8_UInt;
const intk_DepthBufferBits= 24;
#else
const GraphicsFormat k_DepthStencilFormat = GraphicsFormat.D32_SFloat_S8_UInt;
const int k_DepthBufferBits = 32;
#endif
と、SwitchとAndroidはD24_UNorm_S8_UInt、そのほかはD32_SFloat_S8_UIntで指定している。
このD24_UNorm_S8_UIntというGraphicsFormatは、ドキュメントに書いている通りDepthとStencilの2つを32bitとして扱うように定義している。
A two-component, 32-bit packed format that has 8 unsigned integer bits in the stencil component, and 24 unsigned normalized bits in the depth component.
ステンシル コンポーネントに 8 つの符号なし整数ビット、深度コンポーネントに 24 の符号なし正規化ビットを持つ 2 コンポーネントの 32 ビット パック形式。
D24_UNORM_S8_UINT、D32_SFLOAT_S8_UINTとは?
グラフィックスAPIがサポートする深度テクスチャフォーマット。Vulkanを例に挙げると、
-
VK_FORMAT_D32_SFLOAT
: 32-bit float for depth -
VK_FORMAT_D32_SFLOAT_S8_UINT
: 32-bit signed float for depth and 8 bit stencil component -
VK_FORMAT_D24_UNORM_S8_UINT
: 24-bit float for depth and 8 bit stencil component
がサポートされている。
Depth buffering - Vulkan Tutorial
Sebastian Aaltonen氏曰く、2022/11の段階ではAndroid端末におけるD24_UNORM_S8_UINTのカバー率は75%、D32_SFLOAT_S8_UINTは74%と低い。Unty的にもExperimental定義されている。
ただ、基本的にサポートされていないGraphicsFormatの場合、サポートされているGraphicsFormatに切り替わるようになるため、ExperimentalでもUniversalRendererに導入されているのだと思う。
今後はdepthStencilFormatのみ設定すればよい?
UniversalRendererで_CameraDepthTexture
Alloc用RenderTextureDescriptorを定義している箇所では、
depthDescriptor.graphicsFormat = GraphicsFormat.None;
depthDescriptor.depthStencilFormat =k_DepthStencilFormat;
depthDescriptor.depthBufferBits =k_DepthBufferBits;
と、depthStencilFormatとdepthBufferBits両方を設定している。depthStencilFormatだけの変更では足りない?depthBufferBitsの設定ではdepthStencilFormatの値が変更されているから、RenderTexture.GetDepthStencilFormatLegacy
内で何か必要な設定がおこなわれている?
実験として、BreakPointを貼って値がどのように変化するかを確認してみる。
depthBufferBitsに24を代入したが、実際には32と定義されていた。depthBufferBitsのsetterで呼び出されているRenderTexture.GetDepthStencilFormatLegacy
によって、現在のPlatformに適切な値に変更が加えられていそう。DepthやStencilのFormatを呼び出す場合、無難にUniversalRenderer準拠でdepthStencilFormatとdepthBufferBitsそれぞれを設定する方が良いかもしれない。
Discussion