// WL-814k 실측 조사 ② — 조명 · Toon 머티리얼 매칭 · 샘플링 경로 (읽기만) // run: unity command run_script --file AgentScripts/WL814k_Survey2.cs --entry WL814k_Survey2.Run using System; using System.Collections.Generic; using System.IO; using System.Text; using UnityEditor; using UnityEngine; public static class WL814k_Survey2 { const string kTxt = "AgentScripts/WL814k_SURVEY2.txt"; static StringBuilder s_sb; static void L(string s) { s_sb.AppendLine(s); Debug.Log("[WL814k] " + s); } public static void Run() { s_sb = new StringBuilder(); L("WL-814k 실측 ② · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); try { Lights(); ToonMatch("Assets/Res_Addr/PC/Ai01.prefab"); ToonMatch("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab"); SamplePath(); Srp(); } catch (Exception ex) { L("EXCEPTION " + ex); } File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); Debug.Log("[WL814k] → " + kTxt); } // 게임 맵의 방향광 실측 static void Lights() { L(""); L("== 방향광 (Res_Addr/Map/WL_Nature.prefab + Ingame 씬) =="); var map = AssetDatabase.LoadAssetAtPath("Assets/Res_Addr/Map/WL_Nature.prefab"); if (map != null) { foreach (var lt in map.GetComponentsInChildren(true)) L(string.Format(" [map] {0} type={1} color={2} intensity={3} shadows={4} euler={5}", lt.name, lt.type, lt.color, lt.intensity, lt.shadows, lt.transform.eulerAngles.ToString("F2"))); } else L(" WL_Nature.prefab 없음"); foreach (var sc in new[] { "Assets/Scenes/Ingame.unity", "Assets/Scenes/Title.unity" }) { if (!File.Exists(sc)) { L(" " + sc + " 없음"); continue; } var txt = File.ReadAllText(sc); int i = txt.IndexOf("m_Type: 1"); L(" " + sc + " · Light(dir) 블록 " + (i >= 0 ? "있음" : "없음") + " · 파일 " + new FileInfo(sc).Length + " B"); } L(" RenderSettings.ambientMode(현재 씬) = " + RenderSettings.ambientMode + " · ambientLight = " + RenderSettings.ambientLight + " · ambientIntensity = " + RenderSettings.ambientIntensity + " · sun = " + (RenderSettings.sun == null ? "null" : RenderSettings.sun.name)); } // 캐릭터 머티리얼 → *_Toon.mat 존재 여부 static void ToonMatch(string prefab) { L(""); L("== Toon 매칭 " + prefab + " =="); var go = AssetDatabase.LoadAssetAtPath(prefab); if (go == null) { L(" 로드 실패"); return; } var seen = new HashSet(); foreach (var r in go.GetComponentsInChildren(true)) foreach (var m in r.sharedMaterials) { if (m == null || !seen.Add(m.name)) continue; string toon = "Assets/WL/Look/Env/Materials/" + m.name + "_Toon.mat"; var t = AssetDatabase.LoadAssetAtPath(toon); L(" " + m.name.PadRight(16) + " [" + (m.shader == null ? "-" : m.shader.name) + "] → " + (t != null ? "Toon 있음" : "Toon 없음")); } } // 샘플링 경로 확인 — Generic/Humanoid 둘 다 AnimationMode 로 찍히는가 static void SamplePath() { L(""); L("== 샘플링 경로 (AnimationMode.SampleAnimationClip) =="); foreach (var pair in new[] { new[]{ "Assets/Res_Addr/PC/Ai01.prefab", "Idle" }, new[]{ "Assets/Res_Addr/Mobs/Mob/Batty_A.prefab", "Attack" } }) { var go = AssetDatabase.LoadAssetAtPath(pair[0]); if (go == null) { L(" " + pair[0] + " 로드 실패"); continue; } var inst = (GameObject)PrefabUtility.InstantiatePrefab(go); try { var anim = inst.GetComponentInChildren(true); AnimationClip clip = null; foreach (var c in anim.runtimeAnimatorController.animationClips) if (c.name == pair[1]) { clip = c; break; } if (clip == null) { L(" 클립 " + pair[1] + " 없음"); continue; } // 대표 본의 t=0 / t=len/2 포즈 차이를 잰다 var bones = inst.GetComponentsInChildren(true); Transform probe = bones.Length > 3 ? bones[bones.Length / 2] : inst.transform; AnimationMode.StartAnimationMode(); AnimationMode.BeginSampling(); AnimationMode.SampleAnimationClip(inst, clip, 0f); AnimationMode.EndSampling(); Vector3 p0 = probe.localPosition; Quaternion r0 = probe.localRotation; AnimationMode.BeginSampling(); AnimationMode.SampleAnimationClip(inst, clip, clip.length * 0.5f); AnimationMode.EndSampling(); Vector3 p1 = probe.localPosition; Quaternion r1 = probe.localRotation; AnimationMode.StopAnimationMode(); L(string.Format(" {0} · clip {1} · probe {2} · Δpos {3:0.0000} · Δrot {4:0.00}° → {5}", Path.GetFileNameWithoutExtension(pair[0]), clip.name, probe.name, Vector3.Distance(p0, p1), Quaternion.Angle(r0, r1), (Vector3.Distance(p0, p1) > 0.0001f || Quaternion.Angle(r0, r1) > 0.05f) ? "샘플링 OK" : "변화 없음(확인필요)")); } catch (Exception ex) { L(" EXCEPTION " + ex.Message); if (AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode(); } finally { UnityEngine.Object.DestroyImmediate(inst); } } } static void Srp() { L(""); L("== 렌더 파이프라인 =="); var rp = UnityEngine.Rendering.GraphicsSettings.defaultRenderPipeline; L(" defaultRenderPipeline = " + (rp == null ? "null(빌트인)" : rp.name + " (" + AssetDatabase.GetAssetPath(rp) + ")")); L(" currentRenderPipeline = " + (UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline == null ? "null" : UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline.name)); L(" QualitySettings.renderPipeline = " + (QualitySettings.renderPipeline == null ? "null" : QualitySettings.renderPipeline.name)); L(" SystemInfo.graphicsDeviceType = " + SystemInfo.graphicsDeviceType + " · supportsComputeShaders = " + SystemInfo.supportsComputeShaders); L(" Application.isBatchMode = " + Application.isBatchMode); // Unlit 투명 셰이더 후보 foreach (var s in new[] { "Sprites/Default", "Unlit/Transparent", "Universal Render Pipeline/Unlit", "Universal Render Pipeline/2D/Sprite-Unlit-Default" }) L(" Shader.Find(\"" + s + "\") = " + (Shader.Find(s) != null ? "OK" : "없음")); } }