前情提要
由于自己项目里要做一个效果,大略也是按照坐标从A贴图溶解变为B贴图,但在溶解过程中还需加上边缘效果等,看此插件效果好,功能强大,故阅读之。然其代码由于支持丰富,代码略多,文件繁多,记录一下看的过程略作解释。(顺便把代码都贴到一个页面方便自己查看=v=)
插件地址
https://assetstore.unity.com/packages/vfx/shaders/advanced-dissolve-111598
插件效果
组织方式(以XYZ切割那个场景举例)
一开始看会摸不着头脑,故给出一个大略的看的顺序,否则不知控制器在哪儿,shader的参数又是由哪个脚本控制。
- c# part
c#脚本首先看场景上名字带Controller的
Controller_Cutout.cs
Controller_Cutout.cs
用cs控制shader/material的切割参数如果是global则给material的一系列Global参数赋值,命名为下面的+
_Global
如果不用global就给所有material赋值,大致有1
2
3
4
5
6
7
8
9materials[i].SetTexture("_DissolveMap1", texture1);
materials[i].SetVector("_DissolveMap1_ST", new Vector4(texture1Tiling.x, texture1Tiling.y, texture1Offset.x, texture1Offset.y));
materials[i].SetVector("_DissolveMap1_Scroll", texture1Scroll);
materials[i].SetFloat("_DissolveMap1Intensity", texture1Intensity);
materials[i].SetFloat("_DissolveMap1Channel", (int)texture1Channel);
materials[i].SetFloat("_DissolveNoiseStrength", noise);
materials[i].SetFloat("_DissolveAlphaSourceTexturesUVSet", uvSet == UVSET.UV0 ? 0 : 1);
materials[i].SetFloat("_DissolveSourceAlphaTexturesBlend", textureBlend == TEXTURE_BLEND.Multiple ? 0 : 1);
Controller_Edge.cs
- 用cs控制shader/material的边缘参数
同样分为Global和非Global,主要为:1
2
3
4
5
6
7
8
9
10
11
12
13materials[i].SetFloat("_DissolveEdgeWidth", width);
materials[i].SetFloat("_DissolveEdgeShape", (int)shape);
materials[i].SetColor("_DissolveEdgeColor", color);
materials[i].SetFloat("_DissolveEdgeColorIntensity", intensity);
materials[i].SetTexture("_DissolveEdgeTexture", texture);
materials[i].SetFloat("_DissolveEdgeTextureReverse", reverse ? 1 : 0);
materials[i].SetFloat("_DissolveEdgeTextureMipmap", blur);
materials[i].SetFloat("_DissolveEdgeTextureAlphaOffset", alphaOffset);
materials[i].SetFloat("_DissolveEdgeTexturePhaseOffset", phaseOffset);
materials[i].SetFloat("_DissolveEdgeTextureIsDynamic", isDynamic ? 1 : 0);
materials[i].SetFloat("_DissolveGIMultiplier", GIMultyplier > 0 ? GIMultyplier : 0);
- shader part
找场景上被切了的物体,看它用的哪个shader,比如xyz场景里用的是Assets/VacuumShaders/Advanced Dissolve/Shaders/Physically Based/Specular.shader
Properties
- shader part - Properties
先来看它的Properties:
首先是Specular常见的贴图和参数然后是溶解常用参数,以及上面c#去控制的,在mat面板被隐藏的参数,我只放一个贴图相关的参数,其实插件支持几张图1
2
3
4
5
6
7
8
9_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGBA)", 2D) = "white" {}
_BumpMap("Normalmap", 2D) = "bump" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Specular("Specular", Range(0,1)) = 0.0
[Enum(Main Map Alpha,0,Specular Map Alpha,1)] _SpecularAlpha(" Source", Float) = 0
_SpecularColor(" Specular Color", Color) = (0.2,0.2,0.2)
_SpecularMap(" Specular Map (RGBA)", 2D) = "white" {}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[Cutout]_Cutoff(" Alpha Cutoff", Range(0,1)) = 0.5
//Mask
[HideInInspector][KeywordEnum(None, XYZ Axis, Plane, Sphere, Box, Cylinder, Cone)] _DissolveMask("Mak", Float) = 0
[HideInInspector][Enum(X,0,Y,1,Z,2)] _DissolveMaskAxis("Axis", Float) = 0
[HideInInspector][Enum(World,0,Local,1)] _DissolveMaskSpace("Space", Float) = 0
[HideInInspector] _DissolveMaskOffset("Offset", Float) = 0
[HideInInspector] _DissolveMaskInvert("Invert", Float) = 1
[HideInInspector][KeywordEnum(One, Two, Three, Four)] _DissolveMaskCount("Count", Float) = 0
[HideInInspector] _DissolveMaskPosition("", Vector) = (0,0,0,0)
[HideInInspector] _DissolveMaskNormal("", Vector) = (1,0,0,0)
[HideInInspector] _DissolveMaskRadius("", Float) = 1
//Alpha Source
[HideInInspector] [KeywordEnum(Main Map Alpha, Custom Map, Two Custom Maps, Three Custom Maps)] _DissolveAlphaSource("Alpha Source", Float) = 0
[HideInInspector] _DissolveMap1("", 2D) = "white" { }
[HideInInspector] [UVScroll] _DissolveMap1_Scroll("", Vector) = (0,0,0,0)
[HideInInspector] _DissolveMap1Intensity("", Range(0, 1)) = 1
[HideInInspector] [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)] _DissolveMap1Channel("", INT) = 3
//Edge
[HideInInspector] _DissolveEdgeWidth("Edge Size", Range(0,1)) = 0.25
[HideInInspector][Enum(Cutout Source,0,Main Map,1)] _DissolveEdgeDistortionSource("Distortion Source", Float) = 0
[HideInInspector] _DissolveEdgeDistortionStrength("Distortion Strength", Range(0, 2)) = 0
//Color
[HideInInspector] _DissolveEdgeColor("Edge Color", Color) = (0,1,0,1)
[HideInInspector][PositiveFloat] _DissolveEdgeColorIntensity("Intensity", FLOAT) = 0
[HideInInspector][Enum(Solid,0,Smooth,1, Smooth Squared,2)] _DissolveEdgeShape("Shape", INT) = 0
[HideInInspector][KeywordEnum(None, Gradient, Main Map, Custom)] _DissolveEdgeTextureSource("", Float) = 0
[HideInInspector][NoScaleOffset] _DissolveEdgeTexture("Edge Texture", 2D) = "white" { }
[HideInInspector][Toggle] _DissolveEdgeTextureReverse("Reverse", FLOAT) = 0
[HideInInspector] _DissolveEdgeTexturePhaseOffset("Offset", FLOAT) = 0
[HideInInspector] _DissolveEdgeTextureAlphaOffset("Offset", Range(-1, 1)) = 0
[HideInInspector] _DissolveEdgeTextureMipmap("", Range(0, 10)) = 1
[HideInInspector][Toggle] _DissolveEdgeTextureIsDynamic("", Float) = 0
shader part 入口
shader part - funcs入口
每个pass下都有1
2文章后面会主要看一个pass的vert & frag
1
2v2f_surf vert_surf
void frag_surfshader part - cginc
自定义引用1
2
shader part 实现
- shader part - 具体实现
- vert_surf 各种给frag需要的坐标做准备
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
61v2f_surf vert_surf (appdata_full v) {
UNITY_SETUP_INSTANCE_ID(v);
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
CURVED_WORLD_TRANSFORM_POINT_AND_NORMAL(v.vertex, v.normal, v.tangent)
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
o.pack0.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
o.pack1.xy = TRANSFORM_TEX(v.texcoord, _SpecularMap);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
// SH/ambient and vertex lights
o.sh = 0;
// Approximated illumination from non-important point lights
o.sh += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, worldPos, worldNormal);
o.sh = ShadeSHPerVertex (worldNormal, o.sh);
UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
//注意这里
//VacuumShaders
ADVANCED_DISSOLVE_INIT_DATA(o.pos, v.texcoord.xy, v.texcoord1.xy, o)
return o;
} - ADVANCED_DISSOLVE_INIT_DATA (in AdvancedDissolve.cginc)
1
2
3
4
5
6
- DissolveVertex2Fragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16inline void DissolveVertex2Fragment(float4 positionCS, float2 vertexUV0, float2 vertexUV1, inout float4 dissolveMapUV)
{
dissolveMapUV = 0;
dissolveMapUV = ComputeScreenPos(positionCS);
float2 texUV = VALUE_UVSET == 0 ? vertexUV0 : vertexUV1;
dissolveMapUV = float4(texUV.xy, 0, 0);
} - frag
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
123fixed4 frag_surf (v2f_surf IN) : SV_Target {
UNITY_SETUP_INSTANCE_ID(IN);
float3 worldPos = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w);
float3 normalWS = float3(IN.tSpace0.z, IN.tSpace1.z, IN.tSpace2.z);
//!!! 这边就是计算切割了,沿着这个方法往下查
float4 alpha = AdvancedDissolveGetAlpha(IN.pack0.xy, worldPos, normalWS, IN.dissolveUV);
// alpha算出来.a 范围为-1 or 0~1
DoDissolveClip(alpha);
float3 dissolveAlbedo = 0;
float3 dissolveEmission = 0;
// 1 alpha 2 - 3- 4 : _MainTex
float dissolveBlend = DoDissolveAlbedoEmission(alpha, dissolveAlbedo, dissolveEmission, IN.pack0.xy, 0);
//下面几乎都是正常的pbr光照
// prepare and unpack data
Input surfIN;
UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
UNITY_EXTRACT_FOG(IN);
UNITY_RECONSTRUCT_TBN(IN);
UNITY_EXTRACT_TBN(IN);
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
surfIN.uv_BumpMap.x = 1.0;
surfIN.uv_SpecularMap.x = 1.0;
surfIN.uv_MainTex = IN.pack0.xy;
surfIN.uv_BumpMap = IN.pack0.zw;
surfIN.uv_SpecularMap = IN.pack1.xy;
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
SurfaceOutputStandardSpecular o = (SurfaceOutputStandardSpecular)0;
SurfaceOutputStandardSpecular o;
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Occlusion = 1.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
o.Normal = fixed3(0,0,1);
// call surface function
surf (surfIN, o);
//这两句就是边缘着色了,另一篇讲溶解的介绍里也有: https://blog.csdn.net/w9503/article/details/105321355?utm_medium=distribute.pc_relevant.none-task-blog-title-2&spm=1001.2101.3001.4242
o.Albedo = lerp(o.Albedo, dissolveAlbedo, dissolveBlend);
o.Emission = lerp(o.Emission, dissolveEmission, dissolveBlend);
// compute lighting & shadowing factor
UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
fixed4 c = 0;
float3 worldN;
worldN.x = dot(_unity_tbn_0, o.Normal);
worldN.y = dot(_unity_tbn_1, o.Normal);
worldN.z = dot(_unity_tbn_2, o.Normal);
worldN = normalize(worldN);
o.Normal = worldN;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = _LightColor0.rgb;
gi.light.dir = lightDir;
// Call GI (lightmaps/SH/reflections) lighting function
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = worldPos;
giInput.worldViewDir = worldViewDir;
giInput.atten = atten;
giInput.lightmapUV = IN.lmap;
giInput.lightmapUV = 0.0;
giInput.ambient = IN.sh;
giInput.ambient.rgb = 0.0;
giInput.probeHDR[0] = unity_SpecCube0_HDR;
giInput.probeHDR[1] = unity_SpecCube1_HDR;
giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
giInput.boxMax[0] = unity_SpecCube0_BoxMax;
giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
giInput.boxMax[1] = unity_SpecCube1_BoxMax;
giInput.boxMin[1] = unity_SpecCube1_BoxMin;
giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
LightingStandardSpecular_GI(o, giInput, gi);
// realtime lighting: call lighting function
c += LightingStandardSpecular (o, worldViewDir, gi);
c.rgb += o.Emission;
UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
//!!!
return DoOutputForward(c, o.Alpha);
} - frag 引用
关键词:AdvancedDissolveGetAlpha
DoDissolveClip
DoDissolveAlbedoEmission
DoOutputForward
一个个来AdvancedDissolveGetAlpha
1
2
3
4
5
6
7
8
9
10
11
12// texcoord0: mainTex的texcorrd
// positionWS: worldPos
// normalWS: worldNormal
// dissolveUV: vert里算完的dissolveUV
float4 AdvancedDissolveGetAlpha(float2 texcoord0, float3 positionWS, float3 normalWS, float4 dissolveUV)
{
return ReadDissolveAlpha_Triplanar(positionWS, normalWS);
return ReadDissolveAlpha(texcoord0, dissolveUV, positionWS);
}ReadDissolveAlpha
(简化版,源代码中有诸多#ifdef,不便于阅读,故采取当前用到的展示)1
2
3
4
5
6
7
8
9
10
11//注意AdvancedDissolve.cginc引用了Variables.cginc,代码中的变量在Variables里找
inline float4 ReadDissolveAlpha(float2 mainTexUV, float4 dissolveMapUV, float3 vertexPos)
{
float4 alphaSource = 1;
float2 uv1 = dissolveMapUV.xy * VALUE_MAP1_ST.xy + VALUE_MAP1_ST.zw + VALUE_MAP1_SCROLL.xy * TIME;
alphaSource = READ_TEXTURE_2D(VALUE_MAP1, VALUE_MAP1_SAMPLER, uv1, VALUE_MAP1_INTENSITY);
alphaSource.a = alphaSource[VALUE_MAP1_CHANNEL];
float noise = ((alphaSource.a - 0.5) * 2) * VALUE_NOISE_STRENGTH;
alphaSource.a = ReadMaskValue(vertexPos, noise);
return alphaSource;
}Variables.cginc
1
2
3
4
5
6
7
8
9
10
11
12
// texture1
// tilling offset那个东西
//vector3, 用的xy
//float 0~1
//rgba- 结合上两个翻译版:
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
30inline float4 ReadDissolveAlpha(float2 mainTexUV, float4 dissolveMapUV, float3 vertexPos)
{
float4 alphaSource = 1;
float2 uv1 = dissolveMapUV.xy * _DissolveMap1_ST.xy + _DissolveMap1_ST.zw + _DissolveMap1_Scroll.xy * TIME;
alphaSource = READ_TEXTURE_2D(_DissolveMap1, sampler_DissolveMap1, uv1, _DissolveMap1Intensity);
alphaSource.a = alphaSource[_DissolveMap1Channel];
float noise = ((alphaSource.a - 0.5) * 2) * VALUE_NOISE_STRENGTH;
alphaSource.a = ReadMaskValue(vertexPos, noise);
return alphaSource;
}
inline float ReadMaskValue(float3 vertexPos, float noise)
{
float cutout = -1;
//world 0 or local 1
//if(VALUE_MASK_SPACE > 0.5)
vertexPos = mul(unity_WorldToObject, float4(vertexPos, 1)).xyz;
//VALUE_CUTOFF_AXIS: X:0 Y Z
// VALUE_MASK_OFFSET: _DissolveMaskOffset
// INVERT: 1 or -1 正反方向
cutout = (vertexPos - VALUE_MASK_OFFSET)[(int)VALUE_CUTOFF_AXIS] * VALUE_AXIS_INVERT;
cutout += noise;
return (cutout > 0 ? cutout : -1);
}
- vert_surf 各种给frag需要的坐标做准备