184 lines
11 KiB
C#
184 lines
11 KiB
C#
// WL-816e — Play 중 진단 · 성능 실측 · 오프스크린 캡처 (배치모드 헤드리스에서도 동작)
|
|
public static class WL816e_Play
|
|
{
|
|
const string Dir = "Screenshots_WL/WL816e/";
|
|
const int W = 1080, H = 1920;
|
|
|
|
public static void Run() { Report("b", true); }
|
|
public static void RunOff() { Report("a", true); }
|
|
|
|
public static void Report(string tag, bool shoot)
|
|
{
|
|
var sb = new System.Text.StringBuilder();
|
|
var cfg = WL.Look.Farm.WLIslandLookSettings.Instance;
|
|
sb.AppendLine("isPlaying=" + UnityEngine.Application.isPlaying + " · scene=" +
|
|
UnityEngine.SceneManagement.SceneManager.GetActiveScene().name +
|
|
" · sceneCount=" + UnityEngine.SceneManagement.SceneManager.sceneCount);
|
|
sb.AppendLine("SO : enabled_=" + (cfg == null ? -1 : cfg.enabled_) +
|
|
" applyLook=" + (cfg == null ? -1 : cfg.applyLook) +
|
|
" grass=" + (cfg == null ? -1 : cfg.grassEnabled) +
|
|
" maxInstances=" + (cfg == null ? -1 : cfg.maxInstances));
|
|
sb.AppendLine("IslandLook: 렌더러 " + WL.Look.Farm.WLIslandLook.SwappedRenderers +
|
|
" · 슬롯 " + WL.Look.Farm.WLIslandLook.SwappedSlots +
|
|
" · rescan " + WL.Look.Farm.WLIslandLook.Rescans +
|
|
" · dirLight " + WL.Look.Farm.WLIslandLook.LightingApplied +
|
|
" · refLook " + WL.Look.Farm.WLIslandLook.ReferenceLookApplied +
|
|
" · grassSpawned " + WL.Look.Farm.WLIslandLook.GrassSpawned +
|
|
" · grassRebuild " + WL.Look.Farm.WLIslandLook.GrassRebuilds);
|
|
sb.AppendLine("Grass : " + WL.Look.Farm.WLIslandGrass.LastLog);
|
|
sb.AppendLine("RefLook : applied=" + WL.Look.Arena.WLReferenceLook.IsApplied
|
|
+ " outlined=" + WL.Look.Arena.WLReferenceLook.OutlinedRenderers
|
|
+ " contrastMat=" + WL.Look.Arena.WLReferenceLook.ContrastMaterials);
|
|
sb.AppendLine("ambient : " + UnityEngine.RenderSettings.ambientMode + " " + UnityEngine.RenderSettings.ambientLight
|
|
+ " · skybox=" + (UnityEngine.RenderSettings.skybox != null ? UnityEngine.RenderSettings.skybox.name : "없음")
|
|
+ " · fog=" + UnityEngine.RenderSettings.fog);
|
|
var ls = UnityEngine.Object.FindObjectsByType<UnityEngine.Light>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
|
for (int i = 0; i < ls.Length; i++)
|
|
sb.AppendLine("light : " + ls[i].name + " " + ls[i].type + " " + ls[i].color + " I=" + ls[i].intensity + " " + ls[i].shadows);
|
|
|
|
// 섬 현황
|
|
var mgr = UnityEngine.Object.FindFirstObjectByType<CryingSnow.FarmingIsland.IslandManager>(UnityEngine.FindObjectsInactive.Include);
|
|
int unlocked = 0, total = 0;
|
|
var isls = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Island>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
|
|
for (int i = 0; i < isls.Length; i++) { total++; if (isls[i].IsUnlocked) unlocked++; }
|
|
sb.AppendLine("island : 총 " + total + " · 열린 " + unlocked +
|
|
" · coin=" + (mgr == null ? -1 : mgr.Coin) +
|
|
" · navmesh=" + (mgr == null ? false : mgr.HasNavMesh));
|
|
|
|
// 씬 정적 비용
|
|
var rends = UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
|
long tris = 0; int slots = 0;
|
|
var shaders = new System.Collections.Generic.Dictionary<string, int>();
|
|
for (int i = 0; i < rends.Length; i++)
|
|
{
|
|
var r = rends[i];
|
|
if (r is UnityEngine.ParticleSystemRenderer) continue;
|
|
UnityEngine.Mesh mesh = null;
|
|
var mr = r as UnityEngine.MeshRenderer;
|
|
var sk = r as UnityEngine.SkinnedMeshRenderer;
|
|
if (mr != null) { var mf = r.GetComponent<UnityEngine.MeshFilter>(); if (mf != null) mesh = mf.sharedMesh; }
|
|
else if (sk != null) mesh = sk.sharedMesh;
|
|
if (mesh != null) for (int s = 0; s < mesh.subMeshCount; s++) tris += mesh.GetIndexCount(s) / 3;
|
|
var ms = r.sharedMaterials;
|
|
for (int m = 0; m < ms.Length; m++)
|
|
{
|
|
if (ms[m] == null) continue; slots++;
|
|
string sh = ms[m].shader.name;
|
|
shaders[sh] = shaders.TryGetValue(sh, out int v) ? v + 1 : 1;
|
|
}
|
|
}
|
|
sb.Append("씬 정적 : 렌더러 " + rends.Length + " · 슬롯 " + slots + " · 삼각형 " + tris.ToString("N0") + " · 셰이더 ");
|
|
foreach (var kv in shaders) sb.Append(kv.Key + " x" + kv.Value + " · ");
|
|
sb.AppendLine();
|
|
|
|
// ── 성능 실측(같은 카메라로 N 프레임 렌더 시간) ────────────────
|
|
var cam = FindCam("MainCamera");
|
|
if (cam != null)
|
|
{
|
|
var perf = Measure(cam, 60);
|
|
sb.AppendLine("성능(" + tag + ") : " + perf);
|
|
}
|
|
|
|
if (shoot)
|
|
{
|
|
System.IO.Directory.CreateDirectory(Dir);
|
|
Shot(cam, Dir + tag + "_play_main.png");
|
|
Shot(TopDownCam(), Dir + tag + "_play_top.png");
|
|
Shot(DemoAngleCam(), Dir + tag + "_play_demoangle.png");
|
|
sb.AppendLine("캡처 " + tag + "_play_main / _play_top / _play_demoangle");
|
|
}
|
|
UnityEngine.Debug.Log("[WL816e Play " + tag + "]\n" + sb.ToString());
|
|
}
|
|
|
|
/// <summary>같은 카메라를 N 번 렌더해 프레임 시간을 잰다 + 마지막 프레임의 드로우콜/삼각형.</summary>
|
|
public static string Measure(UnityEngine.Camera cam, int frames)
|
|
{
|
|
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
|
rt.antiAliasing = 1; rt.Create();
|
|
var prevT = cam.targetTexture;
|
|
cam.targetTexture = rt;
|
|
cam.Render(); // 워밈업
|
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
|
for (int i = 0; i < frames; i++) cam.Render();
|
|
sw.Stop();
|
|
int dc = UnityEditor.UnityStats.drawCalls;
|
|
int batches = UnityEditor.UnityStats.batches;
|
|
int setPass = UnityEditor.UnityStats.setPassCalls;
|
|
int tri = UnityEditor.UnityStats.triangles;
|
|
int vert = UnityEditor.UnityStats.vertices;
|
|
cam.targetTexture = prevT;
|
|
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
|
|
double ms = sw.Elapsed.TotalMilliseconds / frames;
|
|
return "렌더 " + ms.ToString("F2") + " ms/frame (= " + (1000.0 / System.Math.Max(0.001, ms)).ToString("F0") + " FPS 환산)"
|
|
+ " · 드로우콜 " + dc + " · 배치 " + batches + " · SetPass " + setPass
|
|
+ " · 삼각형 " + tri.ToString("N0") + " · 정점 " + vert.ToString("N0");
|
|
}
|
|
|
|
// ── 카메라 ─────────────────────────────────────────────────────────
|
|
public static UnityEngine.Camera TopDownCam()
|
|
{
|
|
var go = UnityEngine.GameObject.Find("__WL816eTop");
|
|
if (go == null) { go = new UnityEngine.GameObject("__WL816eTop"); go.hideFlags = UnityEngine.HideFlags.DontSave; }
|
|
var c = go.GetComponent<UnityEngine.Camera>();
|
|
if (c == null) c = go.AddComponent<UnityEngine.Camera>();
|
|
c.orthographic = true; c.orthographicSize = 9f;
|
|
c.nearClipPlane = 0.3f; c.farClipPlane = 500f;
|
|
c.clearFlags = UnityEngine.CameraClearFlags.Skybox;
|
|
c.depth = -100f;
|
|
var rot = UnityEngine.Quaternion.Euler(50f, 0f, 0f);
|
|
go.transform.rotation = rot;
|
|
go.transform.position = new UnityEngine.Vector3(0f, 0f, 4f) - rot * UnityEngine.Vector3.forward * 40f;
|
|
if (go.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() == null)
|
|
go.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
|
return c;
|
|
}
|
|
|
|
public static UnityEngine.Camera DemoAngleCam()
|
|
{
|
|
var go = UnityEngine.GameObject.Find("__WL816eDemoAngle");
|
|
if (go == null) { go = new UnityEngine.GameObject("__WL816eDemoAngle"); go.hideFlags = UnityEngine.HideFlags.DontSave; }
|
|
var c = go.GetComponent<UnityEngine.Camera>();
|
|
if (c == null) c = go.AddComponent<UnityEngine.Camera>();
|
|
c.orthographic = true; c.orthographicSize = 10f;
|
|
c.nearClipPlane = 0.3f; c.farClipPlane = 500f;
|
|
c.clearFlags = UnityEngine.CameraClearFlags.Skybox;
|
|
c.backgroundColor = new UnityEngine.Color(0.192f, 0.302f, 0.475f, 0f);
|
|
c.depth = -100f;
|
|
var rot = UnityEngine.Quaternion.Euler(30f, 60f, 0f);
|
|
go.transform.rotation = rot;
|
|
go.transform.position = new UnityEngine.Vector3(0f, 0.6f, 4f) - rot * UnityEngine.Vector3.forward * 60f;
|
|
if (go.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() == null)
|
|
go.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
|
return c;
|
|
}
|
|
|
|
public static UnityEngine.Camera FindCam(string name)
|
|
{
|
|
var cams = UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(
|
|
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
|
for (int i = 0; i < cams.Length; i++) if (cams[i].name == name) return cams[i];
|
|
for (int i = 0; i < cams.Length; i++) if (cams[i].name.StartsWith("__WL")) continue; else return cams[i];
|
|
return cams.Length > 0 ? cams[0] : null;
|
|
}
|
|
|
|
public static void Shot(UnityEngine.Camera cam, string path)
|
|
{
|
|
if (cam == null) return;
|
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
|
|
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
|
rt.antiAliasing = 1; rt.Create();
|
|
var prevT = cam.targetTexture; var prevA = UnityEngine.RenderTexture.active;
|
|
cam.targetTexture = rt;
|
|
cam.Render();
|
|
UnityEngine.RenderTexture.active = rt;
|
|
var tex = new UnityEngine.Texture2D(W, H, UnityEngine.TextureFormat.RGB24, false);
|
|
tex.ReadPixels(new UnityEngine.Rect(0, 0, W, H), 0, 0);
|
|
tex.Apply();
|
|
System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex));
|
|
UnityEngine.RenderTexture.active = prevA;
|
|
cam.targetTexture = prevT;
|
|
UnityEngine.Object.DestroyImmediate(tex);
|
|
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
|
|
}
|
|
}
|