• RuntimesUnity
  • URPSpineSpriteのWrite to Depth有効時の描画ついて

初歩的な質問かもしれませんが、よろしくお願いします。

Unity 2022.3.10f1 Spine4.2.32を使用しています。
UnityAssetStoreのURP Stylized Water Shader(無料)のようなを使用し、水中を表現しようと考えています。
上記アセットとSpineモデルをそのまま組み合わせてもSpineモデルを無視した描画がされるため、以下の設定を行いました。

・SpineモデルパーツのMaterialのShaderはUniversalRenderPipeline/Spine/Spriteに設定
・Write to Depthを有効
・Depth Alpha Cutoffは0.5
・Fixed Normalsを有効
・SkeletonAnimationのZ Spacingを-0.01に設定


水の揺らぎの中にSpineモデルが存在しているような描画がされるようになりましたが、モデルテクスチャの半透明部分が透けてしまいました。
Depth Aplha Cutoffである程度軽減できますが、それも完全ではなく、数値を上げるほど描画が美しくなくなってしまいます。

これを解決する方法、もしくは別の方法があれば教えていただけますでしょうか。

    Related Discussions
    ...

    Spineモデルの半透明部分が透けてしまう問題は、Write to Depthを有効にした際の一般的な問題です。以下の方法で改善を試みることができます:

    1. Depth Alpha Cutoffの調整:
      現在、Depth Alpha Cutoffを0.5に設定しているようですが、これを微調整して最適な値を見つけることが重要です。高すぎる値は描画の美しさを損なう可能性があるため、適切なバランスを見つける必要があります。

    2. シェーダーのカスタマイズ:
      Spine/Skeleton Lit ZWriteのようなシンプルなシェーダーをベースに、必要に応じてカスタマイズすることが考えられます。以下のようにシェーダーを変更してみてください:

         Shader "Spine/Skeleton Lit Depth Write" {
             Properties {
                 // 既存のプロパティ
             }
             SubShader {
                 Tags { "Queue"="AlphaTest" }
                 Pass {
                     ZWrite On
                     // 既存のシェーダーコード
                 }
             }
         }

      これにより、深度バッファへの書き込みを有効にしつつ、透明度の問題を軽減できます。

    3. 描画順序の調整:
      SkeletonAnimationコンポーネントのZ Spacingを調整することで、描画順序を変更し、透明部分の問題を軽減することができます。現在は-0.01に設定されていますが、他の値も試してみてください。

    4. Stencil Bufferの使用:
      ステンシルバッファを使用して、透明部分の描画を制御する方法もあります。以下のようにシェーダーを変更してみてください:

         Pass {
             Stencil {
                 Ref 1
                 Comp Always
                 Pass Replace
             }
             ColorMask 0
         }

      これにより、透明部分が正しく描画されるようになります。

    これらの方法を試して、最適な解決策を見つけてください。

    Hatahata 詳細な条件を添えてご質問いただきありがとうございます。ただ恐れ入りますが「現在得られている結果」と「期待している結果」が分からないとアドバイスをすることが難しいため、Spineboyなどのサンプルスケルトンに、カスタマイズしたシェーダーを適用した画像を投稿していただけないでしょうか?
    お手数ですが正確なサポートのためにご協力いただけますと幸いです。

    お手数をおかけします。
    SpineBoyではかなり分かりにくいので、再び自作モデルも含めることをお許しください。

    http://unholy-creation.net/files/sample.png
    現状としてはWrite to Depthを有効にすると、半透明のピクセルが後ろ側に設定されているパーツ画像を貫通し、背景に至るまで透過していると推測される状態となっています。
    Write to Depthを無効にした場合、右のような描写になります。
    理想としてはWrite to Depthを有効にし、下側にある水のシェーダーにSpineモデルの映像を反映させつつ、Write to Depthを無効にしたときのようなモデルの描写にすることです。

    よろしくお願いします。

      Hatahata 画像を投稿していただきありがとうございます!この問題については以下のスレッドのHaraldの回答が参考になるかと思います:
      https://ja.esotericsoftware.com/forum/d/11454-sprite-shader-depth-write/5

      In this case you cannot handle this in a single render pass - that's where you need the two different alpha cutoff thresholds:
      1) one that is low enough to not discard the transparent pixel in the first pass, and then
      2) another one at e.g. 0.5 that blurs everything that is mostly transparent and therefore shall count as background.
      This case is where the camera.RenderWithShader() replacement shaders come in handy, since they can render another pass just to write different depth values.

      もし異なるアルファカットオフしきい値で2回描画するようにしてみても問題が解消しなければ再度ご質問いただけますと幸いです。

      @Hatahata Thanks for sharing a screenshot of the issue, this helps a lot. The issue is showing a theoretical problem when rendering transparent objects while writing to the Z Buffer, which can unfortrunately not be solved perfectly. The general problem is that opaque and alpha-tested objects are rendered in front-to-back order while writing to the Z-buffer. Then afterwards transparent objects are rendered in back-to-front order, but they don't render where the Z-buffer is already set to a closer distance.

      The quality-wise best solution, as Misaki mentioned, would be to render the object twice:

      1. Low-Quality write to Z-Buffer: With alpha-test and write-to-depth enabled and a more aggressive alpha threshold (a value close to 1.0 or at 1.0) which cuts away more, but writes to the z buffer for the screen-space reflection post processing effects.
      2. High-Quality transparent: Render the mesh with normal transparency settings, write-to-depth disabled.

      This way you should get the normal high-quality blending in semi-transparent areas, while the Z-buffer will only be written at opaque pixels.

      Another solution (or improvement in general) would be to change the Render Queue setting of the Material which writes to the Z-buffer from Alpha Test to Transparent. You could also experiment with setting the Render Queue to Transparent - 1 and + 1 respectively.

      ご返信ありがとうございます!
      レンダリングを重ね合わせることで問題を解決できること自体は理解できましたが、私は個人で独学でゲームを制作しており、今のところシェーダーのコードに触れたことがなく知識を持ち合わせておりません。
      ご提示いただいたフォーラムなどを参考に、具体的にどのようにすればアルファしきい値を変えて2回レンダリングが出来るかなどを学習したいと思います。
      少し時間がかかるかもしれませんが、また後日結果を報告させていただきます。