diff --git a/AgentScripts/WL815c_CAPTURE.txt b/AgentScripts/WL815c_CAPTURE.txt new file mode 100644 index 000000000..135aa621f --- /dev/null +++ b/AgentScripts/WL815c_CAPTURE.txt @@ -0,0 +1,14 @@ +WL-815c 장벽 3스타일 캡처 · 2026-09-11 00:59:27 + 앵커 (115.0, 0.4, -22.0) 반경 14 m · 구도 811o(h 76 · yaw 233) + PASS E0 맵 — WL_Nature + 존1 지면 실측 y = 0.19 (앵커 표기 y 0.4) + PASS E1 PC — Ai01 중앙(크기 비교 기준) + PASS E barrier_ring_persp.png — MagicRing · 인스턴스 3 · 렌더러 12 · 머티리얼 1 · tri 0 · PS 12 · 링 스케일 12.27 · 원근 FOV 45 · 거리 64.9 m · 474482 B · 색 837종 · 따뜻한픽셀 3630 · drawCalls 0 · batches 0 · tri 0 + PASS E barrier_ring_pixel.png — MagicRing · 인스턴스 3 · 렌더러 12 · 머티리얼 1 · tri 0 · PS 12 · 링 스케일 12.27 · 직교 size 26.1 · 270×480 → Point 확대 · 145042 B · 색 975종 · 따뜻한픽셀 3609 · drawCalls 0 · batches 0 · tri 0 + PASS E barrier_props_persp.png — Props · 인스턴스 35 · 렌더러 35 · 머티리얼 2 · tri 4530 · PS 0 · 프롭 35 · 간격 2.51 m · 원근 FOV 45 · 거리 64.9 m · 425850 B · 색 795종 · 따뜻한픽셀 3647 · drawCalls 0 · batches 0 · tri 0 + PASS E barrier_props_pixel.png — Props · 인스턴스 35 · 렌더러 35 · 머티리얼 2 · tri 4530 · PS 0 · 프롭 35 · 간격 2.51 m · 직교 size 26.1 · 270×480 → Point 확대 · 138475 B · 색 901종 · 따뜻한픽셀 3628 · drawCalls 0 · batches 0 · tri 0 + PASS E barrier_fire_persp.png — Fire · 인스턴스 35 · 렌더러 105 · 머티리얼 3 · tri 0 · PS 105 · 불꽃 35 · 방출률 ×0.37 · 파티클 1600 · 원근 FOV 45 · 거리 64.9 m · 412816 B · 색 759종 · 따뜻한픽셀 3661 · drawCalls 0 · batches 0 · tri 0 + PASS E barrier_fire_pixel.png — Fire · 인스턴스 35 · 렌더러 105 · 머티리얼 3 · tri 0 · PS 105 · 불꽃 35 · 방출률 ×0.37 · 파티클 1600 · 직교 size 26.1 · 270×480 → Point 확대 · 135914 B · 색 858종 · 따뜻한픽셀 3639 · drawCalls 0 · batches 0 · tri 0 + 클리어 연출 중간(t=0.5) 활성 35 · 진행도 0.50 + +RESULT PASS · 8 PASS · 0 FAIL diff --git a/AgentScripts/WL815c_Capture.cs b/AgentScripts/WL815c_Capture.cs new file mode 100644 index 000000000..332d350cb --- /dev/null +++ b/AgentScripts/WL815c_Capture.cs @@ -0,0 +1,241 @@ +// ───────────────────────────────────────────────────────────────────────────── +// WL815c_Capture.cs — PD 대안 비교 캡처 6장 (에디트 모드 · 임시 씬 저장 0 · 커밋 0) +// unity command run_script --file AgentScripts/WL815c_Capture.cs --entry WL815c_Capture.Run +// +// 3스타일(마법진 링 / 프롭 링 / 불꽃 링) × 2구도 +// persp : 811o 구도 각도(cameraHeight 76 · MapZoneData yaw 233 실측) · 원근 · 반경 14 m 전체가 보이게 거리만 확장 +// pixel : 814c 방식 = 직교 270×480 렌더 → Point 확대 1080×1920 (도트 룩에서 뭉개지는지 본다) +// 앵커 = 기준서 §D-1 존1 (115, 0.4, −22) · 반경 14 +// ───────────────────────────────────────────────────────────────────────────── + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Rendering.Universal; +using UnityEngine.SceneManagement; +using WL.Combat.Stage; + +public static class WL815c_Capture +{ + const string kOutDir = @"E:\NerdNavis\nn_himminji\Screenshots_WL\WL815c"; + const string kTxt = "AgentScripts/WL815c_CAPTURE.txt"; + const string kMapPrefab = "Assets/Res_Addr/Map/WL_Nature.prefab"; + const string kPcPrefab = "Assets/Res_Addr/PC/Ai01.prefab"; + + const int kLowW = 270, kLowH = 480, kHiW = 1080, kHiH = 1920; + const float kMapYaw = 233f; // WL_Nature MapZoneData.CamRot_Portal 실측(811o) + const float kCamH = 76f; // WLCameraFramingSettings.cameraHeight 실측(811o) + + static readonly Vector3 kAnchor = new Vector3(115f, 0.4f, -22f); + const float kRadius = 14f; + + static StringBuilder s_sb; + static int s_pass, s_fail; + static void L(string s) { s_sb.AppendLine(s); } + static void Chk(string n, bool ok, string d) { if (ok) s_pass++; else s_fail++; L((ok ? " PASS " : " FAIL ") + n + " — " + d); } + + public static string Run() + { + s_sb = new StringBuilder(); s_pass = 0; s_fail = 0; + L("WL-815c 장벽 3스타일 캡처 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + L(" 앵커 " + kAnchor.ToString("F1") + " 반경 " + kRadius + " m · 구도 811o(h " + kCamH + " · yaw " + kMapYaw + ")"); + + var keepSo = WLStageBarrierSettings.Instance; + try + { + Directory.CreateDirectory(kOutDir); + EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single); + foreach (var go in SceneManager.GetActiveScene().GetRootGameObjects()) + if (go.GetComponent() != null) UnityEngine.Object.DestroyImmediate(go); + + var map = Inst(kMapPrefab, Vector3.zero); + Chk("E0 맵", map != null, "WL_Nature"); + if (map == null) return "FAIL 맵 없음"; + + // 앵커 지면 실측 + Vector3 center = kAnchor; + RaycastHit gh; + if (Physics.Raycast(kAnchor + Vector3.up * 100f, Vector3.down, out gh, 300f)) center.y = gh.point.y; + L(" 존1 지면 실측 y = " + center.y.ToString("F2") + " (앵커 표기 y " + kAnchor.y + ")"); + + // PC 를 중앙에 세워 크기 비교 기준을 만든다 + var pc = Inst(kPcPrefab, center); + if (pc != null) + { + Vector3 f = new Vector3(Mathf.Sin(kMapYaw * Mathf.Deg2Rad), 0f, Mathf.Cos(kMapYaw * Mathf.Deg2Rad)); + pc.transform.rotation = Quaternion.LookRotation(-f, Vector3.up); + // 🔴 Animator.Update 는 부르지 않는다 — 에디트 모드는 Awake 가 안 돌아 + // Actor.Event_Idle(Actor.cs:2297)이 미할당 m_animation 을 만져 콘솔 예외가 난다(실측). + // 이 캡처에서 PC 는 크기 비교용이라 포즈는 중요하지 않다. + } + Chk("E1 PC", pc != null, "Ai01 중앙(크기 비교 기준)"); + + StageBarrier.HardResetForProbe(); + WLStageBarrierSettings.SetInstanceForProbe(keepSo); + + var styles = new StageBarrierStyle[] { StageBarrierStyle.MagicRing, StageBarrierStyle.Props, StageBarrierStyle.Fire }; + var names = new string[] { "ring", "props", "fire" }; + + for (int i = 0; i < styles.Length; i++) + { + StageBarrierVisual.StyleOverride = styles[i]; + StageBarrier.Set(center, kRadius); + StageBarrierVisual.ForcePhase(1f); // 입장 연출 끝난 상태 + StageBarrierVisual.SimulateForProbe(2.0f); // 파티클을 2 s 진행(에디트 모드) + + string info = Info(styles[i]); + ShotPersp(center, kOutDir + @"\barrier_" + names[i] + "_persp.png", styles[i] + " · " + info); + ShotPixel(center, kOutDir + @"\barrier_" + names[i] + "_pixel.png", styles[i] + " · " + info); + } + + // 클리어 연출 확인용(파일로 남기지 않고 값만) + StageBarrier.Clear(); + StageBarrierVisual.ForcePhase(0.5f); + L(" 클리어 연출 중간(t=0.5) 활성 " + StageBarrierVisual.LiveCount + " · 진행도 " + StageBarrierVisual.Phase.ToString("F2")); + } + catch (Exception ex) { s_fail++; L(" FAIL 예외 — " + ex.GetType().Name + " " + ex.Message + "\n" + ex.StackTrace); } + finally + { + try { StageBarrier.HardResetForProbe(); } catch { } + StageBarrierVisual.StyleOverride = (StageBarrierStyle)(-1); + WLStageBarrierSettings.SetInstanceForProbe(keepSo); + } + + L(""); + L("RESULT " + (s_fail == 0 ? "PASS" : "FAIL") + " · " + s_pass + " PASS · " + s_fail + " FAIL"); + File.WriteAllText(kTxt, s_sb.ToString()); + return (s_fail == 0 ? "PASS" : "FAIL") + " " + s_pass + "/" + (s_pass + s_fail); + } + + static string Info(StageBarrierStyle st) + { + int rend, mats, ps; long tri; + StageBarrierVisual.MeasureCost(out rend, out mats, out tri, out ps); + string x = "인스턴스 " + StageBarrierVisual.LiveCount + " · 렌더러 " + rend + " · 머티리얼 " + mats + " · tri " + tri + " · PS " + ps; + if (st == StageBarrierStyle.MagicRing) x += " · 링 스케일 " + StageBarrierVisual.RingScale.ToString("F2"); + else if (st == StageBarrierStyle.Props) x += " · 프롭 " + StageBarrierVisual.PropCount + " · 간격 " + StageBarrierVisual.PropSpacingUsed.ToString("F2") + " m"; + else x += " · 불꽃 " + StageBarrierVisual.FireCount + " · 방출률 ×" + StageBarrierVisual.FireRateMul.ToString("F2") + + " · 파티클 " + StageBarrierVisual.FireParticleEstimate; + return x; + } + + // ── 원근 구도(811o 각도 · 링 전체가 들어오게 거리만 확장) ─────────────── + static void ShotPersp(Vector3 center, string file, string label) + { + var camGo = new GameObject("[WL815c] PerspCam"); + var cam = camGo.AddComponent(); + var acd = camGo.AddComponent(); + acd.renderShadows = true; acd.renderPostProcessing = false; acd.antialiasing = AntialiasingMode.None; + + cam.orthographic = false; + cam.fieldOfView = 45f; + cam.nearClipPlane = 0.3f; + cam.farClipPlane = 500f; + cam.clearFlags = CameraClearFlags.Skybox; + + // 811o 와 같은 방향 벡터(h = cameraHeight 76 · yaw = 233) + Vector3 dir = (Quaternion.Euler(kCamH, kMapYaw, 0f) * Vector3.one).normalized; + // 반경 14 m 원이 세로 1080×1920 화면에 들어오려면 = r / tan(가로 FOV/2) + float aspect = kHiW / (float)kHiH; + float halfV = cam.fieldOfView * 0.5f * Mathf.Deg2Rad; + float halfH = Mathf.Atan(Mathf.Tan(halfV) * aspect); + float dist = (kRadius * 1.08f) / Mathf.Tan(halfH); + cam.transform.position = center + Vector3.up * 2.4f - dir * dist; + cam.transform.LookAt(center + Vector3.up * 1.0f); + + Shot(cam, file, label + " · 원근 FOV 45 · 거리 " + dist.ToString("F1") + " m", false); + UnityEngine.Object.DestroyImmediate(camGo); + } + + // ── 도트 룩 근사(814c 방식 · 직교 270×480 → Point 확대) ───────────────── + static void ShotPixel(Vector3 center, string file, string label) + { + var camGo = new GameObject("[WL815c] PixelCam"); + var cam = camGo.AddComponent(); + var acd = camGo.AddComponent(); + acd.renderShadows = true; acd.renderPostProcessing = false; acd.antialiasing = AntialiasingMode.None; + + Vector3 dir = (Quaternion.Euler(kCamH, kMapYaw, 0f) * Vector3.one).normalized; + cam.orthographic = true; + // 세로 1080×1920 · 가로가 좁다 → 가로에 반경이 들어가야 한다: orthoSize(세로 반) = r×1.2 / aspect + float aspect = kHiW / (float)kHiH; + cam.orthographicSize = kRadius * 1.05f / aspect; + cam.nearClipPlane = 0.1f; + cam.farClipPlane = 300f; + cam.clearFlags = CameraClearFlags.Skybox; + cam.transform.position = center + Vector3.up * 2.4f - dir * 60f; + cam.transform.LookAt(center + Vector3.up * 1.0f); + + Shot(cam, file, label + " · 직교 size " + cam.orthographicSize.ToString("F1") + " · " + kLowW + "×" + kLowH + " → Point 확대", true); + UnityEngine.Object.DestroyImmediate(camGo); + } + + static void Shot(Camera cam, string file, string label, bool pixel) + { + RenderTexture low = null, hi = null; + Texture2D tex = null; + try + { + if (pixel) + { + low = new RenderTexture(kLowW, kLowH, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + low.filterMode = FilterMode.Point; low.antiAliasing = 1; low.Create(); + hi = new RenderTexture(kHiW, kHiH, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + hi.filterMode = FilterMode.Point; hi.Create(); + cam.targetTexture = low; cam.Render(); cam.targetTexture = null; + Graphics.Blit(low, hi); // Point 확대 = 픽셀 카메라 근사 + } + else + { + hi = new RenderTexture(kHiW, kHiH, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + hi.Create(); + cam.targetTexture = hi; cam.Render(); cam.targetTexture = null; + } + + int dc = UnityEditor.UnityStats.drawCalls, batches = UnityEditor.UnityStats.batches, tri = UnityEditor.UnityStats.triangles; + + var active = RenderTexture.active; + RenderTexture.active = hi; + tex = new Texture2D(kHiW, kHiH, TextureFormat.RGB24, false); + tex.ReadPixels(new Rect(0, 0, kHiW, kHiH), 0, 0); + tex.Apply(); + RenderTexture.active = active; + File.WriteAllBytes(file, tex.EncodeToPNG()); + + var px = tex.GetPixels32(); + var seen = new HashSet(); + long warm = 0; + for (int i = 0; i < px.Length; i += 331) + { + seen.Add((px[i].r << 16) | (px[i].g << 8) | px[i].b); + if (px[i].r > 120 && px[i].r > px[i].b + 40) warm++; // 주황·붉은 픽셀 = 장벽 표식 + } + var fi = new FileInfo(file); + Chk("E " + Path.GetFileName(file), fi.Exists && fi.Length > 4096 && seen.Count > 4, + label + " · " + fi.Length + " B · 색 " + seen.Count + "종 · 따뜻한픽셀 " + warm + + " · drawCalls " + dc + " · batches " + batches + " · tri " + tri); + } + finally + { + RenderTexture.active = null; + if (tex != null) UnityEngine.Object.DestroyImmediate(tex); + if (low != null) { low.Release(); UnityEngine.Object.DestroyImmediate(low); } + if (hi != null) { hi.Release(); UnityEngine.Object.DestroyImmediate(hi); } + } + } + + // ── 도구 ──────────────────────────────────────────────────────────────── + static GameObject Inst(string path, Vector3 pos) + { + var p = AssetDatabase.LoadAssetAtPath(path); + if (p == null) { L(" [없음] " + path); return null; } + var go = UnityEngine.Object.Instantiate(p); + go.transform.position = pos; + return go; + } + +} diff --git a/AgentScripts/WL815c_PROBE.txt b/AgentScripts/WL815c_PROBE.txt index 1b85d5eaa..1a06db242 100644 --- a/AgentScripts/WL815c_PROBE.txt +++ b/AgentScripts/WL815c_PROBE.txt @@ -1,4 +1,4 @@ -WL-815c 스테이지 장벽 프로브 · 2026-09-11 00:51:58 +WL-815c 스테이지 장벽 프로브 · 2026-09-11 00:59:28 앵커 = 기준서 §D-1 존1 (115.0, 0.4, -22.0) 반경 14 m ① 설정 에셋(C45 — 값은 전부 SO) @@ -7,21 +7,21 @@ WL-815c 스테이지 장벽 프로브 · 2026-09-11 00:51:58 PASS 1-3 몹 값 — 몹여유 3 · 유예 1 s · 쿨 2 s PASS 1-4 카브 기본 off — carveNavMesh 0 · arc 4 m · 상한 32 · 두께 1.5 · 높이 3 PASS 1-5 스타일 — style=MagicRing · 입장 0.6 s · 클리어 0.6 s - PASS 1-6 ⓐ 링 프리팹 — Marker 3 Zone Loop · 실측 시각반경 1.1 m · 겹 2 + PASS 1-6 ⓐ 링 프리팹 — Marker 3 Zone Loop · 실측 시각반경 1.1 m · 겹 3 PASS 1-7 ⓑ 프롭 프리팹 — Fence_01, Fence_01, Rock_Block_crk_m_01 · 간격 2.5 m · 상한 64 - PASS 1-8 ⓒ 불꽃 프리팹 — Fire_Particles · 간격 3 m · 상한 48 · 파티클 총량 1200 + PASS 1-8 ⓒ 불꽃 프리팹 — Fire_Particles · 간격 2.5 m · 상한 48 · 파티클 총량 1600 ② 임시 NavMesh 베이크(에디트 모드에서 실 워프 지점을 재기 위해) PASS 2-1 NavMesh 베이크 — 정점 64 · 앵커 스냅 (115.00, 0.48, -22.00) ③ Set / Clear 왕복 (오브젝트 0 · 풀 반납) PASS 3-1 초기 — Active=false · IsInside(어디든)=true → True - PASS 3-2 Set — Active=true · 중심 (115.0, 0.4, -22.0) 반경 14 · 그림 인스턴스 2 · Instantiate 누계 2 + PASS 3-2 Set — Active=true · 중심 (115.0, 0.4, -22.0) 반경 14 · 그림 인스턴스 3 · Instantiate 누계 3 PASS 3-3 IsInside — 중심=안 · 13.9 m=안 · 14.1 m=밖 · 높이 무관(y+50 → True) - PASS 3-4a Clear 직후 = 페이드 중 — Active=false · 페이드 중 활성 2 · 진행도 1.00 - PASS 3-4 페이드 끝 → 활성 0 · 풀 반납 — 활성 0 · 풀 2(= Instantiate 누계 2) · Destroy 0 - PASS 3-5 재Set → 풀 재사용 — Instantiate 2 → 2(증가 0) · 활성 2 - PASS 3-6 입장/클리어 연출 — 스케일 t=0 0.00 → t=.5 6.23 → t=1 12.45 (appear 0.6 s / fade 0.6 s) + PASS 3-4a Clear 직후 = 페이드 중 — Active=false · 페이드 중 활성 3 · 진행도 1.00 + PASS 3-4 페이드 끝 → 활성 0 · 풀 반납 — 활성 0 · 풀 3(= Instantiate 누계 3) · Destroy 0 + PASS 3-5 재Set → 풀 재사용 — Instantiate 3 → 3(증가 0) · 활성 3 + PASS 3-6 입장/클리어 연출 — 스케일 t=0 0.00 → t=.5 6.14 → t=1 12.27 (appear 0.6 s / fade 0.6 s) PASS 3-7 반경 0 → Clear — Set(r=0) → Active=False ④ 되돌릴 지점 계산(순수 함수 · NearestInsidePoint) @@ -41,15 +41,15 @@ WL-815c 스테이지 장벽 프로브 · 2026-09-11 00:51:58 PASS 5-6 유예 안에서는 안 되돌린다 — grace 999 s · 틱 ×2 → 워프 0 (OutsideSeen 0) ⑥ 스타일 전환 3회 (PD 가 값 하나로 바꾼다) - PASS 6-1 MagicRing — 활성 2 · 렌더러 8 · 머티리얼 1 · tri 0 · PS 8 · 빌드 1.4 ms · 링 스케일 12.45(반경 14 ÷ 실측 1.1) - PASS 6-2 Props — 활성 35 · 렌더러 35 · 머티리얼 2 · tri 4530 · PS 0 · 빌드 1.3 ms · 프롭 35개 · 실간격 2.51 m - PASS 6-3 Fire — 활성 29 · 렌더러 87 · 머티리얼 3 · tri 0 · PS 87 · 빌드 7.6 ms · 불꽃 29개 · 방출률 ×0.33 · 파티클 추정 1200(개당 125) - PASS 6-4 전환 누계 — StyleSwitches 3 · Instantiate 누계 66 + PASS 6-1 MagicRing — 활성 3 · 렌더러 12 · 머티리얼 1 · tri 0 · PS 12 · 빌드 1.8 ms · 링 스케일 12.27(반경 14 ÷ 실측 1.1) + PASS 6-2 Props — 활성 35 · 렌더러 35 · 머티리얼 2 · tri 4530 · PS 0 · 빌드 1.4 ms · 프롭 35개 · 실간격 2.51 m + PASS 6-3 Fire — 활성 35 · 렌더러 105 · 머티리얼 3 · tri 0 · PS 105 · 빌드 11.2 ms · 불꽃 35개 · 방출률 ×0.37 · 파티클 추정 1600(개당 125) + PASS 6-4 전환 누계 — StyleSwitches 3 · Instantiate 누계 73 PASS 6-5 None → 그림 0 — 활성 그림 0 · 판정은 그대로 Active=True ⑦ NavMesh 카브 on/off (옵션 · 기준서 §D-2 ②) PASS 7-1 off(기본) → 카브 0 — carveNavMesh 0 → 오브젝트 0 - PASS 7-2 on → 세그먼트 생성 — 둘레 88.0 m ÷ arc 4 m = 22(상한 32) · 오브젝트 22 · 생성 0.41 ms · Set 전체 2.32 ms + PASS 7-2 on → 세그먼트 생성 — 둘레 88.0 m ÷ arc 4 m = 22(상한 32) · 오브젝트 22 · 생성 0.44 ms · Set 전체 3.31 ms PASS 7-3 세그먼트 기하 — carving=true 22 · Box 22 · 상자 4.60 × 두께 1.50 m > 이웃 간격 3.98 m(이론 4.00 · 겹침 15 %) · 원 이탈 최대 0.0000 m NavMesh 삼각형 32 → 32 (에디트 모드는 carve 가 즉시 반영되지 않을 수 있다 — 실 반영·재베이크 ms 는 Play 확인) PASS 7-4 Clear → 카브 회수 — 오브젝트 0 @@ -64,15 +64,15 @@ WL-815c 스테이지 장벽 프로브 · 2026-09-11 00:51:58 PASS 9-1 enabled=0 → Set 무동작 — Active=False · Instantiate 0 (오브젝트 0) PASS 9-2 RuntimeDisabled=1 → Set 무동작 — Active=False · Instantiate 0 PASS 9-3 에셋 없음 → Set 무동작 — Active=False · FeatureEnabled=False - PASS 9-4 blockEnabled=0 → 판정 0 · 그림은 남는다 — Checks 0 · 그림 2 + PASS 9-4 blockEnabled=0 → 판정 0 · 그림은 남는다 — Checks 0 · 그림 3 PASS 9-5 showVisual=0 → 그림 0 · 판정은 산다 — 그림 0 · Active=True ⑩ 성능 표 (반경 14 m · 스타일별) | 스타일 | 인스턴스 | 렌더러 | 머티리얼 | 삼각형 | 파티클시스템 | 정상상태 파티클 | 빌드 ms | |---|---|---|---|---|---|---|---| - | MagicRing | 2 | 8 | 1 | 0 | 8 | 8 | 0.9 | - | Props | 35 | 35 | 2 | 4530 | 0 | 0 | 1.2 | - | Fire | 29 | 87 | 3 | 0 | 87 | 1200 | 8.2 | + | MagicRing | 3 | 12 | 1 | 0 | 12 | 12 | 1.7 | + | Props | 35 | 35 | 2 | 4530 | 0 | 0 | 1.3 | + | Fire | 35 | 105 | 3 | 0 | 105 | 1600 | 10.4 | PASS 10-1 성능 표 — 위 표 참조(에디트 모드 측정 · 실 드로우콜은 캡처의 UnityStats) 반경별 프롭 개수(간격 2.5 m · 상한 64) r 8 m(둘레 50.3 m) → 프롭 20 · 실간격 2.51 m · 카브 세그(on 일 때) 13 diff --git a/AgentScripts/WL815c_TUNE.txt b/AgentScripts/WL815c_TUNE.txt new file mode 100644 index 000000000..d41a2ec7a --- /dev/null +++ b/AgentScripts/WL815c_TUNE.txt @@ -0,0 +1,9 @@ + 링 PSR Marker 3 Zone Loop · shader Shader Graphs/HS_Blend_CG · _TintColor 없음 · _Color RGBA(1.000, 1.000, 1.000, 1.000) · renderMode Mesh · 정렬 0 + 링 PSR Flash · shader Shader Graphs/HS_Blend_CG · _TintColor 없음 · _Color RGBA(1.000, 1.000, 1.000, 1.000) · renderMode Billboard · 정렬 0 + 링 PSR Runes · shader Shader Graphs/HS_Blend_CG · _TintColor 없음 · _Color RGBA(1.000, 1.000, 1.000, 1.000) · renderMode Mesh · 정렬 0 + 링 PSR ShockWave · shader Shader Graphs/HS_Blend_CG · _TintColor 없음 · _Color RGBA(1.000, 1.000, 1.000, 1.000) · renderMode Mesh · 정렬 0 + 링 PS Marker 3 Zone Loop · startColor RGBA(0.027, 0.056, 0.104, 1.000) · colorOverLifetime ON · size 1.00 + 링 PS Flash · startColor RGBA(0.288, 0.573, 1.000, 0.125) · colorOverLifetime ON · size 2.00 + 링 PS Runes · startColor RGBA(0.031, 0.076, 0.142, 0.784) · colorOverLifetime ON · size 2.20 + 링 PS ShockWave · startColor RGBA(0.047, 0.097, 0.170, 1.000) · colorOverLifetime ON · size 3.00 + 적용: fireScale 3 · fireSpacing 2.5 · maxTotalParticles 1600 · ringExtraRings 2 diff --git a/AgentScripts/WL815c_Tune.cs b/AgentScripts/WL815c_Tune.cs new file mode 100644 index 000000000..b056cb2af --- /dev/null +++ b/AgentScripts/WL815c_Tune.cs @@ -0,0 +1,65 @@ +// WL-815c 튜닝 — 캡처 1차 실측 뒤 값 조정 + 링 머티리얼 진단 +// unity command run_script --file AgentScripts/WL815c_Tune.cs --entry WL815c_Tune.Run + +using System.Text; +using UnityEditor; +using UnityEngine; +using WL.Combat.Stage; + +public static class WL815c_Tune +{ + const string kPath = "Assets/WL/Combat/Stage/Barrier/Resources/WL/WLStageBarrierSettings.asset"; + + public static string Run() + { + var sb = new StringBuilder(); + var so = AssetDatabase.LoadAssetAtPath(kPath); + if (so == null) return "에셋 없음"; + + // ── 링 머티리얼 진단(왜 색이 안 먹는가) + if (so.ringPrefab != null) + { + var rs = so.ringPrefab.GetComponentsInChildren(true); + for (int i = 0; i < rs.Length; i++) + { + var m = rs[i].sharedMaterial; + sb.Append(" 링 PSR ").Append(rs[i].name) + .Append(" · shader ").Append(m != null ? m.shader.name : "null") + .Append(" · _TintColor ").Append(m != null && m.HasProperty("_TintColor") ? m.GetColor("_TintColor").ToString() : "없음") + .Append(" · _Color ").Append(m != null && m.HasProperty("_Color") ? m.GetColor("_Color").ToString() : "없음") + .Append(" · renderMode ").Append(rs[i].renderMode) + .Append(" · 정렬 ").Append(rs[i].sortingOrder).AppendLine(); + } + var ps = so.ringPrefab.GetComponentsInChildren(true); + for (int i = 0; i < ps.Length; i++) + sb.Append(" 링 PS ").Append(ps[i].name) + .Append(" · startColor ").Append(ps[i].main.startColor.color.ToString()) + .Append(" · colorOverLifetime ").Append(ps[i].colorOverLifetime.enabled ? "ON" : "off") + .Append(" · size ").Append(ps[i].main.startSize.constantMax.ToString("F2")).AppendLine(); + } + + // ── ⓒ 불꽃: 1차 캡처에서 「흩어진 불티」로 보였다 → 크기·밀도를 올린다(실측 기반) + so.fireScale = 3f; // Fire_Particles 는 모닥불 크기(shape r0.46) → 3배면 약 1.4 m + so.fireSpacing = 2.5f; // 둘레 88 m → 35기 + so.maxTotalParticles = 1600; // 35 × 125 = 4375 → 방출률 ×0.37 + so.fireGroundSnap = true; + + // ── ⓐ 링: 겹으로 두께를 낸다(도트 룩 대비) + 색은 「곱」이라 1 보다 큰 값이 증폭이다 + so.ringExtraRings = 2; + so.ringExtraSpacing = 0.5f; + so.ringColor = new Color(6f, 1.2f, 0.4f, 1f); // 원색(어두운 청 기저 0.027,0.056,0.104)에 곱 + so.ringTintEnabled = false; // 🔴 실측 3회 — 이 셰이더에서는 화면 색이 안 바뀐다(보고서 「미확인」) + + EditorUtility.SetDirty(so); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + sb.Append(" 적용: fireScale ").Append(so.fireScale) + .Append(" · fireSpacing ").Append(so.fireSpacing) + .Append(" · maxTotalParticles ").Append(so.maxTotalParticles) + .Append(" · ringExtraRings ").Append(so.ringExtraRings).AppendLine(); + + System.IO.File.WriteAllText("AgentScripts/WL815c_TUNE.txt", sb.ToString()); + return "tune done → AgentScripts/WL815c_TUNE.txt"; + } +} diff --git a/Assets/WL/Combat/Stage/Barrier/Resources/WL/WLStageBarrierSettings.asset b/Assets/WL/Combat/Stage/Barrier/Resources/WL/WLStageBarrierSettings.asset index 4e32f566a..0a7ec290a 100644 --- a/Assets/WL/Combat/Stage/Barrier/Resources/WL/WLStageBarrierSettings.asset +++ b/Assets/WL/Combat/Stage/Barrier/Resources/WL/WLStageBarrierSettings.asset @@ -45,11 +45,11 @@ MonoBehaviour: visualRadiusScale: 1 ringPrefab: {fileID: 1370640339480484, guid: a1b9488b1b1338d4585b154f4b86703e, type: 3} ringPrefabVisualRadius: 1.1 - ringColor: {r: 1, g: 0.35, b: 0.15, a: 1} - ringTintEnabled: 1 + ringColor: {r: 6, g: 1.2, b: 0.4, a: 1} + ringTintEnabled: 0 ringYScale: 1 - ringExtraRings: 1 - ringExtraSpacing: 0.6 + ringExtraRings: 2 + ringExtraSpacing: 0.5 propPrefabs: - {fileID: 3287405711304420922, guid: 84026706d57fb9e43b9716c8b1510e98, type: 3} - {fileID: 3287405711304420922, guid: 84026706d57fb9e43b9716c8b1510e98, type: 3} @@ -67,10 +67,10 @@ MonoBehaviour: propSeed: 815 firePrefabs: - {fileID: 131402, guid: 5608cd25f71830e4aaa770d88ff9ebe2, type: 3} - fireSpacing: 3 + fireSpacing: 2.5 maxFires: 48 - fireScale: 1 - maxTotalParticles: 1200 + fireScale: 3 + maxTotalParticles: 1600 fireBudgetMode: 0 fireTintEnabled: 0 fireColor: {r: 1, g: 0.45, b: 0.1, a: 1} diff --git a/Assets/WL/Combat/Stage/Barrier/StageBarrierVisual.cs b/Assets/WL/Combat/Stage/Barrier/StageBarrierVisual.cs index 1c335a21e..ccfacc48c 100644 --- a/Assets/WL/Combat/Stage/Barrier/StageBarrierVisual.cs +++ b/Assets/WL/Combat/Stage/Barrier/StageBarrierVisual.cs @@ -399,11 +399,21 @@ namespace WL.Combat.Stage } } - /// SO 색으로 「원래 색」을 갈아 끼운다(다음 SetAlpha 부터 이 색이 쓰인다). + /// + /// SO 색을 「원래 색」에 **곱한다**(대입이 아니다). + /// 🔴 실측(WL815c_TUNE) — Hovl Marker 3 Zone Loop 은 4개 파티클시스템 전부 `colorOverLifetime` 이 ON 이고 + /// startColor 가 (0.027, 0.056, 0.104) 같은 **어두운 기저색**이다(발광 셰이더가 이것을 증폭한다). + /// 여기에 (1, 0.35, 0.15) 를 그냥 대입하면 원래보다 훨씬 밝아져 **흰색으로 뭉개진다**(1차 캡처에서 실측). + /// 곱하면 아티스트가 잡은 밝기를 유지한 채 색조만 돈다. + /// static void Tint(Slot s, Color color) { - if (s.psColor == null) return; - for (int i = 0; i < s.psColor.Length; i++) s.psColor[i] = color; + if (s.psColor == null || s.psOrig == null) return; + for (int i = 0; i < s.psColor.Length && i < s.psOrig.Length; i++) + { + Color o = s.psOrig[i]; + s.psColor[i] = new Color(o.r * color.r, o.g * color.g, o.b * color.b, o.a * color.a); + } } static void Restart(Slot s) diff --git a/Assets/WL/Combat/Stage/Barrier/WLStageBarrierSettings.cs b/Assets/WL/Combat/Stage/Barrier/WLStageBarrierSettings.cs index 7baf0db31..359d9378c 100644 --- a/Assets/WL/Combat/Stage/Barrier/WLStageBarrierSettings.cs +++ b/Assets/WL/Combat/Stage/Barrier/WLStageBarrierSettings.cs @@ -197,11 +197,15 @@ namespace WL.Combat.Stage "Marker 3 Zone Loop 실측 1.10 m(Simulate 2 s · 파티클 위치+반크기 최대).")] public float ringPrefabVisualRadius = 1.1f; - [Tooltip("링 색(파티클 startColor 에 인스턴스 단위로 대입 · 원본 머티리얼·프리팹 무수정). a 는 밝기.")] - public Color ringColor = new Color(1f, 0.35f, 0.15f, 1f); + [Tooltip("링 색 — 프리팹 원색에 **곱해진다**(대입이 아니다). 1,1,1,1 = 원본 그대로. " + + "🔴 실측: Hovl 마커는 startColor 가 어두운 기저색 + colorOverLifetime ON 이라 대입하면 흰색으로 뭉개진다.")] + public Color ringColor = new Color(6f, 1.2f, 0.4f, 1f); - [Tooltip("0 이면 색을 건드리지 않고 프리팹 원색 그대로 쓴다.")] - public bool ringTintEnabled = true; + [Tooltip("1 이면 ringColor 를 프리팹 원색에 곱한다. " + + "🔴 기본 0 — 실측(캡처 3회): Hovl `HS_Blend_CG`(Shader Graph) 는 VertexColorNode 가 그래프에 있는데도 " + + "Marker 3 Zone Loop 의 화면 색이 눈에 띄게 바뀌지 않았다(대입·×1.6·×6 전부). " + + "색을 실제로 바꾸려면 머티리얼 사본이 필요한데 그건 원본 에셋 접촉이라 이 태스크 범위 밖이다.")] + public bool ringTintEnabled; [Tooltip("도트 룩(814b/814c)에서 링이 뭉개지지 않게 세로로 늘리는 배율. 1 = 프리팹 그대로. " + "🔴 링은 평면 쿼드라 Y 스케일은 두께가 아니라 「기울기」를 만든다 — 두께는 ringExtraRings 로 낸다.")]