// WL-814t 캡처 — 레퍼런스 느낌 4요소 단독/단계/종합 (Play 중 한 프레임 안에서 전부 렌더) // 한 프레임 안에서 찍는 이유: 구름 그림자(_Time)·포즈가 프레임마다 움직여 세션 간 비교가 노이즈투성이가 된다(814s 미확인⑤). // run_script --file AgentScripts/WL814t_Capture.cs --entry WL814t_Capture.Run using System.Collections.Generic; using UnityEngine; using WL.Look.Arena; public static class WL814t_Capture { const string Dir = @"E:\NerdNavis\WL_wt\gameplay\Screenshots_WL\WL814t"; const int W = 1080, H = 1920; const float Close = 3.4f; // 도트A 프리셋과 같은 직교 반높이 = 비교 기준 const float Wide = 10f; // 아레나 씬의 실제 카메라 static Camera s_cam; static Vector3 s_camPos, s_charCenter; static float s_camSize; static System.Text.StringBuilder s_log; public static string Run() { s_log = new System.Text.StringBuilder(); System.IO.Directory.CreateDirectory(Dir); s_cam = Camera.main; if (s_cam == null) { var cs = Object.FindObjectsByType(FindObjectsSortMode.None); if (cs.Length > 0) s_cam = cs[0]; } if (s_cam == null) return "no camera"; s_camPos = s_cam.transform.position; s_camSize = s_cam.orthographicSize; var pc = GameObject.Find("PC_LH_M05"); var rs = pc != null ? pc.GetComponentsInChildren(false) : new Renderer[0]; Bounds b = new Bounds(pc != null ? pc.transform.position : Vector3.zero, Vector3.zero); bool first = true; foreach (var r in rs) { if (r == null || !r.enabled) continue; if (first) { b = r.bounds; first = false; } else b.Encapsulate(r.bounds); } s_charCenter = b.center; s_log.AppendLine("charCenter=" + s_charCenter.ToString("F3") + " bodyH=" + b.size.y.ToString("F3") + " · 화면 캐릭터 키 @ortho3.4 = " + (b.size.y / (2f * Close) * H).ToString("F0") + " px · @ortho10 = " + (b.size.y / (2f * Wide) * H).ToString("F0") + " px"); var cfg = WLReferenceLookSettings.Instance; if (cfg == null) return "no settings asset"; // ── ⓐ 지금(814s) — 아무것도 안 얹은 상태 Shot2("a_now", Nothing(cfg), Close, 0); Shot2("a_now_wide", Nothing(cfg), Wide, 0); Shot2("a_now_pixel", Nothing(cfg), Close, 240); // ── 4요소 단독 Shot2("b_outline_only", Only(cfg, true, false, false, false), Close, 0); Shot2("c_contrast_only", Only(cfg, false, true, false, false), Close, 0); Shot2("d_mood_only", Only(cfg, false, false, true, false), Close, 0); Shot2("e_rim_only", Only(cfg, false, false, false, true), Close, 0); // ── Ⓐ 외곽선 4단 (PD: 굵게 · 상한을 올린 2/4/6/8 px) float[] ws = { 2f, 4f, 6f, 8f }; for (int i = 0; i < ws.Length; i++) { var o = Only(cfg, true, false, false, false); o.outlineWidth = ws[i]; o.outlineWidthBackground = Mathf.Max(1f, ws[i] * 0.45f); Shot2("o" + (i + 1) + "_outline_" + ws[i].ToString("F0") + "px", o, Close, 0); } // 외곽선 색 — 순검정 vs 아주 어두운 보라 { var o = Only(cfg, true, false, false, false); o.outlineWidth = 6f; o.outlineWidthBackground = 2.7f; o.outlineColor = Color.black; Shot2("o5_color_pureblack", o, Close, 0); o.outlineColor = new Color(0.043f, 0.031f, 0.067f, 1f); Shot2("o6_color_darkviolet", o, Close, 0); } // ── Ⓑ 대비 3단 float[] mds = { 0.10f, 0.05f, 0.0f }; for (int i = 0; i < mds.Length; i++) { var o = Only(cfg, false, true, false, false); o.minimumDarkness = mds[i]; o.charShades = 0; Shot2("c" + (i + 1) + "_darkness_" + mds[i].ToString("F2"), o, Close, 0); } // ── Ⓑ2 캐릭터 색단계 7 / 4 / 3 (레퍼런스2 = 부위당 2~3단) int[] shades = { 0, 4, 3 }; for (int i = 0; i < shades.Length; i++) { var o = Only(cfg, false, true, false, false); o.charShades = shades[i]; Shot2("s" + (i + 1) + "_shades_" + (shades[i] == 0 ? 7 : shades[i]), o, Close, 0); } // ── Ⓒ 분위기 3단 float[] ms = { 0.35f, 0.65f, 1.0f }; for (int i = 0; i < ms.Length; i++) { var o = Only(cfg, false, false, true, false); o.moodStrength = ms[i]; Shot2("m" + (i + 1) + "_mood_" + ms[i].ToString("F2"), o, Close, 0); } // ── Ⓓ 림 3단 float[] rss = { 0.6f, 1.25f, 2.2f }; for (int i = 0; i < rss.Length; i++) { var o = Only(cfg, false, false, false, true); o.rimStrength = rss[i]; Shot2("r" + (i + 1) + "_rim_" + rss[i].ToString("F2"), o, Close, 0); } // ── ⓕ 종합안 (비픽셀) var fin = WLReferenceLook.Opt.FromSettings(cfg); Shot2("f_final", fin, Close, 0); Shot2("f_final_wide", fin, Wide, 0); // ── ⓕ2 종합안 + 도트 — 도트A 프리셋(orthoSize 3.4 · pixelHeight 240) var fp = fin; fp.outlineWidth = cfg.outlineWidthPixelMode; fp.outlineWidthBackground = Mathf.Max(0.5f, cfg.outlineWidthPixelMode * 0.5f); Shot2("f_final_pixel", fp, Close, 240); var fp2 = fp; fp2.outlineWidth = cfg.outlineWidthPixelMode * 2f; fp2.outlineWidthBackground = cfg.outlineWidthPixelMode; Shot2("f_final_pixel_w2", fp2, Close, 240); Shot2("f_final_pixel_thick", fin, Close, 240); // 비픽셀 두께 그대로 → 저해상도에서 뭉개지는지 // ── 원복 확인 Shot2("z_restored_check", Nothing(cfg), Close, 0); s_cam.transform.position = s_camPos; s_cam.orthographicSize = s_camSize; s_log.AppendLine("DONE"); return s_log.ToString(); } static WLReferenceLook.Opt Nothing(WLReferenceLookSettings cfg) { var o = WLReferenceLook.Opt.FromSettings(cfg); o.outline = false; o.contrast = false; o.mood = false; o.rim = false; return o; } static WLReferenceLook.Opt Only(WLReferenceLookSettings cfg, bool a, bool b, bool c, bool d) { var o = WLReferenceLook.Opt.FromSettings(cfg); o.outline = a; o.contrast = b; o.mood = c; o.rim = d; return o; } /// 카메라를 먼저 맞춘 뒤(줌 비례 두께가 카메라를 읽는다) 적용 → 렌더. static void Shot2(string name, WLReferenceLook.Opt o, float orthoSize, int pixelHeight) { s_cam.orthographicSize = orthoSize; s_cam.transform.position = s_charCenter - s_cam.transform.forward * 30f; WLReferenceLook.Apply(o, WLReferenceLookSettings.Instance); Shot(name, pixelHeight); } /// 한 장 렌더. pixelHeight 0 = 1080×1920 그대로, >0 = 저해상도 RT 로 찍어 점보간 확대(도트). static void Shot(string name, int pixelHeight) { int rw = W, rh = H; if (pixelHeight > 0) { rh = pixelHeight; rw = Mathf.RoundToInt(pixelHeight * (float)W / H); } var rt = new RenderTexture(rw, rh, 24, RenderTextureFormat.ARGB32); rt.antiAliasing = 1; rt.filterMode = pixelHeight > 0 ? FilterMode.Point : FilterMode.Bilinear; rt.Create(); var prevTarget = s_cam.targetTexture; s_cam.targetTexture = rt; s_cam.Render(); s_cam.targetTexture = prevTarget; var prevActive = RenderTexture.active; RenderTexture.active = rt; var src = new Texture2D(rw, rh, TextureFormat.RGB24, false); src.ReadPixels(new Rect(0, 0, rw, rh), 0, 0); src.Apply(); RenderTexture.active = prevActive; Texture2D outTex = src; if (pixelHeight > 0) { outTex = new Texture2D(W, H, TextureFormat.RGB24, false); var sp = src.GetPixels32(); var dp = new Color32[W * H]; for (int y = 0; y < H; y++) { int sy = Mathf.Min(rh - 1, y * rh / H); for (int x = 0; x < W; x++) { int sx = Mathf.Min(rw - 1, x * rw / W); dp[y * W + x] = sp[sy * rw + sx]; } } outTex.SetPixels32(dp); outTex.Apply(); } System.IO.File.WriteAllBytes(System.IO.Path.Combine(Dir, name + ".png"), outTex.EncodeToPNG()); s_log.AppendLine("shot " + name + " " + rw + "x" + rh + " · ortho " + s_cam.orthographicSize.ToString("F2") + " · " + WLReferenceLook.LastLog); if (outTex != src) Object.Destroy(outTex); Object.Destroy(src); rt.Release(); Object.Destroy(rt); } }