unity-shader-post-screenRipple

buildin效果图

urp效果图

ScreenRipple.shader

ScreenRipple.shader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
Shader "HHF/Post/ScreenRipple"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_GradTex ("Gradient", 2D) = "white" {}
_WaveColor ("Wave Color", color) = (0, 0, 0, 0)
_StartParam ("Start Param", Vector) = (0.49, 0.5, 0, 0)
_WaveParam ("Wave Param", Vector) = (1, 1, 1, 0)
}

SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" }
Cull Off ZWrite Off ZTest Always

Pass
{
HLSLPROGRAM
// Required to compile gles 2.0 with standard srp library
#pragma prefer_hlslcc gles
#pragma exclude_renderers d3d11_9x
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"

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

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

CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
half4 _WaveColor;
float4 _StartParam;
float4 _WaveParam;
CBUFFER_END

TEXTURE2D (_MainTex);SAMPLER(sampler_MainTex);
TEXTURE2D (_GradTex);SAMPLER(sampler_GradTex);

float calcWaveGradient(float2 position)
{
float d = length(position - _StartParam.xy);
float t = _Time.y - _StartParam.z - d * _StartParam.w;
return (SAMPLE_TEXTURE2D(_GradTex, sampler_GradTex, float2(t, 0)).a - 0.5f) * 2;
}

v2f vert (appdata v)
{
v2f o;
o.positionCS = TransformObjectToHClip(v.vertex.xyz);
o.uv = v.uv;
return o;
}

half4 frag (v2f i) : SV_Target
{
const float2 dx = float2(0.01f, 0);
const float2 dy = float2(0, 0.01f);

float2 wp = i.uv * _WaveParam.xy;
float w = calcWaveGradient(wp);
float2 dw = float2(calcWaveGradient(wp + dx) - w, calcWaveGradient(wp + dy) - w);
float2 duv = dw * 0.2f * _WaveParam.z;
half c = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv + duv).r;
float fr = pow(length(dw) * _WaveParam.w, 3);

return lerp(c, _WaveColor, fr);
}

ENDHLSL
}
}

SubShader
{
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 positionCS : SV_POSITION;
};

sampler2D _MainTex;
float4 _MainTex_ST;

sampler2D _GradTex;
half4 _WaveColor;
float4 _StartParam;
float4 _WaveParam;


float calcWaveGradient(float2 position)
{
float d = length(position - _StartParam.xy);
float t = _Time.y - _StartParam.z - d * _StartParam.w;
return (tex2D(_GradTex, float2(t, 0)).a - 0.5f) * 2;
}

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

half4 frag (v2f i) : SV_Target
{
const float2 dx = float2(0.01f, 0);
const float2 dy = float2(0, 0.01f);

float2 wp = i.uv * _WaveParam.xy;
float w = calcWaveGradient(wp);
float2 dw = float2(calcWaveGradient(wp + dx) - w, calcWaveGradient(wp + dy) - w);
float2 duv = dw * 0.2f * _WaveParam.z;
half c = tex2D(_MainTex, i.uv + duv);
float fr = pow(length(dw) * _WaveParam.w, 3);

return lerp(c, _WaveColor, fr);
}
ENDCG
}
}
}

ScreenRipple.cs

ScreenRipple.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
using UnityEngine;

namespace OKShader
{
/// <summary>
/// 屏幕波纹
/// </summary>
public class ScreenRipple : IPostEffect
{
public AnimationCurve waveform = new AnimationCurve(
new Keyframe(0.00f, 0.50f, 0, 0),
new Keyframe(0.05f, 1.0f, 0, 0),
new Keyframe(0.15f, 0.1f, 0, 0),
new Keyframe(0.25f, 0.8f, 0, 0),
new Keyframe(0.35f, 0.3f, 0, 0),
new Keyframe(0.45f, 0.6f, 0, 0),÷
new Keyframe(0.55f, 0.4f, 0, 0),
new Keyframe(0.65f, 0.55f, 0, 0),
new Keyframe(0.75f, 0.46f, 0, 0),
new Keyframe(0.85f, 0.52f, 0, 0),
new Keyframe(0.95f, 0.5f, 0, 0)
); // 波形曲线

[Range(0.01f, 1.0f)]
public float waveStrength = 0.5f; // 波浪强度

public Color waveColor = Color.gray; // 波浪颜色

[Range(0.01f, 5f)]
public float waveColorStrength = 2.1f; // 波浪颜色强度

[Range(1.0f, 3.0f)]
public float waveSpeed = 1.25f; // 波浪速度


private Texture2D m_gradientTexture; // 梯度纹理图

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

protected override void OnInit()
{
m_shader = this.Shader;
m_material = this.CreateMaterial(Shader);
}

protected override void OnRun(object[] arrParam)
{
this.CreateGradientTexture();

Camera c = this.GetComponent<Camera>();

m_material.SetTexture("_GradTex", m_gradientTexture);
m_material.SetColor("_WaveColor", waveColor);
m_material.SetVector("_StartParam", new Vector4( 0.5f * c.aspect, 0.5f, Time.timeSinceLevelLoad, 1 / waveSpeed));
m_material.SetVector("_WaveParam", new Vector4(c.aspect, 1, waveStrength, waveColorStrength));
}

protected override void OnPostEffectDestroy()
{
if (m_gradientTexture != null)
{
Destroy(m_gradientTexture);
m_gradientTexture = null;
}
}

/// <summary>
/// 创建梯度图
/// </summary>
private void CreateGradientTexture()
{
if (m_gradientTexture != null)
{
return;
}

m_gradientTexture = new Texture2D(512, 1, TextureFormat.Alpha8, false);
m_gradientTexture.name = "ScreenRippleTex";
m_gradientTexture.wrapMode = TextureWrapMode.Clamp;
m_gradientTexture.filterMode = FilterMode.Bilinear;

for (var i = 0; i < m_gradientTexture.width; i++)
{
var x = 1.0f / m_gradientTexture.width * i;
var a = waveform.Evaluate(x);
m_gradientTexture.SetPixel(i, 0, new Color(a, a, a, a));
}

m_gradientTexture.Apply();
}
}
}

ScreenRippleController.cs

ScreenRippleController.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using UnityEngine;
using UnityEngine.Rendering;

namespace OKShader
{
public class ScreenRippleController : MonoBehaviour
{
public AnimationCurve waveform = new AnimationCurve(
new Keyframe(0.00f, 0.50f, 0, 0),
new Keyframe(0.05f, 1.0f, 0, 0),
new Keyframe(0.15f, 0.1f, 0, 0),
new Keyframe(0.25f, 0.8f, 0, 0),
new Keyframe(0.35f, 0.3f, 0, 0),
new Keyframe(0.45f, 0.6f, 0, 0),
new Keyframe(0.55f, 0.4f, 0, 0),
new Keyframe(0.65f, 0.55f, 0, 0),
new Keyframe(0.75f, 0.46f, 0, 0),
new Keyframe(0.85f, 0.52f, 0, 0),
new Keyframe(0.95f, 0.5f, 0, 0)
); // 波形曲线

[Range(0.01f, 1.0f)]
public float waveStrength = 0.5f; // 波浪强度

public Color waveColor = Color.gray; // 波浪颜色

[Range(0.01f, 5f)]
public float waveColorStrength = 2.1f; // 波浪颜色强度

[Range(1.0f, 3.0f)]
public float waveSpeed = 1.25f; // 波浪速度


private Texture2D m_gradientTexture; // 梯度纹理图

public VolumeProfile volumeProfile;
ScreenRippleUrp screenRipple;

void Update()
{
if (volumeProfile == null) return;
if (screenRipple == null) volumeProfile.TryGet<ScreenRippleUrp>(out screenRipple);
if (screenRipple == null) return;

}

private void OnGUI()
{
if (GUI.Button(new Rect(100, 100, 100, 100), "Run"))
{
this.CreateGradientTexture();

Camera c = Camera.main;

screenRipple.Gradient.value = m_gradientTexture;
screenRipple.WaveColor.value = waveColor;
screenRipple.StartParam.value = new Vector4( 0.5f * c.aspect, 0.5f, Time.timeSinceLevelLoad, 1 / waveSpeed);
screenRipple.WaveParam.value = new Vector4(c.aspect, 1, waveStrength, waveColorStrength);
}
}

/// <summary>
/// 创建梯度图
/// </summary>
private void CreateGradientTexture()
{
if (m_gradientTexture != null)
{
return;
}

m_gradientTexture = new Texture2D(512, 1, TextureFormat.Alpha8, false);
m_gradientTexture.name = "ScreenRippleTex";
m_gradientTexture.wrapMode = TextureWrapMode.Clamp;
m_gradientTexture.filterMode = FilterMode.Bilinear;

for (var i = 0; i < m_gradientTexture.width; i++)
{
var x = 1.0f / m_gradientTexture.width * i;
var a = waveform.Evaluate(x);
m_gradientTexture.SetPixel(i, 0, new Color(a, a, a, a));
}

m_gradientTexture.Apply();
}
}
}