// WL-816e 실측 프로브 2 — 섬 타일 윗면 기하 · 길 메시 · Island01 텍스처 · 816a 머티리얼 값 public static class WL816e_Probe2 { public static void Run() { var sb = new System.Text.StringBuilder(); // ── Island01.png 픽셀 ────────────────────────────────────────── var tex = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/FarmingIsland/Textures/Islands/Island01.png"); sb.AppendLine("=== Island01.png " + (tex == null ? "null" : tex.width + "x" + tex.height + " fmt=" + tex.format) + " ==="); if (tex != null) { var path = UnityEditor.AssetDatabase.GetAssetPath(tex); var imp = UnityEditor.AssetImporter.GetAtPath(path) as UnityEditor.TextureImporter; sb.AppendLine(" readable=" + (imp == null ? "?" : imp.isReadable.ToString()) + " filter=" + tex.filterMode + " wrap=" + tex.wrapMode); try { for (int y = tex.height - 1; y >= 0; y--) { var line = new System.Text.StringBuilder(" y" + y + ": "); for (int x = 0; x < tex.width; x++) { var c = tex.GetPixel(x, y); line.Append("(" + c.r.ToString("F2") + "," + c.g.ToString("F2") + "," + c.b.ToString("F2") + ") "); } sb.AppendLine(line.ToString()); } } catch (System.Exception e) { sb.AppendLine(" 픽셀 읽기 실패: " + e.Message); } } // ── 816a 머티리얼 값 ─────────────────────────────────────────── string[] mp = { "Assets/WL/Look/Farm/Materials/Farm_Island01_ToonTex.mat", "Assets/WL/Look/Farm/Materials/Farm_Palette_ToonTex.mat", "Assets/WL/Look/Farm/Materials/Farm_Road01_ToonTex.mat", "Assets/FarmingIsland/Materials/Islands/Island01.mat", "Assets/FarmingIsland/Materials/Roads/Road01.mat", }; for (int i = 0; i < mp.Length; i++) { var m = UnityEditor.AssetDatabase.LoadAssetAtPath(mp[i]); if (m == null) { sb.AppendLine("MAT 없음 " + mp[i]); continue; } sb.AppendLine("MAT " + m.name + " shader=" + m.shader.name); string[] keys = { "_DiffuseColor", "_ShadowDiffuseColor", "_BaseColor", "_Color", "_Shades", "_Brightness", "_MinimumDarkness", "_AmbientStrength", "_Outline", "_OutlineThickness" }; for (int k = 0; k < keys.Length; k++) { if (!m.HasProperty(keys[k])) continue; int id = UnityEngine.Shader.PropertyToID(keys[k]); if (keys[k].Contains("Color") || keys[k] == "_Outline") sb.AppendLine(" " + keys[k] + "=" + m.GetColor(id).ToString("F4")); else sb.AppendLine(" " + keys[k] + "=" + m.GetFloat(id).ToString("F4")); } if (m.HasProperty("_BaseMap")) { var t = m.GetTexture("_BaseMap"); sb.AppendLine(" _BaseMap=" + (t == null ? "none" : t.name)); } } // ── Level01: 섬 메시 목록 · 윗면 기하 · 길 메시 ────────────────── UnityEditor.SceneManagement.EditorSceneManager.OpenScene("Assets/FarmingIsland/Scenes/Level01.unity", UnityEditor.SceneManagement.OpenSceneMode.Single); var mgr = UnityEngine.Object.FindFirstObjectByType(UnityEngine.FindObjectsInactive.Include); var t1 = typeof(CryingSnow.FarmingIsland.IslandManager); var fIsl = t1.GetField("islandMeshes", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var fRoad = t1.GetField("roadMeshes", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var islMeshes = fIsl.GetValue(mgr) as System.Collections.Generic.List; var roadMeshes = fRoad.GetValue(mgr) as System.Collections.Generic.List; sb.AppendLine("=== islandMeshes " + (islMeshes == null ? 0 : islMeshes.Count) + " · roadMeshes " + (roadMeshes == null ? 0 : roadMeshes.Count) + " ==="); for (int i = 0; islMeshes != null && i < islMeshes.Count && i < 50; i++) { var m = islMeshes[i]; if (m == null) { sb.AppendLine(" isl[" + i + "] null"); continue; } TopFace(m, sb, " isl[" + i + "] " + m.name); } for (int i = 0; roadMeshes != null && i < roadMeshes.Count; i++) { var m = roadMeshes[i]; if (m == null) { sb.AppendLine(" road[" + i + "] null"); continue; } TopFace(m, sb, " road[" + i + "] " + m.name); } // ── 마스크 그림(메시 47 · 0 · 46) ─────────────────────────────── int[] show = { 47, 0, 46, 33 }; for (int s = 0; s < show.Length; s++) { if (islMeshes == null || show[s] >= islMeshes.Count) continue; Ascii(islMeshes[show[s]], sb, "ISLAND MASK [" + show[s] + "] " + islMeshes[show[s]].name, 0.001f); } if (roadMeshes != null && roadMeshes.Count > 15) Ascii(roadMeshes[15], sb, "ROAD MASK [15] " + roadMeshes[15].name, 0.001f); if (roadMeshes != null && roadMeshes.Count > 5) Ascii(roadMeshes[5], sb, "ROAD MASK [5] " + roadMeshes[5].name, 0.001f); UnityEngine.Debug.Log(sb.ToString()); } static void TopFace(UnityEngine.Mesh m, System.Text.StringBuilder sb, string label) { var v = m.vertices; var tri = m.triangles; int upTri = 0; float area = 0f; float maxY = -9999f, topY = -9999f; for (int i = 0; i < v.Length; i++) if (v[i].y > maxY) maxY = v[i].y; for (int i = 0; i + 2 < tri.Length; i += 3) { var a = v[tri[i]]; var b = v[tri[i + 1]]; var c = v[tri[i + 2]]; var n = UnityEngine.Vector3.Cross(b - a, c - a); if (n.y <= 0f) continue; float ay = (a.y + b.y + c.y) / 3f; if (ay < maxY - 0.05f) continue; upTri++; area += n.magnitude * 0.5f; if (ay > topY) topY = ay; } sb.AppendLine(label + " verts=" + v.Length + " tris=" + (tri.Length / 3) + " bounds=" + m.bounds.ToString() + " maxY=" + maxY.ToString("F3") + " 윗면tri=" + upTri + " 윗면면적=" + area.ToString("F2") + "㎡"); } static void Ascii(UnityEngine.Mesh m, System.Text.StringBuilder sb, string label, float eps) { sb.AppendLine("--- " + label + " (32x32 over local -4..4) ---"); var v = m.vertices; var tri = m.triangles; float maxY = -9999f; for (int i = 0; i < v.Length; i++) if (v[i].y > maxY) maxY = v[i].y; for (int r = 31; r >= 0; r--) { var line = new System.Text.StringBuilder(" "); for (int c = 0; c < 32; c++) { float x = -4f + (c + 0.5f) * 0.25f; float z = -4f + (r + 0.5f) * 0.25f; line.Append(Inside(v, tri, x, z, maxY) ? '#' : '.'); } sb.AppendLine(line.ToString()); } } static bool Inside(UnityEngine.Vector3[] v, int[] tri, float px, float pz, float maxY) { for (int i = 0; i + 2 < tri.Length; i += 3) { var a = v[tri[i]]; var b = v[tri[i + 1]]; var c = v[tri[i + 2]]; var n = UnityEngine.Vector3.Cross(b - a, c - a); if (n.y <= 0f) continue; if ((a.y + b.y + c.y) / 3f < maxY - 0.05f) continue; float d1 = (px - b.x) * (a.z - b.z) - (a.x - b.x) * (pz - b.z); float d2 = (px - c.x) * (b.z - c.z) - (b.x - c.x) * (pz - c.z); float d3 = (px - a.x) * (c.z - a.z) - (c.x - a.x) * (pz - a.z); bool neg = (d1 < 0) || (d2 < 0) || (d3 < 0); bool pos = (d1 > 0) || (d2 > 0) || (d3 > 0); if (!(neg && pos)) return true; } return false; } }