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 usedMaterialList = new List(); // // 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(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 }