最近找到了 Google Poly 的插件 (Unity asset store 里下载就可以), 看里面的 Shader 很棒,所以开这个专栏来进行学习 (重点是应用) 主要是两个 cginc

后面会对每个效果进行代码拆解

# Brush.cginc 和 Particles.cginc

# Brush/Partice/Snow

# 属性

1
2
3
4
5
6
7
8
9
Properties {
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
_MainTex ("Particle Texture", 2D) = "white" {}
_ScrollRate("Scroll Rate", Float) = 1.0
_ScrollDistance("Scroll Distance", Vector) = (1.0, 0, 0)
_ScrollJitterIntensity("Scroll Jitter Intensity", Float) = 1.0
_ScrollJitterFrequency("Scroll Jitter Frequency", Float) = 1.0
_SpreadRate ("Spread Rate", Range(0.3, 5)) = 1.539
}
  • TintColor: 色调
  • MainTex: 主要贴图
  • ScrollRate: 滚动频率 (下落)
  • ScrollDistance: 滚动方向
  • ScrollJitterIntensity: 滚动偏差强度
  • ScrollJitterFrequency: 滚动偏差频率
  • SpreadRate: 传播率 (没看懂)

# 渲染流程

先上代码

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
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

Shader "Brush/Particle/Snow" {
Properties {
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
_MainTex ("Particle Texture", 2D) = "white" {}
_ScrollRate("Scroll Rate", Float) = 1.0
_ScrollDistance("Scroll Distance", Vector) = (1.0, 0, 0)
_ScrollJitterIntensity("Scroll Jitter Intensity", Float) = 1.0
_ScrollJitterFrequency("Scroll Jitter Frequency", Float) = 1.0
_SpreadRate ("Spread Rate", Range(0.3, 5)) = 1.539
}

Category {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True" }
Blend SrcAlpha One
AlphaTest Greater .01
ColorMask RGB
Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }

SubShader {
Pass {

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_particles
#pragma multi_compile __ AUDIO_REACTIVE
#pragma multi_compile __ TBT_LINEAR_TARGET
#pragma target 3.0

#include "UnityCG.cginc"
#include "../../../Shaders/Include/Brush.cginc"
#include "../../../Shaders/Include/Particles.cginc"

sampler2D _MainTex;
fixed4 _TintColor;

struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};

float4 _MainTex_ST;
float _ScrollRate;
float3 _ScrollDistance;
float _ScrollJitterIntensity;
float _ScrollJitterFrequency;
float _SpreadRate;

v2f vert (ParticleVertexWithSpread_t v)
{
v2f o;
v.color = TbVertToSrgb(v.color);
float birthTime = v.texcoord.w;
float rotation = v.texcoord.z;
float halfSize = GetParticleHalfSize(v.corner.xyz, v.center, birthTime);
float spreadProgress = SpreadProgress(birthTime, _SpreadRate);
float4 center = SpreadParticle(v, spreadProgress);
float4 center_WS = mul(unity_ObjectToWorld, center);

// Custom vertex animation
float scrollAmount = _Time.y;
float t = fmod(scrollAmount * _ScrollRate + v.color.a, 1);
float4 dispVec = (t - .5f) * float4(_ScrollDistance, 0.0);
dispVec.x += sin(t * _ScrollJitterFrequency + _Time.y) * _ScrollJitterIntensity;
dispVec.z += cos(t * _ScrollJitterFrequency * .5 + _Time.y) * _ScrollJitterIntensity;
dispVec.xyz = spreadProgress * dispVec * kDecimetersToWorldUnits;
center_WS += mul(xf_CS, dispVec);


float4 corner_WS = OrientParticle_WS(center_WS.xyz, halfSize, v.vid, rotation);
#ifdef AUDIO_REACTIVE
o.color = musicReactiveColor(v.color, _BeatOutput.w);
corner_WS = musicReactiveAnimationWorldSpace(corner_WS, v.color, _BeatOutput.w, corner_WS.y*5);
#else
o.color = v.color;
#endif

o.vertex = mul(UNITY_MATRIX_VP, corner_WS);
o.color.a = pow(1 - abs(2*(t - .5)), 3);
o.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
return o;
}

// Input color is srgb
fixed4 frag (v2f i) : SV_Target
{
return SrgbToNative(2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord));
}
ENDCG
}
}
}
}

首先是透明三个标签 然后是从 Particles.cginc 里引用的输入结构体 ParticleVertexWithSpread_t

1
2
3
4
5
6
7
8
9
#define ParticleVertexWithSpread_t ParticleVertex_t

struct ParticleVertex_t {
uint vid : SV_VertexID;
float4 corner : POSITION; // pos: corner of randomly-oriented quad
float3 center : TEXCOORD1;
fixed4 color : COLOR;
float4 texcoord : TEXCOORD0; // xy: texcoord z: rotation w: birth time
};`

函数解释

TbVertToSrgb (Texture buffer vert to srgb) LinearToSrgb (float4 color)- 线性空间到 srgb

1
2
3
4
5
6
7
8
9
float4 LinearToSrgb(float4 color) {
// Approximation http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
float3 linearColor = color.rgb;
float3 S1 = sqrt(linearColor);
float3 S2 = sqrt(S1);
float3 S3 = sqrt(S2);
color.rgb = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * linearColor;
return color;
}

用来根据边角位置和中心位置计算当前粒子的大小,以及从创建开始的时间 (用来根据时间让他慢慢变小)
GetParticleHalfSize(float3 corner, float3 center, float birthTime)
- corner : 边角对象空间的位置 (仅用来计算大小) - center: 对象空间下的中心位置 完全出生 - birthTime: 粒子出生时间 _ParticleUnpackTime (inout birthTime): 解包粒子得到时间
一般小大:

1
2
float sizeAdjust = _ParticleUnpackTime(/* inout */ birthTime);
float halfSize = length(corner - center) * kRecipSquareRootOfTwo * sizeAdjust;

kRecipSquareRootOfTwo = 0.70710678;

这个函数是计算粒子位置从他的起始到重置点动画的中间值

1
2
3
float4 SpreadParticle(ParticleVertexWithSpread_t particle, float progress) {
return float4(particle.center.xyz, 1);
}

计算当前的透明度

1
float t = fmod(scrollAmount * _ScrollRate + v.color.a, 1);

这个不受光