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就好办了



用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.添加角度的衰减

无衰减
比较假的原因
修正效果
//倾斜衰减
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<Camera>();
        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
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271