NB_FX
This commit is contained in:
386
Packages/NB_FX/NBShaders/Editor/ParticleBaseTyflowVATGUI.cs
Normal file
386
Packages/NB_FX/NBShaders/Editor/ParticleBaseTyflowVATGUI.cs
Normal file
@@ -0,0 +1,386 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using NBShader;
|
||||
|
||||
namespace NBShaderEditor
|
||||
{
|
||||
internal sealed class ParticleBaseTyflowVATGUI
|
||||
{
|
||||
private const string TyflowSubModeProperty = "_TyFlowVATSubMode";
|
||||
private const int TyflowSkinModeStart = 2;
|
||||
private const float TyflowParticleHighestNonSkinMode = 1.5f;
|
||||
|
||||
private readonly ShaderGUIHelper _helper;
|
||||
|
||||
private static readonly string[] TyflowAnimationModeNames =
|
||||
{
|
||||
"Absolute positions",
|
||||
"Relative offsets",
|
||||
"Skin (R)",
|
||||
"Skin (PR)",
|
||||
"Skin (PRSAVE)",
|
||||
"Skin (PRSXYZ)"
|
||||
};
|
||||
|
||||
private static readonly string[] TyflowModeKeywords =
|
||||
{
|
||||
"_TYFLOW_VAT_ABSOLUTE",
|
||||
"_TYFLOW_VAT_RELATIVE",
|
||||
"_TYFLOW_VAT_SKIN_R",
|
||||
"_TYFLOW_VAT_SKIN_PR",
|
||||
"_TYFLOW_VAT_SKIN_PRSAVE",
|
||||
"_TYFLOW_VAT_SKIN_PRSXYZ"
|
||||
};
|
||||
|
||||
public ParticleBaseTyflowVATGUI(ShaderGUIHelper helper)
|
||||
{
|
||||
_helper = helper;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
DrawTyflowSettings();
|
||||
SyncKeywords();
|
||||
}
|
||||
|
||||
public static void AppendRequiredVertexStreams(
|
||||
Material material,
|
||||
List<ParticleSystemVertexStream> streams,
|
||||
List<string> streamList)
|
||||
{
|
||||
if (!IsTyflowParticleModeEnabled(material))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddStream(streams, streamList, ParticleSystemVertexStream.UV2, ParticleBaseGUI.streamUV2Text);
|
||||
}
|
||||
|
||||
private void DrawTyflowSettings()
|
||||
{
|
||||
_helper.DrawTexture("VAT texture", "_VATTex", drawScaleOffset: false, drawWrapMode: false);
|
||||
_helper.DrawFloat("ImportScale", "_ImportScale");
|
||||
_helper.DrawPopUp("TyFlow VAT Sub Mode", TyflowSubModeProperty, TyflowAnimationModeNames);
|
||||
|
||||
if (HasUnsupportedParticleMode())
|
||||
{
|
||||
EditorGUILayout.HelpBox("该 TyFlow VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。", MessageType.Warning);
|
||||
}
|
||||
else if (HasParticleUV2Conflict())
|
||||
{
|
||||
EditorGUILayout.HelpBox("TyFlow VAT uses UV2 (TEXCOORD0.zw) as vertexIndex / vertexCount in ParticleSystem mode. Flipbook blending or Special UV (UV2) conflicts with it; VAT takes priority.", MessageType.Warning);
|
||||
}
|
||||
|
||||
_helper.DrawToggle("Deforming skin", "_DeformingSkin");
|
||||
_helper.DrawFloat("Skin bone count", "_SkinBoneCount");
|
||||
_helper.DrawToggle("RGBA encoded", "_RGBAEncoded");
|
||||
_helper.DrawToggle("RGBA half", "_RGBAHalf");
|
||||
_helper.DrawToggle("Gamma correction", "_LinearToGamma");
|
||||
_helper.DrawToggle("VAT includes normals", "_VATIncludesNormals");
|
||||
_helper.DrawToggle("Affects shadows", "_AffectsShadows");
|
||||
_helper.DrawFloat("Frame", "_Frame");
|
||||
DrawFrameCustomDataSelect();
|
||||
_helper.DrawFloat("Frames", "_Frames");
|
||||
_helper.DrawToggle("Frame interpolation", "_FrameInterpolation");
|
||||
_helper.DrawToggle("Loop", "_Loop");
|
||||
_helper.DrawToggle("Interpolate loop", "_InterpolateLoop");
|
||||
_helper.DrawToggle("Autoplay", "_Autoplay");
|
||||
_helper.DrawFloat("AutoplaySpeed", "_AutoplaySpeed");
|
||||
}
|
||||
|
||||
private void DrawFrameCustomDataSelect()
|
||||
{
|
||||
const int dataBitPos = W9ParticleShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_VAT_FRAME;
|
||||
const int dataIndex = 2;
|
||||
W9ParticleShaderFlags.CutomDataComponent component = GetCurrentCustomDataComponent(dataBitPos, dataIndex);
|
||||
if (!IsAnyTyflowParticleModeEnabled() || _helper.shaderFlags == null || _helper.shaderFlags.Length == 0)
|
||||
{
|
||||
if (component != W9ParticleShaderFlags.CutomDataComponent.Off)
|
||||
{
|
||||
component = W9ParticleShaderFlags.CutomDataComponent.Off;
|
||||
for (int i = 0; i < _helper.shaderFlags.Length; i++)
|
||||
{
|
||||
if (_helper.shaderFlags[i] is W9ParticleShaderFlags flags)
|
||||
{
|
||||
flags.SetCustomDataFlag(component, dataBitPos, dataIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(string, string) nameTuple = ("VATFrameCustomData", "");
|
||||
|
||||
EditorGUI.showMixedValue = CustomDataHasMixedValue(dataBitPos, dataIndex);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
component = (W9ParticleShaderFlags.CutomDataComponent)EditorGUILayout.Popup(new GUIContent("VAT Frame CustomData"), (int)component, ParticleBaseGUI.CustomDataOptions);
|
||||
EditorGUI.showMixedValue = false;
|
||||
|
||||
Action applySelection = () =>
|
||||
{
|
||||
for (int i = 0; i < _helper.shaderFlags.Length; i++)
|
||||
{
|
||||
if (_helper.shaderFlags[i] is W9ParticleShaderFlags flags)
|
||||
{
|
||||
flags.SetCustomDataFlag(component, dataBitPos, dataIndex);
|
||||
}
|
||||
}
|
||||
|
||||
_helper.ResetTool.CheckOnValueChange(nameTuple);
|
||||
};
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
applySelection();
|
||||
}
|
||||
|
||||
_helper.ResetTool.DrawResetModifyButton(
|
||||
new Rect(),
|
||||
nameTuple,
|
||||
resetCallBack: () =>
|
||||
{
|
||||
component = W9ParticleShaderFlags.CutomDataComponent.Off;
|
||||
applySelection();
|
||||
},
|
||||
onValueChangedCallBack: applySelection,
|
||||
checkHasModifyOnValueChange: () => GetCurrentCustomDataComponent(dataBitPos, dataIndex) != W9ParticleShaderFlags.CutomDataComponent.Off,
|
||||
checkHasMixedValueOnValueChange: () => CustomDataHasMixedValue(dataBitPos, dataIndex));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
_helper.ResetTool.EndResetModifyButtonScope();
|
||||
}
|
||||
|
||||
private W9ParticleShaderFlags.CutomDataComponent GetCurrentCustomDataComponent(int dataBitPos, int dataIndex)
|
||||
{
|
||||
if (_helper.shaderFlags == null || _helper.shaderFlags.Length == 0)
|
||||
{
|
||||
return W9ParticleShaderFlags.CutomDataComponent.Off;
|
||||
}
|
||||
|
||||
if (_helper.shaderFlags[0] is W9ParticleShaderFlags flags)
|
||||
{
|
||||
return flags.GetCustomDataFlag(dataBitPos, dataIndex);
|
||||
}
|
||||
|
||||
return W9ParticleShaderFlags.CutomDataComponent.Off;
|
||||
}
|
||||
|
||||
private bool CustomDataHasMixedValue(int dataBitPos, int dataIndex)
|
||||
{
|
||||
if (_helper.shaderFlags == null || _helper.shaderFlags.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
W9ParticleShaderFlags.CutomDataComponent component = W9ParticleShaderFlags.CutomDataComponent.UnKnownOrMixed;
|
||||
for (int i = 0; i < _helper.shaderFlags.Length; i++)
|
||||
{
|
||||
if (!(_helper.shaderFlags[i] is W9ParticleShaderFlags flags))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
W9ParticleShaderFlags.CutomDataComponent current = flags.GetCustomDataFlag(dataBitPos, dataIndex);
|
||||
if (component == W9ParticleShaderFlags.CutomDataComponent.UnKnownOrMixed)
|
||||
{
|
||||
component = current;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (component != current)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool HasUnsupportedParticleMode()
|
||||
{
|
||||
if (_helper.mats == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _helper.mats.Count; i++)
|
||||
{
|
||||
if (IsUnsupportedParticleMode(_helper.mats[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsAnyTyflowParticleModeEnabled()
|
||||
{
|
||||
if (_helper.mats == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _helper.mats.Count; i++)
|
||||
{
|
||||
if (IsTyflowParticleModeEnabled(_helper.mats[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool HasParticleUV2Conflict()
|
||||
{
|
||||
if (_helper.mats == null || _helper.mats.Count == 0 || _helper.shaderFlags == null || _helper.shaderFlags.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _helper.mats.Count; i++)
|
||||
{
|
||||
Material mat = _helper.mats[i];
|
||||
if (!IsTyflowParticleModeEnabled(mat))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
W9ParticleShaderFlags flags = _helper.shaderFlags[i] as W9ParticleShaderFlags;
|
||||
if (flags == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool usesFlipbookBlending = mat.IsKeywordEnabled("_FLIPBOOKBLENDING_ON");
|
||||
bool usesSpecialUVOnUV2 = flags.CheckIsUVModeOn(W9ParticleShaderFlags.UVMode.SpecialUVChannel) &&
|
||||
!flags.CheckFlagBits(W9ParticleShaderFlags.FLAG_BIT_PARTICLE_1_USE_TEXCOORD2, index: 1);
|
||||
if (usesFlipbookBlending || usesSpecialUVOnUV2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsTyflowParticleModeEnabled(Material material)
|
||||
{
|
||||
if (material == null ||
|
||||
!material.HasProperty("_VAT_Toggle") ||
|
||||
!material.HasProperty("_VATMode") ||
|
||||
!material.HasProperty("_MeshSourceMode") ||
|
||||
material.GetFloat("_VAT_Toggle") <= 0.5f ||
|
||||
Mathf.RoundToInt(material.GetFloat("_VATMode")) != (int)ParticleBaseGUI.VATMode.Tyflow)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ParticleBaseGUI.MeshSourceMode meshSourceMode = (ParticleBaseGUI.MeshSourceMode)Mathf.RoundToInt(material.GetFloat("_MeshSourceMode"));
|
||||
if (meshSourceMode != ParticleBaseGUI.MeshSourceMode.Particle &&
|
||||
meshSourceMode != ParticleBaseGUI.MeshSourceMode.UIParticle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetMaterialSubMode(material) <= TyflowParticleHighestNonSkinMode;
|
||||
}
|
||||
|
||||
private static bool IsUnsupportedParticleMode(Material material)
|
||||
{
|
||||
if (material == null ||
|
||||
!material.HasProperty("_VAT_Toggle") ||
|
||||
!material.HasProperty("_VATMode") ||
|
||||
!material.HasProperty("_MeshSourceMode") ||
|
||||
material.GetFloat("_VAT_Toggle") <= 0.5f ||
|
||||
Mathf.RoundToInt(material.GetFloat("_VATMode")) != (int)ParticleBaseGUI.VATMode.Tyflow)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ParticleBaseGUI.MeshSourceMode meshSourceMode = (ParticleBaseGUI.MeshSourceMode)Mathf.RoundToInt(material.GetFloat("_MeshSourceMode"));
|
||||
if (meshSourceMode != ParticleBaseGUI.MeshSourceMode.Particle &&
|
||||
meshSourceMode != ParticleBaseGUI.MeshSourceMode.UIParticle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetMaterialSubMode(material) >= TyflowSkinModeStart;
|
||||
}
|
||||
|
||||
private static int GetMaterialSubMode(Material material)
|
||||
{
|
||||
if (!material.HasProperty(TyflowSubModeProperty))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Clamp(Mathf.RoundToInt(material.GetFloat(TyflowSubModeProperty)), 0, TyflowModeKeywords.Length - 1);
|
||||
}
|
||||
|
||||
private void SyncKeywords()
|
||||
{
|
||||
if (_helper.mats == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _helper.mats.Count; i++)
|
||||
{
|
||||
SyncKeywords(_helper.mats[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SyncKeywords(Material mat)
|
||||
{
|
||||
if (mat == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetSubModeKeyword(mat, GetMaterialSubMode(mat));
|
||||
}
|
||||
|
||||
internal static void ClearKeywords(Material mat)
|
||||
{
|
||||
if (mat == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetSubModeKeyword(mat, -1);
|
||||
}
|
||||
|
||||
private static void SetSubModeKeyword(Material mat, int enabledIndex)
|
||||
{
|
||||
for (int i = 0; i < TyflowModeKeywords.Length; i++)
|
||||
{
|
||||
mat.DisableKeyword(TyflowModeKeywords[i]);
|
||||
}
|
||||
|
||||
if (enabledIndex >= 0 && enabledIndex < TyflowModeKeywords.Length)
|
||||
{
|
||||
mat.EnableKeyword(TyflowModeKeywords[enabledIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddStream(
|
||||
List<ParticleSystemVertexStream> streams,
|
||||
List<string> streamList,
|
||||
ParticleSystemVertexStream stream,
|
||||
string streamLabel)
|
||||
{
|
||||
if (streams.Contains(stream))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
streams.Add(stream);
|
||||
streamList.Add(streamLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user