371 lines
9.6 KiB
C#
371 lines
9.6 KiB
C#
using System;
|
||
using UnityEngine;
|
||
// using Sirenix.OdinInspector;
|
||
// using Unity.Mathematics;
|
||
using UnityEngine.UI;
|
||
using System.Collections.Generic;
|
||
#if UNITY_EDITOR
|
||
using UnityEditor;
|
||
#endif
|
||
|
||
[ExecuteInEditMode]
|
||
public class AnimationSheetHelper : MonoBehaviour,IMaterialModifier
|
||
{
|
||
|
||
public bool isParticleBaseShader = true;
|
||
|
||
public string propertyName = "_BaseMap_ST";
|
||
|
||
private int _propertyID;
|
||
private int _particleBaseAniBlendStPropertyID = Shader.PropertyToID("_BaseMap_AnimationSheetBlend_ST");
|
||
private int _particleBaseAniBlendIntensityPropertyID = Shader.PropertyToID("_AnimationSheetHelperBlendIntensity");
|
||
private static readonly int ParticleShaderFlagsId = Shader.PropertyToID("_W9ParticleShaderFlags");
|
||
private static readonly int ParticleShaderFlags1Id = Shader.PropertyToID("_W9ParticleShaderFlags1");
|
||
private static readonly int NBShaderFlagsId = Shader.PropertyToID("_NBShaderFlags");
|
||
private static readonly int NBShaderFlags1Id = Shader.PropertyToID("_NBShaderFlags1");
|
||
private const int FlagBitUIEffectOn = 1 << 14;
|
||
private const int FlagBitAnimationSheetHelper = 1 << 15;
|
||
private const int FlagBitUIEffectBaseMapMode = 1 << 22;
|
||
|
||
|
||
|
||
// [LabelText("序列帧图横向帧数量")]
|
||
// [OnValueChanged("Init")]
|
||
public int xSize = 4;
|
||
|
||
// [LabelText("序列帧图纵向帧数量")]
|
||
// [OnValueChanged("Init")]
|
||
public int ySize = 4;
|
||
|
||
// [LabelText("手动控制播放")]
|
||
public bool manualPlay = false;
|
||
|
||
// [ShowIf("manualPlay")]
|
||
// [LabelText("手动播放位置")] [Range(0, 1)]
|
||
public float manualPlayePos = 0;
|
||
|
||
// [LabelText("播放速度fps")]
|
||
// [HideIf("manualPlay")]
|
||
public float speed = 16;
|
||
|
||
// [ReadOnly]
|
||
// [LabelText("TillingOffset")]
|
||
public Vector4 scaleOffset;
|
||
// [ReadOnly]
|
||
public Material mat;
|
||
|
||
// [ReadOnly]
|
||
public int frameIndex;
|
||
// [ReadOnly]
|
||
public int frameCount;
|
||
|
||
private float _time;
|
||
|
||
private float _xScale;
|
||
private float _yScale;
|
||
|
||
private static List<Material> usedMaterialList = new List<Material>();
|
||
|
||
|
||
// // Start is called before the first frame update
|
||
// void Start()
|
||
// {
|
||
// Debug.Log( "ASUpadate_Start");
|
||
// Init();
|
||
// }
|
||
private void OnEnable()
|
||
{
|
||
// Debug.Log( "ASUpadate_OnEnable");
|
||
Init();
|
||
#if UNITY_EDITOR
|
||
EditorApplication.update += EditorUpdate;
|
||
#endif
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
Init();
|
||
|
||
//清掉,避免参数保留。
|
||
if (isParticleBaseShader)
|
||
{
|
||
if (mat)
|
||
{
|
||
GetShaderFlagIds(mat, out _, out int flags1Id);
|
||
ClearFlagBits(mat, flags1Id, FlagBitAnimationSheetHelper);
|
||
}
|
||
}
|
||
|
||
if (usedMaterialList.Contains(mat))
|
||
{
|
||
usedMaterialList.Remove(mat);
|
||
}
|
||
#if UNITY_EDITOR
|
||
EditorApplication.update -= EditorUpdate;
|
||
#endif
|
||
}
|
||
|
||
// [Button("初始化")]
|
||
public void Init()
|
||
{
|
||
_time = 0;
|
||
if (xSize <= 0)
|
||
{
|
||
xSize = 1;
|
||
}
|
||
|
||
if (ySize <= 0)
|
||
{
|
||
ySize = 1;
|
||
}
|
||
frameCount = xSize * ySize;
|
||
|
||
_xScale = 1 / (float)xSize;
|
||
_yScale = 1 / (float)ySize;
|
||
// if (frameCount <= 0)
|
||
// {
|
||
// frameCount = 1;
|
||
// }
|
||
// scaleOffset = new Vector4(1f/(float)xSize,1f/ (float)ySize, 0, 0);
|
||
|
||
if (gameObject.TryGetComponent(out Graphic g))
|
||
{
|
||
if (Application.isPlaying)
|
||
{
|
||
mat = g.materialForRendering;
|
||
}
|
||
else
|
||
{
|
||
mat = g.material;
|
||
}
|
||
}
|
||
else if (gameObject.TryGetComponent(out Renderer r))
|
||
{
|
||
if (Application.isPlaying)
|
||
{
|
||
mat = r.material;
|
||
}
|
||
else
|
||
{
|
||
mat = r.sharedMaterial;
|
||
}
|
||
// Debug.Log("AS_GetRenderer:Mat--"+mat.name);
|
||
|
||
}
|
||
else
|
||
{
|
||
mat = null;
|
||
}
|
||
|
||
InitParticleBaseShaderToggle();
|
||
// InitPostProcessToggle();
|
||
|
||
|
||
_propertyID = Shader.PropertyToID(propertyName);
|
||
if (mat != null)
|
||
{
|
||
mat.SetVector(_propertyID,CalSt(0));
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
public void InitParticleBaseShaderToggle()
|
||
{
|
||
if (isParticleBaseShader)
|
||
{
|
||
GetShaderFlagIds(mat, out int flagsId, out int flags1Id);
|
||
// Debug.Log(CheckFlagBits(mat, ParticleShaderFlags1Id, FlagBitUIEffectBaseMapMode));
|
||
if(CheckFlagBits(mat, flagsId, FlagBitUIEffectOn) && !CheckFlagBits(mat, flags1Id, FlagBitUIEffectBaseMapMode))
|
||
{
|
||
propertyName = "_UI_MainTex_ST";
|
||
}
|
||
else
|
||
{
|
||
propertyName = "_BaseMap_ST";
|
||
}
|
||
if (mat)
|
||
{
|
||
SetFlagBits(mat, flags1Id, FlagBitAnimationSheetHelper);
|
||
}
|
||
}
|
||
// else
|
||
// {
|
||
// if (mat)
|
||
// {
|
||
// if (mat.shader.name == "Mh2/Effects/Particle_NiuBi")
|
||
// {
|
||
// _flags.SetMaterial(mat);
|
||
// _flags.ClearFlagBits(W9ParticleShaderFlags.FLAG_BIT_PARTICLE_1_ANIMATION_SHEET_HELPER,index:1);
|
||
// }
|
||
// }
|
||
// }
|
||
}
|
||
|
||
// public void InitPostProcessToggle()
|
||
// {
|
||
// if (isPostProcessShader)
|
||
// {
|
||
// TryGetComponent<PostProcessingController>(out postProcessingController);
|
||
// }
|
||
// else
|
||
// {
|
||
// postProcessingController = null;
|
||
// }
|
||
// }
|
||
|
||
|
||
// Update is called once per frame
|
||
private int _lastIndex;
|
||
private int _nextIndex = 1;
|
||
private float _blendLerp;
|
||
private void Update()
|
||
{
|
||
// if (!isPostProcessShader)//后处理控制不通过才知。
|
||
// {
|
||
// if(!mat || _propertyID==0) return;
|
||
// }
|
||
|
||
|
||
|
||
float frameIndexFloat;
|
||
if (manualPlay)
|
||
{
|
||
float playPos = Mathf.Repeat(manualPlayePos, 1f);
|
||
frameIndexFloat = playPos * frameCount;
|
||
}
|
||
else
|
||
{
|
||
if (!Application.isPlaying)
|
||
{
|
||
#if UNITY_EDITOR
|
||
_time += (float)editorDeltaTime * speed;
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
_time += Time.deltaTime * speed;
|
||
}
|
||
frameIndexFloat = _time % frameCount;
|
||
}
|
||
frameIndex = (int) frameIndexFloat;
|
||
if (frameIndex == frameCount)
|
||
{
|
||
frameIndex = frameCount - 1;
|
||
}
|
||
|
||
|
||
if (_lastIndex != frameIndex)
|
||
{
|
||
// if (isPostProcessShader)
|
||
// {
|
||
// postProcessingController.distortSpeedTexSt = CalSt(frameIndex);
|
||
// }
|
||
// else
|
||
// {
|
||
mat.SetVector(_propertyID,CalSt(frameIndex));
|
||
// }
|
||
_lastIndex = frameIndex;
|
||
_nextIndex = frameIndex + 1;
|
||
if (isParticleBaseShader)
|
||
{
|
||
mat.SetVector(_particleBaseAniBlendStPropertyID,CalSt(_nextIndex));
|
||
}
|
||
|
||
}
|
||
|
||
if (isParticleBaseShader)
|
||
{
|
||
_blendLerp = Mathf.Repeat(frameIndexFloat,1f);
|
||
mat.SetFloat(_particleBaseAniBlendIntensityPropertyID,_blendLerp);
|
||
}
|
||
|
||
}
|
||
|
||
public Material GetModifiedMaterial(Material baseMaterial)
|
||
{
|
||
if (usedMaterialList.Contains(baseMaterial))
|
||
{
|
||
//有可能打断UI合批,烦请客户端判断
|
||
Material newMat = Instantiate(baseMaterial);
|
||
mat = newMat;
|
||
usedMaterialList.Add(newMat);
|
||
}
|
||
else
|
||
{
|
||
mat = baseMaterial;
|
||
usedMaterialList.Add(baseMaterial);
|
||
}
|
||
return mat;
|
||
}
|
||
|
||
|
||
|
||
|
||
private Vector4 CalSt(int index)
|
||
{
|
||
float xOffset = (index % xSize)*_xScale;
|
||
float yOffset = (ySize - index / xSize -1)*_yScale;
|
||
return new Vector4(_xScale, _yScale, xOffset, yOffset);
|
||
}
|
||
|
||
private static void SetFlagBits(Material material, int propertyId, int bits)
|
||
{
|
||
if (!material)
|
||
{
|
||
return;
|
||
}
|
||
|
||
material.SetInteger(propertyId, material.GetInteger(propertyId) | bits);
|
||
}
|
||
|
||
private static void ClearFlagBits(Material material, int propertyId, int bits)
|
||
{
|
||
if (!material)
|
||
{
|
||
return;
|
||
}
|
||
|
||
material.SetInteger(propertyId, material.GetInteger(propertyId) & ~bits);
|
||
}
|
||
|
||
private static bool CheckFlagBits(Material material, int propertyId, int bits)
|
||
{
|
||
return material && (material.GetInteger(propertyId) & bits) != 0;
|
||
}
|
||
|
||
private static void GetShaderFlagIds(Material material, out int flagsId, out int flags1Id)
|
||
{
|
||
if (material && (material.HasProperty(NBShaderFlagsId) || material.HasProperty(NBShaderFlags1Id)))
|
||
{
|
||
flagsId = NBShaderFlagsId;
|
||
flags1Id = NBShaderFlags1Id;
|
||
return;
|
||
}
|
||
|
||
flagsId = ParticleShaderFlagsId;
|
||
flags1Id = ParticleShaderFlags1Id;
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
private double editorDeltaTime = 0;
|
||
private double lastEditorTime = 0;
|
||
void EditorUpdate()
|
||
{
|
||
|
||
if (lastEditorTime == 0)
|
||
{
|
||
lastEditorTime = EditorApplication.timeSinceStartup;
|
||
}
|
||
editorDeltaTime = EditorApplication.timeSinceStartup - lastEditorTime;
|
||
lastEditorTime = EditorApplication.timeSinceStartup;
|
||
if (!Application.isPlaying)
|
||
{
|
||
Update();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
}
|