C++幼女先輩

プログラミング成分多め

UNITYの影調査

先程まででUNITYの影の作成ができましたが
今回はもう少し調査してみます

通常表示

f:id:murasame-labo:20180923225658p:plain
ShadowCasterパスを追加し、ちゃんと影を表示できてます

影のみ表示させてみる

影のみは SHADOW_ATTENUATION で取れる
今回は R要素のみに SHADOW_ATTENUATION値を入れる
フラグメントシェーダーの戻り値を下記のように変更

                return float4( SHADOW_ATTENUATION(i), 1,1,1);

SHADOW_ATTENUATIONは 影の部分が0、表が1なので、影の部分のみ青緑になるはず
f:id:murasame-labo:20180926141446p:plain

ちゃんと影部分のみ 青緑になりました

ShadowMapを表示してみる

調査していくなかでシェーダーコードを見ていて発見した
_ShadowMapTexture という名前で シャドウマップを生成しているので、それを表示してみることに
ポストプロセスでもシャドウマップは残っているため ポスプロで表示してみる

ポストプロセス スクリプト

using UnityEngine;

public class PP : MonoBehaviour {

    public Material mat;
    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        Graphics.Blit(src, dest, mat);
    }
}

(本当は Require Cameraとかしたほうが良いが) シンプルに 現在のフレームをそのままシェーダーに通すだけ

シェーダー

Shader "Custom/PPShadowMap"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

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

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            sampler2D _MainTex;
            sampler2D _ShadowMapTexture;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_ShadowMapTexture, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

_ShadowMapTexture という名前で定義されているシャドウマップをそのまま表示してみる

f:id:murasame-labo:20180926154529p:plain

これが シャドウマップだ! ライトからの透視変換なので、すでにこの時点で 元の透視変換行列を失っており スクリーンに投影し辛い

マルチレンダーターゲットで影を別のターゲットにしポストプロセスで合成

UNITYでMRTを使うには 普通のシェーダと同じく、フラグメントシェーダの戻り値をfloatではなく構造体にし SV_Targetn を使えばいい

            struct fout{
                fixed4 c0 : SV_Target0;
                fixed4 c1 : SV_Target1;
                fixed4 c2 : SV_Target2;
                fixed4 c3 : SV_Target3;
                fixed4 c4 : SV_Target4;
                fixed4 c5 : SV_Target5;
                fixed4 c6 : SV_Target6;
                fixed4 c7 : SV_Target7;
            };


...

                o.c0 = fixed4( (ambient + diffuse) * tex + specular, 1.0);
                o.c1 = fixed4( LIGHT_ATTENUATION(i), 1, 1, 1 );

                return o;

ポストプロセス

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class PP_HatchShadow : MonoBehaviour {
    
    public Material mat;


    private RenderTexture camTarget;
    private RenderTexture[] buf = new RenderTexture[8];
    private RenderTexture depth;



    private Camera cam;

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

        for (int i = 0; i < 8; i++){
            buf[i] = new RenderTexture(Screen.width, Screen.height, 0);
            buf[i].Create();
        }

        CommandBuffer cmd = new CommandBuffer();
        RenderTargetIdentifier tar = new RenderTargetIdentifier(BuiltinRenderTextureType.CurrentActive);


        cam.SetTargetBuffers(new RenderBuffer[8] {
            buf[0].colorBuffer, buf[1].colorBuffer
            , buf[2].colorBuffer, buf[3].colorBuffer
            , buf[4].colorBuffer, buf[5].colorBuffer
            , buf[6].colorBuffer, buf[7].colorBuffer
            }, buf[0].depthBuffer);

        mat.SetTexture("_RT0", buf[0]);
        mat.SetTexture("_RT1", buf[1]);
        mat.SetTexture("_RT2", buf[2]);
        mat.SetTexture("_RT3", buf[3]);

        cmd.name = "PPHatchingShadow";
        cmd.Blit(tar, tar, mat);

        cam.AddCommandBuffer(CameraEvent.BeforeImageEffects, cmd);
    }
}

これで、ポストプロセスにて o.c1.x 成分として影がとれるはずだが
結果を言うと デプスがおかしい

原因はどうも、UNITYでは ポストプロセスにてレンダーターゲットが変わって(アーリーデプスの結果が消え)
のようだ

ってことで、今度はこのあたりの調査をしようとおもう