LoginSignup
66
52

More than 5 years have passed since last update.

【Unity3D】 デプスバッファを利用する

Posted at

DepthTextureについて

Cameraから描画する

  • カラーバッファ
    DepthTexture00s.jpg

  • デプスバッファ
    DepthTexture01s.jpg

● 手順
1. Cameraのデプスバッファ描画先にRenderTextureをアタッチする。
2. OnPostRender() で加工したり、画面に出力したりします。

●サンプルコード
```csharp
public class RenderDepthBuffer : MonoBehaviour
{
private RenderTexture m_colorTex;
private RenderTexture m_depthTex;
public Material m_postRenderMat;

void Start ()
{
    Camera cam = GetComponent<Camera>();
    cam.depthTextureMode = DepthTextureMode.Depth;

    // カラーバッファ用 RenderTexture
    m_colorTex = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
    m_colorTex.Create();

    // デプスバッファ用 RenderTexture
    m_depthTex = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.Depth);
    m_depthTex.Create();

    // cameraにカラーバッファとデプスバッファをセットする
    cam.SetTargetBuffers(m_colorTex.colorBuffer, m_depthTex.depthBuffer);
}

void OnPostRender()
{
    // RenderTarget無し:画面に出力される
    Graphics.SetRenderTarget(null);

    // デプスバッファを描画する(m_postRenderMatはテクスチャ画像をそのまま描画するマテリアル)
    Graphics.Blit(m_depthTex, m_postRenderMat);
}

}
```

別のカメラで利用する

カメラAで描画されたデプスバッファを元に、カメラBで別の描画を行う。
とりあえずサンプルコードだけ。

{
    // 1つ目のcameraで描画されたカラーバッファとデプスバッファ
    public RenderTexture m_firstColorTex;
    public RenderTexture m_firstDepthTex;

    // 2つ目のcameraの描画先
    private RenderTexture m_renderBuffer;

    public Material m_postRenderMat;
    public Material m_cutOffMat;

    void Start()
    {
        Camera cam = GetComponent<Camera>();

        // 二つ目のcameraの描画バッファ
        m_renderBuffer = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
        m_renderBuffer.Create();

        // ・カラーバッファは上記で作成したもの
        // ・デプスバッファは別のcameraで描画されたもの
        // をセットする。
        cam.SetTargetBuffers(m_renderBuffer.colorBuffer, m_firstDepthTex);
    }

    void OnPostRender()
    {
        // 描画先を完全にクリアする
        Graphics.SetRenderTarget(null);
        GL.Clear(true, true, new Color(0, 0, 0, 0));

        // 1つ目のcameraで描画されたカラーバッファを画面に描画
        Graphics.Blit(m_firstColorTex, m_postRenderMat, 0);

        // 2つ目のcameraで描画されたカラーバッファを合成
        // そのまま描画すると全て塗りつぶされてしまうので、適当にカットオフマテリアルで描画
        Graphics.Blit(m_renderBuffer, m_cutOffMat, 0);
    }
}

デプスバッファから輪郭を抽出する

  • 最終結果
    DepthEdge01s.jpg

  • 抽出された輪郭
    DepthEdge00s.jpg

●手順
1. cameraにカラーバッファとデプスバッファのRenderTextureを設定
2. OnPostRender() でカラーバッファを画面に描画。
3. デプスバッファから輪郭を抽出して別のRenderTextureへ描画
4. 輪郭テクスチャを画面に合成

●カメラにアタッチするコンポーネント

    private RenderTexture m_colorTex;   // カラーバッファ
    private RenderTexture m_depthTex;   // デプスバッファ
    private RenderTexture m_edgeTex;    // 輪郭描画先のバッファ

    public Material m_postRenderMat;    // カラーバッファ描画用
    public Material m_renderEdgeMat;    // 輪郭抽出シェーダー
    public Material m_cutOffMat;        // 輪郭合成用

    void OnPostRender()
    {
        // カラーバッファを転送(m_postRenderMatはテクスチャ画像をそのまま描画するマテリアル)
        Graphics.SetRenderTarget(null);
        GL.Clear(true, true, new Color(0, 0, 0, 0));
        Graphics.Blit(m_colorTex, m_postRenderMat);

        // 輪郭抽出用RenderTargetへ描画
        Graphics.SetRenderTarget(m_edgeTex);
        GL.Clear(true, true, new Color(0, 0, 0, 0));
        Graphics.Blit(m_depthTex, m_edgeTex, m_renderEdgeMat);

        // 輪郭テクスチャを画面に合成
        Graphics.SetRenderTarget(null);
        Graphics.Blit(m_edgeTex, m_cutOffMat);
    }

●輪郭抽出シェーダー

Shader "Custom/RenderDepthEdge" {
    Properties {
        _MainTex ("Depth Texture", 2D) = "white" {}
        _Threshold ("Edge Threshold", Range(0.0001, 1)) = 0.01
        _EdgeColor ("Edge Color", Color) = (1,1,1,1)
        _Thick("Thick", Range(0.1, 5)) = 1
    }

    SubShader {
        Tags { "RenderType"="Opaque" }
        ZTest Off
        ZWrite Off
        Lighting Off
        AlphaTest Off

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4  _MainTex_ST;
            float _Threshold;
            float4 _EdgeColor;
            float _Thick;
            float4  _MainTex_TexelSize; // 1テクセルを正規化した値

            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
                half2 texcoord : TEXCOORD0;
            };

            v2f vert(appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            fixed4 frag(v2f input) : Color
            {
                float tx = _MainTex_TexelSize.x * _Thick;
                float ty = _MainTex_TexelSize.y * _Thick;

                //※「DirectX9 シェーダープログラミングブック」を参考にしています。
                // 輪郭判定値の計算
                // (-1,-1) ┼─┼ (0, -1)
                //         │  │
                // (-1, 0) ┼─┼ (0,  0)
                // の4ピクセルの対角線同士でデプス値の差を取って2乗したものを加算する
                float col00 = Linear01Depth(tex2D(_MainTex, input.texcoord + half2(-tx, -ty)).r);
                float col10 = Linear01Depth(tex2D(_MainTex, input.texcoord + half2(  0, -ty)).r);
                float col01 = Linear01Depth(tex2D(_MainTex, input.texcoord + half2(-tx,   0)).r);
                float col11 = Linear01Depth(tex2D(_MainTex, input.texcoord + half2(  0,   0)).r);
                float val = (col00 - col11) * (col00 - col11) + (col10 - col01) * (col10 - col01);

                // 閾値以下ならクリップする
                if(val < _Threshold)
                {
                    clip(-1);
                }

                fixed4 col = _EdgeColor;
                return col;
            }
            ENDCG
        }
    } 
}
66
52
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
66
52