// WL-816j2 β€” β‘‘ πŸ”΄ νŒμ •μ€ **PD 카메라 ꡬ도**(MainCamera Β· FOV 60 Β· 45Β° Β· 22 m Β· 1280Γ—720)μ—μ„œ. // 무늬 μ„  3단 Β· 띠 폭 3단 Β· κ±°ν’ˆ 색 쀑립화 Β· 사방 확인 Β· μ„±λŠ₯(λ“œλ‘œμš°μ½œΒ·ms/frame) μ „/ν›„. // πŸ”΄ Play 쀑 에셋 μˆ˜μ • 0 β€” 물은 λŸ°νƒ€μž„ Material 볡사본, λ λŠ” μ»΄ν¬λ„ŒνŠΈμ˜ λŸ°νƒ€μž„ μ˜€λ²„λΌμ΄λ“œ. using System.Collections; using System.Text; using UnityEngine; using UnityEngine.Rendering.Universal; using UnityEngine.SceneManagement; using WL.Look.Farm; using FIIsland = CryingSnow.FarmingIsland.Island; public static class WL816j2_Verify { public const string D = "Screenshots_WL/WL816j2/"; public const int PW = 1280, PH = 720; // πŸ”΄ PD ν™”λ©΄κ³Ό 같은 해상도·화각 public const string C_Light = "Color_1ec6cccf8ead489ebb917674f7e8b3b1"; public const string C_Foam = "Color_e1f155248d144786a62fc1585ca21e9a"; public const string R_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5"; public const string R_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e"; public static void Open() { UnityEditor.SceneManagement.EditorSceneManager.OpenScene( "Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single); } public static void Start() { var go = GameObject.Find("~WL816j2V"); if (go != null) Object.DestroyImmediate(go); go = new GameObject("~WL816j2V"); go.AddComponent(); } public static Texture2D Grab(Camera cam, int w, int h) { var rt = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); rt.antiAliasing = 1; rt.Create(); var pT = cam.targetTexture; var pA = RenderTexture.active; cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt; var t = new Texture2D(w, h, TextureFormat.RGB24, false); t.ReadPixels(new Rect(0, 0, w, h), 0, 0); t.Apply(); RenderTexture.active = pA; cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt); return t; } /// PD κ΅¬λ„λ‘œ 찍고 ⓐ λ¬Ό 무늬 μ„  λŒ€λΉ„ β“‘ κ±°ν’ˆ(밝은 ν”½μ…€) ν‰κ· μƒ‰Β·λΉ„μœ¨μ„ μž°λ‹€. public static string Shot(Camera cam, string path) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); var t = Grab(cam, PW, PH); System.IO.File.WriteAllBytes(path, t.EncodeToPNG()); var px = t.GetPixels32(); // ⓐ 무늬 μ„  λŒ€λΉ„ β€” πŸ”΄ **λ°”λ‹€λ§Œ μžˆλŠ” μ™Όμͺ½ μ•„λž˜ ꡬ역**(섬·UI κ°€ μ ˆλŒ€ μ•ˆ λ“€μ–΄μ˜¨λ‹€)μ—μ„œλ§Œ μž°λ‹€ double sum = 0, sum2 = 0; int n = 0; for (int y = 20; y < 320; y += 2) for (int x = 20; x < 340; x += 2) { var c = px[y * PW + x]; float lum = (0.299f * c.r + 0.587f * c.g + 0.114f * c.b) / 255f; sum += lum; sum2 += lum * lum; n++; } double mean = n > 0 ? sum / n : 0, sd = n > 0 ? System.Math.Sqrt(System.Math.Max(0, sum2 / n - mean * mean)) : 0; // β“‘ κ±°ν’ˆ(밝은 ν”½μ…€) β€” ν™”λ©΄ μ•„λž˜ 55 %(UI νšŒν”Ό)μ—μ„œ λΉ„μœ¨κ³Ό 색 long fr = 0, fg = 0, fb = 0; int fn = 0, tot = 0; int y1 = (int)(PH * 0.55f); for (int y = 0; y < y1; y++) for (int x = 0; x < PW; x += 2) { var c = px[y * PW + x]; tot++; if (c.r > 200 && c.g > 195 && c.b > 195) { fr += c.r; fg += c.g; fb += c.b; fn++; } } Object.DestroyImmediate(t); string foam = fn == 0 ? "κ±°ν’ˆ 0%" : "κ±°ν’ˆ " + (100f * fn / tot).ToString("F2") + "% 색 #" + ((int)(fr / fn)).ToString("X2") + ((int)(fg / fn)).ToString("X2") + ((int)(fb / fn)).ToString("X2") + " (Rβˆ’B " + ((int)(fr / fn) - (int)(fb / fn)) + ")"; return "λ°”λ‹€ λ¬΄λŠ¬λŒ€λΉ„ Οƒ=" + sd.ToString("F4") + " Β· " + foam + " β†’ " + path; } public static float Ms(Camera cam, int frames) { var rt = new RenderTexture(PW, PH, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); rt.antiAliasing = 1; rt.Create(); var pT = cam.targetTexture; cam.targetTexture = rt; for (int i = 0; i < 10; i++) cam.Render(); var sw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < frames; i++) cam.Render(); sw.Stop(); cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt); return (float)sw.Elapsed.TotalMilliseconds / frames; } public static void Strip(string[] paths, string outPath) { var ts = new Texture2D[paths.Length]; int w = 0, h = 0; for (int i = 0; i < paths.Length; i++) { if (!System.IO.File.Exists(paths[i])) return; ts[i] = new Texture2D(2, 2, TextureFormat.RGB24, false); ts[i].LoadImage(System.IO.File.ReadAllBytes(paths[i])); w = Mathf.Max(w, ts[i].width); h += ts[i].height; } var o = new Texture2D(w, h, TextureFormat.RGB24, false); var f = new Color32[w * h]; for (int i = 0; i < f.Length; i++) f[i] = new Color32(24, 24, 28, 255); o.SetPixels32(f); int y = h; for (int i = 0; i < ts.Length; i++) { y -= ts[i].height; o.SetPixels32(0, y, ts[i].width, ts[i].height, ts[i].GetPixels32()); } o.Apply(); System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outPath)); System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG()); Object.DestroyImmediate(o); for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]); } } public class WL816j2_VerifyRunner : MonoBehaviour { static StringBuilder sb; static void L(string s) { sb.AppendLine(s); } const string D = WL816j2_Verify.D; const string MatDir = "Assets/WL/Look/Farm/Materials/"; void Start() { StartCoroutine(Co()); } IEnumerator Co() { sb = new StringBuilder(); L("=== WL-816j2 β€” PD ꡬ도(FOV 60 Β· 45Β° Β· 22 m Β· 1280Γ—720)μ—μ„œ λ‹€μ‹œ λ§žμΆ˜λ‹€ ==="); var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive); while (op != null && !op.isDone) yield return null; for (int i = 0; i < 8; i++) yield return new WaitForSeconds(1f); Renderer water = null; foreach (var r in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r; Camera live = null; foreach (var c in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) { if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue; if (c.name.StartsWith("~WL816")) continue; if (live == null || c.depth > live.depth) live = c; } var foam = Object.FindFirstObjectByType(FindObjectsInactive.Include); if (water == null || live == null) { L("πŸ”΄ λ¬Ό/카메라 μ—†μŒ"); Done(); yield break; } L("카메라 " + live.name + " pos=" + live.transform.position.ToString("F2") + " 각=" + live.transform.eulerAngles.ToString("F0") + " fov=" + live.fieldOfView + " Β· 거리 " + live.transform.position.magnitude.ToString("F1") + " m"); L("λ¬Ό = " + water.sharedMaterial.name + " Β· λ‘˜λ ˆ 띠 = " + (foam == null ? "πŸ”΄ μ—†μŒ" : WLShoreFoam.LastLog)); var E = water.sharedMaterial; var Dm = UnityEditor.AssetDatabase.LoadAssetAtPath(MatDir + "Farm_Water_WL_D.mat"); // ── 1) μ§€κΈˆ(main μƒνƒœ = λ¬Ό D Β· 띠 μ—†μŒ) ───────────────────── if (foam != null) foam.GetComponent().enabled = false; water.sharedMaterial = Dm; yield return null; yield return new WaitForSeconds(0.3f); L(""); L("1) μ§€κΈˆ(main Β· λ¬Ό D Β· 띠 μ—†μŒ) " + WL816j2_Verify.Shot(live, D + "a_now_pd.png")); // ── 2) 무늬 μ„  3단 (띠 없이 Β· 물만) ────────────────────────── L(""); L("2) 무늬 흰 μ„  3단 β€” LightColor (물색 0.36/0.69/0.82 에 κ°€κΉŒμšΈμˆ˜λ‘ 은은)"); var lc = new[] { new Color(0.80f, 0.90f, 0.96f), new Color(0.60f, 0.82f, 0.91f), new Color(0.45f, 0.74f, 0.86f) }; var ls = new string[3]; for (int i = 0; i < 3; i++) { var m = new Material(E); m.SetColor(WL816j2_Verify.C_Light, lc[i]); water.sharedMaterial = m; yield return null; yield return new WaitForSeconds(0.2f); ls[i] = D + "b_line" + (i + 1) + ".png"; L(" " + lc[i] + " " + WL816j2_Verify.Shot(live, ls[i])); } WL816j2_Verify.Strip(ls, D + "b_line_steps.png"); // 데λͺ¨(FI 원본) 물의 μ„  λŒ€λΉ„ = κΈ°μ€€ var FI = UnityEditor.AssetDatabase.LoadAssetAtPath(MatDir + "Farm_SimpleWater_Demo.mat"); water.sharedMaterial = FI; yield return null; yield return new WaitForSeconds(0.2f); L(" [κΈ°μ€€] 데λͺ¨ λ¬Ό(FI SimpleWater) " + WL816j2_Verify.Shot(live, D + "b_line0_demo.png")); // ── 3) 띠 폭 3단 (λ¬Ό = E Β· μ„  쀑간값) ─────────────────────── var pick = new Material(E); pick.SetColor(WL816j2_Verify.C_Light, lc[1]); water.sharedMaterial = pick; yield return null; L(""); L("3) λ‘˜λ ˆ 띠 폭 3단 (PD ꡬ도)"); if (foam != null) { foam.GetComponent().enabled = true; var ws = new string[3]; float[] wid = { 0.9f, 1.6f, 2.6f }; for (int i = 0; i < 3; i++) { foam.widthOverride = wid[i]; foam.Rebuild(); yield return null; yield return new WaitForSeconds(0.2f); ws[i] = D + "c_band" + (i + 1) + ".png"; L(" 폭 " + wid[i] + " m Β· " + WLShoreFoam.LastLog); L(" " + WL816j2_Verify.Shot(live, ws[i])); } WL816j2_Verify.Strip(ws, D + "c_band_steps.png"); foam.widthOverride = 0f; foam.Rebuild(); yield return null; } else L(" πŸ”΄ 띠 μ»΄ν¬λ„ŒνŠΈκ°€ μ—†λ‹€"); // ── 4) κ±°ν’ˆ 색 쀑립화 β€” ν™”λ©΄μ—μ„œ Rβˆ’B λ₯Ό 0 에 κ°€κΉκ²Œ ───────── L(""); L("4) κ±°ν’ˆ 색 β€” PD μΊ‘μ²˜κ°€ λΆ„ν™λΉ›μ΄μ—ˆλ‹€. ν™”λ©΄μ—μ„œ μž¬μ„œ 쀑립 ν°μƒ‰μœΌλ‘œ λ§žμΆ˜λ‹€(Rβˆ’B κ°€ 0 에 κ°€κΉŒμšΈμˆ˜λ‘ 쀑립)"); if (foam != null) { var mr = foam.GetComponent(); var tints = new[] { new Color(1f,1f,1f,0.92f), new Color(0.93f,0.97f,1f,0.92f), new Color(0.86f,0.95f,1f,0.90f) }; var cs = new string[3]; for (int i = 0; i < 3; i++) { var mi = new Material(foam.cfg.shoreFoamMaterial); mi.SetColor("_BaseColor", tints[i]); mr.sharedMaterial = mi; yield return null; yield return new WaitForSeconds(0.2f); cs[i] = D + "d_tint" + (i + 1) + ".png"; L(" _BaseColor " + tints[i] + " " + WL816j2_Verify.Shot(live, cs[i])); } WL816j2_Verify.Strip(cs, D + "d_tint_steps.png"); } // ── 5) 사방 확인 + ν™•μž₯ ───────────────────────────────────── // ── 4-b) λ¬Όκ°€ ν™•λŒ€ (띠가 μ–΄λ–»κ²Œ λ³΄μ΄λŠ”μ§€) ─────────────────── if (foam != null) { var mr2 = foam.GetComponent(); mr2.sharedMaterial = foam.cfg.shoreFoamMaterial; var b = mr2.bounds; var zgo = new GameObject("~WL816j2Zoom"); zgo.hideFlags = HideFlags.DontSave; var zc = zgo.AddComponent(); zc.fieldOfView = 34f; zc.nearClipPlane = 0.1f; zc.farClipPlane = 2000f; zc.clearFlags = CameraClearFlags.Skybox; zc.cullingMask = ~0; zc.depth = -100f; zgo.AddComponent().renderPostProcessing = true; zgo.transform.position = new Vector3(b.center.x, 3.2f, b.min.z - 9f); zgo.transform.LookAt(new Vector3(b.center.x, -1f, b.min.z + 2f)); mr2.enabled = false; yield return null; yield return null; L(""); L("4-b) λ¬Όκ°€ ν™•λŒ€ β€” 띠 off " + WL816j2_Verify.Shot(zc, D + "f_zoom_off.png")); mr2.enabled = true; yield return null; yield return null; L(" λ¬Όκ°€ ν™•λŒ€ β€” 띠 on " + WL816j2_Verify.Shot(zc, D + "f_zoom_on.png")); WL816j2_Verify.Strip(new[] { D + "f_zoom_off.png", D + "f_zoom_on.png" }, D + "f_zoom_pair.png"); Object.DestroyImmediate(zgo); } L(""); L("5) 사방 확인(μœ„μ—μ„œ) + 섬 ν™•μž₯"); var top = new GameObject("~WL816j2Top"); top.hideFlags = HideFlags.DontSave; var tc = top.AddComponent(); tc.fieldOfView = 55f; tc.nearClipPlane = 0.1f; tc.farClipPlane = 2000f; tc.clearFlags = CameraClearFlags.Skybox; tc.cullingMask = ~0; tc.depth = -100f; top.AddComponent().renderPostProcessing = true; top.transform.position = new Vector3(0f, 42f, -12f); top.transform.LookAt(Vector3.zero); L(" μœ„μ—μ„œ " + WL816j2_Verify.Shot(tc, D + "e_top_allsides.png")); var islands = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); FIIsland target = null; foreach (var isl in islands) if (isl != null && isl.IsUnlocked && isl.gameObject.activeInHierarchy) target = isl; if (target != null) { target.gameObject.SetActive(false); yield return new WaitForSeconds(2.5f); L(" 1μΉΈ 잠금 β†’ " + WLShoreFoam.LastLog); L(" " + WL816j2_Verify.Shot(tc, D + "e_top_locked.png")); target.gameObject.SetActive(true); yield return new WaitForSeconds(3.5f); L(" λ‹€μ‹œ μ—΄κΈ° β†’ " + WLShoreFoam.LastLog + " Β· 띠 μž¬μƒμ„± " + WL.Look.Farm.WLIslandLook.ShoreFoamRebuilds + "회"); L(" " + WL816j2_Verify.Shot(tc, D + "e_top_unlocked.png")); } WL816j2_Verify.Strip(new[] { D + "e_top_allsides.png", D + "e_top_locked.png", D + "e_top_unlocked.png" }, D + "e_expand_steps.png"); // ── 6) μ„±λŠ₯ β€” 띠 on/off κ΅λŒ€ 2회 ──────────────────────────── L(""); L("6) μ„±λŠ₯ (PD ꡬ도 1280Γ—720 Β· 60ν”„λ ˆμž„ μ˜€ν”„μŠ€ν¬λ¦° Β· μˆœμ„œ κ΅λŒ€ 2회)"); var fr = foam != null ? foam.GetComponent() : null; for (int round = 0; round < 2; round++) { if (fr != null) { fr.enabled = false; yield return null; yield return null; } L(" " + round + "회차 띠 off = " + WL816j2_Verify.Ms(live, 60).ToString("F3") + " ms/frame"); if (fr != null) { fr.enabled = true; yield return null; yield return null; } L(" " + round + "회차 띠 on = " + WL816j2_Verify.Ms(live, 60).ToString("F3") + " ms/frame"); } L(" 띠 = λ Œλ”λŸ¬ 1 Β· 머티리얼 1 Β· λ“œλ‘œμš°μ½œ +1 Β· " + WLShoreFoam.LastLog); L(" ν™”λ©΄ 톡계(에디터) drawCalls=" + UnityEditor.UnityStats.drawCalls + " batches=" + UnityEditor.UnityStats.batches + " tris=" + UnityEditor.UnityStats.triangles); Object.DestroyImmediate(top); Done(); } void Done() { System.IO.File.WriteAllText("AgentScripts/WL816j2_VERIFY.txt", sb.ToString()); Debug.Log("[816j2 verify]\n" + sb); } }