Caustic Effect

1.caustic 效果实现
2.后期处理,在投射caustic的dirLight空间投射
3.消除阴影部分的投射
4.添加投射角度的衰减
5.添加距离衰减控制

1.caustic效果实现

将shadertoy上的uv限制进行修改,取消投射时的重复
https://www.shadertoy.com/view/MdlXz8

            float3 CausticTriTwist(float2 uv,float time )
            {
                const int MAX_ITER = 5;
                float2 p = uv-250;

                float2 i = float2(p);
                float c = 1.0;
                float inten = .005;

                for (int n = 0; n < MAX_ITER; n++) //3.多层叠加
                {
                    float t = time * (1.0 - (3.5 / float(n+1)));
                    i = p + float2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x));//2.空间扭曲
                    c += 1.0/length(float2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten)));//集合操作avg
                }
                
                c /= float(MAX_ITER);
                c = 1.17-pow(c, 1.4);//4.亮度调整
                float val = pow(abs(c), 8.0);
                return val;
            }

2.在dirLight空间进行投射

①深度图求出worldPos;
②脚本传入world to light matrix: _Matrix_W2L, 并将worldPos变换到LightPos;
③用lightPos的xy值进行采样,因为z是光线投射方向,下文也会用到

//worldPos+normal
float3 viewNormal;
float depth01;
DecodeDepthNormal(tex2D(_CameraDepthNormalsTexture,i.uv),depth01,viewNormal);
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv);
float4 pos = float4(i.uv.x*2-1,i.uv.y*2-1,(1-depth)*2-1,1);
pos = mul(_Matrix_P2W , pos);
float3 worldPos = pos.xyz/pos.w;
float4 lightPos = mul(_Matrix_W2L,float4(worldPos,1.0));
                
float2 CausticUV = float3(lightPos.xyz).xy;
float causstic = CausticTriTwist(CausticUV/_Repeat, _Time.y);
_repeat 控制重复

3.消除阴影投射

思路,主要拿到collectShadows就好办了


Caustic Effect_第1张图片
Caustic Effect_第2张图片

用commandBuffer,配合的C# ,unityAPI手册里CommandBuffer里有提到

RenderTargetIdentifier shadowmap = BuiltinRenderTextureType.CurrentActive;
m_ShadowmapCopy = new RenderTexture(myCamera.pixelWidth,myCamera.pixelHeight,0);
CommandBuffer cb = new CommandBuffer();
cb.Blit(shadowmap, new RenderTargetIdentifier(m_ShadowmapCopy));
dirctLight.AddCommandBuffer(LightEvent.AfterScreenspaceMask, cb);
shader
//消除阴影光强
float shadow = tex2D(_dirShadowMap,i.uv).r;
shadow = smoothstep(0.6,1.0,shadow);
causstic *= shadow;

4.添加角度的衰减

无衰减
Caustic Effect_第3张图片
比较假的原因
Caustic Effect_第4张图片
修正效果
Caustic Effect_第5张图片
//倾斜衰减
float3 worldNormal = mul(_Matrix_IV,viewNormal);
float3 lightNormal = mul(_Matrix_W2L,worldNormal);
float attenNormal = max(0,dot(lightNormal,float3(0,0,-1))) ;
float3 caussticCol=_Color * causstic * attenDistance * attenNormal;

5.添加距离衰减控制

_attenDistance 投射的距离
_attenLenght 效果过度融合的长度
还可以自己添加很多方面的控制
比如模拟深度对光强的影响等

//距离衰减
float attenDistance = smoothstep(_attenDistance+_attenLength,_attenDistance-_attenLength,length(_WorldSpaceCameraPos-worldPos));

C#脚本

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

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class CausticEffect : MonoBehaviour
{
    private Camera myCamera=null;
    public Shader effectShader=null;
    private Material effectMaterial=null;
    private RenderTexture m_ShadowmapCopy;

    public Light dirctLight=null;
    public Color causticColor = Color.yellow;
    public float attenDistance = 200;
    public float attenLength=50;
    public float repeat=10;


    private void OnEnable() {
        myCamera = this.GetComponent();
        if(myCamera!=null&&effectShader!=null&&effectShader.isSupported==true&&dirctLight.type==LightType.Directional){
            effectMaterial = new Material(effectShader);
            myCamera.depthTextureMode|=DepthTextureMode.Depth;
            myCamera.depthTextureMode=DepthTextureMode.DepthNormals;

            //get shadow map
            RenderTargetIdentifier shadowmap = BuiltinRenderTextureType.CurrentActive;
            m_ShadowmapCopy = new RenderTexture(myCamera.pixelWidth,myCamera.pixelHeight,0);
            CommandBuffer cb = new CommandBuffer();
            cb.Blit(shadowmap, new RenderTargetIdentifier(m_ShadowmapCopy));
            dirctLight.AddCommandBuffer(LightEvent.AfterScreenspaceMask, cb);
            
        }else
        {
            enabled=false;
            Debug.LogWarning("please check your C# value!");
        }
    }

    private void OnDisable() {
        if(effectMaterial!=null){
            effectMaterial=null;
        }
        
    }

    private void OnRenderImage(RenderTexture src, RenderTexture dest) {
        if(effectMaterial!=null){
            Matrix4x4 viewMatrix = myCamera.worldToCameraMatrix;
            Matrix4x4 projectMatrix = myCamera.projectionMatrix;
            Matrix4x4 _Matrix_P2W = (projectMatrix*viewMatrix).inverse;
            effectMaterial.SetMatrix("_Matrix_P2W",_Matrix_P2W);
            effectMaterial.SetMatrix("_Matrix_IV",viewMatrix.inverse);
            Matrix4x4 lightMatrix =  dirctLight.transform.worldToLocalMatrix;
            effectMaterial.SetMatrix("_Matrix_W2L",lightMatrix);
            effectMaterial.SetColor("_Color", causticColor);
            effectMaterial.SetFloat("_attenDistance",attenDistance);
            effectMaterial.SetFloat("_attenLength",attenLength);
            effectMaterial.SetFloat("_Repeat",repeat);

            effectMaterial.SetTexture("_dirShadowMap",m_ShadowmapCopy);
            
            Graphics.Blit(src,dest,effectMaterial);
        }else
        {
            Graphics.Blit(src,dest);
        }
    }

}

Shader

Shader "Unlit/caustic"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color("Color",Color)=(1,1,0,1)
        _attenDistance("attenDistance",float)=200
        _attenLength("attenLength",float)=50
        _Repeat("Repeat",float)=10
        _dirShadowMap("dirShadowMap",2D)="white"{}

    }
    SubShader
    {
        ZTest Always
        Cull Off
        ZWrite off 

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord:TEXCOORD;
            };

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

            sampler2D _MainTex;
            float3 _Color;
            float _attenDistance;
            float _attenLength;
            float _Repeat;
            sampler2D _CameraDepthTexture;
            sampler2D _CameraDepthNormalsTexture;
            float4x4 _Matrix_P2W;
            float4x4 _Matrix_W2L;
            float4x4 _Matrix_IV;
            sampler2D _dirShadowMap;


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

            float3 CausticTriTwist(float2 uv,float time )
            {
                const int MAX_ITER = 5;
                float2 p = uv-250;

                float2 i = float2(p);
                float c = 1.0;
                float inten = .005;

                for (int n = 0; n < MAX_ITER; n++) //3.多层叠加
                {
                    float t = time * (1.0 - (3.5 / float(n+1)));
                    i = p + float2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x));//2.空间扭曲
                    c += 1.0/length(float2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten)));//集合操作avg
                }
                
                c /= float(MAX_ITER);
                c = 1.17-pow(c, 1.4);//4.亮度调整
                float val = pow(abs(c), 8.0);
                return val;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //场景颜色
                fixed4 col = tex2D(_MainTex,i.uv);

                //worldPos+normal
                float3 viewNormal;
                float depth01;
                DecodeDepthNormal(tex2D(_CameraDepthNormalsTexture,i.uv),depth01,viewNormal);
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv);
                float4 pos = float4(i.uv.x*2-1,i.uv.y*2-1,(1-depth)*2-1,1);
                pos = mul(_Matrix_P2W , pos);
                float3 worldPos = pos.xyz/pos.w;
                float4 lightPos = mul(_Matrix_W2L,float4(worldPos,1.0));
                
                float2 CausticUV = float3(lightPos.xyz).xy;
                float causstic = CausticTriTwist(CausticUV/_Repeat, _Time.y);

                //距离衰减
                float attenDistance = smoothstep(_attenDistance+_attenLength,_attenDistance-_attenLength,length(_WorldSpaceCameraPos-worldPos));

                //消除阴影光强
                float shadow = tex2D(_dirShadowMap,i.uv).r;
                shadow = smoothstep(0.6,1.0,shadow);
                causstic *= shadow;

                //倾斜衰减
                float3 worldNormal = mul(_Matrix_IV,viewNormal);
                float3 lightNormal = mul(_Matrix_W2L,worldNormal);
                float attenNormal = max(0,dot(lightNormal,float3(0,0,-1))) ;
                float3 caussticCol=_Color * causstic * attenDistance * attenNormal;

                float3 finalCol = col + 0.2 * caussticCol;
                return float4(finalCol,1.0);
            }
            ENDCG
        }
    }
}

你可能感兴趣的:(Caustic Effect)