From f78c2c23f7f39a7289d113be21daa44ea6498bbc Mon Sep 17 00:00:00 2001 From: swrring Date: Sat, 12 Sep 2026 18:46:41 +0900 Subject: [PATCH] =?UTF-8?q?[WL-814k]=20=EC=BA=90=EB=A6=AD=ED=84=B0=20?= =?UTF-8?q?=EB=8F=84=ED=8A=B8=20=EC=8A=A4=ED=94=84=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EB=B2=A0=EC=9D=B4=ED=81=AC=201=EC=B0=A8:=20?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=ED=81=AC=20=ED=88=B4=20+=20=EB=9F=B0?= =?UTF-8?q?=ED=83=80=EC=9E=84=20=EB=B9=8C=EB=B3=B4=EB=93=9C(=EB=8F=84?= =?UTF-8?q?=ED=8A=B8=20=EB=AA=A8=EB=93=9C=20=ED=95=9C=EC=A0=95)=20+=20?= =?UTF-8?q?=EC=8B=9C=EB=B2=94=202=EC=A2=85=20(#814)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 --- AgentScripts/WL814k_BAKE.txt | 35 + AgentScripts/WL814k_Bake.cs | 133 ++++ AgentScripts/WL814k_CAPTURE.txt | 11 + AgentScripts/WL814k_DIAG3.txt | 43 ++ AgentScripts/WL814k_DIAG4.txt | 27 + AgentScripts/WL814k_DIAG5.txt | 45 ++ AgentScripts/WL814k_DIAG6.txt | 13 + AgentScripts/WL814k_Diag3.cs | 138 ++++ AgentScripts/WL814k_Diag4.cs | 86 +++ AgentScripts/WL814k_Diag5.cs | 134 ++++ AgentScripts/WL814k_Diag6.cs | 178 +++++ AgentScripts/WL814k_NAMING.txt | 18 + AgentScripts/WL814k_Naming.cs | 109 +++ AgentScripts/WL814k_PROBE.txt | 49 ++ AgentScripts/WL814k_Probe.cs | 686 +++++++++++++++++ AgentScripts/WL814k_SURVEY.txt | 147 ++++ AgentScripts/WL814k_SURVEY2.txt | 38 + AgentScripts/WL814k_SURVEY3.txt | 15 + AgentScripts/WL814k_Survey.cs | 205 ++++++ AgentScripts/WL814k_Survey2.cs | 133 ++++ AgentScripts/WL814k_Survey3.cs | 87 +++ Assets/WL/Look/Sprite.meta | 8 + Assets/WL/Look/Sprite/Baked.meta | 8 + Assets/WL/Look/Sprite/Baked/Ai01.png | Bin 0 -> 165716 bytes Assets/WL/Look/Sprite/Baked/Ai01.png.meta | 181 +++++ .../WL/Look/Sprite/Baked/Ai01_SpriteSet.asset | 86 +++ .../Sprite/Baked/Ai01_SpriteSet.asset.meta | 8 + Assets/WL/Look/Sprite/Baked/Batty_A.png | Bin 0 -> 107778 bytes Assets/WL/Look/Sprite/Baked/Batty_A.png.meta | 181 +++++ .../Look/Sprite/Baked/Batty_A_SpriteSet.asset | 77 ++ .../Sprite/Baked/Batty_A_SpriteSet.asset.meta | 8 + Assets/WL/Look/Sprite/Editor.meta | 8 + Assets/WL/Look/Sprite/Editor/WLSpriteBaker.cs | 696 ++++++++++++++++++ .../Look/Sprite/Editor/WLSpriteBaker.cs.meta | 2 + .../Look/Sprite/Editor/WLSpriteBakerWindow.cs | 92 +++ .../Sprite/Editor/WLSpriteBakerWindow.cs.meta | 2 + Assets/WL/Look/Sprite/Resources.meta | 8 + Assets/WL/Look/Sprite/Resources/WL.meta | 8 + .../Resources/WL/WLSpriteBakeSettings.asset | 119 +++ .../WL/WLSpriteBakeSettings.asset.meta | 8 + .../Resources/WL/WLSpriteLookSettings.asset | 31 + .../WL/WLSpriteLookSettings.asset.meta | 8 + Assets/WL/Look/Sprite/SpriteBillboard.cs | 620 ++++++++++++++++ Assets/WL/Look/Sprite/SpriteBillboard.cs.meta | 2 + Assets/WL/Look/Sprite/WLSpriteBakeSettings.cs | 204 +++++ .../Look/Sprite/WLSpriteBakeSettings.cs.meta | 2 + Assets/WL/Look/Sprite/WLSpriteLookSettings.cs | 101 +++ .../Look/Sprite/WLSpriteLookSettings.cs.meta | 2 + Assets/WL/Look/Sprite/WLSpriteSet.cs | 163 ++++ Assets/WL/Look/Sprite/WLSpriteSet.cs.meta | 2 + 50 files changed, 4965 insertions(+) create mode 100644 AgentScripts/WL814k_BAKE.txt create mode 100644 AgentScripts/WL814k_Bake.cs create mode 100644 AgentScripts/WL814k_CAPTURE.txt create mode 100644 AgentScripts/WL814k_DIAG3.txt create mode 100644 AgentScripts/WL814k_DIAG4.txt create mode 100644 AgentScripts/WL814k_DIAG5.txt create mode 100644 AgentScripts/WL814k_DIAG6.txt create mode 100644 AgentScripts/WL814k_Diag3.cs create mode 100644 AgentScripts/WL814k_Diag4.cs create mode 100644 AgentScripts/WL814k_Diag5.cs create mode 100644 AgentScripts/WL814k_Diag6.cs create mode 100644 AgentScripts/WL814k_NAMING.txt create mode 100644 AgentScripts/WL814k_Naming.cs create mode 100644 AgentScripts/WL814k_PROBE.txt create mode 100644 AgentScripts/WL814k_Probe.cs create mode 100644 AgentScripts/WL814k_SURVEY.txt create mode 100644 AgentScripts/WL814k_SURVEY2.txt create mode 100644 AgentScripts/WL814k_SURVEY3.txt create mode 100644 AgentScripts/WL814k_Survey.cs create mode 100644 AgentScripts/WL814k_Survey2.cs create mode 100644 AgentScripts/WL814k_Survey3.cs create mode 100644 Assets/WL/Look/Sprite.meta create mode 100644 Assets/WL/Look/Sprite/Baked.meta create mode 100644 Assets/WL/Look/Sprite/Baked/Ai01.png create mode 100644 Assets/WL/Look/Sprite/Baked/Ai01.png.meta create mode 100644 Assets/WL/Look/Sprite/Baked/Ai01_SpriteSet.asset create mode 100644 Assets/WL/Look/Sprite/Baked/Ai01_SpriteSet.asset.meta create mode 100644 Assets/WL/Look/Sprite/Baked/Batty_A.png create mode 100644 Assets/WL/Look/Sprite/Baked/Batty_A.png.meta create mode 100644 Assets/WL/Look/Sprite/Baked/Batty_A_SpriteSet.asset create mode 100644 Assets/WL/Look/Sprite/Baked/Batty_A_SpriteSet.asset.meta create mode 100644 Assets/WL/Look/Sprite/Editor.meta create mode 100644 Assets/WL/Look/Sprite/Editor/WLSpriteBaker.cs create mode 100644 Assets/WL/Look/Sprite/Editor/WLSpriteBaker.cs.meta create mode 100644 Assets/WL/Look/Sprite/Editor/WLSpriteBakerWindow.cs create mode 100644 Assets/WL/Look/Sprite/Editor/WLSpriteBakerWindow.cs.meta create mode 100644 Assets/WL/Look/Sprite/Resources.meta create mode 100644 Assets/WL/Look/Sprite/Resources/WL.meta create mode 100644 Assets/WL/Look/Sprite/Resources/WL/WLSpriteBakeSettings.asset create mode 100644 Assets/WL/Look/Sprite/Resources/WL/WLSpriteBakeSettings.asset.meta create mode 100644 Assets/WL/Look/Sprite/Resources/WL/WLSpriteLookSettings.asset create mode 100644 Assets/WL/Look/Sprite/Resources/WL/WLSpriteLookSettings.asset.meta create mode 100644 Assets/WL/Look/Sprite/SpriteBillboard.cs create mode 100644 Assets/WL/Look/Sprite/SpriteBillboard.cs.meta create mode 100644 Assets/WL/Look/Sprite/WLSpriteBakeSettings.cs create mode 100644 Assets/WL/Look/Sprite/WLSpriteBakeSettings.cs.meta create mode 100644 Assets/WL/Look/Sprite/WLSpriteLookSettings.cs create mode 100644 Assets/WL/Look/Sprite/WLSpriteLookSettings.cs.meta create mode 100644 Assets/WL/Look/Sprite/WLSpriteSet.cs create mode 100644 Assets/WL/Look/Sprite/WLSpriteSet.cs.meta diff --git a/AgentScripts/WL814k_BAKE.txt b/AgentScripts/WL814k_BAKE.txt new file mode 100644 index 000000000..9be28072d --- /dev/null +++ b/AgentScripts/WL814k_BAKE.txt @@ -0,0 +1,35 @@ +WL-814k 굽기 · 2026-09-12 18:38:16 · Unity 6000.3.23f1 + +──────── Assets/Res_Addr/PC/Ai01.prefab (루트 스케일 0.7) +Toon 머티리얼 교체 = 12슬롯 (인스턴스에만 · 원본 .mat 무변경) +레이어0 상태 17개: hit, die, idle, run, casting, skill2, attack, attack2, dodge, land, skill3, skill4, skill5, stun, casting_end, lying, getup + 동작 idle ← 상태 [idle/land/getup] · 클립 Idle (2.000s · 4프레임 · loop True) + 동작 run ← 상태 [run/dodge] · 클립 Run (0.533s · 6프레임 · loop True) + 동작 attack ← 상태 [attack/attack2/skill2/skill3/skill4/skill5/casting/casting_end] · 클립 Atk2_wing (1.500s · 6프레임 · loop True) + 동작 hit ← 상태 [hit/stun] · 클립 LightHit (1.000s · 2프레임 · loop True) + 동작 die ← 상태 [die/lying] · 클립 death_F3441 (2.100s · 6프레임 · loop False) +실루엣 실측(프로브 192px) — x [73..119] y [79..129] · 캐릭터 높이 51 px · 폭 47 px → 프레임 56×56 · 발밑 픽셀 (28.5, 19.5) +OK — 프레임 56×56 px · 방향 8 · 총 192칸 · 시트 896×672 · PNG 165,716 B (161.8 KB) · 1.80초 · 캐릭터 51 px + PNG = Assets/WL/Look/Sprite/Baked/Ai01.png + SO = Assets/WL/Look/Sprite/Baked/Ai01_SpriteSet.asset + 동작표 = idle(시작 0·4프레임·2.0fps·상태 [idle/land/getup]·클립 Idle) run(시작 32·6프레임·11.3fps·상태 [run/dodge]·클립 Run) attack(시작 80·6프레임·4.0fps·상태 [attack/attack2/skill2/skill3/skill4/skill5/casting/casting_end]·클립 Atk2_wing) hit(시작 128·2프레임·2.0fps·상태 [hit/stun]·클립 LightHit) die(시작 144·6프레임·2.9fps·상태 [die/lying]·클립 death_F3441) + 발밑 픽셀 (28.5, 19.5) · 픽셀 1개 0.02833 m · 베이크 스케일 0.700 + +──────── Assets/Res_Addr/Mobs/Mob/Batty_A.prefab (프리팹 스케일 그대로) +Toon 머티리얼 교체 = 1슬롯 (인스턴스에만 · 원본 .mat 무변경) +레이어0 상태 8개: run, idle, attack, hit, die, stun, casting, casting_end + 동작 idle ← 상태 [idle] · 클립 Idle (0.958s · 4프레임 · loop True) + 동작 run ← 상태 [run] · 클립 Move (0.958s · 6프레임 · loop True) + 동작 attack ← 상태 [attack/casting/casting_end] · 클립 Attack (0.583s · 6프레임 · loop True) + 동작 hit ← 상태 [hit/stun] · 클립 Damage (0.583s · 2프레임 · loop True) + 동작 die ← 상태 [die] · 클립 Die (1.000s · 6프레임 · loop False) +실루엣 실측(프로브 192px) — x [75..117] y [84..127] · 캐릭터 높이 44 px · 폭 43 px → 프레임 48×48 · 발밑 픽셀 (24.5, 14.5) +OK — 프레임 48×48 px · 방향 8 · 총 192칸 · 시트 768×576 · PNG 107,778 B (105.3 KB) · 1.06초 · 캐릭터 44 px + PNG = Assets/WL/Look/Sprite/Baked/Batty_A.png + SO = Assets/WL/Look/Sprite/Baked/Batty_A_SpriteSet.asset + 동작표 = idle(시작 0·4프레임·4.2fps·상태 [idle]·클립 Idle) run(시작 32·6프레임·6.3fps·상태 [run]·클립 Move) attack(시작 80·6프레임·10.3fps·상태 [attack/casting/casting_end]·클립 Attack) hit(시작 128·2프레임·3.4fps·상태 [hit/stun]·클립 Damage) die(시작 144·6프레임·6.0fps·상태 [die]·클립 Die) + 발밑 픽셀 (24.5, 14.5) · 픽셀 1개 0.02833 m · 베이크 스케일 1.500 + +런타임 SO 연결 — sets 2개 (Assets/WL/Look/Sprite/Resources/WL/WLSpriteLookSettings.asset) + +합계 굽기 시간 = 2.87초 / 2종 → 1종당 1.43초 diff --git a/AgentScripts/WL814k_Bake.cs b/AgentScripts/WL814k_Bake.cs new file mode 100644 index 000000000..b0dfd2fc3 --- /dev/null +++ b/AgentScripts/WL814k_Bake.cs @@ -0,0 +1,133 @@ +// WL-814k 베이크 드라이버 (에디트 모드 전용 · 게임 코드 아님) +// 에셋 만들기 : unity command run_script --file AgentScripts/WL814k_Bake.cs --entry WL814k_Bake.MakeAssets +// 시범 2종 굽기: unity command run_script --file AgentScripts/WL814k_Bake.cs --entry WL814k_Bake.BakeDemo +// 임의 프리팹 : WL814k_Bake.Targets 를 바꾸거나 에디터 창(WL ▸ 도트 스프라이트 굽기)을 쓴다. +// +// 🔴 이 드라이버에만 「어떤 프리팹을 구울지」가 적혀 있다. 툴(Assets/WL/Look/Sprite/Editor/WLSpriteBaker.cs) +// 에는 캐릭터 이름이 0개다 — PD 가 캐릭터 에셋을 바꿔도 툴은 그대로 쓴다. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; +using WL.Look.SpriteBake; +using WL.Look.SpriteBake.EditorTools; + +public static class WL814k_Bake +{ + const string kResDir = "Assets/WL/Look/Sprite/Resources/WL"; + const string kOutDir = "Assets/WL/Look/Sprite/Baked"; + const string kTxt = "AgentScripts/WL814k_BAKE.txt"; + + // 🔴 1차 시범 = PC 1종 + 잡몹 1종 (전수 전환은 PD 승인 뒤) + // 두 번째 값 = 인게임 실제 루트 스케일(0 이면 프리팹 자체 값). + // PC 는 ClassConfig.f_Scale 0.7 로 스폰된다(814b·발주서 실측) → 그 크기로 구워야 + // 스프라이트 1px 이 화면 1px 과 정확히 맞는다. 몹은 프리팹 스케일 그대로(Batty_A = 1.5). + public static readonly string[] Targets = { "Assets/Res_Addr/PC/Ai01.prefab", "Assets/Res_Addr/Mobs/Mob/Batty_A.prefab" }; + public static readonly float[] TargetScales = { 0.7f, 0f }; + + static StringBuilder s_sb; + static void L(string s) { s_sb.AppendLine(s); Debug.Log("[WL814k] " + s); } + + // ═════════════════════════════════════════════════════════════════════════ + // ① 설정 에셋 2개 만들기 + // ═════════════════════════════════════════════════════════════════════════ + public static void MakeAssets() + { + s_sb = new StringBuilder(); + L("WL-814k 설정 에셋 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + Directory.CreateDirectory(kResDir); + Directory.CreateDirectory(kOutDir); + + var bake = AssetDatabase.LoadAssetAtPath(kResDir + "/WLSpriteBakeSettings.asset"); + if (bake == null) + { + bake = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(bake, kResDir + "/WLSpriteBakeSettings.asset"); + L("만듦 " + kResDir + "/WLSpriteBakeSettings.asset"); + } + else L("있음 " + kResDir + "/WLSpriteBakeSettings.asset"); + + var look = AssetDatabase.LoadAssetAtPath(kResDir + "/WLSpriteLookSettings.asset"); + if (look == null) + { + look = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(look, kResDir + "/WLSpriteLookSettings.asset"); + L("만듦 " + kResDir + "/WLSpriteLookSettings.asset"); + } + else L("있음 " + kResDir + "/WLSpriteLookSettings.asset"); + + AssetDatabase.SaveAssetIfDirty(bake); + AssetDatabase.SaveAssetIfDirty(look); + WLSpriteBakeSettings.ClearCache(); + WLSpriteLookSettings.ClearCache(); + + L(string.Format("굽기 기본값 — 내림각 {0:0.000}° · 픽셀 {1:0.00000} m · 방향 {2} · 프레임 {3}(자동 {4}) · 팔레트 {5}단계 · 알파컷 {6}", + bake.PitchDeg, bake.WorldPerPixel, bake.dirCount, bake.frameSize, bake.autoFrameSize, bake.paletteLevels, bake.alphaCutoff)); + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + } + + // ═════════════════════════════════════════════════════════════════════════ + // ② 시범 2종 굽기 + SO 목록 연결 + // ═════════════════════════════════════════════════════════════════════════ + public static void BakeDemo() { BakeList(Targets, TargetScales); } + + public static void BakeList(string[] paths, float[] scales) + { + s_sb = new StringBuilder(); + L("WL-814k 굽기 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " · Unity " + Application.unityVersion); + + var sets = new List(); + double total = 0; + for (int ti = 0; ti < paths.Length; ti++) + { + var p = paths[ti]; + float scale = (scales != null && ti < scales.Length) ? scales[ti] : 0f; + L(""); + L("──────── " + p + (scale > 0f ? " (루트 스케일 " + scale + ")" : " (프리팹 스케일 그대로)")); + // 🔴 굽기마다 설정 에셋을 다시 읽는다 — PNG 임포트가 AssetDatabase 를 돌려 + // 참조만 들고 있던 SO 가 언로드돼 null 이 되는 것을 실측했다(첫 시도 실패 원인). + var cfg = AssetDatabase.LoadAssetAtPath(kResDir + "/WLSpriteBakeSettings.asset"); + if (cfg == null) { L("FAIL — 굽기 설정 에셋 없음. MakeAssets 먼저."); break; } + var r = WLSpriteBaker.Bake(p, cfg, kOutDir, null, scale); + total += r.seconds; + L(r.log.ToString().TrimEnd()); + foreach (var n in r.notes) L(" · 「미확인/주의」 " + n); + if (!r.ok) { L("FAIL"); continue; } + L(string.Format("OK — 프레임 {0}×{0} px · 방향 {1} · 총 {2}칸 · 시트 {3}×{4} · PNG {5:N0} B ({6:N1} KB) · {7:0.00}초 · 캐릭터 {8:0} px", + r.frameSize, r.dirCount, r.totalFrames, r.sheetW, r.sheetH, r.pngBytes, r.pngBytes / 1024.0, r.seconds, r.charPixelHeight)); + L(" PNG = " + r.pngPath); + L(" SO = " + r.setPath); + var set = AssetDatabase.LoadAssetAtPath(r.setPath); + if (set != null) + { + sets.Add(set); + var sb2 = new StringBuilder(); + foreach (var a in set.actions) + sb2.Append(string.Format("{0}(시작 {1}·{2}프레임·{3:0.0}fps·상태 [{4}]·클립 {5}) ", + a.key, a.startIndex, a.frameCount, a.fps, string.Join("/", a.stateNames), a.clipName)); + L(" 동작표 = " + sb2.ToString().TrimEnd()); + L(string.Format(" 발밑 픽셀 ({0:0.0}, {1:0.0}) · 픽셀 1개 {2:0.00000} m · 베이크 스케일 {3:0.000}", + set.footPixelX, set.footPixelY, set.worldPerPixel, set.bakeScale)); + } + } + + // 런타임 SO 에 시트 목록 연결 + var look = AssetDatabase.LoadAssetAtPath(kResDir + "/WLSpriteLookSettings.asset"); + if (look != null) + { + look.sets = sets.ToArray(); + EditorUtility.SetDirty(look); + AssetDatabase.SaveAssetIfDirty(look); + L(""); + L("런타임 SO 연결 — sets " + sets.Count + "개 (" + kResDir + "/WLSpriteLookSettings.asset)"); + } + L(""); + L(string.Format("합계 굽기 시간 = {0:0.00}초 / {1}종 → 1종당 {2:0.00}초", total, paths.Length, total / Math.Max(1, paths.Length))); + Write(); + } + + static void Write() { File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); Debug.Log("[WL814k] → " + kTxt); } +} diff --git a/AgentScripts/WL814k_CAPTURE.txt b/AgentScripts/WL814k_CAPTURE.txt new file mode 100644 index 000000000..0aa9ff41c --- /dev/null +++ b/AgentScripts/WL814k_CAPTURE.txt @@ -0,0 +1,11 @@ +WL-814k 캡처 · 2026-09-12 18:43:29 + ⓐ 3D 원본 → k_1_3d_original.png + 폴링 결과 — PC idle d7 f0 / 몹 idle d1 f0 + ⓑ 스프라이트 교체 → k_2_sprite_baked.png + 정렬 실측(PC 쪽 절반) — 3D x[21..41] y[87..120] / 스프라이트 x[19..40] y[85..121] → Δ좌 -2 · Δ우 -1 · Δ하 -2 · Δ상 1 px + 밝기 실측 — 3D 평균 63.1 · 스프라이트 평균 48.4 (0~255 · 캐릭터 픽셀만) · 캐릭터 픽셀 3D 466 / 스프라이트 619 (외곽선 +153) + 클로즈업 crop 116×46 px → ×9 = 1044×836 (위 3D · 아래 스프라이트) + ⓒ 클로즈업 → k_3_closeup_2x.png + ⓓ 방향 8종 → k_4_directions.png + +캡처 PASS — E:\NerdNavis\nn_himminji\Screenshots_WL\WL814k diff --git a/AgentScripts/WL814k_DIAG3.txt b/AgentScripts/WL814k_DIAG3.txt new file mode 100644 index 000000000..d1699e794 --- /dev/null +++ b/AgentScripts/WL814k_DIAG3.txt @@ -0,0 +1,43 @@ +WL-814k 진단 ③ · 18:24:55 + Animator 살아있나 = True + 샘플링 없음 덮인 426 · x[74..118] y[94..136] + Idle_f0 덮인 445 · x[75..114] y[96..136] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Idle_f1 덮인 436 · x[76..114] y[95..135] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Idle_f2 덮인 439 · x[76..113] y[94..135] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Idle_f3 덮인 441 · x[76..114] y[95..136] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Run_f0 덮인 503 · x[74..119] y[91..144] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Run_f1 덮인 496 · x[75..118] y[107..156] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Run_f2 덮인 502 · x[73..118] y[130..176] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Run_f3 덮인 503 · x[74..118] y[140..189] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Atk2_wing_f0 덮인 513 · x[71..112] y[88..132] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Atk2_wing_f1 덮인 447 · x[74..104] y[89..139] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Atk2_wing_f2 덮인 483 · x[68..109] y[91..131] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + Atk2_wing_f3 덮인 524 · x[69..104] y[83..133] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + LightHit_f0 덮인 448 · x[75..114] y[95..135] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + LightHit_f1 덮인 365 · x[75..113] y[81..113] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + LightHit_f2 덮인 449 · x[79..110] y[83..131] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + LightHit_f3 덮인 443 · x[75..114] y[87..127] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + death_F3441_f0 덮인 453 · x[78..114] y[78..121] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + death_F3441_f1 덮인 351 · x[91..109] y[0..37] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + death_F3441_f2 덮인 338 · x[86..104] y[0..35] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) + death_F3441_f3 덮인 374 · x[83..105] y[0..32] + 루트 localPos (0.000, 0.000, 0.000) · lossyScale (1.000, 1.000, 1.000) diff --git a/AgentScripts/WL814k_DIAG4.txt b/AgentScripts/WL814k_DIAG4.txt new file mode 100644 index 000000000..7eb71c6c7 --- /dev/null +++ b/AgentScripts/WL814k_DIAG4.txt @@ -0,0 +1,27 @@ +WL-814k 진단 ④ · 18:25:49 + +== Assets/Res_Addr/PC/Ai01.prefab == + 직속 자식: blen Group Mesh Root_M + 클립 Run · 위치 커브가 걸린 경로 0개: + f0 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (0.001, 0.990, 0.016) + f1 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (-0.001, 0.845, 0.691) + f2 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (-0.004, 0.990, 1.362) + f3 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (-0.002, 0.845, 2.044) + 클립 death_F3441 · 위치 커브가 걸린 경로 0개: + f0 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (0.021, 0.238, -0.078) + f1 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (0.097, -0.496, -2.949) + f2 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (0.066, -0.456, -2.963) + f3 rootLocal (0.000, 0.000, 0.000) | blen (0.000, 0.000, 0.000) | Group (0.000, 0.000, 0.000) | Mesh (0.000, 0.000, 0.000) | Root_M (0.077, -0.433, -3.045) + +== Assets/Res_Addr/Mobs/Mob/Batty_A.prefab == + 직속 자식: Batty root + 클립 Move · 위치 커브가 걸린 경로 8개: root/Center, root/Center/spine, root/Center/spine/wing_l1, root/Center/spine/wing_l1/wing_l2, root/Center/spine/wing_l1/wing_l2/wing_l3, root/Center/spine/wing_r1, root/Center/spine/wing_r1/wing_r2, root/Center/spine/wing_r1/wing_r2/wing_r3 + f0 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + f1 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + f2 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + f3 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + 클립 Die · 위치 커브가 걸린 경로 8개: root/Center, root/Center/spine, root/Center/spine/wing_l1, root/Center/spine/wing_l1/wing_l2, root/Center/spine/wing_l1/wing_l2/wing_l3, root/Center/spine/wing_r1, root/Center/spine/wing_r1/wing_r2, root/Center/spine/wing_r1/wing_r2/wing_r3 + f0 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + f1 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + f2 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) + f3 rootLocal (0.000, 0.000, 0.000) | Batty (0.000, 0.000, 0.000) | root (0.000, 0.000, 0.000) diff --git a/AgentScripts/WL814k_DIAG5.txt b/AgentScripts/WL814k_DIAG5.txt new file mode 100644 index 000000000..d56a02595 --- /dev/null +++ b/AgentScripts/WL814k_DIAG5.txt @@ -0,0 +1,45 @@ +WL-814k 진단 ⑤ · 18:27:44 + +== Assets/Res_Addr/PC/Ai01.prefab (anim.Play + anim.Update 경로) == + idle_f0 덮인 413 · x[86..110] y[92..136] + idle_f1 덮인 405 · x[86..110] y[92..135] + idle_f2 덮인 410 · x[86..110] y[92..135] + idle_f3 덮인 410 · x[86..110] y[92..136] + run_f0 덮인 474 · x[85..108] y[92..144] + run_f1 덮인 488 · x[85..111] y[91..139] + run_f2 덮인 486 · x[86..112] y[97..144] + run_f3 덮인 490 · x[86..110] y[91..139] + attack_f0 덮인 503 · x[75..109] y[86..132] + attack_f1 덮인 402 · x[80..101] y[89..134] + attack_f2 덮인 460 · x[78..109] y[88..131] + attack_f3 덮인 535 · x[75..103] y[83..133] + hit_f0 덮인 412 · x[86..110] y[91..135] + hit_f1 덮인 349 · x[86..110] y[89..120] + hit_f2 덮인 490 · x[86..111] y[91..141] + hit_f3 덮인 416 · x[86..110] y[92..136] + die_f0 덮인 457 · x[86..107] y[73..121] + die_f1 덮인 512 · x[77..123] y[86..116] + die_f2 덮인 518 · x[79..125] y[81..117] + die_f3 덮인 515 · x[79..123] y[78..114] + +== Assets/Res_Addr/Mobs/Mob/Batty_A.prefab (anim.Play + anim.Update 경로) == + idle_f0 덮인 231 · x[84..108] y[98..112] + idle_f1 덮인 221 · x[84..108] y[97..111] + idle_f2 덮인 231 · x[84..108] y[96..110] + idle_f3 덮인 234 · x[84..108] y[97..112] + run_f0 덮인 256 · x[84..108] y[101..117] + run_f1 덮인 254 · x[84..108] y[99..115] + run_f2 덮인 250 · x[84..108] y[98..113] + run_f3 덮인 254 · x[84..108] y[100..116] + attack_f0 덮인 223 · x[84..108] y[97..111] + attack_f1 덮인 260 · x[84..108] y[106..122] + attack_f2 덮인 256 · x[84..108] y[102..118] + attack_f3 덮인 236 · x[84..108] y[96..111] + hit_f0 덮인 223 · x[84..108] y[97..111] + hit_f1 덮인 195 · x[84..108] y[90..102] + hit_f2 덮인 213 · x[84..108] y[95..109] + hit_f3 덮인 233 · x[84..108] y[99..113] + die_f0 덮인 223 · x[84..108] y[97..111] + die_f1 덮인 215 · x[84..108] y[99..112] + die_f2 덮인 266 · x[84..108] y[87..103] + die_f3 덮인 251 · x[84..108] y[87..101] diff --git a/AgentScripts/WL814k_DIAG6.txt b/AgentScripts/WL814k_DIAG6.txt new file mode 100644 index 000000000..529522475 --- /dev/null +++ b/AgentScripts/WL814k_DIAG6.txt @@ -0,0 +1,13 @@ +WL-814k 진단 ⑥ · 18:44:46 + 3D f0 → 상태 해시 1203776827(attack=1203776827) nt 0.000 + 3D f1 → 상태 해시 1203776827(attack=1203776827) nt 0.167 + 3D f2 → 상태 해시 1203776827(attack=1203776827) nt 0.334 + 3D f3 → 상태 해시 1203776827(attack=1203776827) nt 0.500 + 3D f4 → 상태 해시 1203776827(attack=1203776827) nt 0.667 + 3D f5 → 상태 해시 1203776827(attack=1203776827) nt 0.834 + 스프라이트 f0 → 인덱스 122 (시작 80 + 7*6 + 0) + 스프라이트 f1 → 인덱스 123 (시작 80 + 7*6 + 1) + 스프라이트 f2 → 인덱스 124 (시작 80 + 7*6 + 2) + 스프라이트 f3 → 인덱스 125 (시작 80 + 7*6 + 3) + 스프라이트 f4 → 인덱스 126 (시작 80 + 7*6 + 4) + 스프라이트 f5 → 인덱스 127 (시작 80 + 7*6 + 5) diff --git a/AgentScripts/WL814k_Diag3.cs b/AgentScripts/WL814k_Diag3.cs new file mode 100644 index 000000000..3ec0e4de7 --- /dev/null +++ b/AgentScripts/WL814k_Diag3.cs @@ -0,0 +1,138 @@ +// WL-814k 진단 ③ — AnimationMode 샘플링이 실루엣을 어떻게 바꾸는지 프레임별 실측 +// run: unity command run_script --file AgentScripts/WL814k_Diag3.cs --entry WL814k_Diag3.Run + +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +public static class WL814k_Diag3 +{ + const string kTxt = "AgentScripts/WL814k_DIAG3.txt"; + static string OutDir = @"E:\NerdNavis\nn_himminji\Screenshots_WL\WL814k_diag"; + 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(); + Directory.CreateDirectory(OutDir); + L("WL-814k 진단 ③ · " + DateTime.Now.ToString("HH:mm:ss")); + Test("Assets/Res_Addr/PC/Ai01.prefab", new[] { "Idle", "Run", "Atk2_wing", "LightHit", "death_F3441" }); + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + Debug.Log("[WL814k] → " + kTxt); + } + + static void Test(string prefabPath, string[] clipNames) + { + GameObject pivot = null, inst = null, camGo = null; + RenderTexture rt = null; Texture2D tex = null; + bool am = false; + try + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat; + RenderSettings.ambientLight = new Color(0.212f, 0.227f, 0.259f, 1f); + RenderSettings.fog = false; RenderSettings.skybox = null; + var sun = new GameObject("Sun").AddComponent(); + sun.type = LightType.Directional; sun.intensity = 1.2f; sun.shadows = LightShadows.None; + sun.transform.rotation = Quaternion.Euler(26.4f, 238.6f, 0f); + + var src = AssetDatabase.LoadAssetAtPath(prefabPath); + pivot = new GameObject("Pivot"); + inst = (GameObject)PrefabUtility.InstantiatePrefab(src); + PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + inst.transform.SetParent(pivot.transform, false); + inst.transform.localPosition = Vector3.zero; inst.transform.localRotation = Quaternion.identity; + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c.gameObject); + foreach (var mb in inst.GetComponentsInChildren(true)) if (mb != null) UnityEngine.Object.DestroyImmediate(mb); + var anim = inst.GetComponent(); + L(" Animator 살아있나 = " + (anim != null)); + + float wpp = 3.4f * 2f / 240f; + int P = 192; + camGo = new GameObject("Cam"); + var cam = camGo.AddComponent(); + cam.orthographic = true; cam.orthographicSize = P * wpp * 0.5f; + cam.nearClipPlane = 0.01f; cam.farClipPlane = 200f; + cam.clearFlags = CameraClearFlags.SolidColor; cam.allowHDR = false; cam.allowMSAA = false; + camGo.transform.rotation = Quaternion.Euler(43.609f, 0f, 0f); + camGo.transform.position = -camGo.transform.right * (wpp * 0.5f) - camGo.transform.up * (wpp * 0.5f) - camGo.transform.forward * 50f; + + rt = new RenderTexture(P, P, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + rt.filterMode = FilterMode.Point; rt.antiAliasing = 1; rt.Create(); + tex = new Texture2D(P, P, TextureFormat.RGBA32, false, false); + + var rac = anim.runtimeAnimatorController; + var black = new Color32[P * P]; var white = new Color32[P * P]; + + // ⓐ 샘플링 없이 + Box(cam, rt, tex, P, black, white, "샘플링 없음", null); + + AnimationMode.StartAnimationMode(); am = true; + foreach (var name in clipNames) + { + AnimationClip clip = null; + foreach (var c in rac.animationClips) if (c.name == name) { clip = c; break; } + if (clip == null) { L(" 클립 " + name + " 없음"); continue; } + for (int f = 0; f < 4; f++) + { + float t = clip.length * f / 4f; + AnimationMode.BeginSampling(); + AnimationMode.SampleAnimationClip(inst, clip, t); + AnimationMode.EndSampling(); + inst.transform.localPosition = Vector3.zero; + inst.transform.localRotation = Quaternion.identity; + string tag = name + "_f" + f; + Box(cam, rt, tex, P, black, white, tag, (name == "Idle" && f == 0) ? OutDir + "\\am_" + tag + ".png" : null); + L(" 루트 localPos " + inst.transform.localPosition.ToString("F3") + " · lossyScale " + inst.transform.lossyScale.ToString("F3")); + } + } + AnimationMode.StopAnimationMode(); am = false; + } + catch (Exception ex) { L("EXCEPTION " + ex); } + finally + { + if (am && AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode(); + if (rt != null) { RenderTexture.active = null; rt.Release(); UnityEngine.Object.DestroyImmediate(rt); } + if (tex != null) UnityEngine.Object.DestroyImmediate(tex); + if (camGo != null) UnityEngine.Object.DestroyImmediate(camGo); + if (pivot != null) UnityEngine.Object.DestroyImmediate(pivot); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + } + + static void Box(Camera cam, RenderTexture rt, Texture2D tex, int P, Color32[] black, Color32[] white, string tag, string savePng) + { + Grab(cam, rt, tex, P, Color.black, black, savePng == null ? null : savePng.Replace(".png", "_black.png")); + Grab(cam, rt, tex, P, Color.white, white, savePng == null ? null : savePng.Replace(".png", "_white.png")); + int cov = 0, minX = int.MaxValue, maxX = -1, minY = int.MaxValue, maxY = -1; + for (int y = 0; y < P; y++) + for (int x = 0; x < P; x++) + { + int i = y * P + x; + float c = 1f - (((white[i].r - black[i].r) + (white[i].g - black[i].g) + (white[i].b - black[i].b)) / 765f); + if (c < 0.5f) continue; + cov++; + if (x < minX) minX = x; if (x > maxX) maxX = x; + if (y < minY) minY = y; if (y > maxY) maxY = y; + } + L(string.Format(" {0,-18} 덮인 {1,6} · x[{2}..{3}] y[{4}..{5}]", tag, cov, minX, maxX, minY, maxY)); + } + + static void Grab(Camera cam, RenderTexture rt, Texture2D tex, int P, Color bg, Color32[] outPx, string file) + { + cam.backgroundColor = bg; + cam.targetTexture = rt; cam.Render(); cam.targetTexture = null; + var active = RenderTexture.active; RenderTexture.active = rt; + tex.ReadPixels(new Rect(0, 0, P, P), 0, 0); tex.Apply(false, false); + RenderTexture.active = active; + if (file != null) File.WriteAllBytes(file, tex.EncodeToPNG()); + Array.Copy(tex.GetPixels32(), outPx, outPx.Length); + } +} diff --git a/AgentScripts/WL814k_Diag4.cs b/AgentScripts/WL814k_Diag4.cs new file mode 100644 index 000000000..177dd1f47 --- /dev/null +++ b/AgentScripts/WL814k_Diag4.cs @@ -0,0 +1,86 @@ +// WL-814k 진단 ④ — 루트 모션이 어느 트랜스폼에 실리는지 실측 +// run: unity command run_script --file AgentScripts/WL814k_Diag4.cs --entry WL814k_Diag4.Run + +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +public static class WL814k_Diag4 +{ + const string kTxt = "AgentScripts/WL814k_DIAG4.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("HH:mm:ss")); + Test("Assets/Res_Addr/PC/Ai01.prefab", new[] { "Run", "death_F3441" }); + Test("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab", new[] { "Move", "Die" }); + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + Debug.Log("[WL814k] → " + kTxt); + } + + static void Test(string prefabPath, string[] clipNames) + { + GameObject pivot = null, inst = null; + bool am = false; + try + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + var src = AssetDatabase.LoadAssetAtPath(prefabPath); + pivot = new GameObject("Pivot"); + inst = (GameObject)PrefabUtility.InstantiatePrefab(src); + PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + inst.transform.SetParent(pivot.transform, false); + inst.transform.localPosition = Vector3.zero; inst.transform.localRotation = Quaternion.identity; + var anim = inst.GetComponent(); + var rac = anim.runtimeAnimatorController; + + L(""); + L("== " + prefabPath + " =="); + var kids = new StringBuilder(); + for (int i = 0; i < inst.transform.childCount; i++) kids.Append(inst.transform.GetChild(i).name + " "); + L(" 직속 자식: " + kids); + + AnimationMode.StartAnimationMode(); am = true; + foreach (var name in clipNames) + { + AnimationClip clip = null; + foreach (var c in rac.animationClips) if (c.name == name) { clip = c; break; } + if (clip == null) continue; + var binds = AnimationUtility.GetCurveBindings(clip); + var paths = new System.Collections.Generic.HashSet(); + foreach (var b in binds) if (b.propertyName.StartsWith("m_LocalPosition")) paths.Add(b.path == "" ? "" : b.path); + L(" 클립 " + name + " · 위치 커브가 걸린 경로 " + paths.Count + "개: " + string.Join(", ", new System.Collections.Generic.List(paths).ToArray())); + + for (int f = 0; f < 4; f++) + { + float t = clip.length * f / 4f; + AnimationMode.BeginSampling(); + AnimationMode.SampleAnimationClip(inst, clip, t); + AnimationMode.EndSampling(); + var sb = new StringBuilder(); + sb.Append(string.Format(" f{0} rootLocal {1}", f, inst.transform.localPosition.ToString("F3"))); + for (int i = 0; i < inst.transform.childCount; i++) + { + var ch = inst.transform.GetChild(i); + sb.Append(" | " + ch.name + " " + ch.localPosition.ToString("F3")); + } + L(sb.ToString()); + } + } + AnimationMode.StopAnimationMode(); am = false; + } + catch (Exception ex) { L("EXCEPTION " + ex); } + finally + { + if (am && AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode(); + if (pivot != null) UnityEngine.Object.DestroyImmediate(pivot); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + } +} diff --git a/AgentScripts/WL814k_Diag5.cs b/AgentScripts/WL814k_Diag5.cs new file mode 100644 index 000000000..fbe6e1691 --- /dev/null +++ b/AgentScripts/WL814k_Diag5.cs @@ -0,0 +1,134 @@ +// WL-814k 진단 ⑤ — 「진짜 Animator 로 구동」 경로가 에디트 모드에서 되는지 실측 +// (applyRootMotion=false 인 게임과 똑같은 포즈를 얻을 수 있으면 그게 정답 경로) +// run: unity command run_script --file AgentScripts/WL814k_Diag5.cs --entry WL814k_Diag5.Run + +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +public static class WL814k_Diag5 +{ + const string kTxt = "AgentScripts/WL814k_DIAG5.txt"; + static string OutDir = @"E:\NerdNavis\nn_himminji\Screenshots_WL\WL814k_diag"; + 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(); + Directory.CreateDirectory(OutDir); + L("WL-814k 진단 ⑤ · " + DateTime.Now.ToString("HH:mm:ss")); + Test("Assets/Res_Addr/PC/Ai01.prefab", new[] { "idle", "run", "attack", "hit", "die" }); + Test("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab", new[] { "idle", "run", "attack", "hit", "die" }); + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + Debug.Log("[WL814k] → " + kTxt); + } + + static void Test(string prefabPath, string[] states) + { + GameObject pivot = null, inst = null, camGo = null; + RenderTexture rt = null; Texture2D tex = null; + try + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat; + RenderSettings.ambientLight = new Color(0.212f, 0.227f, 0.259f, 1f); + RenderSettings.fog = false; RenderSettings.skybox = null; + var sun = new GameObject("Sun").AddComponent(); + sun.type = LightType.Directional; sun.intensity = 1.2f; sun.shadows = LightShadows.None; + sun.transform.rotation = Quaternion.Euler(26.4f, 238.6f, 0f); + + var src = AssetDatabase.LoadAssetAtPath(prefabPath); + pivot = new GameObject("Pivot"); + inst = (GameObject)PrefabUtility.InstantiatePrefab(src); + PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + inst.transform.SetParent(pivot.transform, false); + inst.transform.localPosition = Vector3.zero; inst.transform.localRotation = Quaternion.identity; + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in inst.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c.gameObject); + foreach (var mb in inst.GetComponentsInChildren(true)) if (mb != null) UnityEngine.Object.DestroyImmediate(mb); + foreach (var sm in inst.GetComponentsInChildren(true)) if (sm != null) sm.updateWhenOffscreen = true; + + var anim = inst.GetComponent(); + anim.applyRootMotion = false; + anim.cullingMode = AnimatorCullingMode.AlwaysAnimate; + anim.Rebind(); + + float wpp = 3.4f * 2f / 240f; + int P = 192; + camGo = new GameObject("Cam"); + var cam = camGo.AddComponent(); + cam.orthographic = true; cam.orthographicSize = P * wpp * 0.5f; + cam.nearClipPlane = 0.01f; cam.farClipPlane = 200f; + cam.clearFlags = CameraClearFlags.SolidColor; cam.allowHDR = false; cam.allowMSAA = false; + camGo.transform.rotation = Quaternion.Euler(43.609f, 0f, 0f); + camGo.transform.position = -camGo.transform.right * (wpp * 0.5f) - camGo.transform.up * (wpp * 0.5f) - camGo.transform.forward * 50f; + + rt = new RenderTexture(P, P, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + rt.filterMode = FilterMode.Point; rt.antiAliasing = 1; rt.Create(); + tex = new Texture2D(P, P, TextureFormat.RGBA32, false, false); + var black = new Color32[P * P]; var white = new Color32[P * P]; + + L(""); + L("== " + prefabPath + " (anim.Play + anim.Update 경로) =="); + foreach (var st in states) + { + int hash = Animator.StringToHash(st); + if (!anim.HasState(0, hash)) { L(" 상태 " + st + " 없음"); continue; } + for (int f = 0; f < 4; f++) + { + float nt = f / 4f; + anim.Play(hash, 0, nt); + anim.Update(0f); + inst.transform.localPosition = Vector3.zero; + inst.transform.localRotation = Quaternion.identity; + string tag = st + "_f" + f; + Box(cam, rt, tex, P, black, white, tag, (f == 0) ? OutDir + "\\play_" + Path.GetFileNameWithoutExtension(prefabPath) + "_" + tag + ".png" : null); + } + } + } + catch (Exception ex) { L("EXCEPTION " + ex); } + finally + { + if (rt != null) { RenderTexture.active = null; rt.Release(); UnityEngine.Object.DestroyImmediate(rt); } + if (tex != null) UnityEngine.Object.DestroyImmediate(tex); + if (camGo != null) UnityEngine.Object.DestroyImmediate(camGo); + if (pivot != null) UnityEngine.Object.DestroyImmediate(pivot); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + } + + static void Box(Camera cam, RenderTexture rt, Texture2D tex, int P, Color32[] black, Color32[] white, string tag, string savePng) + { + Grab(cam, rt, tex, P, Color.black, black, null); + Grab(cam, rt, tex, P, Color.white, white, savePng); + int cov = 0, minX = int.MaxValue, maxX = -1, minY = int.MaxValue, maxY = -1; + for (int y = 0; y < P; y++) + for (int x = 0; x < P; x++) + { + int i = y * P + x; + float c = 1f - (((white[i].r - black[i].r) + (white[i].g - black[i].g) + (white[i].b - black[i].b)) / 765f); + if (c < 0.5f) continue; + cov++; + if (x < minX) minX = x; if (x > maxX) maxX = x; + if (y < minY) minY = y; if (y > maxY) maxY = y; + } + L(string.Format(" {0,-14} 덮인 {1,6} · x[{2}..{3}] y[{4}..{5}]", tag, cov, minX, maxX, minY, maxY)); + } + + static void Grab(Camera cam, RenderTexture rt, Texture2D tex, int P, Color bg, Color32[] outPx, string file) + { + cam.backgroundColor = bg; + cam.targetTexture = rt; cam.Render(); cam.targetTexture = null; + var active = RenderTexture.active; RenderTexture.active = rt; + tex.ReadPixels(new Rect(0, 0, P, P), 0, 0); tex.Apply(false, false); + RenderTexture.active = active; + if (file != null) File.WriteAllBytes(file, tex.EncodeToPNG()); + Array.Copy(tex.GetPixels32(), outPx, outPx.Length); + } +} diff --git a/AgentScripts/WL814k_Diag6.cs b/AgentScripts/WL814k_Diag6.cs new file mode 100644 index 000000000..06d17afb7 --- /dev/null +++ b/AgentScripts/WL814k_Diag6.cs @@ -0,0 +1,178 @@ +// WL-814k 진단 ⑥ — 3D 프레임 k 와 스프라이트 프레임 k 가 정말 같은 그림인가(격자 비교) +// run: unity command run_script --file AgentScripts/WL814k_Diag6.cs --entry WL814k_Diag6.Run + +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using WL.Look.SpriteBake; + +public static class WL814k_Diag6 +{ + const string kOut = @"E:\NerdNavis\nn_himminji\Screenshots_WL\WL814k_diag"; + const string kTxt = "AgentScripts/WL814k_DIAG6.txt"; + const float kOrtho = 3.4f, kPitch = 43.609f; + const int kLowH = 240; + 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(); + Directory.CreateDirectory(kOut); + L("WL-814k 진단 ⑥ · " + DateTime.Now.ToString("HH:mm:ss")); + try + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + var sun = new GameObject("Sun").AddComponent(); + sun.type = LightType.Directional; sun.shadows = LightShadows.None; + sun.color = new Color(1f, 0.92f, 0.703f, 1f); sun.intensity = 1.2f; + sun.transform.rotation = Quaternion.Euler(26.4f, 238.6f, 0f); + var fill = new GameObject("Fill").AddComponent(); + fill.type = LightType.Directional; fill.shadows = LightShadows.None; + fill.color = new Color(0.596f, 0.703f, 0.839f, 1f); fill.intensity = 0.3f; + fill.transform.rotation = Quaternion.Euler(36.1f, 116.1f, 0f); + RenderSettings.skybox = AssetDatabase.GetBuiltinExtraResource("Default-Skybox.mat"); + RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Skybox; + RenderSettings.ambientIntensity = 1f; RenderSettings.fog = false; + DynamicGI.UpdateEnvironment(); + + var look = WLSpriteLookSettings.Instance; + var actor = Spawn("Assets/Res_Addr/PC/Ai01.prefab", 0.7f); + var set = SpriteBillboard.MatchSet(actor.name, look); + var act = set.FindByKey("attack"); + var anim = actor.GetComponent(); + + int cell = 64, cols = act.frameCount, rows = 2, dir = 7; + var rig = MakeCam(cell, cell); + var sheet = new Color32[cols * cell * rows * cell]; + + // 위 줄 = 3D (매 컷 직전에 포즈를 다시 찍는다) + for (int f = 0; f < cols; f++) + { + actor.transform.rotation = Quaternion.Euler(0f, dir * 45f, 0f); + anim.Play(Animator.StringToHash("attack"), 0, (f + 0.001f) / act.frameCount); + anim.Update(0f); + var st = anim.GetCurrentAnimatorStateInfo(0); + L(string.Format(" 3D f{0} → 상태 해시 {1}(attack={2}) nt {3:0.000}", f, st.shortNameHash, Animator.StringToHash("attack"), st.normalizedTime)); + BlitInto(rig.Grab(), cell, cell, sheet, cols * cell, f * cell, 1 * cell); + } + + // 아래 줄 = 스프라이트 + var e = SpriteBillboard.TryAttach(actor, set); + for (int f = 0; f < cols; f++) + { + actor.transform.rotation = Quaternion.Euler(0f, dir * 45f, 0f); + SpriteBillboard.SetManualFrame(actor, "attack", dir, f); + SpriteBillboard.UpdateAll(rig.cam); + L(string.Format(" 스프라이트 f{0} → 인덱스 {1} (시작 {2} + {3}*{4} + {5})", f, + act.startIndex + dir * act.frameCount + f, act.startIndex, dir, act.frameCount, f)); + BlitInto(rig.Grab(), cell, cell, sheet, cols * cell, f * cell, 0 * cell); + } + SpriteBillboard.RestoreNow("diag6"); + + Save(sheet, cols * cell, rows * cell, kOut + @"\frames_attack_dir7.png", 6); + rig.Dispose(); + } + catch (Exception ex) { L("EXCEPTION " + ex); } + finally + { + SpriteBillboard.RestoreNow("diag6-end"); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + } + + static GameObject Spawn(string p, float scale) + { + var src = AssetDatabase.LoadAssetAtPath(p); + var go = (GameObject)PrefabUtility.InstantiatePrefab(src); + PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + go.name = Path.GetFileNameWithoutExtension(p) + "(Clone)"; + go.transform.position = Vector3.zero; + go.transform.localScale = Vector3.one * scale; + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c.gameObject); + foreach (var mb in go.GetComponentsInChildren(true)) if (mb != null) UnityEngine.Object.DestroyImmediate(mb); + foreach (var sm in go.GetComponentsInChildren(true)) sm.updateWhenOffscreen = true; + var an = go.GetComponent(); + an.applyRootMotion = false; an.cullingMode = AnimatorCullingMode.AlwaysAnimate; an.Rebind(); + var bake = WLSpriteBakeSettings.Instance; + foreach (var rend in go.GetComponentsInChildren(true)) + { + if (rend == null || rend is ParticleSystemRenderer) continue; + var mats = rend.sharedMaterials; bool any = false; + for (int i = 0; i < mats.Length; i++) + { + if (mats[i] == null) continue; + var t = AssetDatabase.LoadAssetAtPath(bake.toonMaterialDir + "/" + mats[i].name + bake.toonMaterialSuffix + ".mat"); + if (t != null) { mats[i] = t; any = true; } + } + if (any) rend.sharedMaterials = mats; + } + return go; + } + + sealed class Rig + { + public Camera cam; public RenderTexture rt; public Texture2D tex; public int w, h; + public Color32[] Grab() + { + cam.targetTexture = rt; cam.Render(); cam.targetTexture = null; + var a = RenderTexture.active; RenderTexture.active = rt; + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); tex.Apply(false, false); + RenderTexture.active = a; + return tex.GetPixels32(); + } + public void Dispose() + { + RenderTexture.active = null; + if (rt != null) { rt.Release(); UnityEngine.Object.DestroyImmediate(rt); } + if (tex != null) UnityEngine.Object.DestroyImmediate(tex); + if (cam != null) UnityEngine.Object.DestroyImmediate(cam.gameObject); + } + } + + static Rig MakeCam(int w, int h) + { + var go = new GameObject("Cam"); + var c = go.AddComponent(); + c.orthographic = true; + c.orthographicSize = h * (2f * kOrtho / kLowH) * 0.5f; + c.nearClipPlane = 0.01f; c.farClipPlane = 200f; + c.clearFlags = CameraClearFlags.SolidColor; + c.backgroundColor = new Color(0.34f, 0.40f, 0.25f, 1f); + c.allowHDR = false; c.allowMSAA = false; + go.transform.rotation = Quaternion.Euler(kPitch, 0f, 0f); + go.transform.position = new Vector3(0f, 0.6f, 0f) - go.transform.forward * 40f; + var rt = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + rt.filterMode = FilterMode.Point; rt.antiAliasing = 1; rt.Create(); + var tex = new Texture2D(w, h, TextureFormat.RGBA32, false, false); + return new Rig { cam = c, rt = rt, tex = tex, w = w, h = h }; + } + + static void BlitInto(Color32[] src, int sw, int sh, Color32[] dst, int dw, int dx, int dy) + { + for (int y = 0; y < sh; y++) + for (int x = 0; x < sw; x++) + { + int di = (dy + y) * dw + (dx + x); + if (di >= 0 && di < dst.Length) dst[di] = src[y * sw + x]; + } + } + + static void Save(Color32[] px, int w, int h, string file, int zoom) + { + int ow = w * zoom, oh = h * zoom; + var o = new Color32[ow * oh]; + for (int y = 0; y < oh; y++) for (int x = 0; x < ow; x++) o[y * ow + x] = px[(y / zoom) * w + (x / zoom)]; + var t = new Texture2D(ow, oh, TextureFormat.RGBA32, false, false); + t.SetPixels32(o); t.Apply(false, false); + File.WriteAllBytes(file, t.EncodeToPNG()); + UnityEngine.Object.DestroyImmediate(t); + } +} diff --git a/AgentScripts/WL814k_NAMING.txt b/AgentScripts/WL814k_NAMING.txt new file mode 100644 index 000000000..f755c17ff --- /dev/null +++ b/AgentScripts/WL814k_NAMING.txt @@ -0,0 +1,18 @@ +WL-814k 이름 규약 표 · 2026-09-12 18:50:03 + 후보 idle = [idle / Idle / wait / IdleA / IdleB] (+보기만: land / getup) + 후보 run = [run / Run / move / Move / walk] (+보기만: dodge) + 후보 attack = [attack / Attack / atk / ATK0 / ATK1] (+보기만: ATK2 / ATK3 / ATK4 / Shoot / attack2 / skill2 / skill3 / skill4 / skill5 / casting / casting_end) + 후보 hit = [hit / Hit / damage / Damage] (+보기만: stun / Swoon) + 후보 die = [die / Die / death / Die0 / Die1] (+보기만: lying / Die2) + +== 개별 프리팹 == + Ai01.prefab 컨트롤러 pcanim_mage 상태 17개 · 매칭 5/5 · idle→idle run→run attack→attack hit→hit die→die + Batty_A.prefab 컨트롤러 Batty_Animations_Check 상태 8개 · 매칭 5/5 · idle→idle run→run attack→attack hit→hit die→die + F06.prefab 컨트롤러 Animations_check 상태 32개 · 매칭 5/5 · idle→IdleA run→Run attack→ATK0 hit→Damage die→Die0 + M05.prefab 컨트롤러 Animations_check 상태 32개 · 매칭 5/5 · idle→IdleA run→Run attack→ATK0 hit→Damage die→Die0 + +== Res_Addr/Mobs 전수 (확장 견적 근거) == + Animator+Controller 보유 프리팹 = 299 · 동작 5종 전부 매칭 = 288 (96.3 %) + 매칭 4/5 동작 = 11종 + 매칭 5/5 동작 = 288종 + 못 찾은 동작 'hit' = 11종 diff --git a/AgentScripts/WL814k_Naming.cs b/AgentScripts/WL814k_Naming.cs new file mode 100644 index 000000000..7c5718920 --- /dev/null +++ b/AgentScripts/WL814k_Naming.cs @@ -0,0 +1,109 @@ +// WL-814k 이름 규약 표 — 「굽기 SO 의 상태 이름 후보」가 어떤 캐릭터에 얼마나 걸리는지 실측 (읽기만 · 굽기 0) +// run: unity command run_script --file AgentScripts/WL814k_Naming.cs --entry WL814k_Naming.Run +// 🔴 여기서도 굽지 않는다 — 1차 시범은 PC 1종 + 잡몹 1종(발주서). 이 표는 「확장하면 뭐가 걸리나」의 근거다. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; +using WL.Look.SpriteBake; + +public static class WL814k_Naming +{ + const string kTxt = "AgentScripts/WL814k_NAMING.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")); + var cfg = AssetDatabase.LoadAssetAtPath("Assets/WL/Look/Sprite/Resources/WL/WLSpriteBakeSettings.asset"); + if (cfg == null) { L("FAIL — 굽기 SO 없음"); File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); return; } + + foreach (var a in cfg.actions) + L(" 후보 " + a.key.PadRight(7) + " = [" + string.Join(" / ", a.stateNames) + "] (+보기만: " + string.Join(" / ", a.alsoMapStateNames) + ")"); + + // ── ① 시범 2종 + PD 가 방금 임포트한 치비 팩(Little Heroes) ───────────── + L(""); + L("== 개별 프리팹 =="); + foreach (var p in new[] + { + "Assets/Res_Addr/PC/Ai01.prefab", + "Assets/Res_Addr/Mobs/Mob/Batty_A.prefab", + "Assets/Suriyun/Characters/Nana/Prefab/F06.prefab", + "Assets/Suriyun/Characters/RedKnight/Prefab/M05/M05.prefab", + }) + One(p, cfg); + + // ── ② 몹 전수 — 확장했을 때 몇 %가 그냥 걸리는지 ─────────────────────── + L(""); + L("== Res_Addr/Mobs 전수 (확장 견적 근거) =="); + var guids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Res_Addr/Mobs" }); + int total = 0, full = 0; + var hist = new Dictionary(); + var missing = new Dictionary(); + foreach (var g in guids) + { + var path = AssetDatabase.GUIDToAssetPath(g); + var go = AssetDatabase.LoadAssetAtPath(path); + if (go == null) continue; + var anim = go.GetComponentInChildren(true); + if (anim == null || anim.runtimeAnimatorController == null) continue; + total++; + var states = States(anim); + int hit = 0; + foreach (var a in cfg.actions) + { + if (Match(a, states) != null) hit++; + else { int c; missing.TryGetValue(a.key, out c); missing[a.key] = c + 1; } + } + if (hit == cfg.actions.Length) full++; + int n; hist.TryGetValue(hit, out n); hist[hit] = n + 1; + } + L(" Animator+Controller 보유 프리팹 = " + total + " · 동작 5종 전부 매칭 = " + full + " (" + (100f * full / Mathf.Max(1, total)).ToString("0.0") + " %)"); + var keys = new List(hist.Keys); keys.Sort(); + foreach (var k in keys) L(" 매칭 " + k + "/5 동작 = " + hist[k] + "종"); + foreach (var kv in missing) L(" 못 찾은 동작 '" + kv.Key + "' = " + kv.Value + "종"); + + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + Debug.Log("[WL814k] → " + kTxt); + } + + static void One(string path, WLSpriteBakeSettings cfg) + { + var go = AssetDatabase.LoadAssetAtPath(path); + if (go == null) { L(" " + path + " → 없음"); return; } + var anim = go.GetComponentInChildren(true); + if (anim == null || anim.runtimeAnimatorController == null) { L(" " + path + " → Animator/Controller 없음"); return; } + var states = States(anim); + var sb = new StringBuilder(); + int hit = 0; + foreach (var a in cfg.actions) + { + var m = Match(a, states); + if (m != null) hit++; + sb.Append(a.key + "→" + (m ?? "✗") + " "); + } + L(string.Format(" {0,-56} 컨트롤러 {1,-24} 상태 {2,2}개 · 매칭 {3}/{4} · {5}", + Path.GetFileName(path), anim.runtimeAnimatorController.name, states.Count, hit, cfg.actions.Length, sb.ToString().Trim())); + } + + static Dictionary States(Animator anim) + { + var d = new Dictionary(StringComparer.OrdinalIgnoreCase); + var ac = anim.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; + if (ac != null && ac.layers.Length > 0 && ac.layers[0].stateMachine != null) + foreach (var ch in ac.layers[0].stateMachine.states) + if (ch.state.motion != null && !d.ContainsKey(ch.state.name)) d[ch.state.name] = ch.state.name; + return d; + } + + static string Match(WLSpriteBakeAction a, Dictionary states) + { + foreach (var n in a.stateNames) { string real; if (states.TryGetValue(n, out real)) return real; } + return null; + } +} diff --git a/AgentScripts/WL814k_PROBE.txt b/AgentScripts/WL814k_PROBE.txt new file mode 100644 index 000000000..34e151ce3 --- /dev/null +++ b/AgentScripts/WL814k_PROBE.txt @@ -0,0 +1,49 @@ +WL-814k 프로브 · 2026-09-12 18:43:19 · Unity 6000.3.23f1 + +== A. 에셋 · 메타 == + PASS A1 굽기 SO — 내림각 43.609° · 픽셀 0.02833 m + PASS A2 런타임 SO — sets 2 + PASS A3 시트 Ai01_SpriteSet — Ai01 · 프레임 56×56 · 16열×12행 · 방향 8 · 총 192칸 · 텍스처 896×672 + PASS A4 임포트 Ai01_SpriteSet — filter Point · mipmap False · 압축 Uncompressed · alphaIsTransparency True · maxSize 1024 · type Default + PASS A5 격자 Ai01_SpriteSet — 칸 192 ≥ 필요 192 · 텍스처 896×672 + PASS A6 동작표 Ai01_SpriteSet — 5개 · idle[0+4] run[32+6] attack[80+6] hit[128+2] die[144+6] + PASS A3 시트 Batty_A_SpriteSet — Batty_A · 프레임 48×48 · 16열×12행 · 방향 8 · 총 192칸 · 텍스처 768×576 + PASS A4 임포트 Batty_A_SpriteSet — filter Point · mipmap False · 압축 Uncompressed · alphaIsTransparency True · maxSize 1024 · type Default + PASS A5 격자 Batty_A_SpriteSet — 칸 192 ≥ 필요 192 · 텍스처 768×576 + PASS A6 동작표 Batty_A_SpriteSet — 5개 · idle[0+4] run[32+6] attack[80+6] hit[128+2] die[144+6] + +== B. 부착 → 원복 (원본 파괴 0 · 렌더러 원값 복원) == + PASS B1 이름 매칭 — 액터 'Ai01(Clone)' → Ai01_SpriteSet + PASS B2 원본 끔 — SMR 11개 → 켜져 있는 것 0개 + PASS B3 쿼드 1개 — [WL814k] SpriteQuad · 부모 Ai01(Clone) · 레이어 3 + PASS B4 파괴 0 — 노드 223 → 224 (쿼드 +1) + PASS B5 원복 — SMR 켜짐 11/11 · 노드 223/223 + +== C. 프레임 · 방향 선택 (Animator 폴링 · 원본 코드 수정 0) == + PASS C1 상태→동작 — 17/17개 상태가 정확한 동작으로 간다 + PASS C2 시간→프레임 — nt 0.13→f0 nt 0.38→f1 nt 0.63→f2 nt 0.88→f3 + PASS C2b 상태 폴링(에디트 모드) — 5/5 · idle→idle run→run attack→attack hit→hit die→die + PASS C3 각도→방향 — 0°→d0 45°→d1 90°→d2 135°→d3 180°→d4 225°→d5 270°→d6 315°→d7 + PASS C4 쿼드 크기 — 월드 1.5867 m (기대 1.5867) · 스케일 보정 1.000 + PASS C5 쿼드 자세 — 카메라 정렬 오차 0.000° + +== D. GC (프레임당 할당 0) == + PASS D1 UpdateAll ×200k — mono Δ 0 B · gen0 0회 + +== E. 시트 내용 (도트화가 실제로 강제됐는가) == + PASS E1 알파 이진화 Ai01_SpriteSet — 불투명 63548 · 반투명 0(0 이어야 한다) + PASS E2 팔레트 양자화 Ai01_SpriteSet — 밝기 6단계 [0 51 102 153 204 255] 밖 픽셀 0개 · 실제 7가지 [0 17 51 102 153 204 255] (외곽선 색 14,11,17 제외) · 색 1819종 + PASS E3 외곽선 Ai01_SpriteSet — 어두운 테두리 픽셀 22159 / 불투명 63548 (34.9 %) + PASS E4 PNG 크기 Ai01_SpriteSet — 165,716 B (161.8 KB) · 896×672 · RGBA32 런타임 2.30 MB + PASS E1 알파 이진화 Batty_A_SpriteSet — 불투명 53848 · 반투명 0(0 이어야 한다) + PASS E2 팔레트 양자화 Batty_A_SpriteSet — 밝기 6단계 [0 51 102 153 204 255] 밖 픽셀 0개 · 실제 6가지 [17 51 102 153 204 255] (외곽선 색 14,11,17 제외) · 색 398종 + PASS E3 외곽선 Batty_A_SpriteSet — 어두운 테두리 픽셀 12096 / 불투명 53848 (22.5 %) + PASS E4 PNG 크기 Batty_A_SpriteSet — 107,778 B (105.3 KB) · 768×576 · RGBA32 런타임 1.69 MB + +== F. C8 롤백 (SO off → 원본 3D 100 %) == + PASS F1 게이트 — RuntimeDisabled → Enabled=false · ShouldBeOn=false + PASS F2 렌더러 100 % 복원 — SMR 11/11 · MR 2/2 + PASS F3 쿼드 0 — 노드 223/223 · 대상 0 + PASS F4 목록 밖 액터 — 'Ai02(Clone)' → 매칭 0 = 원본 3D 그대로 + +RESULT PASS — 34 pass / 0 fail diff --git a/AgentScripts/WL814k_Probe.cs b/AgentScripts/WL814k_Probe.cs new file mode 100644 index 000000000..c9834527b --- /dev/null +++ b/AgentScripts/WL814k_Probe.cs @@ -0,0 +1,686 @@ +// WL-814k 프로브 + 캡처 4장 (게임 코드 아님 · 에디트 모드 전용 · 임시 씬 저장 0 · 커밋 0) +// probe: unity command run_script --file AgentScripts/WL814k_Probe.cs --entry WL814k_Probe.RunAll +// cap : unity command run_script --file AgentScripts/WL814k_Probe.cs --entry WL814k_Probe.Capture +// 🔴 원본 프리팹/머티리얼/애니메이션 수정 0. 씬 저장 0. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Profiling; +using UnityEngine.SceneManagement; +using WL.Look.SpriteBake; + +public static class WL814k_Probe +{ + const string kOutDir = @"E:\NerdNavis\nn_himminji\Screenshots_WL\WL814k"; + const string kTxt = "AgentScripts/WL814k_PROBE.txt"; + const string kTxtCap = "AgentScripts/WL814k_CAPTURE.txt"; + const string kRes = "Assets/WL/Look/Sprite/Resources/WL"; + const string kPcPrefab = "Assets/Res_Addr/PC/Ai01.prefab"; + const string kMobPrefab = "Assets/Res_Addr/Mobs/Mob/Batty_A.prefab"; + + // 도트A 프리셋 실측 = orthoSize 3.4 · pixelHeight 240 · 내림각 43.609° + const float kOrtho = 3.4f, kPitch = 43.609f; + const int kLowH = 240, kLowW = 135, kHiW = 1080, kHiH = 1920; + + static StringBuilder s_sb; + static int s_pass, s_fail; + static void L(string s) { s_sb.AppendLine(s); Debug.Log("[WL814k] " + s); } + static void Chk(string n, bool ok, string d) { if (ok) s_pass++; else s_fail++; L((ok ? " PASS " : " FAIL ") + n + " — " + d); } + static void Write(string p) { File.WriteAllText(p, s_sb.ToString(), new UTF8Encoding(false)); Debug.Log("[WL814k] → " + p); } + + // ═════════════════════════════════════════════════════════════════════════ + // 프로브 + // ═════════════════════════════════════════════════════════════════════════ + public static void RunAll() + { + s_sb = new StringBuilder(); s_pass = 0; s_fail = 0; + L("WL-814k 프로브 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " · Unity " + Application.unityVersion); + try + { + A_Assets(); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + B_AttachRestore(); + C_FrameDir(); + D_Gc(); + E_Sheet(); + F_C8(); + } + catch (Exception ex) { s_fail++; L("EXCEPTION " + ex); } + finally + { + SpriteBillboard.RestoreNow("probe-end"); + WLSpriteLookSettings.RuntimeDisabled = false; + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + L(""); + L("RESULT " + (s_fail == 0 ? "PASS" : "FAIL") + " — " + s_pass + " pass / " + s_fail + " fail"); + Write(kTxt); + } + + // ── A. 에셋 · 메타 ────────────────────────────────────────────────────── + static void A_Assets() + { + L(""); + L("== A. 에셋 · 메타 =="); + var bake = AssetDatabase.LoadAssetAtPath(kRes + "/WLSpriteBakeSettings.asset"); + var look = AssetDatabase.LoadAssetAtPath(kRes + "/WLSpriteLookSettings.asset"); + Chk("A1 굽기 SO", bake != null, bake == null ? "없음" : "내림각 " + bake.PitchDeg.ToString("0.000") + "° · 픽셀 " + bake.WorldPerPixel.ToString("0.00000") + " m"); + Chk("A2 런타임 SO", look != null && look.sets != null && look.sets.Length == 2, look == null ? "없음" : "sets " + look.sets.Length); + if (look == null) return; + foreach (var s in look.sets) + { + Chk("A3 시트 " + (s == null ? "null" : s.name), s != null && s.IsUsable, + s == null ? "null" : string.Format("{0} · 프레임 {1}×{2} · {3}열×{4}행 · 방향 {5} · 총 {6}칸 · 텍스처 {7}×{8}", + s.actorNamePrefix, s.frameWidth, s.frameHeight, s.columns, s.rows, s.dirCount, s.TotalFrames, + s.sheet == null ? 0 : s.sheet.width, s.sheet == null ? 0 : s.sheet.height)); + if (s == null || s.sheet == null) continue; + var ti = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(s.sheet)) as TextureImporter; + Chk("A4 임포트 " + s.name, ti != null && ti.filterMode == FilterMode.Point && !ti.mipmapEnabled + && ti.textureCompression == TextureImporterCompression.Uncompressed && ti.alphaIsTransparency, + ti == null ? "임포터 없음" : "filter " + ti.filterMode + " · mipmap " + ti.mipmapEnabled + " · 압축 " + ti.textureCompression + + " · alphaIsTransparency " + ti.alphaIsTransparency + " · maxSize " + ti.maxTextureSize + " · type " + ti.textureType); + int need = s.TotalFrames; + int cap = s.columns * s.rows; + Chk("A5 격자 " + s.name, cap >= need && s.sheet.width == s.columns * s.frameWidth && s.sheet.height == s.rows * s.frameHeight, + "칸 " + cap + " ≥ 필요 " + need + " · 텍스처 " + s.sheet.width + "×" + s.sheet.height); + var act = new StringBuilder(); + foreach (var a in s.actions) act.Append(a.key + "[" + a.startIndex + "+" + a.frameCount + "] "); + Chk("A6 동작표 " + s.name, s.actions.Length >= 4, s.actions.Length + "개 · " + act.ToString().TrimEnd()); + } + } + + // ── B. 부착 → 원복 ────────────────────────────────────────────────────── + static void B_AttachRestore() + { + L(""); + L("== B. 부착 → 원복 (원본 파괴 0 · 렌더러 원값 복원) =="); + var look = WLSpriteLookSettings.Instance; + var actor = Spawn(kPcPrefab, Vector3.zero, 0.7f); + var set = SpriteBillboard.MatchSet(actor.name, look); + Chk("B1 이름 매칭", set != null, "액터 '" + actor.name + "' → " + (set == null ? "매칭 실패" : set.name)); + if (set == null) { UnityEngine.Object.DestroyImmediate(actor); return; } + + var smrs = actor.GetComponentsInChildren(true); + int before = 0; foreach (var r in smrs) if (r.enabled) before++; + int childBefore = CountAll(actor); + + var e = SpriteBillboard.TryAttach(actor, set); + int after = 0; foreach (var r in smrs) if (r.enabled) after++; + Chk("B2 원본 끔", e != null && after == 0 && before > 0, "SMR " + before + "개 → 켜져 있는 것 " + after + "개"); + Chk("B3 쿼드 1개", e != null && e.quad != null, e == null ? "-" : e.quad.name + " · 부모 " + e.quad.transform.parent.name + " · 레이어 " + e.quad.layer); + Chk("B4 파괴 0", CountAll(actor) == childBefore + 1, "노드 " + childBefore + " → " + CountAll(actor) + " (쿼드 +1)"); + + SpriteBillboard.Detach(actor); + int restored = 0; foreach (var r in smrs) if (r != null && r.enabled) restored++; + Chk("B5 원복", restored == before && CountAll(actor) == childBefore, "SMR 켜짐 " + restored + "/" + before + " · 노드 " + CountAll(actor) + "/" + childBefore); + UnityEngine.Object.DestroyImmediate(actor); + } + + // ── C. 프레임 · 방향 선택 ─────────────────────────────────────────────── + static void C_FrameDir() + { + L(""); + L("== C. 프레임 · 방향 선택 (Animator 폴링 · 원본 코드 수정 0) =="); + var look = WLSpriteLookSettings.Instance; + var cam = MakeCam(kLowW, kLowH); + var actor = Spawn(kPcPrefab, Vector3.zero, 0.7f); + var set = SpriteBillboard.MatchSet(actor.name, look); + var anim = actor.GetComponent(); + anim.applyRootMotion = false; anim.cullingMode = AnimatorCullingMode.AlwaysAnimate; anim.Rebind(); + var e = SpriteBillboard.TryAttach(actor, set); + + // ⓐ 상태 해시 → 동작 + int okState = 0, allState = 0; + foreach (var a in set.actions) + foreach (var n in a.stateNames) + { + allState++; + var found = set.FindByStateHash(Animator.StringToHash(n)); + if (found == a) okState++; + } + Chk("C1 상태→동작", okState == allState, okState + "/" + allState + "개 상태가 정확한 동작으로 간다"); + + // ⓑ normalizedTime → 프레임 + var idle = set.FindByKey("idle"); + var lines = new StringBuilder(); + bool frameOk = true; + for (int f = 0; f < idle.frameCount; f++) + { + float nt = (f + 0.5f) / idle.frameCount; + anim.Play(Animator.StringToHash("idle"), 0, nt); + anim.Update(0f); + SpriteBillboard.UpdateAll(cam.cam); + if (e.frame != f) frameOk = false; + lines.Append("nt " + nt.ToString("0.00") + "→f" + e.frame + " "); + } + Chk("C2 시간→프레임", frameOk, lines.ToString().Trim()); + + // ⓑ-2 기본 상태가 아닌 동작도 폴링으로 맞는가 (에디트 모드 실측) + lines.Length = 0; int hit = 0, tot = 0; + foreach (var a in set.actions) + { + int h = Animator.StringToHash(a.stateNames[0]); + if (!anim.HasState(0, h)) continue; + tot++; + anim.Play(h, 0, 0.5f); + anim.Update(0f); + SpriteBillboard.UpdateAll(cam.cam); + bool ok = e.action != null && e.action.key == a.key; + if (ok) hit++; + lines.Append(a.key + "→" + (e.action == null ? "-" : e.action.key) + (ok ? " " : "✗ ")); + } + Chk("C2b 상태 폴링(에디트 모드)", hit == tot, hit + "/" + tot + " · " + lines.ToString().Trim()); + + // ⓒ 상대 yaw → 방향 + lines.Length = 0; bool dirOk = true; + anim.Play(Animator.StringToHash("idle"), 0, 0f); anim.Update(0f); + for (int d = 0; d < set.dirCount; d++) + { + actor.transform.rotation = Quaternion.Euler(0f, d * (360f / set.dirCount), 0f); + SpriteBillboard.UpdateAll(cam.cam); + if (e.dir != d) dirOk = false; + lines.Append(d * 45 + "°→d" + e.dir + " "); + } + Chk("C3 각도→방향", dirOk, lines.ToString().Trim()); + + // ⓓ 쿼드 크기 = 프레임 px × 픽셀 월드 크기 (스케일 보정 포함) + actor.transform.rotation = Quaternion.identity; + SpriteBillboard.UpdateAll(cam.cam); + float expect = set.frameWidth * set.worldPerPixel * (0.7f / set.bakeScale); + float got = e.quadTf.lossyScale.x; + Chk("C4 쿼드 크기", Mathf.Abs(got - expect) < 0.002f, + string.Format("월드 {0:0.0000} m (기대 {1:0.0000}) · 스케일 보정 {2:0.000}", got, expect, e.scaleK)); + Chk("C5 쿼드 자세", Quaternion.Angle(e.quadTf.rotation, cam.cam.transform.rotation) < 0.01f, + "카메라 정렬 오차 " + Quaternion.Angle(e.quadTf.rotation, cam.cam.transform.rotation).ToString("0.000") + "°"); + + SpriteBillboard.Detach(actor); + UnityEngine.Object.DestroyImmediate(actor); + cam.Dispose(); + } + + // ── D. GC ─────────────────────────────────────────────────────────────── + static void D_Gc() + { + L(""); + L("== D. GC (프레임당 할당 0) =="); + var look = WLSpriteLookSettings.Instance; + var cam = MakeCam(kLowW, kLowH); + var a1 = Spawn(kPcPrefab, Vector3.zero, 0.7f); + var a2 = Spawn(kMobPrefab, new Vector3(1.5f, 0f, 0f), 0f); + SpriteBillboard.TryAttach(a1, SpriteBillboard.MatchSet(a1.name, look)); + SpriteBillboard.TryAttach(a2, SpriteBillboard.MatchSet(a2.name, look)); + + for (int i = 0; i < 200; i++) SpriteBillboard.UpdateAll(cam.cam); // 워밍업 + GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); + long m0 = Profiler.GetMonoUsedSizeLong(); + int g0 = GC.CollectionCount(0); + for (int i = 0; i < 200000; i++) SpriteBillboard.UpdateAll(cam.cam); + long m1 = Profiler.GetMonoUsedSizeLong(); + int g1 = GC.CollectionCount(0); + Chk("D1 UpdateAll ×200k", m1 - m0 == 0 && g1 == g0, "mono Δ " + (m1 - m0) + " B · gen0 " + (g1 - g0) + "회"); + + SpriteBillboard.RestoreNow("gc-probe"); + UnityEngine.Object.DestroyImmediate(a1); UnityEngine.Object.DestroyImmediate(a2); + cam.Dispose(); + } + + // ── E. 시트 내용 ──────────────────────────────────────────────────────── + static void E_Sheet() + { + L(""); + L("== E. 시트 내용 (도트화가 실제로 강제됐는가) =="); + var look = WLSpriteLookSettings.Instance; + foreach (var s in look.sets) + { + if (s == null || s.sheet == null) continue; + var path = AssetDatabase.GetAssetPath(s.sheet); + var bytes = File.ReadAllBytes(path); + var t = new Texture2D(2, 2, TextureFormat.RGBA32, false, false); + t.LoadImage(bytes); + var px = t.GetPixels32(); + // 기대 팔레트 = 채널당 levels 단계 · 여기에 외곽선 색(SO)만 예외로 허용한다 + var bake = AssetDatabase.LoadAssetAtPath(kRes + "/WLSpriteBakeSettings.asset"); + int lv = bake != null ? bake.paletteLevels : 6; + var allowed = new HashSet(); + for (int i = 0; i < lv; i++) allowed.Add(Mathf.RoundToInt((float)i / (lv - 1) * 255f)); + Color32 oc = bake != null ? (Color32)bake.outlineColor : new Color32(14, 11, 17, 255); + + bool bands = bake == null || bake.paletteValueBands; + int opaque = 0, semi = 0, outline = 0, offPalette = 0; + var levels = new HashSet(); + var colors = new HashSet(); + for (int i = 0; i < px.Length; i++) + { + if (px[i].a == 0) continue; + if (px[i].a == 255) opaque++; else semi++; + levels.Add(bands ? Mathf.Max(px[i].r, Mathf.Max(px[i].g, px[i].b)) : px[i].r); + if (!bands) { levels.Add(px[i].g); levels.Add(px[i].b); } + colors.Add((px[i].r << 16) | (px[i].g << 8) | px[i].b); + bool isOutline = px[i].r == oc.r && px[i].g == oc.g && px[i].b == oc.b; + if (isOutline) { outline++; continue; } + if (bands) + { + if (!allowed.Contains(Mathf.Max(px[i].r, Mathf.Max(px[i].g, px[i].b)))) offPalette++; + } + else if (!allowed.Contains(px[i].r) || !allowed.Contains(px[i].g) || !allowed.Contains(px[i].b)) offPalette++; + } + Chk("E1 알파 이진화 " + s.name, semi == 0, "불투명 " + opaque + " · 반투명 " + semi + "(0 이어야 한다)"); + Chk("E2 팔레트 양자화 " + s.name, offPalette == 0, + (bands ? "밝기 " : "채널 ") + lv + "단계 " + Join(allowed) + " 밖 픽셀 " + offPalette + "개 · 실제 " + levels.Count + "가지 " + Join(levels) + + " (외곽선 색 " + oc.r + "," + oc.g + "," + oc.b + " 제외) · 색 " + colors.Count + "종"); + Chk("E3 외곽선 " + s.name, outline > opaque * 0.05f, "어두운 테두리 픽셀 " + outline + " / 불투명 " + opaque + + " (" + (100f * outline / Mathf.Max(1, opaque)).ToString("0.0") + " %)"); + Chk("E4 PNG 크기 " + s.name, bytes.Length > 0, bytes.Length.ToString("N0") + " B (" + (bytes.Length / 1024.0).ToString("0.0") + " KB) · " + + s.sheet.width + "×" + s.sheet.height + " · RGBA32 런타임 " + (s.sheet.width * s.sheet.height * 4 / 1024.0 / 1024.0).ToString("0.00") + " MB"); + UnityEngine.Object.DestroyImmediate(t); + } + } + + static string Join(HashSet s) + { + var l = new List(s); l.Sort(); + var sb = new StringBuilder("["); + foreach (var v in l) sb.Append(v).Append(' '); + return sb.ToString().TrimEnd() + "]"; + } + + // ── F. C8 (SO off → 원본 3D 100 %) ───────────────────────────────────── + static void F_C8() + { + L(""); + L("== F. C8 롤백 (SO off → 원본 3D 100 %) =="); + var look = WLSpriteLookSettings.Instance; + var actor = Spawn(kPcPrefab, Vector3.zero, 0.7f); + var smrs = actor.GetComponentsInChildren(true); + var mrs = actor.GetComponentsInChildren(true); + int smrOn0 = 0; foreach (var r in smrs) if (r.enabled) smrOn0++; + int mrOn0 = 0; foreach (var r in mrs) if (r.enabled) mrOn0++; + int nodes0 = CountAll(actor); + + SpriteBillboard.TryAttach(actor, SpriteBillboard.MatchSet(actor.name, look)); + WLSpriteLookSettings.RuntimeDisabled = true; + Chk("F1 게이트", !WLSpriteLookSettings.Enabled && !SpriteBillboard.ShouldBeOn, "RuntimeDisabled → Enabled=false · ShouldBeOn=false"); + int n = SpriteBillboard.RestoreNow("C8"); + WLSpriteLookSettings.RuntimeDisabled = false; + + int smrOn1 = 0; foreach (var r in smrs) if (r != null && r.enabled) smrOn1++; + int mrOn1 = 0; foreach (var r in mrs) if (r != null && r.enabled) mrOn1++; + Chk("F2 렌더러 100 % 복원", smrOn1 == smrOn0 && mrOn1 == mrOn0, "SMR " + smrOn1 + "/" + smrOn0 + " · MR " + mrOn1 + "/" + mrOn0); + Chk("F3 쿼드 0", CountAll(actor) == nodes0 && SpriteBillboard.ActiveCount == 0, "노드 " + CountAll(actor) + "/" + nodes0 + " · 대상 " + SpriteBillboard.ActiveCount); + + // 시트를 안 가진 액터는 아예 안 걸린다 + var other = Spawn("Assets/Res_Addr/PC/Ai02.prefab", Vector3.zero, 0.7f); + if (other != null) + { + Chk("F4 목록 밖 액터", SpriteBillboard.MatchSet(other.name, look) == null, "'" + other.name + "' → 매칭 0 = 원본 3D 그대로"); + UnityEngine.Object.DestroyImmediate(other); + } + UnityEngine.Object.DestroyImmediate(actor); + } + + // ═════════════════════════════════════════════════════════════════════════ + // 캡처 4장 + // ═════════════════════════════════════════════════════════════════════════ + public static void Capture() + { + s_sb = new StringBuilder(); s_pass = 0; s_fail = 0; + L("WL-814k 캡처 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + Directory.CreateDirectory(kOutDir); + try + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + World(); + var look = WLSpriteLookSettings.Instance; + + // 두 캐릭터를 나란히 (PC 왼쪽 · 몹 오른쪽) + var pc = Spawn(kPcPrefab, new Vector3(-1.0f, 0f, 0f), 0.7f); + var mob = Spawn(kMobPrefab, new Vector3(1.1f, 0f, 0f), 0f); + // 🔴 구운 프레임과 **정확히 같은 시각**으로 3D 를 세운다(프레임 양자화 차이를 A/B 에서 빼기 위해) + PoseFrame(pc, look, "attack", 2, 315f); + PoseFrame(mob, look, "attack", 3, 45f); + + var ground = Ground(); + var cam = MakeCam(kLowW, kLowH); + cam.cam.transform.position = new Vector3(0f, 1.0f, 0f) - cam.cam.transform.forward * 40f; + cam.cam.orthographicSize = kOrtho; + + // 지면만 찍은 기준 컷(실루엣을 차분으로 정확히 잰다) + pc.SetActive(false); mob.SetActive(false); + var bg = cam.Grab(); + pc.SetActive(true); mob.SetActive(true); + + // ⓐ 3D 원본 + var a = cam.Grab(); + SavePoint(a, kLowW, kLowH, kOutDir + @"\k_1_3d_original.png"); + L(" ⓐ 3D 원본 → k_1_3d_original.png"); + + // ⓑ 구운 스프라이트로 교체(같은 구도 · 같은 포즈 · 같은 방향) + var ePc = SpriteBillboard.TryAttach(pc, SpriteBillboard.MatchSet(pc.name, look)); + var eMob = SpriteBillboard.TryAttach(mob, SpriteBillboard.MatchSet(mob.name, look)); + SpriteBillboard.UpdateAll(cam.cam); + L(string.Format(" 폴링 결과 — PC {0} d{1} f{2} / 몹 {3} d{4} f{5}", + ePc.action != null ? ePc.action.key : "-", ePc.dir, ePc.frame, + eMob.action != null ? eMob.action.key : "-", eMob.dir, eMob.frame)); + // 🔴 A/B 는 「같은 포즈」여야 하므로 프레임을 못 박는다(폴링 정확도는 프로브 C 가 따로 잰다) + SpriteBillboard.SetManualFrame(pc, "attack", 7, 2); + SpriteBillboard.SetManualFrame(mob, "attack", 1, 3); + SpriteBillboard.UpdateAll(cam.cam); + var b = cam.Grab(); + SavePoint(b, kLowW, kLowH, kOutDir + @"\k_2_sprite_baked.png"); + L(" ⓑ 스프라이트 교체 → k_2_sprite_baked.png"); + + // 정렬 실측 — 같은 구도에서 3D 실루엣과 스프라이트 실루엣이 몇 px 어긋나는가 + var boxA = Box(a, bg, kLowW, kLowH, 0, kLowW / 2); + var boxB = Box(b, bg, kLowW, kLowH, 0, kLowW / 2); + L(string.Format(" 정렬 실측(PC 쪽 절반) — 3D x[{0}..{1}] y[{2}..{3}] / 스프라이트 x[{4}..{5}] y[{6}..{7}] → Δ좌 {8} · Δ우 {9} · Δ하 {10} · Δ상 {11} px", + boxA[0], boxA[1], boxA[2], boxA[3], boxB[0], boxB[1], boxB[2], boxB[3], + boxB[0] - boxA[0], boxB[1] - boxA[1], boxB[2] - boxA[2], boxB[3] - boxA[3])); + L(string.Format(" 밝기 실측 — 3D 평균 {0:0.0} · 스프라이트 평균 {1:0.0} (0~255 · 캐릭터 픽셀만) · 캐릭터 픽셀 3D {2} / 스프라이트 {3} (외곽선 +{4})", + MeanLum(a, bg), MeanLum(b, bg), CountDiff(a, bg), CountDiff(b, bg), CountDiff(b, bg) - CountDiff(a, bg))); + + // ⓒ 2배 클로즈업 — 위 3D / 아래 스프라이트 + CloseUp(a, b, bg, kLowW, kLowH, kOutDir + @"\k_3_closeup_2x.png"); + L(" ⓒ 클로즈업 → k_3_closeup_2x.png"); + + // ⓓ 방향 8종 한 장 + SpriteBillboard.RestoreNow("capture-dir"); + Directions(cam, pc, mob, ground, kOutDir + @"\k_4_directions.png"); + L(" ⓓ 방향 8종 → k_4_directions.png"); + + cam.Dispose(); + } + catch (Exception ex) { s_fail++; L("EXCEPTION " + ex); } + finally + { + SpriteBillboard.RestoreNow("capture-end"); + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + L(""); + L("캡처 " + (s_fail == 0 ? "PASS" : "FAIL") + " — " + kOutDir); + Write(kTxtCap); + } + + // 방향 8종을 한 장에 — 위 줄 = 3D · 아래 줄 = 스프라이트 + static void Directions(CamRig cam, GameObject pc, GameObject mob, GameObject ground, string file) + { + int cell = 64; // 셀 하나의 저해상도 픽셀 크기 + var rig = MakeCam(cell, cell); + rig.cam.transform.rotation = cam.cam.transform.rotation; + rig.cam.orthographicSize = cell * (2f * kOrtho / kLowH) * 0.5f; + mob.SetActive(false); + pc.transform.position = Vector3.zero; + + int cols = 8, rows = 2; + var sheet = new Color32[cols * cell * rows * cell]; + var look = WLSpriteLookSettings.Instance; + + for (int pass = 0; pass < 2; pass++) + { + if (pass == 1) + { + var e = SpriteBillboard.TryAttach(pc, SpriteBillboard.MatchSet(pc.name, look)); + } + for (int d = 0; d < cols; d++) + { + Pose(pc, "idle", 0.0f, d * 45f); + rig.cam.transform.position = new Vector3(0f, 0.6f, 0f) - rig.cam.transform.forward * 40f; + if (pass == 1) SpriteBillboard.UpdateAll(rig.cam); + var px = rig.Grab(); + BlitInto(px, cell, cell, sheet, cols * cell, d * cell, (rows - 1 - pass) * cell); + } + } + SpriteBillboard.RestoreNow("dir-capture"); + mob.SetActive(true); + SavePoint(sheet, cols * cell, rows * cell, file, 4); + rig.Dispose(); + } + + // 클로즈업 — 캐릭터 주변을 잘라 확대해 위/아래로 붙인다 + static void CloseUp(Color32[] a, Color32[] b, Color32[] bg, int w, int h, string file) + { + var box = Box(a, bg, w, h, 0, w); + int pad = 6; + int x0 = Mathf.Max(0, box[0] - pad), x1 = Mathf.Min(w - 1, box[1] + pad); + int y0 = Mathf.Max(0, box[2] - pad), y1 = Mathf.Min(h - 1, box[3] + pad); + int cw = x1 - x0 + 1, ch = y1 - y0 + 1; + int zoom = Mathf.Max(2, Mathf.Min(1080 / Mathf.Max(1, cw), 900 / Mathf.Max(1, ch))); + int outW = cw * zoom, outH = ch * zoom * 2 + 8; + var outPx = new Color32[outW * outH]; + for (int i = 0; i < outPx.Length; i++) outPx[i] = new Color32(24, 26, 30, 255); + // 아래 = 스프라이트 · 위 = 3D + CropZoom(b, w, h, x0, y0, cw, ch, zoom, outPx, outW, 0, 0); + CropZoom(a, w, h, x0, y0, cw, ch, zoom, outPx, outW, 0, ch * zoom + 8); + L(string.Format(" 클로즈업 crop {0}×{1} px → ×{2} = {3}×{4} (위 3D · 아래 스프라이트)", cw, ch, zoom, outW, outH)); + SaveRaw(outPx, outW, outH, file); + } + + static void CropZoom(Color32[] src, int w, int h, int x0, int y0, int cw, int ch, int zoom, + Color32[] dst, int dw, int dx, int dy) + { + for (int y = 0; y < ch * zoom; y++) + for (int x = 0; x < cw * zoom; x++) + { + int sx = x0 + x / zoom, sy = y0 + y / zoom; + if (sx < 0 || sy < 0 || sx >= w || sy >= h) continue; + int di = (dy + y) * dw + (dx + x); + if (di < 0 || di >= dst.Length) continue; + dst[di] = src[sy * w + sx]; + } + } + + /// 지면만 찍은 컷과 다른 픽셀 = 캐릭터 픽셀. + static bool Diff(Color32[] px, Color32[] bg, int i) + { + if (bg == null) return px[i].a >= 8; + return Mathf.Abs(px[i].r - bg[i].r) + Mathf.Abs(px[i].g - bg[i].g) + Mathf.Abs(px[i].b - bg[i].b) > 8 + || Mathf.Abs(px[i].a - bg[i].a) > 8; + } + + static float MeanLum(Color32[] px, Color32[] bg) + { + double sum = 0; int n = 0; + for (int i = 0; i < px.Length; i++) + { + if (!Diff(px, bg, i)) continue; + sum += 0.299 * px[i].r + 0.587 * px[i].g + 0.114 * px[i].b; n++; + } + return n == 0 ? 0f : (float)(sum / n); + } + + static int CountDiff(Color32[] px, Color32[] bg) + { + int n = 0; + for (int i = 0; i < px.Length; i++) if (Diff(px, bg, i)) n++; + return n; + } + + static int[] Box(Color32[] px, Color32[] bg, int w, int h, int xFrom, int xTo) + { + int minX = int.MaxValue, maxX = -1, minY = int.MaxValue, maxY = -1; + for (int y = 0; y < h; y++) + for (int x = xFrom; x < Mathf.Min(w, xTo); x++) + { + if (!Diff(px, bg, y * w + x)) continue; + if (x < minX) minX = x; if (x > maxX) maxX = x; + if (y < minY) minY = y; if (y > maxY) maxY = y; + } + return new[] { minX, maxX, minY, maxY }; + } + + /// 지면 — PD 가 「게임 화면처럼」 볼 수 있게 단색 평면 1장(커밋 0 · 임시 씬). + static GameObject Ground() + { + var go = GameObject.CreatePrimitive(PrimitiveType.Plane); + go.name = "[WL814k] Ground"; + go.transform.position = Vector3.zero; + go.transform.localScale = new Vector3(6f, 1f, 6f); + UnityEngine.Object.DestroyImmediate(go.GetComponent()); + var mr = go.GetComponent(); + var sh = Shader.Find("Universal Render Pipeline/Lit"); + var m = new Material(sh != null ? sh : Shader.Find("Standard")); + m.hideFlags = HideFlags.HideAndDontSave; + m.SetColor("_BaseColor", new Color(0.34f, 0.40f, 0.25f, 1f)); + m.SetFloat("_Smoothness", 0f); + mr.sharedMaterial = m; + mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + mr.receiveShadows = false; + return go; + } + + // ═════════════════════════════════════════════════════════════════════════ + // 공통 + // ═════════════════════════════════════════════════════════════════════════ + static void World() + { + var bake = AssetDatabase.LoadAssetAtPath(kRes + "/WLSpriteBakeSettings.asset"); + RenderSettings.fog = false; + RenderSettings.skybox = AssetDatabase.GetBuiltinExtraResource("Default-Skybox.mat"); + RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Skybox; + RenderSettings.ambientIntensity = 1f; + DynamicGI.UpdateEnvironment(); + var sun = new GameObject("Sun").AddComponent(); + sun.type = LightType.Directional; sun.shadows = LightShadows.None; + sun.color = bake != null ? bake.sunColor : Color.white; + sun.intensity = bake != null ? bake.sunIntensity : 1.2f; + sun.transform.rotation = Quaternion.Euler(bake != null ? bake.sunEuler : new Vector3(26.4f, 238.6f, 0f)); + if (bake != null && bake.fillIntensity > 0f) + { + var fill = new GameObject("Fill").AddComponent(); + fill.type = LightType.Directional; fill.shadows = LightShadows.None; + fill.color = bake.fillColor; fill.intensity = bake.fillIntensity; + fill.transform.rotation = Quaternion.Euler(bake.fillEuler); + } + } + + static GameObject Spawn(string prefabPath, Vector3 pos, float scale) + { + var src = AssetDatabase.LoadAssetAtPath(prefabPath); + if (src == null) return null; + var go = (GameObject)PrefabUtility.InstantiatePrefab(src); + PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + go.name = Path.GetFileNameWithoutExtension(prefabPath) + "(Clone)"; + go.transform.position = pos; go.transform.rotation = Quaternion.identity; + if (scale > 0.0001f) go.transform.localScale = Vector3.one * scale; + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c); + foreach (var c in go.GetComponentsInChildren(true)) UnityEngine.Object.DestroyImmediate(c.gameObject); + foreach (var mb in go.GetComponentsInChildren(true)) if (mb != null) UnityEngine.Object.DestroyImmediate(mb); + foreach (var sm in go.GetComponentsInChildren(true)) + { sm.updateWhenOffscreen = true; sm.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } + var an = go.GetComponent(); + if (an != null) { an.applyRootMotion = false; an.cullingMode = AnimatorCullingMode.AlwaysAnimate; an.Rebind(); } + // 굽기와 같은 Toon 머티리얼로(같은 조건 비교) + var bake = AssetDatabase.LoadAssetAtPath(kRes + "/WLSpriteBakeSettings.asset"); + if (bake != null && bake.useToonMaterials) + foreach (var rend in go.GetComponentsInChildren(true)) + { + if (rend == null || rend is ParticleSystemRenderer) continue; + var mats = rend.sharedMaterials; bool any = false; + for (int i = 0; i < mats.Length; i++) + { + if (mats[i] == null) continue; + var t = AssetDatabase.LoadAssetAtPath(bake.toonMaterialDir + "/" + mats[i].name + bake.toonMaterialSuffix + ".mat"); + if (t != null) { mats[i] = t; any = true; } + } + if (any) rend.sharedMaterials = mats; + } + return go; + } + + static void Pose(GameObject go, string state, float nt, float yaw) + { + go.transform.rotation = Quaternion.Euler(0f, yaw, 0f); + var an = go.GetComponent(); + if (an == null) return; + int h = Animator.StringToHash(state); + if (!an.HasState(0, h)) return; + an.Play(h, 0, nt); + an.Update(0f); + } + + /// 시트가 가진 프레임 f 와 **같은 시각**으로 3D 를 세운다(A/B 를 같은 포즈로 맞추기 위해). + static void PoseFrame(GameObject go, WLSpriteLookSettings look, string key, int frame, float yaw) + { + var set = SpriteBillboard.MatchSet(go.name, look); + var a = set != null ? set.FindByKey(key) : null; + if (a == null) { Pose(go, key, 0f, yaw); return; } + float nt = a.loop ? (frame + 0.001f) / a.frameCount : (a.frameCount > 1 ? (float)frame / (a.frameCount - 1) : 0f); + Pose(go, key, nt, yaw); + } + + static int CountAll(GameObject go) { return go.GetComponentsInChildren(true).Length; } + + sealed class CamRig + { + public Camera cam; public RenderTexture rt; public Texture2D tex; public int w, h; + public Color32[] Grab() + { + cam.targetTexture = rt; cam.Render(); cam.targetTexture = null; + var active = RenderTexture.active; RenderTexture.active = rt; + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); tex.Apply(false, false); + RenderTexture.active = active; + return tex.GetPixels32(); + } + public void Dispose() + { + RenderTexture.active = null; + if (rt != null) { rt.Release(); UnityEngine.Object.DestroyImmediate(rt); } + if (tex != null) UnityEngine.Object.DestroyImmediate(tex); + if (cam != null) UnityEngine.Object.DestroyImmediate(cam.gameObject); + } + } + + static CamRig MakeCam(int w, int h) + { + var go = new GameObject("[WL814k] CapCam"); + var c = go.AddComponent(); + c.orthographic = true; + c.orthographicSize = h * (2f * kOrtho / kLowH) * 0.5f; + c.nearClipPlane = 0.01f; c.farClipPlane = 200f; + c.clearFlags = CameraClearFlags.SolidColor; + c.backgroundColor = new Color(0.27f, 0.34f, 0.22f, 1f); // 지면 평면 밖은 이 색(지면이 화면을 덮는다) + c.allowHDR = false; c.allowMSAA = false; c.useOcclusionCulling = false; + go.transform.rotation = Quaternion.Euler(kPitch, 0f, 0f); + go.transform.position = new Vector3(0f, 1.0f, 0f) - go.transform.forward * 40f; + var rt = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + rt.filterMode = FilterMode.Point; rt.antiAliasing = 1; rt.Create(); + var tex = new Texture2D(w, h, TextureFormat.RGBA32, false, false); + return new CamRig { cam = c, rt = rt, tex = tex, w = w, h = h }; + } + + // 저해상도 → Point 확대 저장(도트 모드가 화면에 내보내는 방식 그대로) + static void SavePoint(Color32[] px, int w, int h, string file, int zoomOverride = 0) + { + int zoom = zoomOverride > 0 ? zoomOverride : Mathf.Max(1, kHiH / h); + int ow = w * zoom, oh = h * zoom; + var outPx = new Color32[ow * oh]; + for (int y = 0; y < oh; y++) + for (int x = 0; x < ow; x++) + outPx[y * ow + x] = px[(y / zoom) * w + (x / zoom)]; + SaveRaw(outPx, ow, oh, file); + } + + static void SaveRaw(Color32[] px, int w, int h, string file) + { + var t = new Texture2D(w, h, TextureFormat.RGBA32, false, false); + t.SetPixels32(px); t.Apply(false, false); + File.WriteAllBytes(file, t.EncodeToPNG()); + UnityEngine.Object.DestroyImmediate(t); + } + + static void BlitInto(Color32[] src, int sw, int sh, Color32[] dst, int dw, int dx, int dy) + { + for (int y = 0; y < sh; y++) + for (int x = 0; x < sw; x++) + { + int di = (dy + y) * dw + (dx + x); + if (di >= 0 && di < dst.Length) dst[di] = src[y * sw + x]; + } + } +} diff --git a/AgentScripts/WL814k_SURVEY.txt b/AgentScripts/WL814k_SURVEY.txt new file mode 100644 index 000000000..ffe94ba7b --- /dev/null +++ b/AgentScripts/WL814k_SURVEY.txt @@ -0,0 +1,147 @@ +WL-814k 실측 조사 · 2026-09-12 18:04:40 · Unity 6000.3.23f1 + +== ① 카메라 각 (WLLookModeSettings 프리셋 실측) == + [0] 기본 pixelRig=0 h=80 d=3 up=3 ortho=3.8 pxH=480 → 내림각 43.609° · 높이 5.433 m · 수평 4.591 m + [1] 도트A pixelRig=1 h=80 d=3 up=3 ortho=3.4 pxH=240 → 내림각 43.609° · 높이 5.433 m · 수평 4.591 m + [2] 도트B(넓게) pixelRig=1 h=80 d=3 up=3 ortho=4.6 pxH=240 → 내림각 43.609° · 높이 5.433 m · 수평 4.591 m + [3] 도트C(굵게) pixelRig=1 h=80 d=3 up=3 ortho=4.6 pxH=180 → 내림각 43.609° · 높이 5.433 m · 수평 4.591 m + 도트A: orthoSize 3.4 · pixelHeight 240 → 월드 1 m = 35.294 px · 픽셀 1개 = 0.02833 m + +== ② 프리팹 Assets/Res_Addr/PC/Ai01.prefab == + Animator = Ai01 + avatar = AiAvatar · isHuman=True · isValid=True + applyRootMotion = False · cullingMode = CullUpdateTransforms + controller = pcanim_mage (Assets/Res_Addr/Animations/pcanim_mage.controller) + clips = 26 + · LightHit len 1.000s fps 30 frames 30 loop False legacy False hasMotion True hasRoot True empty False + · death_F3441 len 2.100s fps 30 frames 63 loop False legacy False hasMotion False hasRoot True empty False + · Idle len 2.000s fps 30 frames 60 loop True legacy False hasMotion True hasRoot True empty False + · Run len 0.533s fps 30 frames 16 loop True legacy False hasMotion True hasRoot True empty False + · CastspellB_wing len 1.208s fps 24 frames 29 loop True legacy False hasMotion False hasRoot True empty False + · RangeAttack1 len 2.100s fps 30 frames 63 loop False legacy False hasMotion True hasRoot True empty False + · Atk2_wing len 1.500s fps 30 frames 45 loop True legacy False hasMotion False hasRoot True empty False + · Atk_A1_wing len 1.167s fps 24 frames 28 loop True legacy False hasMotion False hasRoot True empty False + · DashForward len 1.333s fps 30 frames 40 loop False legacy False hasMotion True hasRoot True empty False + · Land len 0.500s fps 30 frames 15 loop False legacy False hasMotion True hasRoot True empty False + · RangeAttack2 len 2.167s fps 30 frames 65 loop False legacy False hasMotion True hasRoot True empty False + · SpecialAttack1 len 2.167s fps 30 frames 65 loop False legacy False hasMotion True hasRoot True empty False + · SpecialAttack2 len 2.167s fps 30 frames 65 loop False legacy False hasMotion True hasRoot True empty False + · Stunned len 2.000s fps 30 frames 60 loop True legacy False hasMotion True hasRoot True empty False + · CastspellC_wing len 2.667s fps 24 frames 64 loop False legacy False hasMotion False hasRoot True empty False + · LyingFront len 1.333s fps 30 frames 40 loop True legacy False hasMotion False hasRoot True empty False + · LyingFront_WakeUp len 0.667s fps 30 frames 20 loop False legacy False hasMotion False hasRoot True empty False + · Face_SmileA len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_Ang1 len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_SmileB len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_Ang3 len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_Ang2 len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_SadA len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_SadB len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_Surprise len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + · Face_EyeClose len 1.633s fps 30 frames 49 loop False legacy False hasMotion False hasRoot False empty False + layers = 2 + layer[0] Base Layer · states 17 · default=idle + hit|LightHit|hash 1523721793|full -62788552 + die|death_F3441|hash 964231127|full -1611975250 + idle|Idle|hash -601574123|full -178524345 + run|Run|hash 1349952704|full -152736071 + casting|CastspellB_wing|hash -786711984|full 1053661652 + skill2|RangeAttack1|hash -722835594|full -673593035 + attack|Atk2_wing|hash 1203776827|full 1156809592 + attack2|Atk_A1_wing|hash -1415997692|full 1146074240 + dodge|DashForward|hash -1854944626|full 337872140 + land|Land|hash -1476340264|full -2122346614 + skill3|RangeAttack2|hash -1544726560|full -1595999837 + skill4|SpecialAttack1|hash 1032438339|full 1052404736 + skill5|SpecialAttack2|hash 1250882261|full 1237146774 + stun|Stunned|hash -210448114|full -636777636 + casting_end|CastspellC_wing|hash 380729335|full -1453968558 + lying|LyingFront|hash -478560198|full 1714786232 + getup|LyingFront_WakeUp|hash -1333958798|full 892414192 + layer[1] Emotion · states 11 · default=New State + New State|-|hash -499022955|full 833042322 + SmileA (Emotion)|Face_SmileA|hash 371072321|full -1047046492 + ANG1 (Emotion) 0|Face_Ang1|hash 1042426016|full -374643899 + Indifferent (Emotion)|-|hash 1209094866|full -995248490 + SmileB (Emotion)|Face_SmileB|hash -1879278784|full 1484075173 + ANG3 (Emotion)|Face_Ang3|hash 199512751|full 749628860 + ANG2 (Emotion)|Face_Ang2|hash -898986641|full -316624260 + SadA (Emotion)|Face_SadA|hash -774383980|full -157423225 + SadB (Emotion)|Face_SadB|hash 1211478165|full 1870630790 + Surprise (Emotion)|Face_Surprise|hash -1812836920|full 1375012336 + EyeClose (Emotion)|Face_EyeClose|hash -302154122|full 804927054 + SkinnedMeshRenderer = 11 · MeshRenderer = 2 + 삼각형 합계 = 16645 · 머티리얼 10종 + Ai_hair [Toon/Toon] + Ai_cloth [Toon/Toon] + Ai_skin [Toon/Toon] + bikini10 [Toon/Toon] + Ai_eyeline [Toon/Toon] + Ai_eyeL [Unlit/Transparent] + Ai_eyeR [Unlit/Transparent] + Ai_face [Toon/Toon] + Ai_Lash [Toon/Toon] + cheek [Unlit/Transparent] + bones[0] = 41 + transform 노드 = 223 + root localScale = (1.0000, 1.0000, 1.0000) + root comp: UnityEngine.Transform + root comp: UnityEngine.Animator + root comp: WizardActor + root comp: UnityEngine.AI.NavMeshAgent + root comp: UnityEngine.Rigidbody + root comp: UnityEngine.CapsuleCollider + root comp: SkinnedMeshAfterImage + 바운드(스케일 1) center (0.0000, 0.7372, -0.0195) size (1.3047, 1.7017, 1.0770) · 높이 1.7017 m + 바운드(스케일 0.7) 높이 1.1912 m · 폭 0.9133 m · 깊이 0.7539 m + +== ② 프리팹 Assets/Res_Addr/Mobs/Mob/Batty_A.prefab == + Animator = Batty_A + avatar = BattyAvatar · isHuman=False · isValid=True + applyRootMotion = False · cullingMode = CullUpdateTransforms + controller = Batty_Animations_Check (Assets/ResWork/Suriyun/Monster Pack Darkness/Animations/Batty/Batty_Animations_Check.controller) + clips = 8 + · Move len 0.958s fps 24 frames 23 loop True legacy False hasMotion False hasRoot False empty False + · Idle len 0.958s fps 24 frames 23 loop True legacy False hasMotion False hasRoot False empty False + · Attack len 0.583s fps 24 frames 14 loop True legacy False hasMotion False hasRoot False empty False + · Damage len 0.583s fps 24 frames 14 loop True legacy False hasMotion False hasRoot False empty False + · Die len 1.000s fps 24 frames 24 loop False legacy False hasMotion False hasRoot False empty False + · stun len 0.958s fps 24 frames 23 loop True legacy False hasMotion False hasRoot False empty False + · casting len 0.958s fps 24 frames 23 loop True legacy False hasMotion False hasRoot False empty False + · casting_end len 0.583s fps 24 frames 14 loop True legacy False hasMotion False hasRoot False empty False + layers = 1 + layer[0] Base Layer · states 8 · default=idle + run|Move|hash 1349952704|full -152736071 + idle|Idle|hash -601574123|full -178524345 + attack|Attack|hash 1203776827|full 1156809592 + hit|Damage|hash 1523721793|full -62788552 + die|Die|hash 964231127|full -1611975250 + stun|stun|hash -210448114|full -636777636 + casting|casting|hash -786711984|full 1053661652 + casting_end|casting_end|hash 380729335|full -1453968558 + SkinnedMeshRenderer = 1 · MeshRenderer = 0 + 삼각형 합계 = 896 · 머티리얼 1종 + T_Batty_A [MK/Toon/URP/Standard/Simple] + bones[0] = 8 + transform 노드 = 11 + root localScale = (1.5000, 1.5000, 1.5000) + root comp: UnityEngine.Transform + root comp: UnityEngine.Animator + root comp: MobActor + root comp: UnityEngine.BoxCollider + root comp: NoSeeLongDMob + root comp: UnityEngine.AI.NavMeshAgent + root comp: UnityEngine.Rigidbody + 바운드(스케일 1) center (0.0000, 0.3453, -0.0006) size (0.9355, 0.5372, 0.3566) · 높이 0.5372 m + 바운드(스케일 0.7) 높이 0.2507 m · 폭 0.4366 m · 깊이 0.1664 m + +== ③ 캐릭터 프리팹 수 (확장 견적 근거) == + Res_Addr/PC 프리팹 = 46 + Res_Addr/Mobs 프리팹 = 299 + 그중 Animator+Controller 보유 = 299 · 서로 다른 컨트롤러 79종 + +== ④ 814c Toon 머티리얼 == + Assets/WL/Look/Env/Materials = 258개 + 'Ai_*' → 6개: Ai_cloth_Toon.mat, Ai_eyeline_Toon.mat, Ai_face_Toon.mat, Ai_hair_Toon.mat, Ai_Lash_Toon.mat, Ai_skin_Toon.mat + 'Batty*' → 0개: + WLEnvLookSettings = 있음 diff --git a/AgentScripts/WL814k_SURVEY2.txt b/AgentScripts/WL814k_SURVEY2.txt new file mode 100644 index 000000000..d8b3ec2d3 --- /dev/null +++ b/AgentScripts/WL814k_SURVEY2.txt @@ -0,0 +1,38 @@ +WL-814k 실측 ② · 2026-09-12 18:06:23 + +== 방향광 (Res_Addr/Map/WL_Nature.prefab + Ingame 씬) == + [map] Sun type=Directional color=RGBA(1.000, 0.920, 0.703, 1.000) intensity=1.2 shadows=Soft euler=(26.40, 238.60, 0.00) + [map] Sun_Ambient type=Directional color=RGBA(0.596, 0.703, 0.839, 1.000) intensity=0.3 shadows=None euler=(36.10, 116.10, 0.00) + Assets/Scenes/Ingame.unity · Light(dir) 블록 없음 · 파일 21830 B + Assets/Scenes/Title.unity · Light(dir) 블록 있음 · 파일 54278 B + RenderSettings.ambientMode(현재 씬) = Skybox · ambientLight = RGBA(0.212, 0.227, 0.259, 1.000) · ambientIntensity = 1 · sun = null + +== Toon 매칭 Assets/Res_Addr/PC/Ai01.prefab == + Ai_hair [Toon/Toon] → Toon 있음 + Ai_cloth [Toon/Toon] → Toon 있음 + Ai_skin [Toon/Toon] → Toon 있음 + bikini10 [Toon/Toon] → Toon 있음 + Ai_eyeline [Toon/Toon] → Toon 있음 + cheek [Unlit/Transparent] → Toon 없음 + Ai_eyeL [Unlit/Transparent] → Toon 없음 + Ai_eyeR [Unlit/Transparent] → Toon 없음 + Ai_face [Toon/Toon] → Toon 있음 + Ai_Lash [Toon/Toon] → Toon 있음 + +== Toon 매칭 Assets/Res_Addr/Mobs/Mob/Batty_A.prefab == + T_Batty_A [MK/Toon/URP/Standard/Simple] → Toon 있음 + +== 샘플링 경로 (AnimationMode.SampleAnimationClip) == + Ai01 · clip Idle · probe joint31 · Δpos 0.0000 · Δrot 0.00° → 변화 없음(확인필요) + Batty_A · clip Attack · probe wing_l1 · Δpos 0.0000 · Δrot 49.40° → 샘플링 OK + +== 렌더 파이프라인 == + defaultRenderPipeline = URP-Performant (Assets/Settings/URP-Performant.asset) + currentRenderPipeline = URP-Balanced + QualitySettings.renderPipeline = URP-Balanced + SystemInfo.graphicsDeviceType = Direct3D11 · supportsComputeShaders = True + Application.isBatchMode = True + Shader.Find("Sprites/Default") = OK + Shader.Find("Unlit/Transparent") = OK + Shader.Find("Universal Render Pipeline/Unlit") = OK + Shader.Find("Universal Render Pipeline/2D/Sprite-Unlit-Default") = OK diff --git a/AgentScripts/WL814k_SURVEY3.txt b/AgentScripts/WL814k_SURVEY3.txt new file mode 100644 index 000000000..2f09358b0 --- /dev/null +++ b/AgentScripts/WL814k_SURVEY3.txt @@ -0,0 +1,15 @@ +WL-814k 실측 ③ 샘플링 · 2026-09-12 18:07:00 + +== Assets/Res_Addr/PC/Ai01.prefab == + Idle len 2.00s · AnimationMode Δbounds 2.3995 m · SampleAnimation Δbounds 2.3995 m + Run len 0.53s · AnimationMode Δbounds 2.7951 m · SampleAnimation Δbounds 4.2027 m + Atk2_wing len 1.50s · AnimationMode Δbounds 2.6478 m · SampleAnimation Δbounds 3.8505 m + LightHit len 1.00s · AnimationMode Δbounds 3.1135 m · SampleAnimation Δbounds 3.1256 m + death_F3441 len 2.10s · AnimationMode Δbounds 2.7651 m · SampleAnimation Δbounds 5.0011 m + +== Assets/Res_Addr/Mobs/Mob/Batty_A.prefab == + Idle len 0.96s · AnimationMode Δbounds 1.1362 m · SampleAnimation Δbounds 1.1362 m + Move len 0.96s · AnimationMode Δbounds 1.1362 m · SampleAnimation Δbounds 1.1362 m + Attack len 0.58s · AnimationMode Δbounds 1.1362 m · SampleAnimation Δbounds 1.1362 m + Damage len 0.58s · AnimationMode Δbounds 1.1362 m · SampleAnimation Δbounds 1.1362 m + Die len 1.00s · AnimationMode Δbounds 1.1362 m · SampleAnimation Δbounds 1.1362 m diff --git a/AgentScripts/WL814k_Survey.cs b/AgentScripts/WL814k_Survey.cs new file mode 100644 index 000000000..73f1629c6 --- /dev/null +++ b/AgentScripts/WL814k_Survey.cs @@ -0,0 +1,205 @@ +// WL-814k 실측 조사 (게임 코드 아님 · 에디트 모드 전용 · 에셋 수정 0 · 읽기만) +// run: unity command run_script --file AgentScripts/WL814k_Survey.cs --entry WL814k_Survey.Run +// 🔴 원본 프리팹/머티리얼/애니메이션 수정 0. AssetDatabase.SaveAssets 호출 0. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; + +public static class WL814k_Survey +{ + const string kTxt = "AgentScripts/WL814k_SURVEY.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") + " · Unity " + Application.unityVersion); + + try + { + Cam(); + Prefab("Assets/Res_Addr/PC/Ai01.prefab"); + Prefab("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab"); + Counts(); + ToonMats(); + } + catch (Exception ex) { L("EXCEPTION " + ex); } + + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + Debug.Log("[WL814k] → " + kTxt); + } + + // ── ① 카메라 각 (811o 수식 그대로 · 814d 프리셋 값) ────────────────────── + static void Cam() + { + L(""); + L("== ① 카메라 각 (WLLookModeSettings 프리셋 실측) =="); + var so = Resources.Load("WL/WLLookModeSettings"); + if (so == null) { L(" WLLookModeSettings 없음"); return; } + for (int i = 0; i < so.presets.Length; i++) + { + var p = so.presets[i]; + float down = WL.CameraFraming.CameraFramingOverride.DownAngleDeg(p.cameraHeight, p.distance, p.distanceUp); + float above = WL.CameraFraming.CameraFramingOverride.CamHeightAbove(p.cameraHeight, p.distance, p.distanceUp); + float horiz = WL.CameraFraming.CameraFramingOverride.CamHorizontal(p.cameraHeight, p.distance); + L(string.Format(" [{0}] {1} pixelRig={2} h={3} d={4} up={5} ortho={6} pxH={7} → 내림각 {8:0.000}° · 높이 {9:0.000} m · 수평 {10:0.000} m", + i, p.name, p.pixelRig ? 1 : 0, p.cameraHeight, p.distance, p.distanceUp, p.orthoSize, p.pixelHeight, down, above, horiz)); + } + // 도트A 프리셋 기준 캐릭터 픽셀 + var d = so.presets.Length > 1 ? so.presets[1] : null; + if (d != null) + L(string.Format(" 도트A: orthoSize {0} · pixelHeight {1} → 월드 1 m = {2:0.000} px · 픽셀 1개 = {3:0.00000} m", + d.orthoSize, d.pixelHeight, d.pixelHeight / (2f * d.orthoSize), (2f * d.orthoSize) / d.pixelHeight)); + } + + // ── ② 프리팹 전수 ──────────────────────────────────────────────────────── + static void Prefab(string path) + { + L(""); + L("== ② 프리팹 " + path + " =="); + var go = AssetDatabase.LoadAssetAtPath(path); + if (go == null) { L(" 로드 실패"); return; } + + var anim = go.GetComponentInChildren(true); + L(" Animator = " + (anim == null ? "없음" : anim.gameObject.name)); + if (anim != null) + { + L(" avatar = " + (anim.avatar == null ? "null" : anim.avatar.name + " · isHuman=" + anim.avatar.isHuman + " · isValid=" + anim.avatar.isValid)); + L(" applyRootMotion = " + anim.applyRootMotion + " · cullingMode = " + anim.cullingMode); + var rac = anim.runtimeAnimatorController; + L(" controller = " + (rac == null ? "null" : rac.name + " (" + AssetDatabase.GetAssetPath(rac) + ")")); + if (rac != null) + { + var clips = rac.animationClips; + L(" clips = " + clips.Length); + var seen = new HashSet(); + foreach (var c in clips) + { + if (c == null || !seen.Add(c.name)) continue; + L(string.Format(" · {0,-28} len {1,6:0.000}s fps {2,5:0.#} frames {3,4} loop {4} legacy {5} hasMotion {6} hasRoot {7} empty {8}", + c.name, c.length, c.frameRate, Mathf.RoundToInt(c.length * c.frameRate), c.isLooping, c.legacy, c.hasMotionCurves, c.hasRootCurves, c.empty)); + } + var ac = rac as UnityEditor.Animations.AnimatorController; + if (ac != null) + { + L(" layers = " + ac.layers.Length); + for (int li = 0; li < ac.layers.Length; li++) + { + var lay = ac.layers[li]; + var sm = lay.stateMachine; + if (sm == null) { L(" layer[" + li + "] " + lay.name + " (stateMachine null)"); continue; } + var names = new List(); + foreach (var st in sm.states) + names.Add(st.state.name + "|" + (st.state.motion == null ? "-" : st.state.motion.name) + "|hash " + Animator.StringToHash(st.state.name) + + "|full " + Animator.StringToHash(lay.name + "." + st.state.name)); + L(" layer[" + li + "] " + lay.name + " · states " + names.Count + " · default=" + (sm.defaultState == null ? "-" : sm.defaultState.name)); + foreach (var n in names) L(" " + n); + } + } + } + } + + var smrs = go.GetComponentsInChildren(true); + var mrs = go.GetComponentsInChildren(true); + L(" SkinnedMeshRenderer = " + smrs.Length + " · MeshRenderer = " + mrs.Length); + int tri = 0; var mats = new HashSet(); + foreach (var r in smrs) + { + if (r.sharedMesh != null) tri += r.sharedMesh.triangles.Length / 3; + foreach (var m in r.sharedMaterials) if (m != null) mats.Add(m.name + " [" + (m.shader == null ? "-" : m.shader.name) + "]"); + } + foreach (var r in mrs) + { + var mf = r.GetComponent(); + if (mf != null && mf.sharedMesh != null) tri += mf.sharedMesh.triangles.Length / 3; + foreach (var m in r.sharedMaterials) if (m != null) mats.Add(m.name + " [" + (m.shader == null ? "-" : m.shader.name) + "]"); + } + L(" 삼각형 합계 = " + tri + " · 머티리얼 " + mats.Count + "종"); + foreach (var m in mats) L(" " + m); + + // 본 수 + if (smrs.Length > 0 && smrs[0].bones != null) L(" bones[0] = " + smrs[0].bones.Length); + var allT = go.GetComponentsInChildren(true); + L(" transform 노드 = " + allT.Length); + + // 스케일·ClassConfig + L(" root localScale = " + go.transform.localScale.ToString("F4")); + foreach (var c in go.GetComponents()) + if (c != null) L(" root comp: " + c.GetType().FullName); + + // 인스턴스를 임시로 만들어 바운드 실측(씬 저장 0) + var inst = (GameObject)PrefabUtility.InstantiatePrefab(go); + try + { + inst.transform.position = Vector3.zero; + inst.transform.rotation = Quaternion.identity; + var b = WorldBounds(inst); + L(string.Format(" 바운드(스케일 1) center {0} size {1} · 높이 {2:0.0000} m", b.center.ToString("F4"), b.size.ToString("F4"), b.size.y)); + inst.transform.localScale = Vector3.one * 0.7f; + var b7 = WorldBounds(inst); + L(string.Format(" 바운드(스케일 0.7) 높이 {0:0.0000} m · 폭 {1:0.0000} m · 깊이 {2:0.0000} m", b7.size.y, b7.size.x, b7.size.z)); + } + finally { UnityEngine.Object.DestroyImmediate(inst); } + } + + static Bounds WorldBounds(GameObject root) + { + var rs = root.GetComponentsInChildren(true); + bool any = false; var b = new Bounds(); + foreach (var r in rs) + { + if (r == null || r is ParticleSystemRenderer) continue; + if (!any) { b = r.bounds; any = true; } + else b.Encapsulate(r.bounds); + } + return b; + } + + // ── ③ 전 캐릭터 수 (확장 견적용) ──────────────────────────────────────── + static void Counts() + { + L(""); + L("== ③ 캐릭터 프리팹 수 (확장 견적 근거) =="); + var pc = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Res_Addr/PC" }); + var mob = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Res_Addr/Mobs" }); + L(" Res_Addr/PC 프리팹 = " + pc.Length); + L(" Res_Addr/Mobs 프리팹 = " + mob.Length); + int mobWithAnim = 0; var ctrls = new HashSet(); + foreach (var g in mob) + { + var p = AssetDatabase.GUIDToAssetPath(g); + var go = AssetDatabase.LoadAssetAtPath(p); + if (go == null) continue; + var a = go.GetComponentInChildren(true); + if (a != null && a.runtimeAnimatorController != null) { mobWithAnim++; ctrls.Add(a.runtimeAnimatorController.name); } + } + L(" 그중 Animator+Controller 보유 = " + mobWithAnim + " · 서로 다른 컨트롤러 " + ctrls.Count + "종"); + } + + // ── ④ Toon 머티리얼 (814c) ────────────────────────────────────────────── + static void ToonMats() + { + L(""); + L("== ④ 814c Toon 머티리얼 =="); + string dir = "Assets/WL/Look/Env/Materials"; + var all = AssetDatabase.FindAssets("t:Material", new[] { dir }); + L(" " + dir + " = " + all.Length + "개"); + foreach (var key in new[] { "Ai_", "Batty" }) + { + var hits = new List(); + foreach (var g in all) + { + var p = AssetDatabase.GUIDToAssetPath(g); + if (Path.GetFileName(p).StartsWith(key, StringComparison.OrdinalIgnoreCase)) hits.Add(Path.GetFileName(p)); + } + L(" '" + key + "*' → " + hits.Count + "개: " + string.Join(", ", hits.ToArray())); + } + var envSo = Resources.Load("WL/WLEnvLookSettings"); + L(" WLEnvLookSettings = " + (envSo == null ? "없음" : "있음")); + } +} diff --git a/AgentScripts/WL814k_Survey2.cs b/AgentScripts/WL814k_Survey2.cs new file mode 100644 index 000000000..f1ebf2bb5 --- /dev/null +++ b/AgentScripts/WL814k_Survey2.cs @@ -0,0 +1,133 @@ +// 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" : "없음")); + } +} diff --git a/AgentScripts/WL814k_Survey3.cs b/AgentScripts/WL814k_Survey3.cs new file mode 100644 index 000000000..a194860aa --- /dev/null +++ b/AgentScripts/WL814k_Survey3.cs @@ -0,0 +1,87 @@ +// WL-814k 실측 조사 ③ — Humanoid/Generic 샘플링 경로 확정 (읽기만) +// run: unity command run_script --file AgentScripts/WL814k_Survey3.cs --entry WL814k_Survey3.Run + +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; + +public static class WL814k_Survey3 +{ + const string kTxt = "AgentScripts/WL814k_SURVEY3.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 + { + Test("Assets/Res_Addr/PC/Ai01.prefab", new[] { "Idle", "Run", "Atk2_wing", "LightHit", "death_F3441" }); + Test("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab", new[] { "Idle", "Move", "Attack", "Damage", "Die" }); + } + catch (Exception ex) { L("EXCEPTION " + ex); } + finally { if (AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode(); } + File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); + Debug.Log("[WL814k] → " + kTxt); + } + + static void Test(string prefab, string[] clipNames) + { + L(""); + L("== " + prefab + " =="); + var src = AssetDatabase.LoadAssetAtPath(prefab); + var inst = (GameObject)PrefabUtility.InstantiatePrefab(src); + inst.transform.position = Vector3.zero; inst.transform.rotation = Quaternion.identity; + try + { + var anim = inst.GetComponentInChildren(true); + var rac = anim.runtimeAnimatorController; + foreach (var name in clipNames) + { + AnimationClip clip = null; + foreach (var c in rac.animationClips) if (c.name == name) { clip = c; break; } + if (clip == null) { L(" " + name + " → 클립 없음"); continue; } + + // ⓐ AnimationMode 경로 + float aSpread = Spread(inst, clip, true); + // ⓑ clip.SampleAnimation 경로 + float bSpread = Spread(inst, clip, false); + L(string.Format(" {0,-14} len {1,5:0.00}s · AnimationMode Δbounds {2:0.0000} m · SampleAnimation Δbounds {3:0.0000} m", + name, clip.length, aSpread, bSpread)); + } + } + finally { if (AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode(); UnityEngine.Object.DestroyImmediate(inst); } + } + + // 클립을 8등분해 찍고, 전체 렌더러 바운드 중심의 최대 이동량(= 실제로 포즈가 바뀌었는가) + static float Spread(GameObject inst, AnimationClip clip, bool useAnimationMode) + { + var rs = inst.GetComponentsInChildren(true); + Vector3 min = Vector3.positiveInfinity, max = Vector3.negativeInfinity; + for (int i = 0; i < 8; i++) + { + float t = clip.length * i / 8f; + if (useAnimationMode) + { + AnimationMode.StartAnimationMode(); + AnimationMode.BeginSampling(); + AnimationMode.SampleAnimationClip(inst, clip, t); + AnimationMode.EndSampling(); + AnimationMode.StopAnimationMode(); + } + else + { + clip.SampleAnimation(inst, t); + } + Bounds b = new Bounds(); bool any = false; + foreach (var r in rs) { if (!any) { b = r.bounds; any = true; } else b.Encapsulate(r.bounds); } + if (!any) continue; + min = Vector3.Min(min, b.min); max = Vector3.Max(max, b.max); + } + if (float.IsInfinity(min.x)) return -1f; + return (max - min).magnitude; + } +} diff --git a/Assets/WL/Look/Sprite.meta b/Assets/WL/Look/Sprite.meta new file mode 100644 index 000000000..05ccbf19e --- /dev/null +++ b/Assets/WL/Look/Sprite.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b1e4280b824eb84c9918c582b2df1b1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/WL/Look/Sprite/Baked.meta b/Assets/WL/Look/Sprite/Baked.meta new file mode 100644 index 000000000..6f502d786 --- /dev/null +++ b/Assets/WL/Look/Sprite/Baked.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f60da21b8811ca438a64ff9cf16bd2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/WL/Look/Sprite/Baked/Ai01.png b/Assets/WL/Look/Sprite/Baked/Ai01.png new file mode 100644 index 0000000000000000000000000000000000000000..8e040c004919409e5dcc9b79862b7ef8d54293ee GIT binary patch literal 165716 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

p%ev2x5kFkiPqXnzpI%L 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�*PkXL&ET4yzlfF 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