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();
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
}
}
}