#if UNITY_EDITOR using UnityEditor; using UnityEngine; using System.Collections.Generic; namespace Bitd { public struct stMatcapInfo { public bool _UseMatCap; public Texture _MatCapTex; public Color _MatCapColor; public Texture _MatCapBlendMask; public int _MatCapBlendMode; public stMatcapInfo(bool _useMatCap) { _UseMatCap = _useMatCap; _MatCapTex = null; _MatCapColor = Color.white; _MatCapBlendMask = null; _MatCapBlendMode = 0; } public stMatcapInfo(bool _useMatCap, Texture _matCapTex, Color _matCapColor , Texture _matCapBlendMask, int _matCapBlendMode) { _UseMatCap = _useMatCap; _MatCapTex = _matCapTex; _MatCapColor = _matCapColor; _MatCapBlendMask = _matCapBlendMask; _MatCapBlendMode = _matCapBlendMode; } } public class NiloMaterialMatcapSetter : EditorWindow { private List materials = new List(); // 드래그 앤 드롭으로 받은 Material 목록 private string pEnableName_Front = "_BaseMapStackingLayer"; // 원본 속성 private string pEnableName_Back = "Enable"; private const string targetShaderName = "lilToon"; private Vector2 scrollPosObjects; // 오브젝트 목록 스크롤 위치 [MenuItem("Bitd/닐로툰 매트캡 자동 인식기", false, 153)] public static void ShowWindow() { GetWindow("닐로툰 매트캡 자동 인식기"); } void OnGUI() { GUILayout.Label("아래에 닐로툰 머티리얼들을 넣어주세요", EditorStyles.boldLabel); GUILayout.Label("선택한 닐로툰에서 릴툰 매트캡 값을 찾아 닐로툰에 자동 반영합니다", EditorStyles.helpBox); GUILayout.Space(10); GUILayout.Label("수정할 머티리얼들:", EditorStyles.helpBox); Rect dropArea = GUILayoutUtility.GetRect(0, 50, GUILayout.ExpandWidth(true)); HandleDragAndDrop(dropArea); GUILayout.Label("추가된 머티리얼:", EditorStyles.boldLabel); scrollPosObjects = EditorGUILayout.BeginScrollView(scrollPosObjects, GUILayout.Height(100)); // 최대 높이 제한 foreach (var mat in materials) { EditorGUILayout.ObjectField(mat, typeof(Material), true); } EditorGUILayout.EndScrollView(); GUILayout.Space(5); if (GUILayout.Button("자동 복사 실행")) { ProcessMaterials(); materials.Clear(); } } void HandleDragAndDrop(Rect dropArea) { Event evt = Event.current; switch (evt.type) { case EventType.DragUpdated: case EventType.DragPerform: if (!dropArea.Contains(evt.mousePosition)) return; DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (evt.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (Object draggedObject in DragAndDrop.objectReferences) { if (draggedObject is Material mat) { materials.Add(mat); } } evt.Use(); } break; } } void ProcessMaterials() { Shader lilToonShader = Shader.Find(targetShaderName); if (lilToonShader == null) { Debug.LogError("lilToon Shader를 찾을 수 없습니다. 먼저 프로젝트에 추가해주세요."); return; } foreach (Material originalMaterial in materials) { if (originalMaterial == null) continue; // 원본 머티리얼 복사 Material clonedMaterial = Object.Instantiate(originalMaterial); clonedMaterial.shader = lilToonShader; // 원본 머티리얼을 수정하는 코드는 이후 사용자가 추가할 예정 List matcapInfoList = new List(); stMatcapInfo newInfo1 = GetMatcapInfoByName(clonedMaterial, "_UseMatCap", true); stMatcapInfo newInfo2 = GetMatcapInfoByName(clonedMaterial, "_UseMatCap2nd", false); if (newInfo1._UseMatCap) matcapInfoList.Add(newInfo1); if (newInfo2._UseMatCap) matcapInfoList.Add(newInfo2); foreach (stMatcapInfo matcapInfo in matcapInfoList) { int targetLayerNumber = 0; for (int i = 1; i <= 10; i++) { if (originalMaterial.GetFloat(pEnableName_Front + i.ToString() + pEnableName_Back) < 0.5f) { targetLayerNumber = i; originalMaterial.SetFloat(pEnableName_Front + i.ToString() + pEnableName_Back, 1f); break; } } // 각종 값 초기화 originalMaterial.SetVector("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexUVCenterPivotScalePos", new Vector4(1, 1, 0, 0)); originalMaterial.SetVector("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexUVScaleOffset", new Vector4(1, 1, 0, 0)); originalMaterial.SetVector("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexUVAnimSpeed", new Vector4(0, 0, 0, 0)); originalMaterial.SetVector("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "MaskTexChannel", new Vector4(0, 1, 0, 0)); originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexUVRotatedAngle", 0); originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexUVRotateSpeed", 0); originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "MaskUVIndex", 0); originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "MaskInvertColor", 0); originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexIgnoreAlpha", 0); // 블렌드모드 선택 originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "ColorBlendMode" , matcapInfo._MatCapBlendMode == 0 ? 0 : // 표준 matcapInfo._MatCapBlendMode == 1 ? 2 : // 가산 matcapInfo._MatCapBlendMode == 2 ? 3 : // 스크린 matcapInfo._MatCapBlendMode == 3 ? 4 : 5); // 곱하기 // 매트캡 텍스쳐 넣어주기 originalMaterial.SetTexture("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "Tex" , matcapInfo._MatCapTex); // 매트캡 컬러 넣어주기 originalMaterial.SetColor("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TintColor" , new Color(matcapInfo._MatCapColor.r, matcapInfo._MatCapColor.g, matcapInfo._MatCapColor.b, 1f)); // 매트캡 투명도 넣어주기 originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "MasterStrength" , matcapInfo._MatCapColor.a); // UV 종류 MatcapUV로 바꿔주기 originalMaterial.SetFloat("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "TexUVIndex" , 4); // 매트캡 마스크 넣어주기 originalMaterial.SetTexture("_BaseMapStackingLayer" + targetLayerNumber.ToString() + "MaskTex" , matcapInfo._MatCapBlendMask); } // 클론 머티리얼 삭제 DestroyImmediate(clonedMaterial); } AssetDatabase.SaveAssets(); } private stMatcapInfo GetMatcapInfoByName(Material mat, string propertyName, bool isFirst) { string plusName = string.Empty; if (!isFirst) plusName = "2nd"; if (mat.HasProperty(propertyName) && mat.GetInt(propertyName) == 1) { return new stMatcapInfo(true, mat.GetTexture("_MatCap" + plusName + "Tex"), mat.GetColor("_MatCap" + plusName + "Color") , mat.GetTexture("_MatCap" + plusName + "BlendMask"), mat.GetInt("_MatCap" + plusName + "BlendMode")); } return new stMatcapInfo(false); } } } #endif