NB_FX
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
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
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf793623f3ea13b4db35460280cb6ded
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace NBShader
|
||||
{
|
||||
public class InspectorButtonAttribute : PropertyAttribute
|
||||
{
|
||||
public string Label;
|
||||
public string MethodName;
|
||||
|
||||
public InspectorButtonAttribute(string label, string methodName)
|
||||
{
|
||||
this.Label = label;
|
||||
this.MethodName = methodName;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomPropertyDrawer(typeof(InspectorButtonAttribute))]
|
||||
public class InspectorButtonPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
|
||||
InspectorButtonAttribute buttonAttribute = (InspectorButtonAttribute)attribute;
|
||||
|
||||
|
||||
// 绘制按钮
|
||||
if (GUI.Button(position, buttonAttribute.Label))
|
||||
{
|
||||
// 获取包含该方法的对象
|
||||
var targetObject = property.serializedObject.targetObject;
|
||||
|
||||
// 获取方法信息
|
||||
var methodInfo = targetObject.GetType().GetMethod(buttonAttribute.MethodName,
|
||||
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
if (methodInfo != null)
|
||||
{
|
||||
// 调用方法
|
||||
methodInfo.Invoke(targetObject, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Method '{buttonAttribute.MethodName}' not found in {targetObject.name}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight; // 返回按钮的高度
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45f557806bb54c4dbeaec7a2ded5be83
|
||||
timeCreated: 1737792133
|
||||
@@ -0,0 +1,598 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NBShader
|
||||
{
|
||||
//TODO增加一键去重功能。测试排查BUG
|
||||
[ExecuteInEditMode]
|
||||
public class MaterialPropertyAgent : MonoBehaviour, IMaterialModifier
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct PropertyData
|
||||
{
|
||||
[HideInInspector] public int dataIndexInAgent;
|
||||
[HideInInspector] public MaterialPropertyAgent agent;
|
||||
[HideInInspector] public int id;
|
||||
|
||||
|
||||
public int index;
|
||||
[HideInInspector] public string propName;
|
||||
|
||||
public shaderPropertyType type;
|
||||
|
||||
|
||||
public string descripName;
|
||||
|
||||
|
||||
public Color colorValue;
|
||||
|
||||
public Vector4 vecValue;
|
||||
|
||||
public float floatValue;
|
||||
|
||||
[SerializeField] public IEnumerable propNameList;
|
||||
[HideInInspector] public bool isActive;
|
||||
[HideInInspector] public Shader shader;
|
||||
[HideInInspector] public Material mat;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public float rangMin { get; set; }
|
||||
public float rangMax { get; set; }
|
||||
|
||||
public void setValueByPropChange()
|
||||
{
|
||||
agent.refreshShderPropNameList();
|
||||
if (!agent.isCanUsedIndex(index))
|
||||
{
|
||||
index = agent.getCanUsedIndex();
|
||||
}
|
||||
|
||||
string propertyName = shader.GetPropertyName(index);
|
||||
id = Shader.PropertyToID(propertyName);
|
||||
descripName = shader.GetPropertyDescription(index);
|
||||
type = (shaderPropertyType)shader.GetPropertyType(index);
|
||||
if (type == shaderPropertyType.TexEnv)
|
||||
{
|
||||
propName = propertyName + "_ST";
|
||||
}
|
||||
else
|
||||
{
|
||||
propName = propertyName;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case shaderPropertyType.Color:
|
||||
colorValue = mat.GetColor(id);
|
||||
break;
|
||||
case shaderPropertyType.Float:
|
||||
floatValue = mat.GetFloat(id);
|
||||
break;
|
||||
case shaderPropertyType.Range:
|
||||
Vector2 rangeLimits = shader.GetPropertyRangeLimits(index);
|
||||
rangMin = rangeLimits.x;
|
||||
rangMax = rangeLimits.y;
|
||||
floatValue = mat.GetFloat(id);
|
||||
break;
|
||||
case shaderPropertyType.Vector:
|
||||
vecValue = mat.GetVector(id);
|
||||
break;
|
||||
case shaderPropertyType.TexEnv:
|
||||
string stName = propertyName + "_ST";
|
||||
vecValue = mat.GetVector(stName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void inActivateThis()
|
||||
{
|
||||
isActive = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//因为ShaderUtil只是用于Editor,所以复制一个枚举对属性类型进行识别。
|
||||
|
||||
public enum shaderPropertyType
|
||||
{
|
||||
//
|
||||
// 摘要:
|
||||
// Color Property.
|
||||
Color = 0,
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// Vector Property.
|
||||
Vector = 1,
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// Float Property.
|
||||
Float = 2,
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// Range Property.
|
||||
Range = 3,
|
||||
|
||||
//
|
||||
// 摘要:
|
||||
// Texture Property.
|
||||
TexEnv = 4
|
||||
}
|
||||
|
||||
|
||||
public PropertyData data0 = new PropertyData();
|
||||
|
||||
public PropertyData data1 = new PropertyData();
|
||||
|
||||
public PropertyData data2 = new PropertyData();
|
||||
|
||||
public PropertyData data3 = new PropertyData();
|
||||
|
||||
public PropertyData data4 = new PropertyData();
|
||||
|
||||
public PropertyData data5 = new PropertyData();
|
||||
|
||||
public Shader shader;
|
||||
public Material mat;
|
||||
|
||||
|
||||
public int materialIndex = 0;
|
||||
public Renderer customRenderer;
|
||||
|
||||
void initMatAndShader(bool initMat = false)
|
||||
{
|
||||
if (!initMat)
|
||||
{
|
||||
if (mat != null) return;
|
||||
}
|
||||
|
||||
if (customRenderer || GetComponent<Renderer>())
|
||||
{
|
||||
Material[] materials;
|
||||
Renderer r;
|
||||
if (customRenderer)
|
||||
{
|
||||
r = customRenderer;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = GetComponent<Renderer>();
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
materials = r.materials;
|
||||
}
|
||||
else
|
||||
{
|
||||
materials = r.sharedMaterials;
|
||||
}
|
||||
|
||||
mat = materials[materialIndex];
|
||||
shader = mat.shader;
|
||||
}
|
||||
else if (this.GetComponent<Graphic>())
|
||||
{
|
||||
Graphic graphic = this.GetComponent<Graphic>();
|
||||
|
||||
//测试,要不要用IMaterialModifier来处理
|
||||
// if (Application.isPlaying)
|
||||
// {
|
||||
// graphic.material = Material.Instantiate(graphic.material);
|
||||
// }
|
||||
|
||||
mat = graphic.material;
|
||||
|
||||
|
||||
shader = mat.shader;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("MaterialPropertyAgent未找到材质", this.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
initMatAndShader(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
initMatAndShader(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (mat == null)
|
||||
{
|
||||
// initMatAndShader();
|
||||
return;
|
||||
}
|
||||
|
||||
updateData(data0);
|
||||
updateData(data1);
|
||||
updateData(data2);
|
||||
updateData(data3);
|
||||
updateData(data4);
|
||||
updateData(data5);
|
||||
}
|
||||
|
||||
void updateData(PropertyData data)
|
||||
{
|
||||
if (!data.isActive) return;
|
||||
if (mat == null) return;
|
||||
switch (data.type)
|
||||
{
|
||||
case shaderPropertyType.Color:
|
||||
mat.SetColor(data.propName, data.colorValue);
|
||||
break;
|
||||
case shaderPropertyType.Vector:
|
||||
case shaderPropertyType.TexEnv:
|
||||
mat.SetVector(data.propName, data.vecValue);
|
||||
break;
|
||||
case shaderPropertyType.Float:
|
||||
case shaderPropertyType.Range:
|
||||
mat.SetFloat(data.propName, data.floatValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//实际上是修改了graphic.materialForRendering
|
||||
public Material GetModifiedMaterial(Material baseMaterial)
|
||||
{
|
||||
if (mat)
|
||||
{
|
||||
return mat;
|
||||
}
|
||||
else
|
||||
{
|
||||
return baseMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
private void OnRenderObject()
|
||||
{
|
||||
if (!UnityEditor.EditorApplication.isPlaying)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
public void addProperteData()
|
||||
{
|
||||
refreshShderPropNameList();
|
||||
|
||||
if (!data0.isActive)
|
||||
{
|
||||
initData(ref data0, 0);
|
||||
}
|
||||
else if (!data1.isActive)
|
||||
{
|
||||
initData(ref data1, 1);
|
||||
}
|
||||
else if (!data2.isActive)
|
||||
{
|
||||
initData(ref data2, 2);
|
||||
}
|
||||
else if (!data3.isActive)
|
||||
{
|
||||
initData(ref data3, 3);
|
||||
}
|
||||
else if (!data4.isActive)
|
||||
{
|
||||
initData(ref data4, 4);
|
||||
}
|
||||
else if (!data5.isActive)
|
||||
{
|
||||
initData(ref data5, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("已用掉可用的6个属性");
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllProperty()
|
||||
{
|
||||
data0.isActive = false;
|
||||
data1.isActive = false;
|
||||
data2.isActive = false;
|
||||
data3.isActive = false;
|
||||
data4.isActive = false;
|
||||
data5.isActive = false;
|
||||
}
|
||||
|
||||
public void initData(ref PropertyData data, int dataIndexInAgent)
|
||||
{
|
||||
data.dataIndexInAgent = dataIndexInAgent;
|
||||
data.agent = this;
|
||||
data.shader = shader;
|
||||
data.mat = mat;
|
||||
data.isActive = true;
|
||||
|
||||
data.index = getCanUsedIndex();
|
||||
data.setValueByPropChange();
|
||||
}
|
||||
|
||||
#region TODO自动排除已用Property
|
||||
|
||||
List<string> usedPropertyName = new List<string>();
|
||||
|
||||
void collectUsedPropName()
|
||||
{
|
||||
usedPropertyName.Clear();
|
||||
if (data0.isActive)
|
||||
{
|
||||
usedPropertyName.Add(data0.propName);
|
||||
}
|
||||
|
||||
if (data1.isActive)
|
||||
{
|
||||
usedPropertyName.Add(data1.propName);
|
||||
}
|
||||
|
||||
if (data2.isActive)
|
||||
{
|
||||
usedPropertyName.Add(data2.propName);
|
||||
}
|
||||
|
||||
if (data3.isActive)
|
||||
{
|
||||
usedPropertyName.Add(data3.propName);
|
||||
}
|
||||
|
||||
if (data4.isActive)
|
||||
{
|
||||
usedPropertyName.Add(data4.propName);
|
||||
}
|
||||
|
||||
if (data5.isActive)
|
||||
{
|
||||
usedPropertyName.Add(data5.propName);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCanUsedIndex()
|
||||
{
|
||||
int index = -1;
|
||||
collectUsedPropName();
|
||||
for (int i = 0; i < shaderPropNameArr.Length; i++)
|
||||
{
|
||||
string propertyName;
|
||||
if (shader.GetPropertyType(i) == ShaderPropertyType.Texture)
|
||||
{
|
||||
propertyName = shaderPropNameArr[i] + "_ST";
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyName = shaderPropNameArr[i];
|
||||
}
|
||||
|
||||
if (usedPropertyName.Contains(propertyName)) continue;
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public bool isCanUsedIndex(int i)
|
||||
{
|
||||
string propertyName;
|
||||
if (shader.GetPropertyType(i) == ShaderPropertyType.Texture)
|
||||
{
|
||||
propertyName = shaderPropNameArr[i] + "_ST";
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyName = shaderPropNameArr[i];
|
||||
}
|
||||
|
||||
collectUsedPropName();
|
||||
if (usedPropertyName.Contains(propertyName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string[] shaderPropNameArr;
|
||||
public string[] shaderPropDescripArr;
|
||||
public string[] shaderPropDescripsForSerch;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
// if (XLuaManager.Instance != null)
|
||||
// {
|
||||
// if (XLuaManager.Instance.HasGameStart)//判断是游戏运行状态才进行实例化
|
||||
// {
|
||||
// return;//游戏进行中不允许编辑
|
||||
// }
|
||||
// }
|
||||
// Debug.Log("MaterialPropertyAgent : " + "OnValidate");
|
||||
refreshShderPropNameList();
|
||||
if (TryGetComponent<Renderer>(out Renderer r) || customRenderer)
|
||||
{
|
||||
isRendererMode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isRendererMode = false;
|
||||
}
|
||||
|
||||
if (TryGetComponent<Renderer>(out Renderer r2) || TryGetComponent<Graphic>(out Graphic g))
|
||||
{
|
||||
isGetByComponet = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isGetByComponet = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool isRendererMode = false;
|
||||
public bool isGetByComponet = false;
|
||||
|
||||
public void initMatAndShaderByMaterialIndexChange()
|
||||
{
|
||||
initMatAndShader(true);
|
||||
refreshShderPropNameList();
|
||||
if (data0.isActive && data0.shader != mat.shader)
|
||||
{
|
||||
data0.shader = mat.shader;
|
||||
data0.mat = mat;
|
||||
}
|
||||
|
||||
if (data1.isActive && data1.shader != mat.shader)
|
||||
{
|
||||
data1.shader = mat.shader;
|
||||
data1.mat = mat;
|
||||
}
|
||||
|
||||
if (data2.isActive && data2.shader != mat.shader)
|
||||
{
|
||||
data2.shader = mat.shader;
|
||||
data2.mat = mat;
|
||||
}
|
||||
|
||||
if (data3.isActive && data3.shader != mat.shader)
|
||||
{
|
||||
data3.shader = mat.shader;
|
||||
data3.mat = mat;
|
||||
}
|
||||
|
||||
if (data4.isActive && data4.shader != mat.shader)
|
||||
{
|
||||
data4.shader = mat.shader;
|
||||
data4.mat = mat;
|
||||
}
|
||||
|
||||
if (data5.isActive && data5.shader != mat.shader)
|
||||
{
|
||||
data5.shader = mat.shader;
|
||||
data5.mat = mat;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
List<string> shaderPropNameList = new List<string>();
|
||||
private List<string> shaderPropDescripList = new List<string>();
|
||||
private List<string> shaderPropDescripListForSerch = new List<string>();
|
||||
public void refreshShderPropNameList()
|
||||
{
|
||||
initMatAndShader();
|
||||
if (shader == null) return;
|
||||
|
||||
shaderPropNameList.Clear();
|
||||
shaderPropDescripList.Clear();
|
||||
shaderPropDescripListForSerch.Clear();
|
||||
for (int i = 0; i < shader.GetPropertyCount(); i++)
|
||||
{
|
||||
shaderPropNameList.Add(shader.GetPropertyName(i));
|
||||
string descript = shader.GetPropertyDescription(i);
|
||||
shaderPropDescripList.Add(descript);
|
||||
string lowerDesc = descript.ToLower();
|
||||
if (!(lowerDesc.Contains("ignore") || lowerDesc.Contains("mode") || lowerDesc.Contains("toggle") ||
|
||||
lowerDesc.Contains("enable") || lowerDesc.Contains("flag")))
|
||||
{
|
||||
shaderPropDescripListForSerch.Add(descript);
|
||||
}
|
||||
}
|
||||
|
||||
shaderPropNameArr = shaderPropNameList.ToArray();
|
||||
shaderPropDescripArr = shaderPropDescripList.ToArray();
|
||||
shaderPropDescripsForSerch = shaderPropDescripListForSerch.ToArray();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[CustomPropertyDrawer(typeof(MaterialPropertyAgent.PropertyData))]
|
||||
public class PropertyAgentPropertyDataDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var isActive = property.FindPropertyRelative("isActive");
|
||||
if (isActive.boolValue)
|
||||
{
|
||||
EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
var index = property.FindPropertyRelative("index");
|
||||
MaterialPropertyAgent agent = property.FindPropertyRelative("agent").objectReferenceValue as MaterialPropertyAgent;
|
||||
int preservedIndex = index.intValue;
|
||||
float originLabelWidth = EditorGUIUtility.labelWidth;
|
||||
EditorGUIUtility.labelWidth = 80;
|
||||
index.intValue = EditorGUILayout.Popup("属性名:", index.intValue, agent.shaderPropNameArr);
|
||||
if (preservedIndex != index.intValue)//证明用户进行了更改
|
||||
{
|
||||
if (!agent.isCanUsedIndex(index.intValue))
|
||||
{
|
||||
//TODO给一个报错提示
|
||||
Debug.Log(agent.shader.GetPropertyDescription(index.intValue));
|
||||
index.intValue = agent.getCanUsedIndex();
|
||||
}
|
||||
//此处进行内容刷新
|
||||
data.setValueByPropChange();
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.LabelField("属性类型:", data.type.ToString());
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUIUtility.labelWidth = originLabelWidth;
|
||||
switch (data.type)
|
||||
{
|
||||
case MaterialPropertyAgent.shaderPropertyType.Color:
|
||||
data.colorValue = EditorGUILayout.ColorField(data.descripName + " :", data.colorValue);
|
||||
break;
|
||||
case MaterialPropertyAgent.shaderPropertyType.Vector:
|
||||
data.vecValue = EditorGUILayout.Vector4Field(data.descripName + " :", data.vecValue);
|
||||
break;
|
||||
case MaterialPropertyAgent.shaderPropertyType.Float:
|
||||
data.floatValue = EditorGUILayout.FloatField(data.descripName + ":", data.floatValue);
|
||||
break;
|
||||
case MaterialPropertyAgent.shaderPropertyType.Range:
|
||||
data.floatValue = EditorGUILayout.Slider(data.descripName + ":", data.floatValue, data.rangMin, data.rangMax);
|
||||
break;
|
||||
case MaterialPropertyAgent.shaderPropertyType.TexEnv:
|
||||
data.vecValue = EditorGUILayout.Vector4Field(data.propName + "_ST:", data.vecValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("删除", new[] { GUILayout.Width(200) }))
|
||||
{
|
||||
data.isActive = false;
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 781e80efab11a1d438f7c4d37603bdff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
337
Packages/NB_FX/XuanXuanRenderUtility/Runtime/MeshUI.cs
Normal file
337
Packages/NB_FX/XuanXuanRenderUtility/Runtime/MeshUI.cs
Normal file
@@ -0,0 +1,337 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NBShader
|
||||
{
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
[AddComponentMenu("UI/Mesh UI")]
|
||||
public class MeshUI : MaskableGraphic
|
||||
{
|
||||
[SerializeField] private Mesh mesh;
|
||||
[SerializeField] private List<Material> subMeshMaterials = new List<Material>();
|
||||
|
||||
private readonly List<Vector3> _positions = new List<Vector3>();
|
||||
private readonly List<Vector3> _normals = new List<Vector3>();
|
||||
private readonly List<Vector4> _tangents = new List<Vector4>();
|
||||
private readonly List<Vector2> _uv0S = new List<Vector2>();
|
||||
private readonly List<Color32> _colors = new List<Color32>();
|
||||
private readonly List<int[]> _subMeshIndices = new List<int[]>();
|
||||
private readonly List<int> _renderSubMeshMap = new List<int>();
|
||||
private Mesh _workingMesh;
|
||||
private int _renderSubMeshCount;
|
||||
private bool _hasLoggedUnreadableMesh;
|
||||
|
||||
public Mesh Mesh
|
||||
{
|
||||
get => mesh;
|
||||
set
|
||||
{
|
||||
if (mesh == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mesh = value;
|
||||
_hasLoggedUnreadableMesh = false;
|
||||
SetMaterialDirty();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Material> SubMeshMaterials => subMeshMaterials;
|
||||
|
||||
public override Texture mainTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
Material currentMaterial = material;
|
||||
if (currentMaterial != null && currentMaterial.mainTexture != null)
|
||||
{
|
||||
return currentMaterial.mainTexture;
|
||||
}
|
||||
|
||||
return s_WhiteTexture;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
canvasRenderer.Clear();
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
ReleaseWorkingMesh();
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
vh.Clear();
|
||||
}
|
||||
|
||||
protected override void UpdateGeometry()
|
||||
{
|
||||
if (canvasRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PrepareRenderMesh(out Mesh renderMesh))
|
||||
{
|
||||
canvasRenderer.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
canvasRenderer.SetMesh(renderMesh);
|
||||
}
|
||||
|
||||
protected override void UpdateMaterial()
|
||||
{
|
||||
if (canvasRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int materialCount = Mathf.Max(1, _renderSubMeshCount);
|
||||
canvasRenderer.materialCount = materialCount;
|
||||
|
||||
for (int i = 0; i < materialCount; i++)
|
||||
{
|
||||
Material sourceMaterial = GetRenderMaterial(i);
|
||||
Material modifiedMaterial = sourceMaterial != null ? GetModifiedMaterial(sourceMaterial) : defaultGraphicMaterial;
|
||||
canvasRenderer.SetMaterial(modifiedMaterial, i);
|
||||
}
|
||||
|
||||
canvasRenderer.SetTexture(mainTexture);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
SetMaterialDirty();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void OnDidApplyAnimationProperties()
|
||||
{
|
||||
base.OnDidApplyAnimationProperties();
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
private bool PrepareRenderMesh(out Mesh renderMesh)
|
||||
{
|
||||
renderMesh = null;
|
||||
_renderSubMeshCount = 0;
|
||||
|
||||
if (mesh == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mesh.isReadable)
|
||||
{
|
||||
if (!_hasLoggedUnreadableMesh)
|
||||
{
|
||||
Debug.LogWarning($"MeshUI requires a read/write enabled mesh. Bake a readable mesh in the inspector before using '{mesh.name}'.", this);
|
||||
_hasLoggedUnreadableMesh = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mesh.vertexCount <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CollectRenderableSubMeshes(mesh, _subMeshIndices, _renderSubMeshMap);
|
||||
if (_subMeshIndices.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_renderSubMeshCount = _subMeshIndices.Count;
|
||||
|
||||
if (ShouldUseSourceMesh())
|
||||
{
|
||||
renderMesh = mesh;
|
||||
return true;
|
||||
}
|
||||
|
||||
EnsureWorkingMesh();
|
||||
BuildWorkingMesh();
|
||||
renderMesh = _workingMesh;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ShouldUseSourceMesh()
|
||||
{
|
||||
if (color != Color.white)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _renderSubMeshCount == mesh.subMeshCount;
|
||||
}
|
||||
|
||||
private void BuildWorkingMesh()
|
||||
{
|
||||
Vector3[] srcVertices = mesh.vertices;
|
||||
int vertexCount = srcVertices.Length;
|
||||
PrepareVertexLists(vertexCount);
|
||||
|
||||
Vector2[] srcUv0 = mesh.uv;
|
||||
Vector3[] srcNormals = mesh.normals;
|
||||
Vector4[] srcTangents = mesh.tangents;
|
||||
Color32 vertexColor = color;
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
_positions.Add(srcVertices[i]);
|
||||
_uv0S.Add(srcUv0 != null && i < srcUv0.Length ? srcUv0[i] : Vector2.zero);
|
||||
_normals.Add(srcNormals != null && i < srcNormals.Length ? srcNormals[i] : Vector3.back);
|
||||
_tangents.Add(srcTangents != null && i < srcTangents.Length ? srcTangents[i] : new Vector4(1f, 0f, 0f, 1f));
|
||||
_colors.Add(vertexColor);
|
||||
}
|
||||
|
||||
_workingMesh.Clear();
|
||||
_workingMesh.indexFormat = mesh.indexFormat;
|
||||
_workingMesh.SetVertices(_positions);
|
||||
_workingMesh.SetNormals(_normals);
|
||||
_workingMesh.SetTangents(_tangents);
|
||||
_workingMesh.SetUVs(0, _uv0S);
|
||||
_workingMesh.SetColors(_colors);
|
||||
_workingMesh.subMeshCount = _renderSubMeshCount;
|
||||
|
||||
for (int i = 0; i < _renderSubMeshCount; i++)
|
||||
{
|
||||
_workingMesh.SetTriangles(_subMeshIndices[i], i, false);
|
||||
}
|
||||
|
||||
_workingMesh.RecalculateBounds();
|
||||
}
|
||||
|
||||
private static void CollectRenderableSubMeshes(Mesh sourceMesh, List<int[]> subMeshIndices, List<int> renderSubMeshMap)
|
||||
{
|
||||
subMeshIndices.Clear();
|
||||
renderSubMeshMap.Clear();
|
||||
|
||||
int subMeshCount = Mathf.Max(1, sourceMesh.subMeshCount);
|
||||
for (int subMeshIndex = 0; subMeshIndex < subMeshCount; subMeshIndex++)
|
||||
{
|
||||
if (sourceMesh.GetTopology(subMeshIndex) != MeshTopology.Triangles)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int[] indices = sourceMesh.GetTriangles(subMeshIndex);
|
||||
if (indices == null || indices.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
subMeshIndices.Add(indices);
|
||||
renderSubMeshMap.Add(subMeshIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareVertexLists(int capacity)
|
||||
{
|
||||
_positions.Clear();
|
||||
_normals.Clear();
|
||||
_tangents.Clear();
|
||||
_uv0S.Clear();
|
||||
_colors.Clear();
|
||||
|
||||
if (_positions.Capacity < capacity)
|
||||
{
|
||||
_positions.Capacity = capacity;
|
||||
}
|
||||
|
||||
if (_normals.Capacity < capacity)
|
||||
{
|
||||
_normals.Capacity = capacity;
|
||||
}
|
||||
|
||||
if (_tangents.Capacity < capacity)
|
||||
{
|
||||
_tangents.Capacity = capacity;
|
||||
}
|
||||
|
||||
if (_uv0S.Capacity < capacity)
|
||||
{
|
||||
_uv0S.Capacity = capacity;
|
||||
}
|
||||
|
||||
if (_colors.Capacity < capacity)
|
||||
{
|
||||
_colors.Capacity = capacity;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureWorkingMesh()
|
||||
{
|
||||
if (_workingMesh != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_workingMesh = new Mesh
|
||||
{
|
||||
name = "MeshUI Generated Mesh"
|
||||
};
|
||||
_workingMesh.MarkDynamic();
|
||||
}
|
||||
|
||||
private void ReleaseWorkingMesh()
|
||||
{
|
||||
if (_workingMesh == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(_workingMesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(_workingMesh);
|
||||
}
|
||||
|
||||
_workingMesh = null;
|
||||
}
|
||||
|
||||
private Material GetRenderMaterial(int subMeshIndex)
|
||||
{
|
||||
int sourceSubMeshIndex = subMeshIndex;
|
||||
if (subMeshIndex >= 0 && subMeshIndex < _renderSubMeshMap.Count)
|
||||
{
|
||||
sourceSubMeshIndex = _renderSubMeshMap[subMeshIndex];
|
||||
}
|
||||
|
||||
if (subMeshMaterials != null && sourceSubMeshIndex >= 0 && sourceSubMeshIndex < subMeshMaterials.Count)
|
||||
{
|
||||
Material subMeshMaterial = subMeshMaterials[sourceSubMeshIndex];
|
||||
if (subMeshMaterial != null)
|
||||
{
|
||||
return subMeshMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96ee1f1d0f8f4cb3a4993f12831f42b7
|
||||
timeCreated: 1774387200
|
||||
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBShader
|
||||
{
|
||||
public static class UnityObjectFindCompat
|
||||
{
|
||||
public static T FindAny<T>() where T : Object
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
return Object.FindAnyObjectByType<T>();
|
||||
#else
|
||||
#pragma warning disable 0618
|
||||
return Object.FindObjectOfType<T>();
|
||||
#pragma warning restore 0618
|
||||
#endif
|
||||
}
|
||||
|
||||
public static T[] FindAll<T>() where T : Object
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
return Object.FindObjectsByType<T>(FindObjectsSortMode.None);
|
||||
#else
|
||||
#pragma warning disable 0618
|
||||
return Object.FindObjectsOfType<T>();
|
||||
#pragma warning restore 0618
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6399d1dc93fb4e0c8a757240070a1313
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,192 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBShader
|
||||
{
|
||||
[ExecuteAlways]
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(ParticleSystem))]
|
||||
public sealed class NBParticleLocalTransformHelper : MonoBehaviour
|
||||
{
|
||||
private const string NBShaderName = "Effects/NBShader";
|
||||
private const string LegacyShaderName = "Effects/NBShader(Legacy)";
|
||||
private const string CustomLocalTransformKeyword = "_CUSTOM_LOCAL_TRANSFORM";
|
||||
|
||||
private static readonly int CustomLocalTransformLocalToWorldId =
|
||||
Shader.PropertyToID("_CustomLocalTransformLocalToWorld");
|
||||
|
||||
private static readonly int CustomLocalTransformWorldToLocalId =
|
||||
Shader.PropertyToID("_CustomLocalTransformWorldToLocal");
|
||||
|
||||
private ParticleSystemRenderer _particleRenderer;
|
||||
private Material _runtimeMaterial;
|
||||
private Material _lastAppliedMaterial;
|
||||
private string _lastWarning;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
CacheRenderer();
|
||||
ApplyCustomTransform();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
ApplyCustomTransform();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
CacheRenderer();
|
||||
ApplyCustomTransform();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SetCustomTransformKeyword(false);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
SetCustomTransformKeyword(false);
|
||||
}
|
||||
|
||||
private void CacheRenderer()
|
||||
{
|
||||
if (_particleRenderer == null)
|
||||
{
|
||||
TryGetComponent(out _particleRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyCustomTransform()
|
||||
{
|
||||
if (!TryGetWritableMaterial(out Material material))
|
||||
{
|
||||
DisableLastAppliedKeyword();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lastAppliedMaterial != null && _lastAppliedMaterial != material)
|
||||
{
|
||||
_lastAppliedMaterial.DisableKeyword(CustomLocalTransformKeyword);
|
||||
}
|
||||
|
||||
Matrix4x4 localToWorld = transform.localToWorldMatrix;
|
||||
Matrix4x4 worldToLocal = transform.worldToLocalMatrix;
|
||||
|
||||
material.SetMatrix(CustomLocalTransformLocalToWorldId, localToWorld);
|
||||
material.SetMatrix(CustomLocalTransformWorldToLocalId, worldToLocal);
|
||||
material.EnableKeyword(CustomLocalTransformKeyword);
|
||||
|
||||
_lastAppliedMaterial = material;
|
||||
_lastWarning = null;
|
||||
}
|
||||
|
||||
private void SetCustomTransformKeyword(bool enabled)
|
||||
{
|
||||
Material material = GetExistingMaterial();
|
||||
if (material == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
material.EnableKeyword(CustomLocalTransformKeyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
material.DisableKeyword(CustomLocalTransformKeyword);
|
||||
if (material == _lastAppliedMaterial)
|
||||
{
|
||||
_lastAppliedMaterial = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Material GetExistingMaterial()
|
||||
{
|
||||
if (_lastAppliedMaterial != null)
|
||||
{
|
||||
return _lastAppliedMaterial;
|
||||
}
|
||||
|
||||
CacheRenderer();
|
||||
if (_particleRenderer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
return _runtimeMaterial;
|
||||
}
|
||||
|
||||
return _particleRenderer.sharedMaterial;
|
||||
}
|
||||
|
||||
private bool TryGetWritableMaterial(out Material material)
|
||||
{
|
||||
CacheRenderer();
|
||||
if (_particleRenderer == null)
|
||||
{
|
||||
material = null;
|
||||
LogWarningOnce("NBParticleLocalTransformHelper requires a ParticleSystemRenderer on the same GameObject.");
|
||||
return false;
|
||||
}
|
||||
|
||||
material = Application.isPlaying ? GetRuntimeMaterial() : _particleRenderer.sharedMaterial;
|
||||
if (material == null)
|
||||
{
|
||||
LogWarningOnce("NBParticleLocalTransformHelper could not find a material on the ParticleSystemRenderer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (material.shader == null || !IsSupportedShader(material.shader))
|
||||
{
|
||||
material = null;
|
||||
LogWarningOnce("NBParticleLocalTransformHelper only supports NBShader materials using shader '" +
|
||||
NBShaderName + "' or '" + LegacyShaderName + "'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsSupportedShader(Shader shader)
|
||||
{
|
||||
return shader.name == NBShaderName || shader.name == LegacyShaderName;
|
||||
}
|
||||
|
||||
private Material GetRuntimeMaterial()
|
||||
{
|
||||
if (_runtimeMaterial == null && _particleRenderer != null)
|
||||
{
|
||||
_runtimeMaterial = _particleRenderer.material;
|
||||
}
|
||||
|
||||
return _runtimeMaterial;
|
||||
}
|
||||
|
||||
private void DisableLastAppliedKeyword()
|
||||
{
|
||||
if (_lastAppliedMaterial == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastAppliedMaterial.DisableKeyword(CustomLocalTransformKeyword);
|
||||
_lastAppliedMaterial = null;
|
||||
}
|
||||
|
||||
private void LogWarningOnce(string message)
|
||||
{
|
||||
if (_lastWarning == message)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastWarning = message;
|
||||
Debug.LogWarning(message, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70a2d4dce4af4875b6c1cb93bf60442d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
// using Sirenix.OdinInspector;
|
||||
namespace NBShader
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class NBShaderSpriteHelper : MonoBehaviour
|
||||
{
|
||||
private const string NBShaderName = "Effects/NBShader";
|
||||
private const string LegacyShaderName = "Effects/NBShader(Legacy)";
|
||||
|
||||
public Sprite sprite;
|
||||
|
||||
// [ReadOnly]
|
||||
public SpriteRenderer spRenderer;
|
||||
|
||||
// [ReadOnly]
|
||||
public Image image;
|
||||
|
||||
[InspectorButton("初始化", "Init")] public bool ButtomInspector;
|
||||
|
||||
private Material mat;
|
||||
|
||||
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
if (TryGetComponent<SpriteRenderer>(out SpriteRenderer spr))
|
||||
{
|
||||
spRenderer = spr;
|
||||
sprite = spr.sprite;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TryGetComponent<Image>(out Image im))
|
||||
{
|
||||
image = im;
|
||||
sprite = im.sprite;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (sprite)
|
||||
{
|
||||
Texture texture = sprite.texture;
|
||||
Rect rect = sprite.textureRect;
|
||||
// sharedMaterial.SetVector("_BaseMapReverseST",CalScaleOffset(spRenderer.sprite.textureRect,spRenderer.sprite.texture));
|
||||
|
||||
if (spRenderer)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
mat = spRenderer.material;
|
||||
}
|
||||
else
|
||||
{
|
||||
mat = spRenderer.sharedMaterial;
|
||||
}
|
||||
}
|
||||
else if (image)
|
||||
{
|
||||
mat = image.material;
|
||||
}
|
||||
|
||||
if (mat && IsSupportedShader(mat.shader))
|
||||
{
|
||||
mat.SetVector("_MainTex_Reverse_ST", CalScaleOffset(rect, texture));
|
||||
Debug.Log(mat.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Vector4 CalScaleOffset(Rect textureRect, Texture texture)
|
||||
{
|
||||
//这是一个反向的scale offset。
|
||||
//算法:如果原scale offset。转换后会是 scaleAfter= 1 / scale , offsetAfter = - offset/scale;
|
||||
Vector2 scaleAfter = new Vector2(texture.width / textureRect.width, texture.height / textureRect.height);
|
||||
Vector2 offsetAfter = new Vector2(-(textureRect.x / texture.width) * scaleAfter.x,
|
||||
-(textureRect.y / texture.height) * scaleAfter.y);
|
||||
Vector4 scaleOffset = new Vector4(scaleAfter.x, scaleAfter.y, offsetAfter.x, offsetAfter.y);
|
||||
return scaleOffset;
|
||||
}
|
||||
|
||||
private static bool IsSupportedShader(Shader shader)
|
||||
{
|
||||
return shader && (shader.name == NBShaderName || shader.name == LegacyShaderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58ec7ff2f9b58f5459946ac86028eacf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBShader
|
||||
{
|
||||
public abstract class ShaderFlagsBase
|
||||
{
|
||||
|
||||
private Material _material;
|
||||
|
||||
public Material material
|
||||
{
|
||||
get { return _material; }
|
||||
}
|
||||
|
||||
protected ShaderFlagsBase(Material material)
|
||||
{
|
||||
_material = material;
|
||||
}
|
||||
|
||||
public void SetMaterial(Material material)
|
||||
{
|
||||
_material = material;
|
||||
}
|
||||
|
||||
public Material GetMaterial()
|
||||
{
|
||||
return _material;
|
||||
}
|
||||
|
||||
public abstract int GetShaderFlagsId(int index = 0);
|
||||
protected abstract string GetShaderFlagsName(int index = 0);
|
||||
|
||||
private void SetIntValue(Material material, int flagBits, int index = 0)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
material.SetInteger(GetShaderFlagsId(index), flagBits);
|
||||
#else
|
||||
material.SetInteger(GetShaderFlagsId(index), flagBits);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetFlagBits(int flagBits, MaterialPropertyBlock propertyBlock = null, int index = 0)
|
||||
{
|
||||
if (propertyBlock is null)
|
||||
{
|
||||
if (_material is null) return;
|
||||
int flags = _material.GetInteger(GetShaderFlagsId(index));
|
||||
SetIntValue(_material, flags | flagBits, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
int flags = propertyBlock.GetInt(GetShaderFlagsId(index));
|
||||
propertyBlock.SetInt(GetShaderFlagsId(index), flags | flagBits);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearFlagBits(int flagBits, MaterialPropertyBlock propertyBlock = null, int index = 0)
|
||||
{
|
||||
if (propertyBlock is null)
|
||||
{
|
||||
if (_material is null) return;
|
||||
int flags = _material.GetInteger(GetShaderFlagsId(index));
|
||||
SetIntValue(_material, flags & ~flagBits, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
int flags = propertyBlock.GetInteger(GetShaderFlagsId(index));
|
||||
propertyBlock.SetInteger(GetShaderFlagsId(index), flags & ~flagBits);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckFlagBits(int flagBits, MaterialPropertyBlock propertyBlock = null, int index = 0)
|
||||
{
|
||||
int flags = 0;
|
||||
if (propertyBlock is null)
|
||||
{
|
||||
if (_material is null) throw new NullReferenceException("material");
|
||||
flags = _material.GetInteger(GetShaderFlagsId(index));
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = propertyBlock.GetInteger(GetShaderFlagsId(index));
|
||||
}
|
||||
|
||||
return (flags & flagBits) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bcf591e67bd470e9375d72c63838643
|
||||
timeCreated: 1655437380
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "com.xuanxuan.render.utility",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:15fc0a57446b3144c949da3e2b9737a9"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f9e4d586616f13449cfeb86c5f704c2
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user