From 70a3eb380f772c7afbf7d84b83774110aca03810 Mon Sep 17 00:00:00 2001 From: swrring Date: Tue, 15 Sep 2026 18:17:03 +0900 Subject: [PATCH] =?UTF-8?q?[WL-816w]=20=EC=9A=B8=ED=83=80=EB=A6=AC=20?= =?UTF-8?q?=EC=A7=84=EB=B2=94=20=3D=20FI=20=ED=83=80=EC=9D=BC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=97=90=20=EA=B5=AC=EC=9B=8C=EC=A7=84=20=EB=82=9C?= =?UTF-8?q?=EA=B0=84=20=E2=80=94=20=ED=83=80=EC=9D=BC=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=20=EB=B3=B5=EC=A0=9C=20=ED=9B=84=20=EC=9C=97=EB=A9=B4=20?= =?UTF-8?q?=EC=9C=84=20=EC=82=BC=EA=B0=81=ED=98=95=20=EC=A0=9C=EA=B1=B0(WL?= =?UTF-8?q?IslandTileFenceStrip=20=C2=B7=20stripBakedFences=201)=20=C2=B7?= =?UTF-8?q?=20=EC=84=AC=20=EC=9C=A4=EA=B3=BD=20=ED=92=80=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B4=EB=93=9C=20R=203=20m=C2=B7=EB=84=98=EC=B9=A8=200.6=20?= =?UTF-8?q?(PD=20=EC=8B=A4=EC=B8=A1=20=EC=A7=80=EC=8B=9C=20=C2=B7=20#816)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- Assets/WL/Island/WLIslandGateFlow.cs | 2 + Assets/WL/Island/WLIslandSettings.cs | 6 ++ Assets/WL/Island/WLIslandTileFenceStrip.cs | 77 +++++++++++++++++++ .../Resources/WL/WLIslandLookSettings.asset | 4 +- 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 Assets/WL/Island/WLIslandTileFenceStrip.cs diff --git a/Assets/WL/Island/WLIslandGateFlow.cs b/Assets/WL/Island/WLIslandGateFlow.cs index 1d0193572..9fd6ac3d5 100644 --- a/Assets/WL/Island/WLIslandGateFlow.cs +++ b/Assets/WL/Island/WLIslandGateFlow.cs @@ -90,6 +90,7 @@ namespace WL.Island bool haveFarm = HideFarms(cfg, scene, out farmCenter); HideIslandFences(cfg, scene, null); + WLIslandTileFenceStrip.Apply(cfg, scene); // 2026-09-15 Lead 실측 — 타일 메시에 구워진 난간 제거 // 2026-09-15 PD 「게임 시작 시 섬에 울타리가 여전히 남아 있다」 — 시작 직후 FI 타일 활성화가 렌더러를 다시 켜므로 // farmReHideDelaySeconds 간격으로 3회 더 훑는다(이미 꺼진 것은 건너뛴다 · 값 0 이면 무동작). if (cfg.hideIslandFences != 0 && WLIslandBridge.Runner != null) @@ -459,6 +460,7 @@ namespace WL.Island yield return new WaitForSeconds(wait); if (cfg == null || cfg.hideIslandFences == 0 || !scene.IsValid() || !scene.isLoaded) yield break; HideIslandFences(cfg, scene, null); + WLIslandTileFenceStrip.Apply(cfg, scene); // 확장·재구성으로 타일 메시가 바뀌면 다시 잘라낸다(멱등) if (cfg.hideFarms != 0) { Vector3 _c; HideFarms(cfg, scene, out _c); } // 늦게 생긴 밭의 울타리·소품도 } } diff --git a/Assets/WL/Island/WLIslandSettings.cs b/Assets/WL/Island/WLIslandSettings.cs index 1e095b64e..2a628e5d9 100644 --- a/Assets/WL/Island/WLIslandSettings.cs +++ b/Assets/WL/Island/WLIslandSettings.cs @@ -292,6 +292,12 @@ namespace WL.Island [Tooltip("2026-09-15 PD 「흙 지역도 라운딩」 — 밭 사각형 모서리에서 이 거리(m · 맨해튼 dx+dz) 안의 흙칸은 숨긴다. 0 = 무동작(사각형 그대로).")] public float soilCornerRadius = 1.6f; + [Tooltip("🔴 2026-09-15 Lead 실측 — 남은 울타리는 별도 오브젝트가 아니라 **FI 타일 메시에 구워진 난간**이다. 1 이면 타일 메시를 복제해 윗면 위로 솟은 삼각형을 잘라낸다(원본 메시 무수정 · WLIslandTileFenceStrip). 0 = 원본 메시 그대로.")] + public int stripBakedFences = 1; + + [Tooltip("이 높이(m · 타일 로컬 y · 윗면 = 0)보다 위에 정점이 하나라도 있는 삼각형을 난간으로 보고 버린다.")] + public float fenceStripMinY = 0.15f; + [Tooltip("🔴 §1 — 1 이면 **새로 열린 타일**의 머티리얼 배열을 이미 열려 있는 타일과 **같게** 만든다. " + "실측: 바닥 색 자체는 이미 같지만(main b1e58d795), 새 타일만 외곽선 패스(WL/HullOutline)를 " + "못 받아 경계에서 테두리 유무가 갈린다. 새 머티리얼을 만들지 않고 기존 배열을 물려준다.")] diff --git a/Assets/WL/Island/WLIslandTileFenceStrip.cs b/Assets/WL/Island/WLIslandTileFenceStrip.cs new file mode 100644 index 000000000..4fa9c3fa3 --- /dev/null +++ b/Assets/WL/Island/WLIslandTileFenceStrip.cs @@ -0,0 +1,77 @@ +// ───────────────────────────────────────────────────────────────────────────── +// WLIslandTileFenceStrip.cs — FI 섬 타일 메시에 **구워진 난간(울타리)** 을 잘라낸다. +// +// 2026-09-15 Lead 가 실행 중인 화면을 직접 실측: +// · 별도 오브젝트 `Island (n)/Fence01*` 은 렌더러·콜라이더가 이미 꺼져 있고 SetActive(false) 해도 화면의 울타리는 그대로. +// · 풀 인스턴싱을 꺼도 그대로. 화면 안 렌더러 전수 = 타일(04·07·26·34)·물·캠프·플레이어뿐. +// → 남은 울타리는 **타일 메시 자체에 포함된 삼각형**(재질 1개 · 서브메시 1개 · 브라운 = 텍스처 흙 사분면)이다. +// 조치 = 타일 메시를 복제해 윗면(y=0) 위로 `fenceStripMinY` 이상 솟은 삼각형만 버리고 그 복제본을 물린다. +// 원본 메시·FI 코드 0줄 · 되돌리기 `stripBakedFences 0`(다음 로드부터 원본 메시). +// 🔴 모바일 빌드에서는 FI 타일 FBX 의 Read/Write 가 꺼져 있으면 정점을 못 읽는다(에디터는 읽힌다) — 그때는 임포트 설정 1개 변경 필요. +// ───────────────────────────────────────────────────────────────────────────── + +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; +using FIIsland = CryingSnow.FarmingIsland.Island; + +namespace WL.Island +{ + public static class WLIslandTileFenceStrip + { + static readonly Dictionary s_cache = new Dictionary(); + public static int TilesStripped, TrianglesRemoved, Unreadable; + public static string LastLog = ""; + + /// 섬 씬의 타일(FI Island)마다 메시를 검사해 난간 삼각형이 있으면 잘라낸 복제본으로 바꾼다(멱등). + public static void Apply(WLIslandSettings cfg, Scene scene) + { + if (cfg == null || cfg.stripBakedFences == 0) return; + var isls = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); + int changed = 0; + for (int i = 0; i < isls.Length; i++) + { + var isl = isls[i]; + if (isl == null || (scene.IsValid() && isl.gameObject.scene != scene)) continue; + var mf = isl.GetComponent(); + if (mf == null || mf.sharedMesh == null) continue; + var src = mf.sharedMesh; + if (src.name.EndsWith("_nofence")) continue; + + Mesh dst; + if (!s_cache.TryGetValue(src, out dst)) { dst = Strip(src, cfg.fenceStripMinY); s_cache[src] = dst; } + if (dst != null && dst != src) { mf.sharedMesh = dst; TilesStripped++; changed++; } + } + if (changed > 0) + { + LastLog = "타일 난간 제거 — 타일 " + changed + "개 · 누적 삼각형 " + TrianglesRemoved; + WLIslandBridge.Log(cfg, LastLog); + } + } + + static Mesh Strip(Mesh src, float minY) + { + Vector3[] verts; int[] tris; + try { verts = src.vertices; tris = src.triangles; } + catch (System.Exception) { Unreadable++; return src; } // Read/Write 꺼진 메시 — 손대지 않는다 + if (verts == null || tris == null || tris.Length < 3) return src; + + var keep = new List(tris.Length); + int removed = 0; + for (int t = 0; t + 2 < tris.Length; t += 3) + { + int a = tris[t], b = tris[t + 1], c = tris[t + 2]; + if (verts[a].y > minY || verts[b].y > minY || verts[c].y > minY) { removed++; continue; } + keep.Add(a); keep.Add(b); keep.Add(c); + } + if (removed == 0) return src; + + var m = Object.Instantiate(src); + m.name = src.name + "_nofence"; + m.triangles = keep.ToArray(); + m.RecalculateBounds(); + TrianglesRemoved += removed; + return m; + } + } +} diff --git a/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset b/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset index 6bb6005c5..797c37197 100644 --- a/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset +++ b/Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset @@ -114,8 +114,8 @@ MonoBehaviour: farmEdgeNoise: 0.4 farmEdgeNoiseCell: 0.5 outlineRoundEnabled: 1 - outlineRoundRadius: 1.5 - outlineOverhang: 0.3 + outlineRoundRadius: 3 + outlineOverhang: 0.6 outlineRoundCell: 0.25 propMargin: 0.05 propMaxSize: 7.5