[플러그인] 잘못된 Material 파일 검사 도구
게임 프로젝트의 개발에 따라 수요가 끊임없이 변경되고 자원이 끊임없이 개편되면서 프로젝트에 중복되거나 유행이 지난 자원 파일이 대량으로 남아 있기 때문에 우리는 특정한 자원 파일을 찾을 때 여전히 대량의 무용 파일에서 선별하여 작업 효율을 늦춘다.일부 강박증 사람들은 대량의 무용문서가 프로젝트에 존재하는 것을 참지 못하고 일일이 정리하려고 한다.그러나 우리가 수동으로 어떤 쓸모없는 파일을 정리할 때, 때로는 그것이 정말 '쓸모없는 것' 인지 확인할 수 없다. 어쩌면 그것은 여전히 어떤 장면이나 물체에 연관되어 있을지도 모른다.그래서 나는 오늘 Material 파일을 정리하는 것을 예로 삼아 '잘못된 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 + "
:" + selection.GetType().ToString().Replace("UnityEngine.", "") + "
:" + 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}
:{1}
:{2}", detail.assetPath, detail.type, detail.hierarcyPath);
else
print = string.Format(" :{0}
:{1}
:{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));
}
}
이 도구는 아직 완벽하지 않고 확대하고 최적화해야 할 부분이 많지만 현재의 수요를 충족시킬 수 있다.물론 가장 중요한 것은 하나를 꼽으면 열을 꼽을 수 있고 벽돌을 던져 옥을 끌어올릴 수 있다. 이 사고방식을 통해 도구 플러그인을 더욱 배우고 보완해야 기원과 공유가 가장 큰 발전을 이룰 수 있다.마지막으로 도구 캡처를 드립니다.Ricky Yang 개인 창작, 판권 소유, 전재 주석, 감사합니다.http://blog.csdn.net/yangyy753
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Unity 최적화1. 프레임마다 처리하는 것을 최대한 피한다. 예를 들면: 5프레임당 한 번 처리로 변경할 수 있습니다. 2. 정시 반복 처리는 InvokeRepeating 함수로 이루어집니다. 예를 들어 0.5초 동안 시작한 후 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.