From 89540cab17df58fa02d3ee80ce9f8c4ea3fb6fc2 Mon Sep 17 00:00:00 2001 From: swrring Date: Sun, 13 Sep 2026 17:26:48 +0900 Subject: [PATCH] =?UTF-8?q?[WL-816j]=20=EB=B0=94=EB=8B=B7=EB=AC=BC=20?= =?UTF-8?q?=EB=AC=B4=EB=8A=AC=20=EA=B0=84=EA=B2=A9=20+=20=EC=84=AC=20?= =?UTF-8?q?=EA=B0=80=EC=9E=A5=EC=9E=90=EB=A6=AC=20=EB=AC=BC=EB=B3=B4?= =?UTF-8?q?=EB=9D=BC=20(#816)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 무늬가 넓어 보이던 원인(실측) = 물 평면이 1000×1000 m 인데 UV 는 0~1 뿐이라 Size 7.83 로는 보로노이 무늬 1칸이 21.3 m (섬 타일 8 m · 캐릭터 1.19 m). Size 66.67 로 올려 1칸 2.5 m. 흐름 0.8 m/s(실측 1.16). 무늬 줄 밝기만 낮춤. 물보라 = 셰이더에 이미 있는 깊이 기반 Foam 의 값만 조정(FoamDistance 6 · FoamEdge 1 · 거품알 0.75 m) — 새 시스템·새 렌더러 0. 색(WaterColor·DarkColor)·DeepDistance·Height·WaweSpeed 는 816h 채택값 그대로. Co-Authored-By: Claude Opus 5 --- AgentScripts/WL816j_BUILD.txt | 8 + AgentScripts/WL816j_Build.cs | 76 ++++ AgentScripts/WL816j_FOAM.txt | 57 +++ AgentScripts/WL816j_Foam.cs | 224 +++++++++++ AgentScripts/WL816j_PICK.txt | 18 + AgentScripts/WL816j_PROBE.txt | 35 ++ AgentScripts/WL816j_Pick.cs | 192 +++++++++ AgentScripts/WL816j_Probe.cs | 133 +++++++ AgentScripts/WL816j_VERIFY.txt | 55 +++ AgentScripts/WL816j_Verify.cs | 376 ++++++++++++++++++ .../Look/Farm/Materials/Farm_Water_WL_D.mat | 99 +++++ .../Farm/Materials/Farm_Water_WL_D.mat.meta | 8 + .../Resources/WL/WLIslandLookSettings.asset | 2 +- 13 files changed, 1282 insertions(+), 1 deletion(-) create mode 100644 AgentScripts/WL816j_BUILD.txt create mode 100644 AgentScripts/WL816j_Build.cs create mode 100644 AgentScripts/WL816j_FOAM.txt create mode 100644 AgentScripts/WL816j_Foam.cs create mode 100644 AgentScripts/WL816j_PICK.txt create mode 100644 AgentScripts/WL816j_PROBE.txt create mode 100644 AgentScripts/WL816j_Pick.cs create mode 100644 AgentScripts/WL816j_Probe.cs create mode 100644 AgentScripts/WL816j_VERIFY.txt create mode 100644 AgentScripts/WL816j_Verify.cs create mode 100644 Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat create mode 100644 Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat.meta diff --git a/AgentScripts/WL816j_BUILD.txt b/AgentScripts/WL816j_BUILD.txt new file mode 100644 index 000000000..7cf296692 --- /dev/null +++ b/AgentScripts/WL816j_BUILD.txt @@ -0,0 +1,8 @@ +=== WL-816j 채택값 === +Farm_Water_WL_D.mat (= C 복사본) + Size 66.67 → 무늬 1칸 2.50 m (지금 21.3 m) + Strength 0.004628 · Speed/NoiseSpeed 0.05333 → 무늬가 흐르는 속도 0.8 m/s (실측 1.16 m/s) + LightColor RGBA(0.800, 0.900, 0.960, 1.000) (무늬 줄의 밝기만 · 물색 불변) + FoamScale 1333 → 거품알 0.75 m · FoamSpeed 0.6667 · FoamDistance 6 · FoamEdge 1 + 그대로 = WaterColor RGBA(0.360, 0.690, 0.820, 1.000) DarkColor RGBA(0.170, 0.420, 0.570, 1.000) DeepDistance 7 Height 0.09 WaweSpeed 0.4 +SO waterTo = Farm_Water_WL_D · waterMode = 1 diff --git a/AgentScripts/WL816j_Build.cs b/AgentScripts/WL816j_Build.cs new file mode 100644 index 000000000..d2a68ba28 --- /dev/null +++ b/AgentScripts/WL816j_Build.cs @@ -0,0 +1,76 @@ +// WL-816j — ⑤ 채택값을 에셋으로 (에디트 모드 · Play 중 금지) +// Farm_Water_WL_D.mat = 816h 채택 C 의 복사본 + 무늬/움직임/거품만 수정. +// 색(WaterColor·DarkColor·FoamColor·FoamShadowColor)과 DeepDistance·Height·WaweSpeed 는 C 그대로. +using System.Text; +using UnityEngine; +using UnityEditor; + +public static class WL816j_Build +{ + const string Dir = "Assets/WL/Look/Farm/Materials/"; + const string R_Size = "Vector1_07238257334b4a149e675e2451801030"; + const string R_Speed = "Vector1_8e22a98f75c94b218c49e6c4805e799d"; + const string R_Strength = "Vector1_99cc56b5c6fd474082f07f00a6df94f9"; + const string R_NoiseSpeed = "Vector1_ad7e0fcd37f44d68b68de6f06bb43b96"; + const string R_FoamScale = "Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f"; + const string R_FoamSpeed = "Vector1_3089b6a325a44c1686907af4ee3b0776"; + const string R_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5"; + const string R_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e"; + const string C_Light = "Color_1ec6cccf8ead489ebb917674f7e8b3b1"; + + public static void Run() + { + var sb = new StringBuilder(); + var src = AssetDatabase.LoadAssetAtPath(Dir + "Farm_Water_WL_C.mat"); + if (src == null) { Debug.LogError("[816j] C 없음"); return; } + + string dst = Dir + "Farm_Water_WL_D.mat"; + if (AssetDatabase.LoadAssetAtPath(dst) == null) + { + AssetDatabase.CopyAsset(Dir + "Farm_Water_WL_C.mat", dst); + AssetDatabase.ImportAsset(dst); + } + var m = AssetDatabase.LoadAssetAtPath(dst); + + // 무늬 1칸 2.5 m (평면 1000 m ÷ (Size × 보로노이 6칸)) + const float plane = 1000f, cells = 6f, cellM = 2.5f, flow = 0.8f, foamM = 0.75f, churn = 0.5f; + float size = plane / (cellM * cells); + m.SetFloat(R_Size, size); + m.SetFloat(R_Strength, 0.3085f / size); // 텍스처 기준 뒤틀림은 816h 와 동일 + m.SetFloat(R_Speed, flow * size / plane); + m.SetFloat(R_NoiseSpeed, flow * size / plane); + m.SetColor(C_Light, new Color(0.80f, 0.90f, 0.96f, 1f)); // 무늬 대비만 낮춤(물색은 그대로) + float fs = plane / foamM; + m.SetFloat(R_FoamScale, fs); + m.SetFloat(R_FoamSpeed, churn * fs / plane); + m.SetFloat(R_FoamDistance, 6f); + m.SetFloat(R_FoamEdge, 1f); + EditorUtility.SetDirty(m); + + var cfg = AssetDatabase.LoadAssetAtPath( + "Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset"); + if (cfg == null) { Debug.LogError("[816j] SO 없음"); return; } + var so = new SerializedObject(cfg); + so.FindProperty("waterTo").objectReferenceValue = m; + so.ApplyModifiedPropertiesWithoutUndo(); + EditorUtility.SetDirty(cfg); + AssetDatabase.SaveAssets(); + + sb.AppendLine("=== WL-816j 채택값 ==="); + sb.AppendLine("Farm_Water_WL_D.mat (= C 복사본)"); + sb.AppendLine(" Size " + m.GetFloat(R_Size).ToString("F2") + " → 무늬 1칸 " + (plane / (m.GetFloat(R_Size) * cells)).ToString("F2") + " m (지금 21.3 m)"); + sb.AppendLine(" Strength " + m.GetFloat(R_Strength).ToString("G4") + " · Speed/NoiseSpeed " + m.GetFloat(R_Speed).ToString("G4") + + " → 무늬가 흐르는 속도 " + flow + " m/s (실측 1.16 m/s)"); + sb.AppendLine(" LightColor " + m.GetColor(C_Light) + " (무늬 줄의 밝기만 · 물색 불변)"); + sb.AppendLine(" FoamScale " + m.GetFloat(R_FoamScale).ToString("F0") + " → 거품알 " + foamM + " m · FoamSpeed " + m.GetFloat(R_FoamSpeed).ToString("G4") + + " · FoamDistance " + m.GetFloat(R_FoamDistance) + " · FoamEdge " + m.GetFloat(R_FoamEdge)); + sb.AppendLine(" 그대로 = WaterColor " + m.GetColor("Color_9af4ad59934f40d1ae6565e6ab22c45e") + + " DarkColor " + m.GetColor("Color_ca031ae309ff42bdb95f777248fb961d") + + " DeepDistance " + m.GetFloat("Vector1_566e288f42864b8e9432d81fbdb83f38") + + " Height " + m.GetFloat("Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9") + + " WaweSpeed " + m.GetFloat("Vector1_ff7a2780aaa94ddd86e156c4707e39a2")); + sb.AppendLine("SO waterTo = " + (cfg.waterTo ? cfg.waterTo.name : "없음") + " · waterMode = " + cfg.waterMode); + System.IO.File.WriteAllText("AgentScripts/WL816j_BUILD.txt", sb.ToString()); + Debug.Log("[816j build]\n" + sb); + } +} diff --git a/AgentScripts/WL816j_FOAM.txt b/AgentScripts/WL816j_FOAM.txt new file mode 100644 index 000000000..bb8f00bea --- /dev/null +++ b/AgentScripts/WL816j_FOAM.txt @@ -0,0 +1,57 @@ +[816j foam] +=== WL-816j ③ 가장자리 물보라 — 값만으로 되는가 === +1) 파이프라인 = URP-Balanced · depthTexture=True · opaqueTexture=True + 게임 카메라 MainCamera pos=(0.00, 15.56, -15.56) 각=(45.00, 0.00, 0.00) fov=60 · requiresDepth=UsePipelineSettings · requiresColor=UsePipelineSettings + 물 머티리얼 queue=3000 shader=Shader Graphs/ToonWaterU + +2) 해안선 x=12.00 (z=-3.78) · 물 y=-1 · 바깥으로 가며 바닥 높이 = -2.0→2.00(South) -1.5→2.00(South) -1.0→2.00(South) -0.5→2.00(South) 0.0→2.00(South) 0.5→-1.00(Water) 1.0→-1.00(Water) 1.5→-1.00(Water) 2.0→-1.00(Water) 2.5→-1.00(Water) 3.0→-1.00(Water) + 확대 카메라 pos=(17.50, 2.20, 1.72) + +3) 깊이 텍스처 동작 — DeepDistance 만 바꿔 화면색이 변하는가 + DeepDistance 0.5 → 평균 #6295B8 흰 3.48% → Screenshots_WL/WL816j/h_deep_0.5.png + DeepDistance 7 → 평균 #6494B7 흰 3.39% → Screenshots_WL/WL816j/h_deep_7.png + DeepDistance 400 → 평균 #6594B7 흰 3.40% → Screenshots_WL/WL816j/h_deep_400.png + +4) 🔴 값만으로 되는가 — FoamEdge 1 고정 · FoamDistance 훑기 (무늬 1.67 m · 거품알 0.75 m) + FoamDistance 2.2 → 평균 #739BBB 흰 10.11% → Screenshots_WL/WL816j/h_foamdist0.png + FoamDistance 6 → 평균 #7CA0BE 흰 15.53% → Screenshots_WL/WL816j/h_foamdist1.png + FoamDistance 20 → 평균 #83A3C0 흰 20.45% → Screenshots_WL/WL816j/h_foamdist2.png + FoamDistance 60 → 평균 #83A3C0 흰 20.41% → Screenshots_WL/WL816j/h_foamdist3.png + FoamDistance 200 → 평균 #83A3C0 흰 20.43% → Screenshots_WL/WL816j/h_foamdist4.png + +5) 무늬 대비 3단 — 흰 줄 밝기(LightColor)만. WaterColor/DarkColor 는 816h 채택값 그대로. + LightColor RGBA(1.000, 1.000, 1.000, 1.000) → 평균 #6E9BAE 흰 4.67% → Screenshots_WL/WL816j/i_contrast1.png + LightColor RGBA(0.800, 0.900, 0.960, 1.000) → 평균 #6C9AAE 흰 1.76% → Screenshots_WL/WL816j/i_contrast2.png + LightColor RGBA(0.620, 0.780, 0.880, 1.000) → 평균 #6B9AAE 흰 1.80% → Screenshots_WL/WL816j/i_contrast3.png + +6) 무늬 크기 (게임 카메라 · 대비는 중간값) — 지금 21.3 m / 4 m / 2.5 m / 1.67 m + 1칸 21.3 m → 평균 #759FB0 흰 10.80% → Screenshots_WL/WL816j/j_cell_game0.png + 1칸 4 m → 평균 #6B9AAE 흰 1.80% → Screenshots_WL/WL816j/j_cell_game1.png + 1칸 2.5 m → 평균 #6D9BAF 흰 1.82% → Screenshots_WL/WL816j/j_cell_game2.png + 1칸 1.67 m → 평균 #6D9BAF 흰 1.85% → Screenshots_WL/WL816j/j_cell_game3.png +UnityEngine.Debug:ExtractStackTraceNoAlloc (byte*,int,string) +UnityEngine.StackTraceUtility:ExtractStackTrace () +UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object) +UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[]) +UnityEngine.Logger:Log (UnityEngine.LogType,object) +UnityEngine.Debug:Log (object) +WL816j_FoamRunner:Done () (at AgentScripts/WL816j_Foam.cs:222) +WL816j_FoamRunner/d__4:MoveNext () (at AgentScripts/WL816j_Foam.cs:216) +UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr) + +(Filename: AgentScripts/WL816j_Foam.cs Line: 222) + +There are 2 event systems in the scene. Please ensure there is always exactly one event system in the scene +UnityEngine.Debug:ExtractStackTraceNoAlloc (byte*,int,string) +UnityEngine.StackTraceUtility:ExtractStackTrace () +UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object) +UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[]) +UnityEngine.Logger:Log (UnityEngine.LogType,object) +UnityEngine.Debug:LogWarning (object) +UnityEngine.EventSystems.EventSystem:Update () (at ./Library/PackageCache/com.unity.ugui@27635d171b1a/Runtime/UGUI/EventSystem/EventSystem.cs:528) + +(Filename: ./Library/PackageCache/com.unity.ugui@27635d171b1a/Runtime/UGUI/EventSystem/EventSystem.cs Line: 528) + +There are 2 event systems in the scene. Please ensure there is always exactly one event system in the scene +UnityEngine.Debug:ExtractStackTraceNoAlloc (byte*,int,string) +UnityEngine.StackTraceUtility:ExtractStackTrace () diff --git a/AgentScripts/WL816j_Foam.cs b/AgentScripts/WL816j_Foam.cs new file mode 100644 index 000000000..4474a1ad3 --- /dev/null +++ b/AgentScripts/WL816j_Foam.cs @@ -0,0 +1,224 @@ +// WL-816j — ③ 가장자리 물보라가 「값만으로」 되는지 실측 (가장 싼 해법 먼저) +// 깊이 텍스처가 살아 있는지 · 섬 벽이 수직이라 띠가 0 폭인지 · FoamDistance 를 키우면 되는지. +// 🔴 자기 완결 파일(run_script 는 파일 1개만 컴파일한다). +using System.Collections; +using System.Text; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +public static class WL816j_Foam +{ + public const string D = "Screenshots_WL/WL816j/"; + public const float PlaneW = 1000f, Cells = 6f; + public const string R_Size = "Vector1_07238257334b4a149e675e2451801030"; + public const string R_Speed = "Vector1_8e22a98f75c94b218c49e6c4805e799d"; + public const string R_Strength = "Vector1_99cc56b5c6fd474082f07f00a6df94f9"; + public const string R_NoiseSpeed = "Vector1_ad7e0fcd37f44d68b68de6f06bb43b96"; + public const string R_FoamScale = "Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f"; + public const string R_FoamSpeed = "Vector1_3089b6a325a44c1686907af4ee3b0776"; + public const string R_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5"; + public const string R_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e"; + public const string R_DeepDistance = "Vector1_566e288f42864b8e9432d81fbdb83f38"; + public const string C_Light = "Color_1ec6cccf8ead489ebb917674f7e8b3b1"; + + public static void Start() + { + var go = GameObject.Find("~WL816jFoam"); + if (go != null) Object.DestroyImmediate(go); + go = new GameObject("~WL816jFoam"); + go.AddComponent(); + Debug.Log("[816j] foam 러너 시작"); + } + + public static Material Make(Material src, float cellM, float flowMs) + { + var m = new Material(src); + float size = PlaneW / (cellM * Cells); + m.SetFloat(R_Size, size); + m.SetFloat(R_Strength, 0.3085f / size); + m.SetFloat(R_Speed, flowMs * size / PlaneW); + m.SetFloat(R_NoiseSpeed, flowMs * size / PlaneW); + return m; + } + 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 tex = new Texture2D(w, h, TextureFormat.RGB24, false); + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); tex.Apply(); + RenderTexture.active = pA; cam.targetTexture = pT; + rt.Release(); Object.DestroyImmediate(rt); + return tex; + } + public static string Shot(Camera cam, string path, int w, int h) + { + System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); + var t = Grab(cam, w, h); + System.IO.File.WriteAllBytes(path, t.EncodeToPNG()); + var px = t.GetPixels32(); long r = 0, g = 0, b = 0; int n = 0, white = 0; + for (int i = 0; i < px.Length; i += 7) + { r += px[i].r; g += px[i].g; b += px[i].b; n++; if (px[i].r > 215 && px[i].g > 215 && px[i].b > 215) white++; } + Object.DestroyImmediate(t); + return "평균 #" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(b / n)).ToString("X2") + + " 흰 " + (100f * white / n).ToString("F2") + "% → " + path; + } + 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 += ts[i].width; h = Mathf.Max(h, ts[i].height); + } + var o = new Texture2D(w, h, TextureFormat.RGB24, false); + var fill = new Color32[w * h]; + for (int i = 0; i < fill.Length; i++) fill[i] = new Color32(24, 24, 28, 255); + o.SetPixels32(fill); + int x = 0; + for (int i = 0; i < ts.Length; i++) { o.SetPixels32(x, 0, ts[i].width, ts[i].height, ts[i].GetPixels32()); x += ts[i].width; } + o.Apply(); + System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG()); + Object.DestroyImmediate(o); + for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]); + } +} + +public class WL816j_FoamRunner : MonoBehaviour +{ + static StringBuilder sb; + static void L(string s) { sb.AppendLine(s); } + const string D = WL816j_Foam.D; + + void Start() { StartCoroutine(Co()); } + + IEnumerator Co() + { + sb = new StringBuilder(); + L("=== WL-816j ③ 가장자리 물보라 — 값만으로 되는가 ==="); + + 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("~WL816j")) continue; + if (live == null || c.depth > live.depth) live = c; + } + if (water == null || live == null) { L("🔴 물/카메라 없음"); Done(); yield break; } + var baseMat = water.sharedMaterial; + + var urp = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset; + L("1) 파이프라인 = " + (urp ? urp.name : "없음") + + " · depthTexture=" + (urp ? urp.supportsCameraDepthTexture.ToString() : "?") + + " · opaqueTexture=" + (urp ? urp.supportsCameraOpaqueTexture.ToString() : "?")); + var acd = live.GetComponent(); + L(" 게임 카메라 " + live.name + " pos=" + live.transform.position + " 각=" + live.transform.eulerAngles + + " fov=" + live.fieldOfView + " · requiresDepth=" + (acd ? acd.requiresDepthOption.ToString() : "컴포넌트없음") + + " · requiresColor=" + (acd ? acd.requiresColorOption.ToString() : "-")); + L(" 물 머티리얼 queue=" + baseMat.renderQueue + " shader=" + baseMat.shader.name); + + // ── 2) 섬 가장자리 단면 ───────────────────────────────────── + float zc = -3.78f, shoreX = 0f; + for (float x = 4f; x < 90f; x += 0.25f) + { + RaycastHit h; + if (Physics.Raycast(new Vector3(x, 60f, zc), Vector3.down, out h, 200f) && h.point.y > -0.9f) shoreX = x; + } + var prof = new StringBuilder(); + for (float d = -2f; d <= 3.01f; d += 0.5f) + { + RaycastHit h; + bool hit = Physics.Raycast(new Vector3(shoreX + d, 60f, zc), Vector3.down, out h, 200f); + prof.Append(" " + d.ToString("F1") + "→" + (hit ? h.point.y.ToString("F2") + "(" + h.collider.name + ")" : "없음")); + } + L(""); + L("2) 해안선 x=" + shoreX.ToString("F2") + " (z=" + zc + ") · 물 y=-1 · 바깥으로 가며 바닥 높이 =" + prof); + + var cgo = GameObject.Find("~WL816jShore2"); + if (cgo == null) { cgo = new GameObject("~WL816jShore2"); cgo.hideFlags = HideFlags.DontSave; } + var cam = cgo.GetComponent(); if (cam == null) cam = cgo.AddComponent(); + cam.orthographic = false; cam.fieldOfView = 32f; cam.nearClipPlane = 0.1f; cam.farClipPlane = 2000f; + cam.clearFlags = CameraClearFlags.Skybox; cam.cullingMask = ~0; cam.depth = -100f; + var ad = cgo.GetComponent(); + if (ad == null) ad = cgo.AddComponent(); + ad.renderPostProcessing = true; + cgo.transform.position = new Vector3(shoreX + 5.5f, 2.2f, zc + 5.5f); + cgo.transform.LookAt(new Vector3(shoreX - 0.5f, -1f, zc - 0.5f)); + L(" 확대 카메라 pos=" + cgo.transform.position); + + // ── 3) 깊이 살아 있나 ─────────────────────────────────────── + L(""); + L("3) 깊이 텍스처 동작 — DeepDistance 만 바꿔 화면색이 변하는가"); + foreach (float dd in new float[] { 0.5f, 7f, 400f }) + { + var m = new Material(baseMat); m.SetFloat(WL816j_Foam.R_DeepDistance, dd); + water.sharedMaterial = m; yield return null; yield return null; + L(" DeepDistance " + dd + " → " + WL816j_Foam.Shot(cam, D + "h_deep_" + dd + ".png", 720, 1280)); + } + + // ── 4) 값만으로 되는가 ────────────────────────────────────── + L(""); + L("4) 🔴 값만으로 되는가 — FoamEdge 1 고정 · FoamDistance 훑기 (무늬 1.67 m · 거품알 0.75 m)"); + var sweep = new float[] { 2.2f, 6f, 20f, 60f, 200f }; + var shots = new string[sweep.Length]; + for (int i = 0; i < sweep.Length; i++) + { + var m = WL816j_Foam.Make(baseMat, 1.67f, 0.8f); + m.SetFloat(WL816j_Foam.R_FoamScale, 1000f / 0.75f); + m.SetFloat(WL816j_Foam.R_FoamSpeed, 0.5f * (1000f / 0.75f) / 1000f); + m.SetFloat(WL816j_Foam.R_FoamEdge, 1f); + m.SetFloat(WL816j_Foam.R_FoamDistance, sweep[i]); + water.sharedMaterial = m; yield return null; yield return null; + shots[i] = D + "h_foamdist" + i + ".png"; + L(" FoamDistance " + sweep[i] + " → " + WL816j_Foam.Shot(cam, shots[i], 720, 1280)); + } + WL816j_Foam.Strip(shots, D + "h_foamdist_sweep.png"); + + // ── 5) 무늬 대비 3단 ──────────────────────────────────────── + L(""); + L("5) 무늬 대비 3단 — 흰 줄 밝기(LightColor)만. WaterColor/DarkColor 는 816h 채택값 그대로."); + var lc = new Color[] { new Color(1f, 1f, 1f, 1f), new Color(0.80f, 0.90f, 0.96f, 1f), new Color(0.62f, 0.78f, 0.88f, 1f) }; + var lcShots = new string[3]; + for (int i = 0; i < 3; i++) + { + var m = WL816j_Foam.Make(baseMat, 1.67f, 0.8f); + m.SetColor(WL816j_Foam.C_Light, lc[i]); + water.sharedMaterial = m; yield return null; yield return null; + lcShots[i] = D + "i_contrast" + (i + 1) + ".png"; + L(" LightColor " + lc[i] + " → " + WL816j_Foam.Shot(live, lcShots[i], 1080, 1920)); + } + WL816j_Foam.Strip(lcShots, D + "i_contrast_steps.png"); + + // ── 6) 무늬 크기 (게임 카메라) ────────────────────────────── + L(""); + L("6) 무늬 크기 (게임 카메라 · 대비는 중간값) — 지금 21.3 m / 4 m / 2.5 m / 1.67 m"); + var cellShots = new string[4]; + float[] cs = { 21.3f, 4f, 2.5f, 1.67f }; + for (int i = 0; i < 4; i++) + { + Material m; + if (i == 0) m = baseMat; + else { m = WL816j_Foam.Make(baseMat, cs[i], 0.8f); m.SetColor(WL816j_Foam.C_Light, lc[1]); } + water.sharedMaterial = m; yield return null; yield return null; + cellShots[i] = D + "j_cell_game" + i + ".png"; + L(" 1칸 " + cs[i] + " m → " + WL816j_Foam.Shot(live, cellShots[i], 1080, 1920)); + } + WL816j_Foam.Strip(cellShots, D + "j_cell_game_steps.png"); + + water.sharedMaterial = baseMat; yield return null; + Done(); + } + + void Done() + { + System.IO.File.WriteAllText("AgentScripts/WL816j_FOAM.txt", sb.ToString()); + Debug.Log("[816j foam]\n" + sb); + } +} diff --git a/AgentScripts/WL816j_PICK.txt b/AgentScripts/WL816j_PICK.txt new file mode 100644 index 000000000..43f73b797 --- /dev/null +++ b/AgentScripts/WL816j_PICK.txt @@ -0,0 +1,18 @@ +=== WL-816j ④ 채택값 고르기 (무늬 2.5 m · 흐름 0.8 · 대비 0.80/0.90/0.96 고정) === +해안선 x=12.00 · 확대 카메라 (17.50, 2.20, 1.72) · 섬 전경 카메라 (0.00, 14.00, -20.00) + +1) 거품 띠 3단 — FoamDistance 3 / 6 / 12 (FoamEdge 1 · 거품알 0.75 m · 흐름 0.5 m/s) + [지금 816h C] 확대 흰 4.64% → Screenshots_WL/WL816j/k_band0_now_shore.png · 섬전경 흰 6.27% → Screenshots_WL/WL816j/k_band0_now_game.png + [FoamDistance 3] 확대 흰 7.93% → Screenshots_WL/WL816j/k_band1_shore.png · 섬전경 흰 3.98% → Screenshots_WL/WL816j/k_band1_game.png + [FoamDistance 6] 확대 흰 14.70% → Screenshots_WL/WL816j/k_band2_shore.png · 섬전경 흰 6.84% → Screenshots_WL/WL816j/k_band2_game.png + [FoamDistance 12] 확대 흰 19.11% → Screenshots_WL/WL816j/k_band3_shore.png · 섬전경 흰 12.01% → Screenshots_WL/WL816j/k_band3_game.png + +2) 거품알 3단 — 1.5 / 0.75 / 0.35 m (FoamDistance 6 · FoamEdge 1) + [거품알 1.5 m] 흰 13.39% → Screenshots_WL/WL816j/l_foamcell1.png + [거품알 0.75 m] 흰 13.87% → Screenshots_WL/WL816j/l_foamcell2.png + [거품알 0.35 m] 흰 14.38% → Screenshots_WL/WL816j/l_foamcell3.png + +3) 🔴 카메라 반대쪽 가장자리 확인 — 깊이 기반 거품은 「시선이 물을 지나 벽에 닿는 쪽」에만 생긴다 + 앞쪽(섬을 보는 쪽) 흰 14.28% → Screenshots_WL/WL816j/m_edge_front.png + 뒤쪽(바다만) 흰 3.18% → Screenshots_WL/WL816j/m_edge_back.png + 섬 위에서(사방 가장자리) 흰 1.43% → Screenshots_WL/WL816j/m_edge_top.png diff --git a/AgentScripts/WL816j_PROBE.txt b/AgentScripts/WL816j_PROBE.txt new file mode 100644 index 000000000..77e491d3f --- /dev/null +++ b/AgentScripts/WL816j_PROBE.txt @@ -0,0 +1,35 @@ +=== WL-816j 실측 ① 물 평면 · 무늬 크기 === +물 오브젝트 = Water pos=(0.00, -1.00, 0.00) lossyScale=(100.00, 1.00, 100.00) + mat=SimpleWater shader=Shader Graphs/Simple Water + mesh=Plane verts=121 tris=200 로컬크기=(10.00, 0.00, 10.00) → 월드 1000 × 1000 m + UV0 범위 = u[0.00,1.00] v[0.00,1.00] → UV 1칸 = 월드 1000.0 m + 🔴 정점 간격 = 100.0 m (11×11 격자) → 버텍스 파도(파장 4.4 m)는 표현 불가 + bounds(월드) = (1000.00, 0.00, 1000.00) +섬(물 제외) 렌더러 370개 · 월드 bounds size=(112.00, 17.98, 95.55) center=(4.00, 0.99, -3.78) +기준: 캐릭터 키 1.19 m · 섬 타일 8 m + +[Farm_Water_WL_C] 무늬 관련 속성 전수 + Size = 7.83 + Speed = 0.01 + Strength = 0.0394 + NoiseSpeed = 0.01 + FoamScale = 28 + FoamSpeed = 0.4 + FoamDistance = 2.2 + FoamEdge = 4 + DeepDistance = 7 + Height = 0.09 + WaweSpeed = 0.4 + WaweNormalSize = 2 + WaweNormalSpeed = 0.03 + WaweNormalStrength = 0 + Smoothness = 0 + Metallic = 0 + AlphaValue = 1 + +보로노이 텍스처 = VoronoiVer2 2048×2048 mip=12 wrap=Repeat +🔴 지금 무늬 1칸 = 평면 1000 m ÷ (Size 7.83 × 칸 6) = 21.3 m (섬 타일 8 m · 캐릭터 1.19 m) +🔴 지금 거품 노이즈 1칸 = 1000 m ÷ FoamScale 28 = 35.7 m + 무늬 흐르는 속도 = NoiseSpeed 0.01 타일/s × 타일 127.7 m = 1.28 m/s + → 목표 1칸 1 m 이면 Size = 167 · 2 m 이면 83 · 3 m 이면 56 +참고(벤더 데모 실측) UToonAndRealisticShaderSampleScene 의 Water = 기본 Plane scale 1 = 10 m · ToonWater.mat Size 2 → 타일 5 m · 1칸 0.83 m · FoamScale 50 → 거품칸 0.2 m diff --git a/AgentScripts/WL816j_Pick.cs b/AgentScripts/WL816j_Pick.cs new file mode 100644 index 000000000..c84853244 --- /dev/null +++ b/AgentScripts/WL816j_Pick.cs @@ -0,0 +1,192 @@ +// WL-816j — ④ 채택값 고르기: 무늬 2.5 m · 흐름 0.8 · 대비 중간 고정 → 거품 띠 3단 · 거품알 3단 · 반대편 가장자리 확인 +// 🔴 자기 완결 파일. +using System.Collections; +using System.Text; +using UnityEngine; +using UnityEngine.Rendering.Universal; + +public static class WL816j_Pick +{ + public const string D = "Screenshots_WL/WL816j/"; + public const float PlaneW = 1000f, Cells = 6f; + public const string R_Size = "Vector1_07238257334b4a149e675e2451801030"; + public const string R_Speed = "Vector1_8e22a98f75c94b218c49e6c4805e799d"; + public const string R_Strength = "Vector1_99cc56b5c6fd474082f07f00a6df94f9"; + public const string R_NoiseSpeed = "Vector1_ad7e0fcd37f44d68b68de6f06bb43b96"; + public const string R_FoamScale = "Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f"; + public const string R_FoamSpeed = "Vector1_3089b6a325a44c1686907af4ee3b0776"; + public const string R_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5"; + public const string R_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e"; + public const string C_Light = "Color_1ec6cccf8ead489ebb917674f7e8b3b1"; + public static readonly Color Light2 = new Color(0.80f, 0.90f, 0.96f, 1f); + + public static void Start() + { + var go = GameObject.Find("~WL816jPick"); + if (go != null) Object.DestroyImmediate(go); + go = new GameObject("~WL816jPick"); + go.AddComponent(); + Debug.Log("[816j] pick 러너 시작"); + } + + /// 채택 후보 = 무늬 2.5 m · 흐름 0.8 m/s · 대비 중간 · 거품알/띠는 인자로. + public static Material Cand(Material src, float foamM, float foamDist, float foamEdge, float churn) + { + var m = new Material(src); + float size = PlaneW / (2.5f * Cells); + m.SetFloat(R_Size, size); + m.SetFloat(R_Strength, 0.3085f / size); + m.SetFloat(R_Speed, 0.8f * size / PlaneW); + m.SetFloat(R_NoiseSpeed, 0.8f * size / PlaneW); + m.SetColor(C_Light, Light2); + float fs = PlaneW / foamM; + m.SetFloat(R_FoamScale, fs); + m.SetFloat(R_FoamSpeed, churn * fs / PlaneW); + m.SetFloat(R_FoamDistance, foamDist); + m.SetFloat(R_FoamEdge, foamEdge); + return m; + } + public static Camera Make(string n, Vector3 pos, Vector3 look, float fov) + { + var go = GameObject.Find(n); + if (go == null) { go = new GameObject(n); go.hideFlags = HideFlags.DontSave; } + var c = go.GetComponent(); if (c == null) c = go.AddComponent(); + c.orthographic = false; c.fieldOfView = fov; c.nearClipPlane = 0.1f; c.farClipPlane = 2000f; + c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f; + go.transform.position = pos; go.transform.LookAt(look); + var a = go.GetComponent(); + if (a == null) a = go.AddComponent(); + a.renderPostProcessing = true; + return c; + } + public static string Shot(Camera cam, string path, int w, int h) + { + System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); + 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); + System.IO.File.WriteAllBytes(path, t.EncodeToPNG()); + var px = t.GetPixels32(); int white = 0, n = 0; + for (int i = 0; i < px.Length; i += 5) { n++; if (px[i].r > 225 && px[i].g > 218 && px[i].b > 218) white++; } + Object.DestroyImmediate(t); + return "흰 " + (100f * white / n).ToString("F2") + "% → " + path; + } + 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 += ts[i].width; h = Mathf.Max(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 x = 0; + for (int i = 0; i < ts.Length; i++) { o.SetPixels32(x, 0, ts[i].width, ts[i].height, ts[i].GetPixels32()); x += ts[i].width; } + o.Apply(); + System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG()); + Object.DestroyImmediate(o); + for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]); + } +} + +public class WL816j_PickRunner : MonoBehaviour +{ + static StringBuilder sb; + static void L(string s) { sb.AppendLine(s); } + const string D = WL816j_Pick.D; + + void Start() { StartCoroutine(Co()); } + + IEnumerator Co() + { + sb = new StringBuilder(); + L("=== WL-816j ④ 채택값 고르기 (무늬 2.5 m · 흐름 0.8 · 대비 0.80/0.90/0.96 고정) ==="); + + 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("~WL816j")) continue; + if (live == null || c.depth > live.depth) live = c; + } + if (water == null || live == null) { L("🔴 물/카메라 없음"); Done(); yield break; } + var baseMat = water.sharedMaterial; + + float zc = -3.78f, shoreX = 0f; + for (float x = 4f; x < 90f; x += 0.25f) + { + RaycastHit h; + if (Physics.Raycast(new Vector3(x, 60f, zc), Vector3.down, out h, 200f) && h.point.y > -0.9f) shoreX = x; + } + var shore = WL816j_Pick.Make("~WL816jS", new Vector3(shoreX + 5.5f, 2.2f, zc + 5.5f), new Vector3(shoreX - 0.5f, -1f, zc - 0.5f), 32f); + // 게임 카메라와 같은 각도로 섬 전체 — 앞쪽(카메라쪽)·뒤쪽 가장자리를 한 화면에 + var isle = WL816j_Pick.Make("~WL816jI", new Vector3(0f, 14f, -20f), new Vector3(0f, 0f, 2f), 55f); + L("해안선 x=" + shoreX.ToString("F2") + " · 확대 카메라 " + shore.transform.position + " · 섬 전경 카메라 " + isle.transform.position); + + // ── 1) 거품 띠 3단 (FoamEdge 1 고정) ──────────────────────── + L(""); + L("1) 거품 띠 3단 — FoamDistance 3 / 6 / 12 (FoamEdge 1 · 거품알 0.75 m · 흐름 0.5 m/s)"); + float[] fd = { 3f, 6f, 12f }; + var sS = new string[4]; var gS = new string[4]; + sS[0] = D + "k_band0_now_shore.png"; gS[0] = D + "k_band0_now_game.png"; + water.sharedMaterial = baseMat; yield return null; yield return null; + L(" [지금 816h C] 확대 " + WL816j_Pick.Shot(shore, sS[0], 720, 1280) + " · 섬전경 " + WL816j_Pick.Shot(isle, gS[0], 1080, 1920)); + for (int i = 0; i < 3; i++) + { + water.sharedMaterial = WL816j_Pick.Cand(baseMat, 0.75f, fd[i], 1f, 0.5f); + yield return null; yield return null; yield return new WaitForSeconds(0.2f); + sS[i + 1] = D + "k_band" + (i + 1) + "_shore.png"; gS[i + 1] = D + "k_band" + (i + 1) + "_game.png"; + L(" [FoamDistance " + fd[i] + "] 확대 " + WL816j_Pick.Shot(shore, sS[i + 1], 720, 1280) + + " · 섬전경 " + WL816j_Pick.Shot(isle, gS[i + 1], 1080, 1920)); + } + WL816j_Pick.Strip(sS, D + "k_band_shore_steps.png"); + WL816j_Pick.Strip(gS, D + "k_band_game_steps.png"); + + // ── 2) 거품알 3단 (FoamDistance 6 고정) ───────────────────── + L(""); + L("2) 거품알 3단 — 1.5 / 0.75 / 0.35 m (FoamDistance 6 · FoamEdge 1)"); + float[] fc = { 1.5f, 0.75f, 0.35f }; + var cS = new string[3]; + for (int i = 0; i < 3; i++) + { + water.sharedMaterial = WL816j_Pick.Cand(baseMat, fc[i], 6f, 1f, 0.5f); + yield return null; yield return null; yield return new WaitForSeconds(0.2f); + cS[i] = D + "l_foamcell" + (i + 1) + ".png"; + L(" [거품알 " + fc[i] + " m] " + WL816j_Pick.Shot(shore, cS[i], 720, 1280)); + } + WL816j_Pick.Strip(cS, D + "l_foamcell_steps.png"); + + // ── 3) 반대편(카메라 반대쪽) 가장자리도 거품이 생기나 ──────── + L(""); + L("3) 🔴 카메라 반대쪽 가장자리 확인 — 깊이 기반 거품은 「시선이 물을 지나 벽에 닿는 쪽」에만 생긴다"); + water.sharedMaterial = WL816j_Pick.Cand(baseMat, 0.75f, 6f, 1f, 0.5f); + yield return null; yield return null; + var back = WL816j_Pick.Make("~WL816jB", new Vector3(shoreX + 5.5f, 2.2f, zc + 5.5f), new Vector3(shoreX + 30f, -1f, zc + 30f), 32f); + L(" 앞쪽(섬을 보는 쪽) " + WL816j_Pick.Shot(shore, D + "m_edge_front.png", 720, 1280)); + L(" 뒤쪽(바다만) " + WL816j_Pick.Shot(back, D + "m_edge_back.png", 720, 1280)); + var top = WL816j_Pick.Make("~WL816jT", new Vector3(0f, 42f, -12f), new Vector3(0f, 0f, 0f), 55f); + L(" 섬 위에서(사방 가장자리) " + WL816j_Pick.Shot(top, D + "m_edge_top.png", 1080, 1920)); + WL816j_Pick.Strip(new[] { D + "m_edge_front.png", D + "m_edge_back.png" }, D + "m_edge_pair.png"); + + water.sharedMaterial = baseMat; yield return null; + Done(); + } + + void Done() + { + System.IO.File.WriteAllText("AgentScripts/WL816j_PICK.txt", sb.ToString()); + Debug.Log("[816j pick]\n" + sb); + } +} diff --git a/AgentScripts/WL816j_Probe.cs b/AgentScripts/WL816j_Probe.cs new file mode 100644 index 000000000..848315cf2 --- /dev/null +++ b/AgentScripts/WL816j_Probe.cs @@ -0,0 +1,133 @@ +// WL-816j — ① 실측: 물 평면의 실제 크기 · 셰이더 무늬 속성 전수 · 무늬 1칸이 몇 m 인가 +// 에디트 모드 · 씬 저장 0 · 에셋 수정 0 (읽기만). +using System.Text; +using UnityEngine; +using UnityEditor; +using UnityEditor.SceneManagement; + +public static class WL816j_Probe +{ + const string MatDir = "Assets/WL/Look/Farm/Materials/"; + const string Voronoi = "Assets/ResWork/UToonAndRealisticWater/Textures/Default/VoronoiVer2.png"; + + // 셰이더 속성 = 사람 이름 → 레퍼런스 이름 (ToonWaterU.shadergraph 실측) + public static readonly string[,] P = { + {"Size","Vector1_07238257334b4a149e675e2451801030"}, + {"Speed","Vector1_8e22a98f75c94b218c49e6c4805e799d"}, + {"Strength","Vector1_99cc56b5c6fd474082f07f00a6df94f9"}, + {"NoiseSpeed","Vector1_ad7e0fcd37f44d68b68de6f06bb43b96"}, + {"FoamScale","Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f"}, + {"FoamSpeed","Vector1_3089b6a325a44c1686907af4ee3b0776"}, + {"FoamDistance","Vector1_101dc4546b684d40bc2ff2fc59ab43d5"}, + {"FoamEdge","Vector1_34f757bec6b8422b9aef3b9d97117a6e"}, + {"DeepDistance","Vector1_566e288f42864b8e9432d81fbdb83f38"}, + {"Height","Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9"}, + {"WaweSpeed","Vector1_ff7a2780aaa94ddd86e156c4707e39a2"}, + {"WaweNormalSize","Vector1_68f0c21b684f4b7c9ebef8789113b107"}, + {"WaweNormalSpeed","Vector1_85ea9246e72a44ed9e0482861767c826"}, + {"WaweNormalStrength","Vector1_2b4963cef1de4859983ffcbae94c6f60"}, + {"Smoothness","Vector1_21ae4fce4585460386edec89c9895501"}, + {"Metallic","Vector1_dd1e17693dc14b10b91828bdfd5adaa8"}, + {"AlphaValue","Vector1_7090c8ca8ea84e2d85858ae4beb5be38"}, + }; + public static string Ref(string human) + { + for (int i = 0; i < P.GetLength(0); i++) if (P[i, 0] == human) return P[i, 1]; + return null; + } + + public static void Run() + { + var sb = new StringBuilder(); + sb.AppendLine("=== WL-816j 실측 ① 물 평면 · 무늬 크기 ==="); + + // ── 물 평면 ──────────────────────────────────────────────── + var scn = EditorSceneManager.OpenScene("Assets/FarmingIsland/Scenes/Level01.unity", OpenSceneMode.Additive); + Renderer water = null; + foreach (var r in Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)) + if (r != null && r.gameObject.scene == scn && r.name == "Water") water = r; + + float planeW = 0f; + if (water == null) sb.AppendLine("🔴 Water 렌더러 없음"); + else + { + var mf = water.GetComponent(); + var m = mf != null ? mf.sharedMesh : null; + var t = water.transform; + sb.AppendLine("물 오브젝트 = " + water.name + " pos=" + t.position + " lossyScale=" + t.lossyScale); + sb.AppendLine(" mat=" + (water.sharedMaterial ? water.sharedMaterial.name : "?") + + " shader=" + (water.sharedMaterial && water.sharedMaterial.shader ? water.sharedMaterial.shader.name : "?")); + if (m != null) + { + var b = m.bounds; + planeW = b.size.x * t.lossyScale.x; + sb.AppendLine(" mesh=" + m.name + " verts=" + m.vertexCount + " tris=" + (m.triangles.Length / 3) + + " 로컬크기=" + b.size + " → 월드 " + planeW.ToString("F0") + " × " + (b.size.z * t.lossyScale.z).ToString("F0") + " m"); + var uv = m.uv; + float u0 = 9f, u1 = -9f, v0 = 9f, v1 = -9f; + for (int i = 0; i < uv.Length; i++) + { u0 = Mathf.Min(u0, uv[i].x); u1 = Mathf.Max(u1, uv[i].x); v0 = Mathf.Min(v0, uv[i].y); v1 = Mathf.Max(v1, uv[i].y); } + sb.AppendLine(" UV0 범위 = u[" + u0.ToString("F2") + "," + u1.ToString("F2") + "] v[" + v0.ToString("F2") + "," + v1.ToString("F2") + "]" + + " → UV 1칸 = 월드 " + (planeW / Mathf.Max(0.0001f, u1 - u0)).ToString("F1") + " m"); + // 정점 간격 = 버텍스 파도가 표현 가능한 최소 파장 + int side = Mathf.RoundToInt(Mathf.Sqrt(m.vertexCount)); + sb.AppendLine(" 🔴 정점 간격 = " + (planeW / Mathf.Max(1, side - 1)).ToString("F1") + " m (" + + side + "×" + side + " 격자) → 버텍스 파도(파장 4.4 m)는 표현 불가"); + } + sb.AppendLine(" bounds(월드) = " + water.bounds.size); + } + + // ── 섬 타일 · 기준 크기 ──────────────────────────────────── + Bounds land = new Bounds(); + bool first = true; int landN = 0; + foreach (var r in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) + { + if (r == null || r.gameObject.scene != scn || r == water) continue; + if (r.bounds.size.sqrMagnitude <= 0f) continue; + if (first) { land = r.bounds; first = false; } else land.Encapsulate(r.bounds); + landN++; + } + sb.AppendLine("섬(물 제외) 렌더러 " + landN + "개 · 월드 bounds size=" + land.size + " center=" + land.center); + sb.AppendLine("기준: 캐릭터 키 1.19 m · 섬 타일 8 m"); + + // ── 머티리얼 값 전수 ─────────────────────────────────────── + string[] mats = { "Farm_Water_WL_C" }; + foreach (var mn in mats) + { + var mm = AssetDatabase.LoadAssetAtPath(MatDir + mn + ".mat"); + if (mm == null) { sb.AppendLine("🔴 " + mn + " 없음"); continue; } + sb.AppendLine(""); + sb.AppendLine("[" + mn + "] 무늬 관련 속성 전수"); + for (int i = 0; i < P.GetLength(0); i++) + sb.AppendLine(" " + P[i, 0].PadRight(20) + " = " + mm.GetFloat(P[i, 1]).ToString("G6")); + } + + // ── 무늬 1칸이 몇 m 인가 (보로노이 텍스처 = 한 타일에 6칸 · 파이썬 실측) ── + var tex = AssetDatabase.LoadAssetAtPath(Voronoi); + sb.AppendLine(""); + sb.AppendLine("보로노이 텍스처 = " + (tex ? tex.name + " " + tex.width + "×" + tex.height + " mip=" + tex.mipmapCount + " wrap=" + tex.wrapMode : "없음")); + const float N = 6f; // 한 타일에 들어 있는 보로노이 칸 수(가로) — 실측 + var cur = AssetDatabase.LoadAssetAtPath(MatDir + "Farm_Water_WL_C.mat"); + if (cur != null && planeW > 0f) + { + float size = cur.GetFloat(Ref("Size")); + float foamScale = cur.GetFloat(Ref("FoamScale")); + float noiseSpeed = cur.GetFloat(Ref("NoiseSpeed")); + sb.AppendLine("🔴 지금 무늬 1칸 = 평면 " + planeW.ToString("F0") + " m ÷ (Size " + size + " × 칸 " + N + ") = " + + (planeW / (size * N)).ToString("F1") + " m (섬 타일 8 m · 캐릭터 1.19 m)"); + sb.AppendLine("🔴 지금 거품 노이즈 1칸 = " + planeW.ToString("F0") + " m ÷ FoamScale " + foamScale + " = " + + (planeW / foamScale).ToString("F1") + " m"); + sb.AppendLine(" 무늬 흐르는 속도 = NoiseSpeed " + noiseSpeed + " 타일/s × 타일 " + (planeW / size).ToString("F1") + " m = " + + (noiseSpeed * planeW / size).ToString("F2") + " m/s"); + sb.AppendLine(" → 목표 1칸 1 m 이면 Size = " + (planeW / (1f * N)).ToString("F0") + + " · 2 m 이면 " + (planeW / (2f * N)).ToString("F0") + + " · 3 m 이면 " + (planeW / (3f * N)).ToString("F0")); + } + sb.AppendLine("참고(벤더 데모 실측) UToonAndRealisticShaderSampleScene 의 Water = 기본 Plane scale 1 = 10 m · ToonWater.mat Size 2 → 타일 5 m · 1칸 0.83 m · FoamScale 50 → 거품칸 0.2 m"); + + EditorSceneManager.CloseScene(scn, true); + System.IO.Directory.CreateDirectory("AgentScripts"); + System.IO.File.WriteAllText("AgentScripts/WL816j_PROBE.txt", sb.ToString()); + Debug.Log("[816j probe]\n" + sb); + } +} diff --git a/AgentScripts/WL816j_VERIFY.txt b/AgentScripts/WL816j_VERIFY.txt new file mode 100644 index 000000000..773d67d82 --- /dev/null +++ b/AgentScripts/WL816j_VERIFY.txt @@ -0,0 +1,55 @@ +=== WL-816j 확인 (PD 경로 구조 재현 = InGame 활성 + Level01 Additive) === +Load_Map(900) = 🔴 로그인 없이는 못 탄다 → LoadSceneAsync(Level01, Additive) 로 대체(816f·816h 와 같음) +물 렌더러 = Water mat=Farm_Water_WL_C shader=Shader Graphs/ToonWaterU · 물 교체 1 · 보이는 카메라 = MainCamera +해안선(z=-3.78 에서 +X 방향 마지막 육지) x = 12.0 + +1) 지금 = Farm_Water_WL_C (Size 7.83 → 무늬 1칸 21.3 m · FoamScale 28) + 게임화면 평균=#6D9DB0 → Screenshots_WL/WL816j/a_now_game.png + 바다근접 평균=#7EA0C2 → Screenshots_WL/WL816j/a_now_water.png + 자(정사영 40 m 폭 · 1 m = 27.0 px) 평균=#64A0AA → Screenshots_WL/WL816j/a_now_ruler.png + 가장자리 확대 평균=#6FA3CC → Screenshots_WL/WL816j/a_now_shore.png + 가장자리 흰픽셀 = 9.98 % + +2) 무늬 3단 — 1칸 3 m / 1.67 m / 1 m (움직임은 전부 1.28 m/s 로 고정 · 색·거품 그대로) + [1칸 3 m · Size 56 · Strength 0.00555] + 바다근접 평균=#82A1C3 → Screenshots_WL/WL816j/b_cell1_water.png + 자 평균=#67A2AB → Screenshots_WL/WL816j/b_cell1_ruler.png + [1칸 1.67 m · Size 100 · Strength 0.00309] + 바다근접 평균=#82A1C3 → Screenshots_WL/WL816j/b_cell2_water.png + 자 평균=#67A2AB → Screenshots_WL/WL816j/b_cell2_ruler.png + [1칸 1 m · Size 167 · Strength 0.00185] + 바다근접 평균=#82A1C3 → Screenshots_WL/WL816j/b_cell3_water.png + 자 평균=#69A2AB → Screenshots_WL/WL816j/b_cell3_ruler.png + 3단 한 장 = b_pattern_steps.png(바다근접) · b_pattern_steps_ruler.png(자 · 좌부터 지금/3 m/1.67 m/1 m) + +3) 움직임 3단 — 0.4 / 0.8 / 1.5 m/s (무늬 1칸 1.67 m 고정) · 1.0 초 간격 두 장씩(흐른 거리 확인용) + [0.4 m/s] dt=1.00 s · 두 장 = Screenshots_WL/WL816j/c_flow1_t0.png , Screenshots_WL/WL816j/c_flow1_t1.png (정사영 20 m 폭 · 1 m = 54.0 px) + [0.8 m/s] dt=1.01 s · 두 장 = Screenshots_WL/WL816j/c_flow2_t0.png , Screenshots_WL/WL816j/c_flow2_t1.png (정사영 20 m 폭 · 1 m = 54.0 px) + [1.5 m/s] dt=1.01 s · 두 장 = Screenshots_WL/WL816j/c_flow3_t0.png , Screenshots_WL/WL816j/c_flow3_t1.png (정사영 20 m 폭 · 1 m = 54.0 px) + +4) 🔴 섬 가장자리 물보라 = 셰이더에 **이미 있는 Foam**(깊이 기반)의 값만 조정 — 새 시스템 0 + [거품알 1.5 m · FoamScale 667] 평균=#76A6CE → Screenshots_WL/WL816j/d_foamcell1.png 흰픽셀 10.07 % + [거품알 0.75 m · FoamScale 1333] 평균=#76A6CE → Screenshots_WL/WL816j/d_foamcell2.png 흰픽셀 10.13 % + [거품알 0.375 m · FoamScale 2667] 평균=#76A6CE → Screenshots_WL/WL816j/d_foamcell3.png 흰픽셀 10.17 % + [띠 폭(깊이차) 0.55 m · FoamDistance 2.2] 평균=#76A6CE → Screenshots_WL/WL816j/d_band1.png 흰픽셀 10.19 % + [띠 폭(깊이차) 1.1 m · FoamDistance 4.4] 평균=#76A6CE → Screenshots_WL/WL816j/d_band2.png 흰픽셀 10.06 % + [띠 폭(깊이차) 1.8 m · FoamDistance 7.2] 평균=#76A6CE → Screenshots_WL/WL816j/d_band3.png 흰픽셀 9.79 % + +5) 잔물결 노멀맵 on/off — 셰이더가 이미 샘플링하는 텍스처(WaweNormalStrength 0 이라 꺼져 있던 것) + [off(지금)] 평균=#819FC1 → Screenshots_WL/WL816j/e_normal_off.png + [on 4 m·0.3] 평균=#809FC0 → Screenshots_WL/WL816j/e_normal_on.png + +6) 성능 (같은 카메라 1080×1920 · 60프레임 오프스크린 · 순서 교대 2회) + 0회차 전(816h C) = 0.911 ms/frame + 0회차 후(816j 후보) = 0.939 ms/frame + 1회차 전(816h C) = 1.183 ms/frame + 1회차 후(816j 후보) = 1.126 ms/frame + 드로우콜/렌더러 변화 = 같은 평면 1장 · 머티리얼 1개 · 셰이더 동일 → 0 (값만 다름) + +7) 후보 적용 화면 + 게임화면 평균=#6D98AC → Screenshots_WL/WL816j/f_after_game.png + 바다근접 평균=#809EC0 → Screenshots_WL/WL816j/f_after_water.png + 수평선 평균=#8099BD → Screenshots_WL/WL816j/f_after_horizon.png + 가장자리 평균=#76A6CE → Screenshots_WL/WL816j/f_after_shore.png 흰픽셀 9.94 % + 자 평균=#67A2AB → Screenshots_WL/WL816j/f_after_ruler.png + 좌우 = g_side_by_side.png(좌 지금/우 후보) · g_shore_before_after.png(좌 지금/우 후보 · 가장자리 확대) diff --git a/AgentScripts/WL816j_Verify.cs b/AgentScripts/WL816j_Verify.cs new file mode 100644 index 000000000..210eebfc6 --- /dev/null +++ b/AgentScripts/WL816j_Verify.cs @@ -0,0 +1,376 @@ +// WL-816j — ② PD 경로(구조 재현)에서 무늬 3단 · 움직임 3단 · 가장자리 물보라 · 성능 전/후 +// 🔴 Play 중 에셋(.mat/.asset)을 고치지 않는다 — 런타임 Material 인스턴스만 만들어 렌더러에 건다(§9). +using System.Collections; +using System.Text; +using UnityEngine; +using UnityEngine.Rendering.Universal; +using UnityEngine.SceneManagement; + +public static class WL816j_Verify +{ + public const string Dir = "Screenshots_WL/WL816j/"; + public const int W = 1080, H = 1920; + public const float PlaneW = 1000f; // 실측 + public const float Cells = 6f; // 보로노이 1타일에 든 칸 수(실측) + + public static void Open() + { + UnityEditor.SceneManagement.EditorSceneManager.OpenScene( + "Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single); + Debug.Log("[816j] InGame 열림"); + } + public static void Start() + { + var go = GameObject.Find("~WL816jVerify"); + if (go != null) Object.DestroyImmediate(go); + go = new GameObject("~WL816jVerify"); + go.AddComponent(); + Debug.Log("[816j] verify 러너 시작"); + } + + // ── 카메라 ───────────────────────────────────────────────────── + public static Camera Cam(string name, Vector3 pos, Vector3 euler, float fov) + { + var go = GameObject.Find(name); + if (go == null) { go = new GameObject(name); go.hideFlags = HideFlags.DontSave; } + var c = go.GetComponent(); if (c == null) c = go.AddComponent(); + c.orthographic = false; c.fieldOfView = fov; c.nearClipPlane = 0.3f; c.farClipPlane = 2000f; + c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f; + go.transform.position = pos; go.transform.rotation = Quaternion.Euler(euler); + var ac = go.GetComponent(); + if (ac == null) ac = go.AddComponent(); + ac.renderPostProcessing = true; + return c; + } + /// 🔴 자로 재는 카메라 — 정사영 · 바다만 · 1 m 가 정확히 몇 픽셀인지 안다. + public static Camera RulerCam(float orthoSize) + { + var go = GameObject.Find("~WL816jRuler"); + if (go == null) { go = new GameObject("~WL816jRuler"); go.hideFlags = HideFlags.DontSave; } + var c = go.GetComponent(); if (c == null) c = go.AddComponent(); + c.orthographic = true; c.orthographicSize = orthoSize; + c.nearClipPlane = 0.3f; c.farClipPlane = 400f; c.clearFlags = CameraClearFlags.SolidColor; + c.backgroundColor = Color.black; c.cullingMask = ~0; c.depth = -100f; + go.transform.position = new Vector3(-160f, 60f, -160f); // 섬 밖 열린 바다 + go.transform.rotation = Quaternion.Euler(90f, 0f, 0f); + var ac = go.GetComponent(); + if (ac == null) ac = go.AddComponent(); + ac.renderPostProcessing = false; // 자로 잴 때는 후처리 없이 + return c; + } + public static Camera WaterCam() { return Cam("~WL816jWaterCam", new Vector3(-16f, 5.5f, -16f), new Vector3(10f, 45f, 0f), 45f); } + public static Camera HorizonCam(){ return Cam("~WL816jHorizonCam", new Vector3(-14f, 8f, -14f), new Vector3(4f, 45f, 0f), 55f); } + + // ── 캡처 ─────────────────────────────────────────────────────── + 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 tex = new Texture2D(w, h, TextureFormat.RGB24, false); + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); tex.Apply(); + RenderTexture.active = pA; cam.targetTexture = pT; + rt.Release(); Object.DestroyImmediate(rt); + return tex; + } + public static string Shot(Camera cam, string path) { return Shot(cam, path, W, H); } + public static string Shot(Camera cam, string path, int w, int h) + { + if (cam == null) return "카메라 없음"; + System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); + var tex = Grab(cam, w, h); + System.IO.File.WriteAllBytes(path, tex.EncodeToPNG()); + string s = "평균=" + Band(tex, 0f, 1f); + Object.DestroyImmediate(tex); + return s + " → " + path; + } + public static string Band(Texture2D t, float y0, float y1) + { + int a = Mathf.RoundToInt(y0 * (t.height - 1)), b = Mathf.RoundToInt(y1 * (t.height - 1)); + var px = t.GetPixels32(); long r = 0, g = 0, bl = 0; int n = 0; + for (int y = a; y < b; y += 3) for (int x = 0; x < t.width; x += 3) + { var c = px[y * t.width + x]; r += c.r; g += c.g; bl += c.b; n++; } + if (n == 0) return "-"; + return "#" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(bl / n)).ToString("X2"); + } + /// 흰 픽셀(거품) 비율 % — 물보라가 실제로 생겼는지 숫자로. + public static float FoamPct(Camera cam, int w, int h) + { + var t = Grab(cam, w, h); var px = t.GetPixels32(); int n = 0; + for (int i = 0; i < px.Length; i++) if (px[i].r > 215 && px[i].g > 215 && px[i].b > 215) n++; + Object.DestroyImmediate(t); + return 100f * n / px.Length; + } + public static float Ms(Camera cam, int frames) + { + var rt = new RenderTexture(W, H, 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++) + { ts[i] = Load(paths[i]); if (ts[i] == null) return; w += ts[i].width; h = Mathf.Max(h, ts[i].height); } + var o = new Texture2D(w, h, TextureFormat.RGB24, false); + var fill = new Color32[w * h]; + for (int i = 0; i < fill.Length; i++) fill[i] = new Color32(24, 24, 28, 255); + o.SetPixels32(fill); + int x = 0; + for (int i = 0; i < ts.Length; i++) { o.SetPixels32(x, 0, ts[i].width, ts[i].height, ts[i].GetPixels32()); x += ts[i].width; } + 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 static void Pair(string a, string b, string o) { Strip(new[] { a, b }, o); } + public static Texture2D Load(string p) + { + if (!System.IO.File.Exists(p)) return null; + var t = new Texture2D(2, 2, TextureFormat.RGB24, false); + t.LoadImage(System.IO.File.ReadAllBytes(p)); + return t; + } + + // ── 값 만들기 ────────────────────────────────────────────────── + public const string R_Size = "Vector1_07238257334b4a149e675e2451801030"; + public const string R_Speed = "Vector1_8e22a98f75c94b218c49e6c4805e799d"; + public const string R_Strength = "Vector1_99cc56b5c6fd474082f07f00a6df94f9"; + public const string R_NoiseSpeed = "Vector1_ad7e0fcd37f44d68b68de6f06bb43b96"; + public const string R_FoamScale = "Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f"; + public const string R_FoamSpeed = "Vector1_3089b6a325a44c1686907af4ee3b0776"; + public const string R_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5"; + public const string R_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e"; + public const string R_WaweNormalSize = "Vector1_68f0c21b684f4b7c9ebef8789113b107"; + public const string R_WaweNormalSpeed = "Vector1_85ea9246e72a44ed9e0482861767c826"; + public const string R_WaweNormalStrength = "Vector1_2b4963cef1de4859983ffcbae94c6f60"; + + /// 무늬 1칸을 cellM 미터로, 무늬가 흐르는 속도를 flowMs m/s 로 (색·거품은 손대지 않는다). + public static Material Make(Material src, string name, float cellM, float flowMs) + { + var m = new Material(src); m.name = name; + float size = PlaneW / (cellM * Cells); + m.SetFloat(R_Size, size); + m.SetFloat(R_Strength, 0.3085f / size); // 텍스처 기준 뒤틀림량을 816h 와 똑같이 유지 + m.SetFloat(R_Speed, flowMs * size / PlaneW); + m.SetFloat(R_NoiseSpeed, flowMs * size / PlaneW); + return m; + } + /// 가장자리 거품 — 거품알 크기 foamM(m) · 띠 폭 bandM(깊이차 m) · 흐름 churnMs(m/s). + public static void Foam(Material m, float foamM, float bandM, float churnMs) + { + float fs = PlaneW / foamM; + m.SetFloat(R_FoamScale, fs); + m.SetFloat(R_FoamEdge, 4f); + m.SetFloat(R_FoamDistance, bandM * 4f); // edge=saturate(d/FoamDistance)*FoamEdge → 띠 = FoamDistance/FoamEdge + m.SetFloat(R_FoamSpeed, churnMs * fs / PlaneW); + } +} + +public class WL816j_VerifyRunner : MonoBehaviour +{ + static StringBuilder sb; + static void L(string s) { sb.AppendLine(s); } + const string D = "Screenshots_WL/WL816j/"; + const string MatDir = "Assets/WL/Look/Farm/Materials/"; + + Renderer water; Camera live; + + void Start() { StartCoroutine(Co()); } + + IEnumerator Co() + { + sb = new StringBuilder(); + L("=== WL-816j 확인 (PD 경로 구조 재현 = InGame 활성 + Level01 Additive) ==="); + + bool viaGame = false; + try { if (InGameInfo.Ins != null) { InGameInfo.Ins.Load_Map(900); viaGame = true; } } + catch (System.Exception) { } + L("Load_Map(900) = " + (viaGame ? "성공" : "🔴 로그인 없이는 못 탄다 → LoadSceneAsync(Level01, Additive) 로 대체(816f·816h 와 같음)")); + if (!viaGame) + { + var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive); + while (op != null && !op.isDone) yield return null; + } + for (int i = 0; i < 7; i++) yield return new WaitForSeconds(1f); + + foreach (var r in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) + if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r; + foreach (var c in Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) + { + if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue; + if (c.name.StartsWith("~WL816j")) continue; + if (live == null || c.depth > live.depth) live = c; + } + L("물 렌더러 = " + (water == null ? "🔴 없음" : water.name + " mat=" + water.sharedMaterial.name + " shader=" + water.sharedMaterial.shader.name) + + " · 물 교체 " + WL.Look.Farm.WLIslandLook.WaterSwapped + " · 보이는 카메라 = " + (live ? live.name : "없음")); + var baseMat = water != null ? water.sharedMaterial : null; // = 816h 채택 Farm_Water_WL_C + if (baseMat == null || live == null) { Done(); yield break; } + + // ── 0) 해안선 찾기 (물보라 확대용) ────────────────────────── + float shoreX = 0f, shoreZ = -3.78f; + for (float x = 4f; x < 90f; x += 0.5f) + { + RaycastHit hit; + bool land = Physics.Raycast(new Vector3(x, 60f, shoreZ), Vector3.down, out hit, 200f) && hit.point.y > -0.9f; + if (land) shoreX = x; + } + L("해안선(z=" + shoreZ + " 에서 +X 방향 마지막 육지) x = " + shoreX.ToString("F1")); + var shoreCam = WL816j_Verify.Cam("~WL816jShore", new Vector3(shoreX + 11f, 1.6f, shoreZ + 8f), new Vector3(9f, 215f, 0f), 26f); + + // ── 1) 지금(816h 채택 C) ──────────────────────────────────── + L(""); + L("1) 지금 = " + baseMat.name + " (Size " + baseMat.GetFloat(WL816j_Verify.R_Size).ToString("G4") + + " → 무늬 1칸 " + (1000f / (baseMat.GetFloat(WL816j_Verify.R_Size) * 6f)).ToString("F1") + " m" + + " · FoamScale " + baseMat.GetFloat(WL816j_Verify.R_FoamScale).ToString("G4") + ")"); + L(" 게임화면 " + WL816j_Verify.Shot(live, D + "a_now_game.png")); + L(" 바다근접 " + WL816j_Verify.Shot(WL816j_Verify.WaterCam(), D + "a_now_water.png")); + L(" 자(정사영 40 m 폭 · 1 m = 27.0 px) " + WL816j_Verify.Shot(WL816j_Verify.RulerCam(20f), D + "a_now_ruler.png", 1080, 1080)); + L(" 가장자리 확대 " + WL816j_Verify.Shot(shoreCam, D + "a_now_shore.png")); + L(" 가장자리 흰픽셀 = " + WL816j_Verify.FoamPct(shoreCam, 540, 960).ToString("F2") + " %"); + + // ── 2) 무늬 3단 (움직임은 지금과 같은 1.28 m/s 로 고정) ───── + L(""); + L("2) 무늬 3단 — 1칸 3 m / 1.67 m / 1 m (움직임은 전부 1.28 m/s 로 고정 · 색·거품 그대로)"); + float[] cells = { 3f, 1.67f, 1f }; + var sizeShots = new string[4]; var rulerShots = new string[4]; + sizeShots[0] = D + "a_now_water.png"; rulerShots[0] = D + "a_now_ruler.png"; + var mats = new Material[3]; + for (int i = 0; i < 3; i++) + { + mats[i] = WL816j_Verify.Make(baseMat, "J_cell" + cells[i], cells[i], 1.28f); + water.sharedMaterial = mats[i]; + yield return null; yield return null; yield return new WaitForSeconds(0.3f); + sizeShots[i + 1] = D + "b_cell" + (i + 1) + "_water.png"; + rulerShots[i + 1] = D + "b_cell" + (i + 1) + "_ruler.png"; + L(" [1칸 " + cells[i] + " m · Size " + mats[i].GetFloat(WL816j_Verify.R_Size).ToString("F0") + + " · Strength " + mats[i].GetFloat(WL816j_Verify.R_Strength).ToString("G3") + "]"); + L(" 바다근접 " + WL816j_Verify.Shot(WL816j_Verify.WaterCam(), sizeShots[i + 1])); + L(" 자 " + WL816j_Verify.Shot(WL816j_Verify.RulerCam(20f), rulerShots[i + 1], 1080, 1080)); + } + WL816j_Verify.Strip(sizeShots, D + "b_pattern_steps.png"); + WL816j_Verify.Strip(rulerShots, D + "b_pattern_steps_ruler.png"); + L(" 3단 한 장 = b_pattern_steps.png(바다근접) · b_pattern_steps_ruler.png(자 · 좌부터 지금/3 m/1.67 m/1 m)"); + + // ── 3) 움직임 3단 (무늬는 1.67 m 고정) ────────────────────── + L(""); + L("3) 움직임 3단 — 0.4 / 0.8 / 1.5 m/s (무늬 1칸 1.67 m 고정) · 1.0 초 간격 두 장씩(흐른 거리 확인용)"); + float[] flows = { 0.4f, 0.8f, 1.5f }; + var flowShots = new string[3]; + for (int i = 0; i < 3; i++) + { + var m = WL816j_Verify.Make(baseMat, "J_flow" + flows[i], 1.67f, flows[i]); + water.sharedMaterial = m; + yield return null; yield return null; yield return new WaitForSeconds(0.3f); + string p0 = D + "c_flow" + (i + 1) + "_t0.png"; + string p1 = D + "c_flow" + (i + 1) + "_t1.png"; + float t0 = Time.time; + WL816j_Verify.Shot(WL816j_Verify.RulerCam(10f), p0, 1080, 1080); + yield return new WaitForSeconds(1f); + float dt = Time.time - t0; + WL816j_Verify.Shot(WL816j_Verify.RulerCam(10f), p1, 1080, 1080); + flowShots[i] = p1; + L(" [" + flows[i] + " m/s] dt=" + dt.ToString("F2") + " s · 두 장 = " + p0 + " , " + p1 + + " (정사영 20 m 폭 · 1 m = 54.0 px)"); + } + WL816j_Verify.Strip(flowShots, D + "c_flow_steps.png"); + + // ── 4) 가장자리 물보라 — 거품알 3단 + 띠 폭 3단 ───────────── + L(""); + L("4) 🔴 섬 가장자리 물보라 = 셰이더에 **이미 있는 Foam**(깊이 기반)의 값만 조정 — 새 시스템 0"); + float[] foamCell = { 1.5f, 0.75f, 0.375f }; + var foamShots = new string[4]; foamShots[0] = D + "a_now_shore.png"; + for (int i = 0; i < 3; i++) + { + var m = WL816j_Verify.Make(baseMat, "J_foam" + i, 1.67f, 0.8f); + WL816j_Verify.Foam(m, foamCell[i], 0.55f, 0.5f); + water.sharedMaterial = m; + yield return null; yield return null; yield return new WaitForSeconds(0.3f); + foamShots[i + 1] = D + "d_foamcell" + (i + 1) + ".png"; + L(" [거품알 " + foamCell[i] + " m · FoamScale " + m.GetFloat(WL816j_Verify.R_FoamScale).ToString("F0") + "] " + + WL816j_Verify.Shot(shoreCam, foamShots[i + 1]) + + " 흰픽셀 " + WL816j_Verify.FoamPct(shoreCam, 540, 960).ToString("F2") + " %"); + } + WL816j_Verify.Strip(foamShots, D + "d_foam_cell_steps.png"); + + float[] band = { 0.55f, 1.1f, 1.8f }; + var bandShots = new string[3]; + for (int i = 0; i < 3; i++) + { + var m = WL816j_Verify.Make(baseMat, "J_band" + i, 1.67f, 0.8f); + WL816j_Verify.Foam(m, 0.75f, band[i], 0.5f); + water.sharedMaterial = m; + yield return null; yield return null; yield return new WaitForSeconds(0.3f); + bandShots[i] = D + "d_band" + (i + 1) + ".png"; + L(" [띠 폭(깊이차) " + band[i] + " m · FoamDistance " + m.GetFloat(WL816j_Verify.R_FoamDistance).ToString("G3") + "] " + + WL816j_Verify.Shot(shoreCam, bandShots[i]) + + " 흰픽셀 " + WL816j_Verify.FoamPct(shoreCam, 540, 960).ToString("F2") + " %"); + } + WL816j_Verify.Strip(bandShots, D + "d_foam_band_steps.png"); + + // ── 5) 잔물결 노멀(공짜 — 텍스처는 이미 뽑고 있고 Strength 0 이라 꺼져 있었다) ── + L(""); + L("5) 잔물결 노멀맵 on/off — 셰이더가 이미 샘플링하는 텍스처(WaweNormalStrength 0 이라 꺼져 있던 것)"); + var mOff = WL816j_Verify.Make(baseMat, "J_normOff", 1.67f, 0.8f); WL816j_Verify.Foam(mOff, 0.75f, 1.1f, 0.5f); + var mOn = new Material(mOff); mOn.name = "J_normOn"; + mOn.SetFloat(WL816j_Verify.R_WaweNormalSize, 250f); // 잔물결 1타일 4 m + mOn.SetFloat(WL816j_Verify.R_WaweNormalSpeed, 0.075f); // 4 m × 0.075 = 0.3 m/s + mOn.SetFloat(WL816j_Verify.R_WaweNormalStrength, 0.3f); + string[] nShots = new string[2]; + var pairM = new[] { mOff, mOn }; + for (int i = 0; i < 2; i++) + { + water.sharedMaterial = pairM[i]; + yield return null; yield return null; yield return new WaitForSeconds(0.3f); + nShots[i] = D + "e_normal_" + (i == 0 ? "off" : "on") + ".png"; + L(" [" + (i == 0 ? "off(지금)" : "on 4 m·0.3") + "] " + WL816j_Verify.Shot(WL816j_Verify.WaterCam(), nShots[i])); + } + WL816j_Verify.Strip(nShots, D + "e_normal_pair.png"); + + // ── 6) 성능 — 전(816h C) / 후(후보) 교대 2회 ──────────────── + L(""); + L("6) 성능 (같은 카메라 1080×1920 · 60프레임 오프스크린 · 순서 교대 2회)"); + var cand = mOff; // 후보 = 무늬 1.67 m · 흐름 0.8 · 거품알 0.75 m · 띠 1.1 m + for (int round = 0; round < 2; round++) + { + foreach (var pr in new[] { new object[] { "전(816h C)", baseMat }, new object[] { "후(816j 후보)", cand } }) + { + water.sharedMaterial = pr[1] as Material; + yield return null; yield return null; + L(" " + round + "회차 " + (string)pr[0] + " = " + WL816j_Verify.Ms(live, 60).ToString("F3") + " ms/frame"); + } + } + L(" 드로우콜/렌더러 변화 = 같은 평면 1장 · 머티리얼 1개 · 셰이더 동일 → 0 (값만 다름)"); + + // ── 7) 후보로 마무리 캡처 ─────────────────────────────────── + water.sharedMaterial = cand; yield return null; yield return new WaitForSeconds(0.3f); + L(""); + L("7) 후보 적용 화면"); + L(" 게임화면 " + WL816j_Verify.Shot(live, D + "f_after_game.png")); + L(" 바다근접 " + WL816j_Verify.Shot(WL816j_Verify.WaterCam(), D + "f_after_water.png")); + L(" 수평선 " + WL816j_Verify.Shot(WL816j_Verify.HorizonCam(), D + "f_after_horizon.png")); + L(" 가장자리 " + WL816j_Verify.Shot(shoreCam, D + "f_after_shore.png") + + " 흰픽셀 " + WL816j_Verify.FoamPct(shoreCam, 540, 960).ToString("F2") + " %"); + L(" 자 " + WL816j_Verify.Shot(WL816j_Verify.RulerCam(20f), D + "f_after_ruler.png", 1080, 1080)); + WL816j_Verify.Pair(D + "a_now_game.png", D + "f_after_game.png", D + "g_side_by_side.png"); + WL816j_Verify.Pair(D + "a_now_shore.png", D + "f_after_shore.png", D + "g_shore_before_after.png"); + L(" 좌우 = g_side_by_side.png(좌 지금/우 후보) · g_shore_before_after.png(좌 지금/우 후보 · 가장자리 확대)"); + + water.sharedMaterial = baseMat; yield return null; + Done(); + } + + void Done() + { + System.IO.File.WriteAllText("AgentScripts/WL816j_VERIFY.txt", sb.ToString()); + Debug.Log("[816j verify 완료]\n" + sb); + } +} diff --git a/Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat b/Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat new file mode 100644 index 000000000..de5a0ab44 --- /dev/null +++ b/Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat @@ -0,0 +1,99 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Farm_Water_WL_D + m_Shader: {fileID: -6465566751694194690, guid: 85b142f88e4bec1488c6b275a0e5dc57, + type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - Texture2D_086cedcb1d864765840f9996e4b0002d: + m_Texture: {fileID: 2800000, guid: 945a5174b1a6da34ea1028ed2feeb1e9, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - Texture2D_1d2b8f4484d74423a27218f18b962ade: + m_Texture: {fileID: 2800000, guid: d48aae5302069a94f9410b8d6b76fed1, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - Texture2D_4094dc7f19e94579ac3bbc9c811f51a4: + m_Texture: {fileID: 2800000, guid: 62100fbe73f198245b71c0a6eeeb94f6, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - Texture2D_685ca00e8e7c4cb2b45a9e11981bb64a: + m_Texture: {fileID: 2800000, guid: 5088aa2234cf5b24cad13def77f7da5f, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - Vector1_07238257334b4a149e675e2451801030: 66.666664 + - Vector1_101dc4546b684d40bc2ff2fc59ab43d5: 6 + - Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f: 1333.3334 + - Vector1_21ae4fce4585460386edec89c9895501: 0 + - Vector1_2b4963cef1de4859983ffcbae94c6f60: 0 + - Vector1_3089b6a325a44c1686907af4ee3b0776: 0.6666667 + - Vector1_34f757bec6b8422b9aef3b9d97117a6e: 1 + - Vector1_566e288f42864b8e9432d81fbdb83f38: 7 + - Vector1_68f0c21b684f4b7c9ebef8789113b107: 2 + - Vector1_7090c8ca8ea84e2d85858ae4beb5be38: 1 + - Vector1_85ea9246e72a44ed9e0482861767c826: 0.03 + - Vector1_8e22a98f75c94b218c49e6c4805e799d: 0.05333333 + - Vector1_99cc56b5c6fd474082f07f00a6df94f9: 0.0046275 + - Vector1_ad7e0fcd37f44d68b68de6f06bb43b96: 0.05333333 + - Vector1_c6f2603b30534ec8b0039379573789e3: 1 + - Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9: 0.09 + - Vector1_dd1e17693dc14b10b91828bdfd5adaa8: 0 + - Vector1_ff7a2780aaa94ddd86e156c4707e39a2: 0.4 + - _QueueControl: 0 + - _QueueOffset: 0 + - _XRMotionVectorsPass: 1 + m_Colors: + - Color_1ec6cccf8ead489ebb917674f7e8b3b1: {r: 0.8, g: 0.9, b: 0.96, a: 1} + - Color_2323d69962e04c499c5d5f0925432b55: {r: 0.78, g: 0.86, b: 0.92, a: 1} + - Color_9af4ad59934f40d1ae6565e6ab22c45e: {r: 0.36, g: 0.69, b: 0.82, a: 1} + - Color_ca031ae309ff42bdb95f777248fb961d: {r: 0.17, g: 0.42, b: 0.57, a: 1} + - Color_e1f155248d144786a62fc1585ca21e9a: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &7840779067325084833 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 diff --git a/Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat.meta b/Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat.meta new file mode 100644 index 000000000..b267c83cd --- /dev/null +++ b/Assets/WL/Look/Farm/Materials/Farm_Water_WL_D.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 064fa97251666874e9da5473b09d43bd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset b/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset index ac793f475..b86a165e6 100644 --- a/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset +++ b/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset @@ -64,7 +64,7 @@ MonoBehaviour: skyReleaseDelaySeconds: 1.5 waterMode: 1 waterFrom: {fileID: 2100000, guid: ce0f8fd131f36964dbc918b8c63f838b, type: 2} - waterTo: {fileID: 2100000, guid: c4a590309ecaa044da75b96fa1e150a3, type: 2} + waterTo: {fileID: 2100000, guid: 064fa97251666874e9da5473b09d43bd, type: 2} grassEnabled: 1 scatter: - enabled_: 1