// WL-815c 2차 실측 — 링 실제 시각 반경(Simulate 후 바운즈) · 불꽃 파티클 시스템별 상세 · 바위 프롭 // unity command run_script --file AgentScripts/WL815c_Survey2.cs --entry WL815c_Survey2.Run public static class WL815c_Survey2 { static System.Text.StringBuilder s_sb; static void L(string s) { s_sb.AppendLine(s); UnityEngine.Debug.Log(s); } public static string Run() { s_sb = new System.Text.StringBuilder(); L("WL-815c 2차 실측 · " + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); L(""); L("── 링 프리팹: Simulate 2 s 후 실제 시각 반경(XZ) ──────────────"); string[] rings = { "Assets/ResWork/VFX/Hovl Studio/Map track markers VFX/Prefabs/Marker 3 Zone Loop.prefab", "Assets/ResWork/VFX/Hovl Studio/Map track markers VFX/Prefabs/Marker 5 Circle Loop.prefab", "Assets/ResWork/VFX/Hovl Studio/Map track markers VFX/Prefabs/Marker 7 Danger zone Loop.prefab", "Assets/ResWork/VFX/Hovl Studio/Map track markers VFX/Prefabs/Marker 8 Safe zone Loop.prefab", }; for (int i = 0; i < rings.Length; i++) SimRadius(rings[i]); L(""); L("── 불꽃 후보: 파티클 시스템별 상세 ────────────────────────────"); string[] fires = { "Assets/LMHPOLY/Low Poly Nature Bundle/Rocks/Bonus Assets/Prefabs/ParticleSystem/Fire_Particles.prefab", "Assets/ResWork/VFX/Hovl Studio/Epic Toon VFX 2/Prefabs/Fire buff/Fire buff.prefab", "Assets/ResWork/EricWang/GameVFX Collection Vol3/Prefabs/FX_Flameflow_floor.prefab", }; for (int i = 0; i < fires.Length; i++) Detail(fires[i]); L(""); L("── LMHPOLY 바위(비 LOD · Rock 계열) ───────────────────────────"); var guids = UnityEditor.AssetDatabase.FindAssets("t:Prefab", new string[] { "Assets/LMHPOLY/Low Poly Nature Bundle/Rocks" }); int shown = 0; for (int i = 0; i < guids.Length && shown < 8; i++) { string p = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]); string n = System.IO.Path.GetFileNameWithoutExtension(p); if (p.Contains("/LOD/") || n.EndsWith("_LOD")) continue; if (!(n.StartsWith("Rock") || n.StartsWith("Stone") || n.StartsWith("Boulder"))) continue; Brief(p); shown++; } if (shown == 0) { L(" Rock/Stone/Boulder 접두 프리팹 0 — 폴더 구조 표본:"); for (int i = 0; i < guids.Length && i < 12; i++) L(" " + UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i])); } L(""); L("── 울타리 프롭 pivot·회전 확인(둘레 배치 적합성) ───────────────"); string[] fences = { "Assets/ResWork/LowPolyFantasyVillage_URP/Prefabs/Props/Fence_01.prefab", "Assets/ResWork/LowPolyFantasyVillage_URP/Prefabs/Props/FenceBig_01.prefab", "Assets/3DPixelArtEnvironment/Prefabs/Stone_1.prefab", }; for (int i = 0; i < fences.Length; i++) Pivot(fences[i]); string outFile = "AgentScripts/WL815c_SURVEY2.txt"; System.IO.File.WriteAllText(outFile, s_sb.ToString()); return "survey2 done → " + outFile; } static void SimRadius(string path) { var go = UnityEditor.AssetDatabase.LoadAssetAtPath(path); if (go == null) { L(" [없음] " + path); return; } var inst = UnityEngine.Object.Instantiate(go); inst.transform.position = UnityEngine.Vector3.zero; var pss = inst.GetComponentsInChildren(true); for (int i = 0; i < pss.Length; i++) { pss[i].Clear(true); pss[i].Simulate(2.0f, true, true, false); } float maxR = 0f, maxY = 0f, minY = 0f; int alive = 0; for (int i = 0; i < pss.Length; i++) { int c = pss[i].particleCount; alive += c; if (c == 0) continue; var buf = new UnityEngine.ParticleSystem.Particle[c]; int got = pss[i].GetParticles(buf); bool world = pss[i].main.simulationSpace == UnityEngine.ParticleSystemSimulationSpace.World; for (int k = 0; k < got; k++) { var p = buf[k].position; if (!world) p = pss[i].transform.TransformPoint(p); float r = new UnityEngine.Vector2(p.x, p.z).magnitude; float sz = buf[k].GetCurrentSize(pss[i]) * 0.5f; if (r + sz > maxR) maxR = r + sz; if (p.y > maxY) maxY = p.y; if (p.y < minY) minY = p.y; } } // 파티클이 0이면 메시/빌보드 크기로 대신 잰다 float rendR = 0f; var rends = inst.GetComponentsInChildren(true); for (int i = 0; i < rends.Length; i++) { var b = rends[i].bounds; rendR = UnityEngine.Mathf.Max(rendR, UnityEngine.Mathf.Max(b.extents.x, b.extents.z)); } L(" " + System.IO.Path.GetFileNameWithoutExtension(path)); L(" Simulate(2 s) 살아있는 파티클 " + alive + " · 시각 반경(XZ) " + maxR.ToString("F2") + " m · 높이 " + minY.ToString("F2") + "~" + maxY.ToString("F2") + " m · 렌더러 바운즈 반경 " + rendR.ToString("F2") + " m"); for (int i = 0; i < pss.Length; i++) { var m = pss[i].main; var sh = pss[i].shape; var e = pss[i].emission; string bursts = ""; if (e.burstCount > 0) { var arr = new UnityEngine.ParticleSystem.Burst[e.burstCount]; e.GetBursts(arr); float tot = 0f; for (int k = 0; k < arr.Length; k++) tot += arr[k].count.constantMax * UnityEngine.Mathf.Max(1, arr[k].cycleCount); bursts = " · 버스트 " + e.burstCount + "종 총 " + tot.ToString("F0"); } L(" ├ " + pss[i].name + " : max " + m.maxParticles + " · rate " + (e.enabled ? e.rateOverTime.constantMax : 0f).ToString("F1") + "/s" + bursts + " · life " + m.startLifetime.constantMax.ToString("F2") + " s · size " + m.startSize.constantMax.ToString("F2") + " · shape " + (sh.enabled ? sh.shapeType.ToString() + " r" + sh.radius.ToString("F2") : "off") + " · scale " + pss[i].transform.lossyScale.ToString("F2") + " · 지금 " + pss[i].particleCount); } UnityEngine.Object.DestroyImmediate(inst); } static void Detail(string path) { var go = UnityEditor.AssetDatabase.LoadAssetAtPath(path); if (go == null) { L(" [없음] " + path); return; } var inst = UnityEngine.Object.Instantiate(go); var pss = inst.GetComponentsInChildren(true); float steady = 0f; L(" " + System.IO.Path.GetFileNameWithoutExtension(path) + " · PS " + pss.Length); for (int i = 0; i < pss.Length; i++) { var m = pss[i].main; var e = pss[i].emission; float r = e.enabled ? e.rateOverTime.constantMax : 0f; float life = m.startLifetime.constantMax; float st = UnityEngine.Mathf.Min(r * life, m.maxParticles); steady += st; L(" ├ " + pss[i].name + " : rate " + r.ToString("F1") + "/s × life " + life.ToString("F2") + " s = " + st.ToString("F0") + " (max " + m.maxParticles + ") · size " + m.startSize.constantMax.ToString("F2") + " · loop " + (m.loop ? "Y" : "N") + " · 정지공간 " + m.simulationSpace); } L(" ⇒ 인스턴스 1개 정상상태 추정 " + steady.ToString("F0") + " 파티클"); UnityEngine.Object.DestroyImmediate(inst); } static void Brief(string path) { var go = UnityEditor.AssetDatabase.LoadAssetAtPath(path); if (go == null) return; var inst = UnityEngine.Object.Instantiate(go); var rends = inst.GetComponentsInChildren(true); long tris = 0; bool has = false; UnityEngine.Bounds b = default(UnityEngine.Bounds); for (int i = 0; i < rends.Length; i++) { var mf = rends[i].GetComponent(); if (mf != null && mf.sharedMesh != null) tris += mf.sharedMesh.triangles.Length / 3; if (!has) { b = rends[i].bounds; has = true; } else b.Encapsulate(rends[i].bounds); } L(" " + System.IO.Path.GetFileNameWithoutExtension(path) + " · " + path); L(" 크기 " + b.size.ToString("F2") + " · tri " + tris + " · 렌더러 " + rends.Length); UnityEngine.Object.DestroyImmediate(inst); } static void Pivot(string path) { var go = UnityEditor.AssetDatabase.LoadAssetAtPath(path); if (go == null) return; var inst = UnityEngine.Object.Instantiate(go); inst.transform.position = UnityEngine.Vector3.zero; inst.transform.rotation = UnityEngine.Quaternion.identity; var rends = inst.GetComponentsInChildren(true); bool has = false; UnityEngine.Bounds b = default(UnityEngine.Bounds); for (int i = 0; i < rends.Length; i++) { if (!has) { b = rends[i].bounds; has = true; } else b.Encapsulate(rends[i].bounds); } L(" " + System.IO.Path.GetFileNameWithoutExtension(path) + " : pivot→바운즈중심 " + b.center.ToString("F2") + " · 크기 " + b.size.ToString("F2") + " · 긴축 " + (b.size.x >= b.size.z ? "X " + b.size.x.ToString("F2") : "Z " + b.size.z.ToString("F2")) + " · 바닥 y " + (b.center.y - b.extents.y).ToString("F2")); UnityEngine.Object.DestroyImmediate(inst); } }