一些Editor整理(为自己)

///unity 如何修改材质属性和更换shader//

使用setfloat修改值

1

code  renderer.material.SetFloat("_TransVal", TranValue);

这是shader里面的一句

1

_TransVal("Transparency_Value", Range(0,1)) = 0.5

1

code renderer.material.shader = Shader.Find("Custom/SimpleAlpha");

代码控制切换shader。

using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEngine;
public class ReplaceShaderByFileDir : EditorWindow
{
    Shader shader;
    Shader originShader;
    bool isShowReplaceGo = false;  //是否显示被替换的物体
    string tipMsg = null;
    MessageType tipMsgType = MessageType.Info;
    List<GameObject> replaceGoList = new List<GameObject>();
    int matCount = 0;   //材质的数量
    Vector2 scrollPos = Vector2.zero;
    [MenuItem("Editor/替换场景中的shader")]
    public static void OpenWindow()
    {
        //创建窗口
        ReplaceShaderByFileDir window = GetWindow<ReplaceShaderByFileDir>(false, "替换场景中的shader");
        window.Show();
    }
    void OnGUI()
    {
        GUILayout.Label("原shader:");
        originShader = (Shader)EditorGUILayout.ObjectField(originShader, typeof(Shader), true);
        //ObjectField(string label, Object obj, Type objType, bool allowSceneObjects, GUILayoutOption[] paramsOptions)
        //label字段前面的可选标签   obj字段显示的物体   objType物体的类型    allowSceneObjects允许指定场景物体..
        //返回:Object,用户设置的物体
        GUILayout.Label("替换shader :");
        shader = (Shader)EditorGUILayout.ObjectField(shader, typeof(Shader), true);
        GUILayout.Space(8);
        //开始一个水平组,所有被渲染的控件,在这个组里一个接着一个被水平放置。该组必须调用EndHorizontal关闭。
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("批量替换", GUILayout.Height(30)))
        {
            Replace();
        }
        if (GUILayout.Button("重置", GUILayout.Height(30)))
        {
            Reset();
        }
        //关闭水平组
        GUILayout.EndHorizontal();
        //提示信息
        if (!string.IsNullOrEmpty(tipMsg))
        {
            //创建一个帮助框,第一个参数是显示的文本,第二个参数是帮助框的提示图标类型
            EditorGUILayout.HelpBox(tipMsg, tipMsgType);
        }
        //创建勾选框
        isShowReplaceGo = GUILayout.Toggle(isShowReplaceGo, "显示被替换的GameObject");
        if (isShowReplaceGo)
        {
            if (replaceGoList.Count > 0)
            {
                //开始滚动视图,scrollPos用于显示的滚动位置
                scrollPos = GUILayout.BeginScrollView(scrollPos, GUILayout.Width(Screen.width), GUILayout.Height(Screen.height - 200));
                foreach (var go in replaceGoList)
                {
                    EditorGUILayout.ObjectField(go, typeof(GameObject), true);
                }
                //结束滚动视图
                GUILayout.EndScrollView();
            }
            else
            {
                EditorGUILayout.LabelField("替换个数为0");
            }
        }
    }
    /// <summary>
    /// 替换Shader
    /// </summary>
    void Replace()
    {
        replaceGoList.Clear();
        if (shader == null)
        {
            tipMsg = "shader为空!";
            tipMsgType = MessageType.Error;
            return;
        }
        if (originShader == null)
        {
            tipMsg = "指定的shader为空!";
            tipMsgType = MessageType.Error;
            return;
        }
        else if (originShader.Equals(shader))
        {
            tipMsg = "替换的shader和指定的shader相同!";
            tipMsgType = MessageType.Error;
            return;
        }
        Dictionary<GameObject, Material[]> matDict = GetAllScenceMaterial();
        List<Material> replaceMatList = new List<Material>();
        foreach (var item in matDict)
        {
            GameObject tempGo = item.Key;
            Material[] mats = item.Value;
            int length = mats.Length;
            for (int i = 0; i < length; i++)
            {
                var mat = mats[i];
                if (mat != null && mat.shader.Equals(originShader))
                {
                    if (!mat.shader.Equals(shader))
                    {
                        replaceGoList.Add(tempGo);
                        if (!replaceMatList.Contains(mat))
                            replaceMatList.Add(mat);
                    }
                }
            }
        }
        //替换Material的数量
        int replaceMatCount = replaceMatList.Count;
        for (int i = 0; i < replaceMatCount; i++)
        {
            UpdateProgress(i, replaceMatCount, "替换中...");
            //替换Shader
            replaceMatList[i].shader = shader;
            //启用GPU Instancing
            replaceMatList[i].enableInstancing = true;
            //设置脏标志,标记目标物体已改变,当资源已改变并需要保存到磁盘,Unity内部使用dirty标识来查找
            EditorUtility.SetDirty(replaceMatList[i]);
        }
        // 刷新编辑器,使刚创建的资源立刻被导入,才能接下来立刻使用上该资源
        AssetDatabase.Refresh();
        // 一般所有资源修改完后调用,调用后Unity会重新导入修改过后的资源
        AssetDatabase.SaveAssets();
        tipMsg = "替换成功!替换了" + replaceMatCount + "个Material," + replaceGoList.Count + "个GameObject";
        tipMsgType = MessageType.Info;
        //关闭进度条
        EditorUtility.ClearProgressBar();
    }
    /// <summary>
    /// 替换shader的可视化进程
    /// </summary>
    void UpdateProgress(int progress, int progressMax, string info)
    {
        string title = "Processing...[" + progress + " / " + progressMax + "]";
        float value = (float)progress / progressMax;
        //显示进度条
        EditorUtility.DisplayProgressBar(title, info, value);
    }
    /// <summary>
    /// 重置
    /// </summary>
    void Reset()
    {
        tipMsg = null;
        shader = null;
        originShader = null;
        matCount = 0;
        replaceGoList.Clear();
        isShowReplaceGo = false;
    }
    /// <summary>
    /// 获取所有场景中的Material
    /// </summary>
    /// <returns></returns>
    Dictionary<GameObject, Material[]> GetAllScenceMaterial()
    {
        Dictionary<GameObject, Material[]> dict = new Dictionary<GameObject, Material[]>();
        List<GameObject> gos = GetAllSceneGameObject();
        foreach (var go in gos)
        {
            Renderer render = go.GetComponent<Renderer>();
            if (render != null)
            {
                Material[] mats = render.sharedMaterials;
                if (mats != null && mats.Length > 0 && !dict.ContainsKey(go))
                {
                    dict.Add(go, mats);
                    matCount += mats.Length;
                }
            }
        }
        return dict;
    }
    /// <summary>
    /// 获取所有场景中的物体
    /// </summary>
    /// <returns></returns>
    List<GameObject> GetAllSceneGameObject()
    {
        List<GameObject> list = new List<GameObject>();
        //获取当前活动的场景
        Scene scene = SceneManager.GetActiveScene();
        //获取场景中所有根游戏对象
        GameObject[] rootGos = scene.GetRootGameObjects();
        foreach (var go in rootGos)
        {
            Transform[] childs = go.transform.GetComponentsInChildren<Transform>(true);
            foreach (var child in childs)
            {
                list.Add(child.gameObject);
            }
        }
        return list;
    }
}
 

EditorUtility.SetDirty(Object target)

=======================================

Unity Gizmos 绘制扇形线框扇形是用线条拼起来的,实心的扇形的是提前生成好mesh,然后用drawmesh

 
using UnityEngine;
 
public static class GizmosTools
{
    /// <summary>
    /// 绘制半圆
    /// </summary>
    public static void DrawWireSemicircle(Vector3 origin,Vector3 direction,float radius,int angle)
    {
        DrawWireSemicircle(origin,direction,radius,angle,Vector3.up);
    }
    public static void DrawWireSemicircle(Vector3 origin,Vector3 direction,float radius,int angle,Vector3 axis)
    {
        Vector3 leftdir = Quaternion.AngleAxis(-angle/2, axis)*direction;
        Vector3 rightdir = Quaternion.AngleAxis(angle/2, axis)*direction;
 
        Vector3 currentP = origin + leftdir * radius;
        Vector3 oldP;
        if (angle!=360)
        {
            Gizmos.DrawLine(origin,currentP);
        }
        for (int i = 0; i < angle/10; i++)
        {
            Vector3 dir= Quaternion.AngleAxis(10*i, axis)*leftdir;
            oldP = currentP;
            currentP=origin + dir * radius;
            Gizmos.DrawLine(oldP,currentP);
        }
        oldP = currentP;
        currentP=origin + rightdir * radius;
        Gizmos.DrawLine(oldP,currentP);
        if (angle!=360)
        {
            Gizmos.DrawLine(currentP,origin);
        }
       
    }
 
    public static Mesh SemicircleMesh(float radius,int angle,Vector3 axis)
    {
        Vector3 leftdir = Quaternion.AngleAxis(-angle/2, axis)*Vector3.forward;
        Vector3 rightdir = Quaternion.AngleAxis(angle/2, axis)*Vector3.forward;
        int pcount = angle / 10;
        //顶点
        Vector3[] vertexs = new Vector3[3+pcount];
        vertexs[0] = Vector3.zero;
        int index = 1;
        vertexs[index] = leftdir * radius;
        index++;
        for (int i = 0; i < pcount; i++)
        {
            Vector3 dir= Quaternion.AngleAxis(10*i, axis)*leftdir;
            vertexs[index]= dir * radius;
            index++;
        }
        vertexs[index] = rightdir * radius;
        //三角面
        int[] triangles=new int[3*(1+pcount)];
        for (int i = 0; i < 1+pcount; i++)
        {
            triangles[3 * i] = 0;
            triangles[3 * i + 1] = i+1;
            triangles[3 * i + 2] = i+2;
        }
        
        Mesh mesh=new Mesh();
        mesh.vertices = vertexs;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
        return mesh;
    }
}

=======================================

选中想要优化的文件夹或文件,右键Animation->裁剪浮点数去除Scale。

using System;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using UnityEditor;
using System.IO;

namespace EditorTool
{
    class AnimationOpt
    {
        static Dictionary<uint,string> _FLOAT_FORMAT;
        static MethodInfo getAnimationClipStats;
        static FieldInfo sizeInfo;
        static object[] _param = new object[1];

        static AnimationOpt ()
        {
            _FLOAT_FORMAT = new Dictionary<uint, string> ();
            for (uint i = 1; i < 6; i++) {
                _FLOAT_FORMAT.Add (i, "f" + i.ToString ());
            }
            Assembly asm = Assembly.GetAssembly (typeof(Editor));
            getAnimationClipStats = typeof(AnimationUtility).GetMethod ("GetAnimationClipStats", BindingFlags.Static | BindingFlags.NonPublic);
            Type aniclipstats = asm.GetType ("UnityEditor.AnimationClipStats");
            sizeInfo = aniclipstats.GetField ("size", BindingFlags.Public | BindingFlags.Instance);
        }

        AnimationClip _clip;
        string _path;

        public string path { get{ return _path;} }

        public long originFileSize { get; private set; }

        public int originMemorySize { get; private set; }

        public int originInspectorSize { get; private set; }

        public long optFileSize { get; private set; }

        public int optMemorySize { get; private set; }

        public int optInspectorSize { get; private set; }

        public AnimationOpt (string path, AnimationClip clip)
        {
            _path = path;
            _clip = clip;
            _GetOriginSize ();
        }

        void _GetOriginSize ()
        {
            originFileSize = _GetFileZie ();
            originMemorySize = _GetMemSize ();
            originInspectorSize = _GetInspectorSize ();
        }

        void _GetOptSize ()
        {
            optFileSize = _GetFileZie ();
            optMemorySize = _GetMemSize ();
            optInspectorSize = _GetInspectorSize ();
        }

        long _GetFileZie ()
        {
            FileInfo fi = new FileInfo (_path);
            return fi.Length;
        }

        int _GetMemSize ()
        {
            return Profiler.GetRuntimeMemorySize (_clip);
        }

        int _GetInspectorSize ()
        {
            _param [0] = _clip;
            var stats = getAnimationClipStats.Invoke (null, _param);
            return (int)sizeInfo.GetValue (stats);
        }

        void _OptmizeAnimationScaleCurve ()
        {
            if (_clip != null) {
                //去除scale曲线
                foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(_clip)) {
                    string name = theCurveBinding.propertyName.ToLower ();
                    if (name.Contains ("scale")) {
                        AnimationUtility.SetEditorCurve (_clip, theCurveBinding, null);
                        Debug.LogFormat ("关闭{0}的scale curve", _clip.name);
                    }
                } 
            }
        }

        void _OptmizeAnimationFloat_X (uint x)
        {
            if (_clip != null && x > 0) {
                //浮点数精度压缩到f3
                AnimationClipCurveData[] curves = null;
                curves = AnimationUtility.GetAllCurves (_clip);
                Keyframe key;
                Keyframe[] keyFrames;
                string floatFormat;
                if (_FLOAT_FORMAT.TryGetValue (x, out floatFormat)) {
                    if (curves != null && curves.Length > 0) {
                        for (int ii = 0; ii < curves.Length; ++ii) {
                            AnimationClipCurveData curveDate = curves [ii];
                            if (curveDate.curve == null || curveDate.curve.keys == null) {
                                //Debug.LogWarning(string.Format("AnimationClipCurveData {0} don't have curve; Animation name {1} ", curveDate, animationPath));
                                continue;
                            }
                            keyFrames = curveDate.curve.keys;
                            for (int i = 0; i < keyFrames.Length; i++) {
                                key = keyFrames [i];
                                key.value = float.Parse (key.value.ToString (floatFormat));
                                key.inTangent = float.Parse (key.inTangent.ToString (floatFormat));
                                key.outTangent = float.Parse (key.outTangent.ToString (floatFormat));
                                keyFrames [i] = key;
                            }
                            curveDate.curve.keys = keyFrames;
                            _clip.SetCurve (curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve);
                        }
                    }
                } else {
                    Debug.LogErrorFormat ("目前不支持{0}位浮点", x);
                }
            }
        }

        public void Optimize (bool scaleOpt, uint floatSize)
        {
            if (scaleOpt) {
                _OptmizeAnimationScaleCurve ();
            }
            _OptmizeAnimationFloat_X (floatSize);
            _GetOptSize ();
        }

        public void Optimize_Scale_Float3 ()
        {
            Optimize (true, 3);
        }

        public void LogOrigin ()
        {
            _logSize (originFileSize, originMemorySize, originInspectorSize);
        }

        public void LogOpt ()
        {
            _logSize (optFileSize, optMemorySize, optInspectorSize);
        }

        public void LogDelta ()
        {

        }

        void _logSize (long fileSize, int memSize, int inspectorSize)
        {
            Debug.LogFormat ("{0} \nSize=[ {1} ]", _path, string.Format ("FSize={0} ; Mem->{1} ; inspector->{2}",
                EditorUtility.FormatBytes (fileSize), EditorUtility.FormatBytes (memSize), EditorUtility.FormatBytes (inspectorSize)));
        }
    }

    public class OptimizeAnimationClipTool
    {
        static List<AnimationOpt> _AnimOptList = new List<AnimationOpt> ();
        static List<string> _Errors = new List<string>();
        static int _Index = 0;

        [MenuItem("Assets/Animation/裁剪浮点数去除Scale")]
        public static void Optimize()
        {
            _AnimOptList = FindAnims ();
            if (_AnimOptList.Count > 0)
            {
                _Index = 0;
                _Errors.Clear ();
                EditorApplication.update = ScanAnimationClip;
            }
        }

        private static void ScanAnimationClip()
        {
            AnimationOpt _AnimOpt = _AnimOptList[_Index];
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("优化AnimationClip", _AnimOpt.path, (float)_Index / (float)_AnimOptList.Count);
            _AnimOpt.Optimize_Scale_Float3();
            _Index++;
            if (isCancel || _Index >= _AnimOptList.Count)
            {
                EditorUtility.ClearProgressBar();
                Debug.Log(string.Format("--优化完成--    错误数量: {0}    总数量: {1}/{2}    错误信息↓:\n{3}\n----------输出完毕----------", _Errors.Count, _Index, _AnimOptList.Count, string.Join(string.Empty, _Errors.ToArray())));
                Resources.UnloadUnusedAssets();
                GC.Collect();
                AssetDatabase.SaveAssets();
                EditorApplication.update = null;
                _AnimOptList.Clear();
                _cachedOpts.Clear ();
                _Index = 0;
            }
        }

        static Dictionary<string,AnimationOpt> _cachedOpts = new Dictionary<string, AnimationOpt> ();

        static AnimationOpt _GetNewAOpt (string path)
        {
            AnimationOpt opt = null;
            if (!_cachedOpts.ContainsKey(path)) {
                AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip> (path);
                if (clip != null) {
                    opt = new AnimationOpt (path, clip);
                    _cachedOpts [path] = opt;
                }
            }
            return opt;
        }

        static List<AnimationOpt> FindAnims()
        {
            string[] guids = null;
            List<string> path = new List<string>();
            List<AnimationOpt> assets = new List<AnimationOpt> ();
            UnityEngine.Object[] objs = Selection.GetFiltered(typeof(object), SelectionMode.Assets);
            if (objs.Length > 0)
            {
                for(int i = 0; i < objs.Length; i++)
                {
                    if (objs [i].GetType () == typeof(AnimationClip))
                    {
                        string p = AssetDatabase.GetAssetPath (objs [i]);
                        AnimationOpt animopt = _GetNewAOpt (p);
                        if (animopt != null)
                            assets.Add (animopt);
                    }
                    else
                        path.Add(AssetDatabase.GetAssetPath (objs [i]));
                }
                if(path.Count > 0)
                    guids = AssetDatabase.FindAssets (string.Format ("t:{0}", typeof(AnimationClip).ToString().Replace("UnityEngine.", "")), path.ToArray());
                else
                    guids = new string[]{};
            }
            for(int i = 0; i < guids.Length; i++)
            {
                string assetPath = AssetDatabase.GUIDToAssetPath (guids [i]);
                AnimationOpt animopt = _GetNewAOpt (assetPath);
                if (animopt != null)
                    assets.Add (animopt);
            }
            return assets;
        }
    }
}

===========================================

能做到去掉Scale曲线,降低浮点精度

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

using System;

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using UnityEditor;

public static class RemoveAnimationClipScale

{

    [MenuItem("Tools/Animation/Remove Animation Clip Scale")]

    public static void RemoveAnimationClipScaleMenu()

    {

        int i = 0;

        int total = 0;

        try

        {

            EditorUtility.DisplayProgressBar("Remove Animation Clip Scale""Collecting Animation Clip", 0);

            var gos = EnumAssets.EnumInCurrentSelection<UnityEngine.AnimationClip>();

            total = gos.Count();

            if (total > 0)

            {

                foreach (var go in gos)

                {

                    EditorUtility.DisplayProgressBar("Remove Animation Clip Scale", go.name, i * 1.0f / total);

                    OnPostprocessAnimation(go);

                    i++;

                }  

            }

        }

        catch (Exception)

        {

        }

        finally

        {

            EditorUtility.ClearProgressBar();

            AssetDatabase.Refresh();

            AssetDatabase.SaveAssets();

            Debug.Log("Tools/Animation/Optimize Animation: total[" + total + "]");

        }

    }

    static void OnPostprocessAnimation(AnimationClip theAnimation)

    {

        try

        {

            //去除scale曲线

            foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(theAnimation))

            {

                string name = theCurveBinding.propertyName.ToLower();

                if (name.Contains("scale"))

                {

                    AnimationUtility.SetEditorCurve(theAnimation, theCurveBinding, null);

                }

            }

            //浮点数精度压缩到f3

            AnimationClipCurveData[] curves = null;

            curves = AnimationUtility.GetAllCurves(theAnimation);

            Keyframe key;

            Keyframe[] keyFrames;

            for (int ii = 0; ii < curves.Length; ++ii)

            {

                AnimationClipCurveData curveDate = curves[ii];

                if (curveDate.curve == null || curveDate.curve.keys == null)

                {

                    //Debug.LogWarning(string.Format("AnimationClipCurveData {0} don't have curve; Animation name {1} ", curveDate, animationPath));

                    continue;

                }

                keyFrames = curveDate.curve.keys;

                for (int i = 0; i < keyFrames.Length; i++)

                {

                    key = keyFrames[i];

                    key.value = float.Parse(key.value.ToString("f3"));

                    key.inTangent = float.Parse(key.inTangent.ToString("f3"));

                    key.outTangent = float.Parse(key.outTangent.ToString("f3"));

                    keyFrames[i] = key;

                }

                curveDate.curve.keys = keyFrames;

                theAnimation.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve);

            }

        }

        catch (Exception e)

        {

            Debug.LogError(string.Format("CompressAnimationClip Failed !!! animationPath : {0} error: {1}", theAnimation.name, e));

        }

    }

}

=========================================

取BlobSize代码

AnimationClip aniClip = AssetDatabase.LoadAssetAtPath<AnimationClip> (path);
var fileInfo = new System.IO.FileInfo(path);
Debug.Log(fileInfo.Length);//FileSize
Debug.Log(Profiler.GetRuntimeMemorySize (aniClip));//MemorySize

Assembly asm = Assembly.GetAssembly(typeof(Editor));
MethodInfo getAnimationClipStats = typeof(AnimationUtility).GetMethod("GetAnimationClipStats", BindingFlags.Static | BindingFlags.NonPublic);
Type aniclipstats = asm.GetType("UnityEditor.AnimationClipStats");
FieldInfo sizeInfo = aniclipstats.GetField ("size", BindingFlags.Public | BindingFlags.Instance);

var stats = getAnimationClipStats.Invoke(null, new object[]{aniClip});
Debug.Log(EditorUtility.FormatBytes((int)sizeInfo.GetValue(stats)));//BlobSize

=====================================

用反射物理射线的方法,把这个脚本放到Editor下

/**
 * Author: YinPeiQuan
**/
using UnityEngine;
using UnityEditor;
using System;
using System.Linq;
using System.Reflection;
 
[InitializeOnLoad]
public class RayHitRefrelection
{
    public static Type type_HandleUtility;
    protected static MethodInfo meth_IntersectRayMesh;
 
    static RayHitRefrelection()
    {
        var editorTypes = typeof(Editor).Assembly.GetTypes();
 
        type_HandleUtility = editorTypes.FirstOrDefault(t => t.Name == "HandleUtility");
        meth_IntersectRayMesh = type_HandleUtility.GetMethod("IntersectRayMesh", (BindingFlags.Static | BindingFlags.NonPublic));
    }
 
    public static bool IntersectRayMesh(Ray ray, MeshFilter meshFilter, out RaycastHit hit)
    {
        return IntersectRayMesh(ray, meshFilter.mesh, meshFilter.transform.localToWorldMatrix, out hit);
    }
 
    static object[] parameters = new object[4];
    public static bool IntersectRayMesh(Ray ray, Mesh mesh, Matrix4x4 matrix, out RaycastHit hit)
    {
        parameters[0] = ray;
        parameters[1] = mesh;
        parameters[2] = matrix;
        parameters[3] = null;
        bool result = (bool)meth_IntersectRayMesh.Invoke(null, parameters);
        hit = (RaycastHit)parameters[3];
        return result;
    }
}

使用方法,从scene视图中心发条射线检测,获取射线射中的点

    public static Vector3 GetSceneViewPosition()
    {
        if (null == SceneView.lastActiveSceneView)
        {
            return Vector3.zero;
        }
 
        Ray ray = SceneView.lastActiveSceneView.camera.ScreenPointToRay(new Vector3(SceneView.lastActiveSceneView.camera.pixelWidth / 2, SceneView.lastActiveSceneView.camera.pixelHeight / 2, 0));
        MeshFilter[] componentsInChildren = GameObject.FindObjectsOfType<MeshFilter>();
        float num = float.PositiveInfinity;
        Vector3 point = Vector3.zero;
        foreach (MeshFilter meshFilter in componentsInChildren)
        {
            Mesh sharedMesh = meshFilter.sharedMesh;
            RaycastHit hit;
            if (sharedMesh
                && RayHitRefrelection.IntersectRayMesh(ray, sharedMesh, meshFilter.transform.localToWorldMatrix, out hit)
                && hit.distance < num)
            {
                point = hit.point;
                num = hit.distance;
            }
        }
        return point;
    }

=====================================

http://api.fanyi.baidu.com/api/trans/product/apidoc 这个是百度翻译api文档

代码里面必须要加appid和password(秘钥)

上面地址打开管理控制台就可以申请,是免费的

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Net;
using System.Security.Cryptography;
using System.Text;
 
public class TranslateLanguageTool : EditorWindow
{
    //可以直接到百度翻译API的官网申请
    //一定要去申请,不然程序的翻译功能不能使用
    private static string appId = "";
    private static string password = "";
 
    [MenuItem("Tools/翻译工具")]
    public static void Open()
    {
        GetWindow<TranslateLanguageTool>("工具");
    }
 
    private Dictionary<string, Dictionary<int, string>> dic = new Dictionary<string, Dictionary<int, string>>();
 
    string sourceStr = "";
    string id = "";
 
    public void OnGUI()
    {
        id = EditorGUILayout.TextField("id", id);
        sourceStr = EditorGUILayout.TextField("中文", sourceStr);
        if (GUILayout.Button("程序专用翻译"))
        {
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.ara);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.en);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.fra);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.de);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.pt);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.ru);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.spa);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.cht);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.th);
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.vie);
        }
        if (GUILayout.Button("翻译"))
        {
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.ara, "阿拉伯");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.fra, "法语");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.de, "德语");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.pt, "葡萄牙");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.ru, "俄语");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.spa, "西班牙");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.th, "泰语");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.cht, "繁体中文");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.vie, "越南语");
            GetTranslationFromBaiduFanyi(id, sourceStr, Language.zh, Language.en, "英文");
        }
    }
 
 
    private static TranslationResult GetTranslationFromBaiduFanyi(string id, string q, Language from, Language to, string language = "")
    {
 
        string jsonResult = String.Empty;
        //源语言
        string languageFrom = from.ToString().ToLower();
        //目标语言
        string languageTo = to.ToString().ToLower();
        //随机数
        string randomNum = System.DateTime.Now.Millisecond.ToString();
        //md5加密
        string md5Sign = GetMD5WithString(appId + q + randomNum + password);
        //url
        string url = String.Format("http://api.fanyi.baidu.com/api/trans/vip/translate?q={0}&from={1}&to={2}&appid={3}&salt={4}&sign={5}",
            q,
            languageFrom,
            languageTo,
            appId,
            randomNum,
            md5Sign
            );
        WebClient wc = new WebClient();
        try
        {
            jsonResult = wc.DownloadString(url);
        }
        catch
        {
            jsonResult = string.Empty;
        }
        //结果转json
        TranslationResult temp = LitJson.JsonMapper.ToObject<TranslationResult>(jsonResult);
        if (null != temp)
        {
            if (string.IsNullOrEmpty(language))
            {
                for (int i = 0; i < temp.trans_result.Length; i++)
                {
                    string str = @"{""Key"":" + id + @",""Content"":" + @"""" + temp.trans_result[i].dst + @"""" + "},";
                    Debug.LogError(str);
                }
            }
            else
            {
                for (int i = 0; i < temp.trans_result.Length; i++)
                {
                    string str = language + "|" + temp.trans_result[i].dst;
                    Debug.LogError(str);
                }
            }
        }
        return null;
    }
 
    private static string GetMD5WithString(string input)
    {
        if (input == null)
        {
            return null;
        }
        MD5 md5Hash = MD5.Create();
        //将输入字符串转换为字节数组并计算哈希数据  
        byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
        //创建一个 Stringbuilder 来收集字节并创建字符串  
        StringBuilder sBuilder = new StringBuilder();
        //循环遍历哈希数据的每一个字节并格式化为十六进制字符串  
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("x2"));
        }
        //返回十六进制字符串  
        return sBuilder.ToString();
    }
}
 
public class Translation
{
    public string src { get; set; }
    public string dst { get; set; }
}
 
public enum Language
{
    //百度翻译API官网提供了多种语言,这里只列了几种
    zh,
    en,
    spa,
    fra,
    th,
    ara,
    ru,
    pt,
    de,
    el,
    vie,
    cht,
    yue,
}
 
public class TranslationResult
{
    //错误码,翻译结果无法正常返回
    public string Error_code { get; set; }
    public string Error_msg { get; set; }
    public string from { get; set; }
    public string to { get; set; }
    public string Query { get; set; }
    //翻译正确,返回的结果
    //这里是数组的原因是百度翻译支持多个单词或多段文本的翻译,在发送的字段q中用换行符(\n)分隔
    public Translation[] trans_result { get; set; }
}

=========================================

规则是:
% = ctrl
# = Shift
& = Alt
LEFT/RIGHT/UP/DOWN = 上下左右
F1…F2 = F...
HOME, END, PGUP, PGDN = 键盘上的特殊功能键
特别注意的是,如果是键盘上的普通按键,比如a~z,则要写成_a ~ _z这种带_前缀的  _%#&_LEFT

==========================================

特效发射粒子数 查找

思路步骤如下:

1.    在Editor文件夹下新建一个脚本文件,命名为EffectEmitChecker.cs

2.    Resource.LoadAll所有的特效文件存入一个数组

3.    循环遍历特效数组并PrefabUtility.InstantiatePrefab()生成一个实例

4.    获取ParticleEmitter组件,并把相关信息缓存到一个List中

5.    DestroyImmediate()删除生成的实例

6.    List根据发射粒子数大小排序

7.    在OnGUI()中展示List中的数据

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;


public class EffectEmitChecker : EditorWindow
{
    float ThumbnailWidth = 40;
    float ThumbnailHeight = 40;
    GUIStyle style = new GUIStyle();
    Vector2 vec2 = new Vector2(0, 0);
    List<EffectParticle> listEffect = new List<EffectParticle>();   //缓存特效信息


    [MenuItem("Effect/Effect Emit Checker")]
    static void MainTask()
    {
        EffectEmitChecker window = GetWindow<EffectEmitChecker>();
        window.LoadEffect();   //加载特效
        window.Show();
    }


    void OnGUI()
    {
        ListEffect();
    }


    void LoadEffect()
    {
        Object[] objs = Resources.LoadAll("Prefabs/AAA");  //"Effects/"读取所有特效文件,可以根据情况改变地址
        for (int i = 0; i < objs.Length; i++)
        {
            GameObject go = PrefabUtility.InstantiatePrefab(objs[i]) as GameObject; //创建实例
            if (go == null) continue;
            ParticleRenderer[] renderers = go.GetComponentsInChildren<ParticleRenderer>(true);  //获取特效实例下的所有ParticleRenderer组件
            foreach (ParticleRenderer render in renderers)
            {
                EffectParticle effect = new EffectParticle();
                ParticleEmitter emitter = render.GetComponent<ParticleEmitter>();   //获取ParticleEmitter组件
                effect.name = objs[i].name;
                effect.material = render.sharedMaterial;
                if (emitter != null)
                {
                    effect.maxEmission = emitter.maxEmission;   //最大发射粒子数赋值
                }
                effect.prefab = objs[i];
                listEffect.Add(effect);
            }
            DestroyImmediate(go);   //销毁实例
        }
        listEffect.Sort((x, y) => { return y.maxEmission.CompareTo(x.maxEmission); });  //从大到小排序
        style.normal.textColor = Color.red;
        style.fixedWidth = 120;
    }


    void ListEffect()
    {
        vec2 = EditorGUILayout.BeginScrollView(vec2);
        foreach (EffectParticle effectParticle in listEffect)
        {
            if (effectParticle != null)
            {
                GUILayout.BeginHorizontal();


                Material mat = effectParticle.material;
                if (mat != null)
                {
                    //根据材质找到相应的纹理显示
                    Texture texture = mat.mainTexture;
                    if (texture != null)
                        GUILayout.Box(texture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
                    else
                        GUILayout.Box("N/A", GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));


                    GUILayout.Label("Shader:" + mat.shader.name, GUILayout.Width(140)); //Shader名称


                    //特效主颜色显示
                    if (mat.HasProperty("_Color"))
                        EditorGUILayout.ColorField(mat.color, GUILayout.Width(50));
                    else if (mat.HasProperty("_TintColor"))
                        EditorGUILayout.ColorField(mat.GetColor("_TintColor"), GUILayout.Width(50));
                    else
                        GUILayout.Box("N/A", GUILayout.Width(50));
                }


                //发射粒子数判断
                float emission = effectParticle.maxEmission;
                if (emission < 50)
                    GUILayout.Label("MaxEmission:" + emission.ToString(), GUILayout.Width(120));
                else
                    GUILayout.Label("MaxEmission:" + emission.ToString(), style);   //字体标红


                //特效名称,并可定位到相应文件
                if (GUILayout.Button(effectParticle.name))
                    Selection.activeObject = effectParticle.prefab;


                //文件所在路径节点
                //GUILayout.TextField("Node:" + effectParticle.prefab.g);


                GUILayout.EndHorizontal();
            }
        }
        EditorGUILayout.EndScrollView();
    }


    //特效信息实体类
    class EffectParticle
    {
        public string name;
        public Material material;
        public float maxEmission;
        public Object prefab;
        public bool bScaleWithTransform;
        public EffectParticle()
        {
            maxEmission = 0;
        }
    }
}

无效Material 检测

  • 获取并显示我们在Project视图中选择的物体(可以是任何物体,不过暂时只对Material进行处理,未来可以拓展处理其他物体)
  • 遍历需要检测的物体路径,目前分为三个检测点:场景、特效、角色
  • 因为存在一个Material关联多个物体,所以要用Dictionary<string,List<XXX>>的形式存储数据,分类显示
  • 如果检测到就显示出Material和关联物体的相关信息,没有检测到就标注红色并伴有“删除”按钮以供删除。
  • 获取并显示我们在Project视图中选择的物体(可以是任何物体,不过暂时只对Material进行处理,未来可以拓展处理其他物体)
  • 遍历需要检测的物体路径,目前分为三个检测点:场景、特效、角色
  • 因为存在一个Material关联多个物体,所以要用Dictionary<string,List<XXX>>的形式存储数据,分类显示
  • 如果检测到就显示出Material和关联物体的相关信息,没有检测到就标注红色并伴有“删除”按钮以供删除。
    using UnityEngine;
    using System.Collections;
    using UnityEditor;
    using System.Collections.Generic;
    using System.IO;


    public class MaterialReferenceChecker : EditorWindow
    {
        Dictionary<string, List<MatDetail>> dictMat = new Dictionary<string, List<MatDetail>>();
        int texWidth = 40;
        int texHeight = 40;
        Vector2 vec2 = new Vector2(0, 0);
        bool isCheck = false;
        bool isCheckScene = true;
        bool isCheckEffect = true;
        bool isCheckCharacter = true;
        GameObject effectObj = null;
        GameObject characterObj = null;
        Object[] objs;


        [MenuItem("Tools/Check Material References")]
        public static void Init()
        {
            MaterialReferenceChecker window = GetWindow<MaterialReferenceChecker>();
            window.Show();
        }


        void OnGUI()
        {
            if (!isCheck)
            {
                if (objs != null && objs.Length > 100)  //防止选择太多物体,运算量太大
                {
                    GUILayout.Label("你一次性选择太多资源(超过100个)!请重新选择资源,再点击“刷新”");
                    if (GUILayout.Button("刷新"))
                    {
                        objs = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
                    }
                    return;
                }
                objs = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
                GUILayout.BeginHorizontal();
                if (objs == null || objs.Length <= 0)
                {
                    GUILayout.Label("你没有选择任何物体,请在Project选择,按住Ctrl可以多选");
                    return;
                }
                else
                {
                    GUILayout.Label("你选择了以下物体:共(" + objs.Length + ")个");
                }
                GUILayout.EndHorizontal();
                vec2 = GUILayout.BeginScrollView(vec2);
                for (int i = 0; i < objs.Length; i++)
                {
                    ListSelections(objs[i]);
                }
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("开始查找关联"))
                {
                    OnCheckReferences();
                    isCheck = true;
                }
                isCheckScene = GUILayout.Toggle(isCheckScene, "遍历场景", GUILayout.Width(70));
                isCheckEffect = GUILayout.Toggle(isCheckEffect, "遍历特效", GUILayout.Width(70));
                isCheckCharacter = GUILayout.Toggle(isCheckCharacter, "遍历角色", GUILayout.Width(70));
                GUILayout.EndHorizontal();
                ListMaterials();
                GUILayout.EndScrollView();
            }
            else
            {
                //刷新数据,必须刷新才能重新查找
                vec2 = GUILayout.BeginScrollView(vec2);
                for (int i = 0; i < objs.Length; i++)
                {
                    ListSelections(objs[i]);
                }
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("刷新"))
                {
                    isCheck = false;
                    dictMat.Clear();
                }
                GUILayout.EndHorizontal();
                ListMaterials();
                GUILayout.EndScrollView();
            }
        }


        //选中物体列表
        void ListSelections(Object selection)
        {
            GUILayout.BeginHorizontal();
            if (selection is Material || selection is Texture)
            {
                Texture tex = null;
                if (selection is Material)
                {
                    Material mat = selection as Material;
                    if (mat.HasProperty("_MainTex")) tex = mat.mainTexture;
                }
                else if (selection is Texture)
                {
                    tex = selection as Texture;
                }
                if (tex != null)
                {
                    //在新窗口打开图片大图
                    if (GUILayout.Button(tex, GUILayout.Width(texWidth), GUILayout.Height(texHeight)))
                    {
                        ZoomInTexture window = GetWindow<ZoomInTexture>();
                        window.texture = tex;
                        window.minSize = new Vector2(tex.width, tex.height);
                    }
                }
                else
                {
                    GUILayout.Box("N/A", GUILayout.Width(texWidth), GUILayout.Height(texHeight));
                }
            }
            else
            {
                GUILayout.Box("N/A", GUILayout.Width(texWidth), GUILayout.Height(texHeight));
            }
            GUILayout.Label("名称:" + selection.name + "\n类型:" + selection.GetType().ToString().Replace("UnityEngine.", "") + "\n路径:" + AssetDatabase.GetAssetPath(selection));
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
        }


        //关联物体列表
        void ListMaterials()
        {
            if (dictMat == null || dictMat.Count <= 0)
            {
                GUILayout.Label("没有关联物体,请点击“开始查找关联”按钮");
                return;
            }
            foreach (string item in dictMat.Keys)
            {
                List<MatDetail> detailList = dictMat[item];
                if (detailList != null && detailList.Count > 0)
                {
                    GUILayout.Space(20);
                    GUILayout.Label("==================《" + item + "》【Material】==================");
                    foreach (MatDetail detail in detailList)
                    {
                        GUILayout.BeginHorizontal();
                        //输出可以点击寻找路径的图片
                        if (detail.mat != null && detail.mat.HasProperty("_MainTex") && detail.mat.mainTexture != null)
                        {
                            if (GUILayout.Button(detail.mat.mainTexture, GUILayout.Width(texWidth), GUILayout.Height(texHeight)))
                            {
                                Selection.activeObject = detail.mat;
                            }
                        }
                        else
                        {
                            if (GUILayout.Button("N/A", GUILayout.Width(texWidth), GUILayout.Height(texHeight)))
                            {
                                Selection.activeObject = detail.mat;
                            }
                        }
                        //输出信息
                        string print = "";
                        if (detail.type == "Effect" || detail.type == "Character")
                            print = string.Format("所在路径:{0}\n关联类型:{1}\n关联物体:{2}", detail.assetPath, detail.type, detail.hierarcyPath);
                        else
                            print = string.Format("所在路径:{0}\n关联场景:{1}\n关联物体:{2}", detail.assetPath, detail.type, detail.hierarcyPath);
                        if (detail.type == "NULL")
                        {
                            GUIStyle style = new GUIStyle();
                            style.normal.textColor = Color.red;
                            GUILayout.Label(print, style);
                            if (GUILayout.Button("删除", GUILayout.Width(40)))
                            {
                                if (AssetDatabase.DeleteAsset(detail.assetPath))
                                {
                                    ShowNotification(new GUIContent("删除成功"));
                                }
                            }
                        }
                        else
                        {
                            GUILayout.Label(print);
                        }
                        GUILayout.EndHorizontal();
                    }
                }
            }
        }


        //开始查找引用
        void OnCheckReferences()
        {
            Object[] objs = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
            if (objs == null || objs.Length <= 0) return;


            dictMat.Clear();
            for (int i = 0; i < objs.Length; i++)
            {
                List<MatDetail> listDetail = new List<MatDetail>();
                if (objs[i] is Material)
                {
                    //遍历所有场景关联物体
                    if (isCheckScene)
                    {
                        if (EditorBuildSettings.scenes.Length <= 0)
                        {
                            Debug.LogError("你的可查找场景为空,请在Builder Setting中添加场景");
                            return;
                        }
                        foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
                        {
                            if (scene.enabled)
                            {
                                EditorApplication.OpenScene(scene.path);
                                if (objs[i] is Material)
                                {
                                    MatDetail detail = SetMaterial(objs[i], scene.path);
                                    if (detail != null) listDetail.Add(detail);
                                }
                            }
                        }
                    }
                    //遍历Resources特效目录
                    if (isCheckEffect)
                    {
                        Object[] effects = Resources.LoadAll("Effects");  //Resources下的地址,根据需求修改
                        for (int j = 0; j < effects.Length; j++)
                        {
                            if (objs[i] is Material)
                            {
                                MatDetail detail = SetEffectMaterial(objs[i], effects[j]);
                                DestroyImmediate(effectObj);
                                if (detail != null) listDetail.Add(detail);
                            }
                        }
                    }
                    //遍历角色目录
                    if (isCheckCharacter)
                    {
                        Object[] characters = GetAssetsOfType(Application.dataPath + "/Characters/", typeof(GameObject), ".prefab"); //自定义地址,根据需求修改
                        for (int j = 0; j < characters.Length; j++)
                        {
                            if (objs[i] is Material)
                            {
                                MatDetail detail = SetCharactersMaterial(objs[i], characters[j]);
                                DestroyImmediate(characterObj);
                                if (detail != null) listDetail.Add(detail);
                            }
                        }
                    }
                }
                //找不到关联的处理
                if (listDetail.Count <= 0)
                {
                    MatDetail detail = new MatDetail();
                    detail.mat = objs[i] as Material;
                    detail.assetPath = AssetDatabase.GetAssetPath(objs[i]);
                    listDetail.Add(detail);
                }
                dictMat.Add(objs[i].name, listDetail);
            }
        }


        //获取prefab
        public static Object[] GetAssetsOfType(string directPath, System.Type type, string fileExtension)
        {
            List<Object> tempObjects = new List<Object>();
            DirectoryInfo directory = new DirectoryInfo(directPath);
            FileInfo[] goFileInfo = directory.GetFiles("*" + fileExtension, SearchOption.AllDirectories);


            int goFileInfoLength = goFileInfo.Length;
            FileInfo tempGoFileInfo;
            string tempFilePath;
            Object tempGO;
            for (int i = 0; i < goFileInfoLength; i++)
            {
                tempGoFileInfo = goFileInfo[i];
                if (tempGoFileInfo == null)
                    continue;


                tempFilePath = tempGoFileInfo.FullName;
                tempFilePath = tempFilePath.Replace(@"\", "/").Replace(Application.dataPath, "Assets");


                tempGO = AssetDatabase.LoadAssetAtPath(tempFilePath, typeof(Object)) as Object;
                if (tempGO == null)
                {
                    Debug.LogWarning("Skipping Null");
                    continue;
                }
                else if (tempGO.GetType() != type)
                {
                    Debug.LogWarning("Skipping " + tempGO.GetType().ToString());
                    continue;
                }


                tempObjects.Add(tempGO);
            }


            return tempObjects.ToArray();
        }


        //获取场景材质
        MatDetail SetMaterial(Object obj, string scenePath)
        {
            Renderer[] renderers = (Renderer[])FindObjectsOfType(typeof(Renderer)); //这种取法方便,但是disactive的物体取不到,待完善
            return GetMatDetail(renderers, obj, scenePath);
        }


        //获取特效材质
        MatDetail SetEffectMaterial(Object select, Object effect)
        {
            effectObj = PrefabUtility.InstantiatePrefab(effect) as GameObject;
            if (effectObj == null) return null;
            Renderer[] renderers = effectObj.GetComponentsInChildren<Renderer>(true);
            return GetMatDetail(renderers, select, "Effect");
        }


        //获取角色材质
        MatDetail SetCharactersMaterial(Object select, Object character)
        {
            characterObj = PrefabUtility.InstantiatePrefab(character) as GameObject;
            if (characterObj == null) return null;
            SkinnedMeshRenderer[] renderers = characterObj.GetComponentsInChildren<SkinnedMeshRenderer>(true);
            foreach (SkinnedMeshRenderer renderer in renderers)
            {
                Material[] mats = renderer.sharedMaterials;
                foreach (Material mat in mats)
                {
                    string assetPath = AssetDatabase.GetAssetPath(select);
                    if (assetPath == AssetDatabase.GetAssetPath(mat))
                    {
                        MatDetail detail = new MatDetail();
                        detail.assetPath = assetPath;
                        detail.mat = mat;
                        detail.type = "Character";
                        detail.hierarcyPath = GetHierarcyPath(renderer.gameObject);
                        return detail;
                    }
                }
            }
            return null;
        }


        //设置并获取MatDetail
        MatDetail GetMatDetail(Renderer[] renderers, Object select, string scenePath)
        {
            foreach (Renderer renderer in renderers)
            {
                //获取材质
                Material[] mats = renderer.sharedMaterials;
                foreach (Material mat in mats)
                {
                    string assetPath = AssetDatabase.GetAssetPath(select);
                    if (assetPath == AssetDatabase.GetAssetPath(mat))
                    {
                        MatDetail detail = new MatDetail();
                        detail.assetPath = assetPath;
                        detail.mat = mat;
                        detail.type = scenePath;
                        detail.hierarcyPath = GetHierarcyPath(renderer.gameObject);
                        return detail;
                    }
                }
            }
            return null;
        }


        //设置路径
        string GetHierarcyPath(GameObject go)
        {
            string path = "/" + go.name;
            while (go.transform.parent != null)
            {
                go = go.transform.parent.gameObject;
                path = "/" + go.name + path;
            }
            return path;
        }


        //材质详情
        class MatDetail
        {
            public Material mat;
            public string assetPath;
            public string type;
            public string hierarcyPath;
            public MatDetail()
            {
                mat = null;
                assetPath = "";
                type = "NULL";
                hierarcyPath = "NULL";
            }
        }
    }


    //查看大图片
    public class ZoomInTexture : EditorWindow
    {
        public Texture texture;


        void OnGUI()
        {
            GUILayout.Box(texture, GUILayout.Width(texture.width), GUILayout.Height(texture.height));
        }
    }

  • 获取并显示我们在Project视图中选择的物体(可以是任何物体,不过暂时只对Material进行处理,未来可以拓展处理其他物体)
  • 遍历需要检测的物体路径,目前分为三个检测点:场景、特效、角色
  • 因为存在一个Material关联多个物体,所以要用Dictionary<string,List<XXX>>的形式存储数据,分类显示
  • 如果检测到就显示出Material和关联物体的相关信息,没有检测到就标注红色并伴有“删除”按钮以供删除。
  • PrefabUtility.CreateEmptyPrefab
  • PrefabUtility.ReplacePrefab
  • PrefabUtility.DisconnectPrefabInstance
  • PrefabUtility.GetPrefabParent
  • PrefabUtility.ConnectGameObjectToPrefab
  • 断开引用

        断开Prefab引用的代码如下

    [MenuItem("Tools/Prefab/去除引用")]

    public static void BreakPrefabRef()

    {

        var select = Selection.activeGameObject;

        if (select.activeInHierarchy)

        {

            PrefabUtility.DisconnectPrefabInstance(select);

            Selection.activeGameObject = null;

            var prefab = PrefabUtility.CreateEmptyPrefab("Assets/empty.prefab");

            PrefabUtility.ReplacePrefab(select, prefab, ReplacePrefabOptions.ConnectToPrefab);

            PrefabUtility.DisconnectPrefabInstance(select);

            AssetDatabase.DeleteAsset("Assets/empty.prefab");

        }

    }

        虽然PrefabUtility.DisconnectPrefabInstance有断开Prefab的含义,但是如果仅仅使用这个函数会出现下面这个情况,名字的颜色从蓝变白,看起来已经不是一个prefab,但是从Inspector面板中还是能够看到Prefab标记以及Prefab实例才会出现的那三个Select、Revert、Apply按钮。

  • [MenuItem("Tools/Prefab/替换引用")]

    public static void RelocalPrefabRef()

    {

        var select = Selection.activeGameObject;

        if (select.activeInHierarchy)

        {

            var ab = PrefabUtility.GetPrefabParent(select);

            if (ab == null)

                return;

            var oripath = AssetDatabase.GetAssetPath(ab);

            var filters = new[] { "prefab file", "prefab" };

            var tar = EditorUtility.OpenFilePanelWithFilters("select target", Application.dataPath, filters);

            if (string.IsNullOrEmpty(tar))

                return;

            tar = FileUtil.GetProjectRelativePath(tar);

            var tarprefab = AssetDatabase.LoadAssetAtPath<GameObject>(tar);

            if (tarprefab == null)

                return;

            var gname = select.name;

            var enable = select.activeInHierarchy;

            var pos = select.transform.localPosition;

            var rot = select.transform.localRotation;

            var scale = select.transform.localScale;

            var go = PrefabUtility.ConnectGameObjectToPrefab(select, tarprefab);

            go.transform.localPosition = pos;

            go.transform.localRotation = rot;

            go.transform.localScale = scale;

            go.name = gname;

            go.SetActive(enable);

            Debug.LogFormat("Replace Prefab From:{0} to {1}", oripath, tar);

        }

    }

        代码中主要的流程为

  • 使用Selection.activeGameObject获取选中的物体
  • 使用PrefabUtility.GetPrefabParent获取这个物体在project中的源prefab
  • 使用AssetDatabase.GetAssetPath获取源prefab在project中的路径(后面用于log)
  • 使用EditorUtility.OpenFilePanelWithFilters打开一个文件选择窗口让玩家选择一个源prefab
  • 使用FileUtil.GetProjectRelativePath获取这个源prefab相对于工程的路径
  • 使用将这个源prefab加载到内存中
  • 为了保持替换后的位置关系,这里记录了原来的位置信息
  • 使用PrefabUtility.ConnectGameObjectToPrefab重新将选中的物体链接到玩家选择的源prefab上,完成prefab引用替换
  • 还原原来的位置关系
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值