优化特效-溶解材质

This commit is contained in:
tianmo committed 2026-10-12 10:38:19 +08:00
1 parent 5d58cb3743
commit 5bf02177df
32 files changed
+6537 -8

No files matched your search

+137 -2
View File
@@ -1,5 +1,6 @@
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
// UIMask 的材质面板:分组折叠 + 中文标签。
// shader 里用 CustomEditor "UIMaskShaderGUI" 挂上这个类。
@@ -9,6 +10,9 @@ public class UIMaskShaderGUI : ShaderGUI
{
private const string FoldKeyPrefix = "UIMask.GUI.";
// 用来读取 shader 里声明的默认值(新建一个隐藏材质读它的初始值)
private static Material defaultsMaterial;
private class Group
{
public string Label;
@@ -45,7 +49,17 @@ public class UIMaskShaderGUI : ShaderGUI
{
Label = "溶解",
Toggle = "_UseDissolve",
Props = new[] { "_DissolveTex", "_DissolveChannel", "_Dissolve", "_DissolveWidth" }
Props = new[]
{
"_DissolveTex",
"_DissolveChannel",
"_Dissolve",
"_DissolveWidth",
"_DissolveEdgeColor",
"_DissolveEdgeSharpness",
"_DissolveHighlightColor",
"_DissolveHighlightWidth"
}
},
new Group
{
@@ -82,11 +96,15 @@ public class UIMaskShaderGUI : ShaderGUI
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
bool newExpanded = EditorGUILayout.Foldout(expanded, group.Label, true, EditorStyles.foldoutHeader);
GUILayout.FlexibleSpace();
if (toggle != null)
{
GUILayout.FlexibleSpace();
editor.ShaderProperty(toggle, GUIContent.none, 0);
}
if (GUILayout.Button(new GUIContent("重置", "把本组参数恢复为 shader 默认值"), EditorStyles.miniButton, GUILayout.Width(42f)))
{
ResetGroup(editor, props, group);
}
EditorGUILayout.EndHorizontal();
if (newExpanded != expanded)
@@ -104,6 +122,123 @@ public class UIMaskShaderGUI : ShaderGUI
EditorGUILayout.EndVertical();
}
// 把某一组的属性恢复成 shader 默认值(启用开关同时同步它的关键字)
private static void ResetGroup(MaterialEditor editor, MaterialProperty[] props, Group group)
{
Material sample = null;
foreach (Object target in editor.targets)
{
sample = target as Material;
if (sample != null)
{
break;
}
}
if (sample == null)
{
return;
}
if (defaultsMaterial == null || defaultsMaterial.shader != sample.shader)
{
if (defaultsMaterial != null)
{
Object.DestroyImmediate(defaultsMaterial);
}
defaultsMaterial = new Material(sample.shader) { hideFlags = HideFlags.HideAndDontSave };
}
Undo.RecordObjects(editor.targets, "Reset " + group.Label);
foreach (string name in EnumerateNames(group))
{
MaterialProperty prop = FindProperty(name, props, false);
if (prop == null || !defaultsMaterial.HasProperty(name))
{
continue;
}
switch (prop.type)
{
case MaterialProperty.PropType.Color:
prop.colorValue = defaultsMaterial.GetColor(name);
break;
case MaterialProperty.PropType.Vector:
prop.vectorValue = defaultsMaterial.GetVector(name);
break;
case MaterialProperty.PropType.Texture:
prop.textureValue = defaultsMaterial.GetTexture(name);
break;
default:
float value = defaultsMaterial.GetFloat(name);
prop.floatValue = value;
// 开关类属性(_UseXxx)要把关键字一起恢复,否则面板勾选和实际编译状态会对不上
if (name.StartsWith("_Use"))
{
SetKeyword(editor, KeywordOf(name), value > 0.5f);
}
break;
}
}
foreach (Object target in editor.targets)
{
EditorUtility.SetDirty(target);
}
}
private static IEnumerable<string> EnumerateNames(Group group)
{
if (!string.IsNullOrEmpty(group.Toggle))
{
yield return group.Toggle;
}
foreach (string row in group.Props)
{
int separator = row.IndexOf('|');
if (separator < 0)
{
yield return row;
}
else
{
yield return row.Substring(0, separator);
yield return row.Substring(separator + 1);
}
}
}
private static string KeywordOf(string propertyName)
{
string trimmed = propertyName.StartsWith("_") ? propertyName.Substring(1) : propertyName;
return "_" + trimmed.ToUpperInvariant() + "_ON";
}
private static void SetKeyword(MaterialEditor editor, string keyword, bool enabled)
{
foreach (Object target in editor.targets)
{
var material = target as Material;
if (material == null)
{
continue;
}
if (enabled)
{
material.EnableKeyword(keyword);
}
else
{
material.DisableKeyword(keyword);
}
}
}
// group.Props 里一项 = 一行;写 "A|B" 表示这两个单值属性并排在同一行
private static void DrawProps(MaterialEditor editor, MaterialProperty[] props, string[] rows)
{
+4
View File
@@ -114,6 +114,8 @@ Material:
- _DetailNormalMapScale: 1
- _Dissolve: 0
- _DissolveChannel: 3
- _DissolveEdgeSharpness: 2
- _DissolveHighlightWidth: 0.08
- _DissolveWidth: 0
- _Distortion: 0
- _DstBlend: 10
@@ -163,6 +165,8 @@ Material:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _ClipRect: {r: -1, g: -1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _DissolveEdgeColor: {r: 0, g: 0, b: 0, a: 1}
- _DissolveHighlightColor: {r: 0, g: 0, b: 0, a: 1}
- _EdgeColor: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _MainTexTiling: {r: 1, g: 1, b: 0, a: 0}
+20 -1
View File
@@ -9,7 +9,7 @@
// Blend 是固定功能状态,不参与 shader 变体表,所以切换混合模式不产生额外变体。
// 面向美术:程序/技术类参数一律用 [HideInInspector] 隐藏(混合模式内部值、Stencil 组、
// 顶点 Mask 翻转),需要时由程序控制,材质面板只留艺术参数。
Shader "VFX/VFX" {
Shader "VFX/Yeomai_VFX" {
Properties {
[UIMaskBlendMode] _BlendMode ("混合模式", Float) = 0
[HideInInspector] _SrcBlend ("Src Blend", Float) = 5
@@ -38,6 +38,12 @@ Properties {
[UIMaskChannel] _DissolveChannel("通道", Float) = 3
_Dissolve ("溶解进度", Range(0, 1.01)) = 0
_DissolveWidth ("溶解宽度", Range(0, 1)) = 0
// 默认黑色 = 不叠加任何颜色,保证新参数不影响原有溶解效果
[HDR]_DissolveEdgeColor ("溶解边缘颜色", Color) = (0, 0, 0, 1)
_DissolveEdgeSharpness ("边缘锐度 (越大越细)", Range(0.001, 8)) = 2
// 第二层:贴边界的细亮圈(烧纸的燃烧边),同样默认黑色不影响原效果
[HDR]_DissolveHighlightColor ("溶解边缘高亮", Color) = (0, 0, 0, 1)
_DissolveHighlightWidth ("高亮宽度 (越小越细)", Range(0.001, 0.5)) = 0.08
[Toggle] _UseUIMaskClip("启用", Float) = 0
_ClipRect("裁切矩形 (由 Mask / RectMask2D 控制)", Vector) = (-1, -1, 1, 1)
[Toggle] _UseVertexMask("启用", Float) = 0
@@ -124,6 +130,10 @@ Category {
float _DissolveChannel;
fixed _Dissolve;
fixed _DissolveWidth;
fixed4 _DissolveEdgeColor;
fixed _DissolveEdgeSharpness;
fixed4 _DissolveHighlightColor;
fixed _DissolveHighlightWidth;
#endif
// 通道选择:0=R 1=G 2=B 3=A。用点乘取通道,避免动态分量索引(SM2.0 不支持)
@@ -244,6 +254,15 @@ Category {
fixed dissolveMap = UIMaskSampleChannel(_DissolveTex, i.texcoordDissolve, _DissolveChannel);
fixed dissolveAlpha = saturate(smoothstep( DissolveWithParticle, (DissolveWithParticle+_DissolveWidth), dissolveMap));
col.a *= dissolveAlpha;
// 溶解边缘色:越靠近溶解边界越亮。已溶解区域 alpha≈0 不可见,所以视觉上就是沿着溶解轮廓的一圈颜色。
// 做火焰时把颜色设成 HDR 橙红(用 HDR 拾色器的强度调亮),边缘就会像在燃烧。
fixed dissolveEdge = pow(1.0 - dissolveAlpha, _DissolveEdgeSharpness);
col.rgb += _DissolveEdgeColor.rgb * dissolveEdge;
// 细亮圈:只在溶解边界(dissolveAlpha ≈ 0.5)附近加亮,越靠近边界越亮,
// 宽度由 _DissolveHighlightWidth 控制;颜色用 HDR 拉高就是"烧得发白"的亮边。
fixed highlightBand = saturate(1.0 - abs(dissolveAlpha - 0.5) / max(_DissolveHighlightWidth, 0.0001));
col.rgb += _DissolveHighlightColor.rgb * smoothstep(0.0, 1.0, highlightBand);
#endif
#if _USEUIMASKCLIP_ON
+191
View File
@@ -0,0 +1,191 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: particle
m_Shader: {fileID: 4800000, guid: 7ddbc50ff7d2d42939fd3e9816f2baf4, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _USEDISSOLVE_ON
m_InvalidKeywords:
- _USEUVTRAIL_ON
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DissolveTex:
m_Texture: {fileID: 2800000, guid: 94c4ffff470a043f68f9d388161c3b2a, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: 7ca288cbfc0684bbf876ce03dca16a9a, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _Mask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _RampTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _UVNoiseTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _AlphaScale: 1
- _AlphaToMask: 0
- _Blend: 0
- _BlendMode: 1
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _ColorMask: 15
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _Dissolve: 0.4
- _DissolveChannel: 0
- _DissolveEdgeSharpness: 0.001
- _DissolveHighlightWidth: 0.203
- _DissolveWidth: 0.174
- _Distortion: 0
- _DstBlend: 10
- _DstBlendAlpha: 0
- _EdgeGlow: 1
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _GlowScale: 1
- _MaskChannel: 3
- _MaskSpeedU: 0
- _MaskSpeedV: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _RenderFace: 0
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SpeedU: 0
- _SpeedV: 0
- _SrcBlend: 5
- _SrcBlendAlpha: 1
- _Stencil: 0
- _StencilComp: 8
- _StencilOp: 0
- _StencilReadMask: 255
- _StencilWriteMask: 255
- _Surface: 0
- _UseDissolve: 1
- _UseHardEdge: 0
- _UseMask: 0
- _UseMaskUvAni: 0
- _UseReceiveFog: 0
- _UseUIMaskClip: 0
- _UseUvAni: 0
- _UseUvDistortion: 0
- _UseUvTrail: 1
- _UseVertexMask: 0
- _VertexFlipX: 1
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _ClipRect: {r: -1, g: -1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _DissolveEdgeColor: {r: 1, g: 0.03199675, b: 0, a: 1}
- _DissolveHighlightColor: {r: 4, g: 2.8794167, b: 0, a: 1}
- _EdgeColor: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _MainTexTiling: {r: 1, g: 1, b: 0, a: 0}
- _NoiseScroll: {r: 0, g: 0, b: 1, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
- _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5}
- _VertexOffset: {r: 0, g: 0, b: 1, a: 1}
m_BuildTextureStacks: []
--- !u!114 &4124507439711967337
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 7
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3658e00c2630f4b04a4a1286aea0abb6
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant: