Project_WL/Assets/WL/Look/Farm/WLDungeonGrassInstancer.cs

97 lines
5.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ─────────────────────────────────────────────────────────────────────────────
// WLDungeonGrassInstancer.cs — 던전 데모 인스턴서의 「물 밑 풀 빼기」판 (#851 · 2026-10-12)
//
// PD 「던전에 들어갈 경우 일부 잔디 이미지가 어색하게 보이는 현상(원형 지역에 패턴처럼 듬성듬성 나있는 지형)을 자연스럽게」.
// 실측(WL_Dungeon01): 지형 스플랫이 전부 풀 층이라 데모 인스턴서가 **둥근 연못 바닥에도** 풀잎을 심었고,
// 풀잎이 투명한 물 너머로 격자처럼 비쳤다(연못 바닥 −0.85 m · 수면 −0.10 m).
//
// ■ 하는 일 — 원본 `TerrainInstancesBehaviour` 의 생성 결과를 그대로 받아, 수면 사각형 안이면서 지형 높이가
// 수면보다 `margin` 이상 낮은 점(= 물에 잠긴 뿌리)만 뺀다. 원본 스크립트 0줄 · 씬 파일 0줄.
// ■ 교체 방법 — `Replace` 가 정보를 정적 칸에 둔 뒤 AddComponent 한다 → Awake 에서 원본 값을 복사하고 OnEnable 에서 한 번에 심는다
// (AddComponent 직후 빈 값으로 OnEnable 이 돌면 데모 스크립트가 LogError → 오류 팝업 · 813z 규칙).
// 🔴 Debug.LogError / Debug.LogException 을 쓰지 않는다.
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections.Generic;
using UnityEngine;
using DemoInstancer = global::Environment.Instancing.TerrainInstancesBehaviour;
using DemoSettings = global::Environment.Instancing.InstancingSettings;
using DemoData = global::Environment.Instancing.InstanceData;
namespace WL.Look.Farm
{
public sealed class WLDungeonGrassInstancer : DemoInstancer
{
/// <summary>수면 하나 — 렌더러 바운즈의 xz 사각형 + 수면 높이.</summary>
public struct Pool { public float minX, maxX, minZ, maxZ, surfaceY; }
// ── 진단(프로브·로그가 읽는다)
public static int LastKept, LastDropped;
readonly List<Pool> _pools = new List<Pool>();
float _margin;
struct Setup { public DemoInstancer src; public List<Pool> pools; public float margin; }
static Setup? s_next;
/// <summary>원본을 끄고(버퍼 해제는 호출 쪽) 같은 오브젝트에 이 판을 붙여 다시 심는다. 돌려주는 값 = 새 인스턴서(실패 시 null).</summary>
public static WLDungeonGrassInstancer Replace(DemoInstancer src, List<Pool> pools, float margin)
{
if (src == null || src.GetComponent<Terrain>() == null) return null;
var have = src.GetComponent<WLDungeonGrassInstancer>();
if (have != null) return have;
s_next = new Setup { src = src, pools = pools, margin = margin };
try { return src.gameObject.AddComponent<WLDungeonGrassInstancer>(); } // Awake(값 복사) → OnEnable(심기)
finally { s_next = null; }
}
void Awake()
{
if (!s_next.HasValue) return;
var s = s_next.Value;
FirstLayer = s.src.FirstLayer; SecondLayer = s.src.SecondLayer; ThirdLayer = s.src.ThirdLayer; FourthLayer = s.src.FourthLayer;
PositionVariance = s.src.PositionVariance; ScaleVariance = s.src.ScaleVariance;
_pools.Clear(); if (s.pools != null) _pools.AddRange(s.pools);
_margin = Mathf.Max(0f, s.margin);
}
public override Dictionary<DemoSettings, List<DemoData>> GetInstanceData()
{
var data = base.GetInstanceData();
if (data == null || _pools.Count == 0) return data;
var t = GetComponent<Terrain>();
if (t == null || t.terrainData == null) return data;
// 원본은 위치에서 지형 바운즈 중심을 빼고, 그릴 때 「바운즈 중심 + 터레인 위치」를 더한다 → 월드 = 이 원점 + TRS 위치
Vector3 origin = t.transform.position + t.terrainData.bounds.center;
int kept = 0, dropped = 0;
var result = new Dictionary<DemoSettings, List<DemoData>>(data.Count);
foreach (var kv in data)
{
var list = kv.Value;
var keep = new List<DemoData>(list.Count);
for (int i = 0; i < list.Count; i++)
{
Vector4 c = list[i].TRS.GetColumn(3);
if (Underwater(t, new Vector3(origin.x + c.x, 0f, origin.z + c.z))) { dropped++; continue; }
keep.Add(list[i]); kept++;
}
result.Add(kv.Key, keep);
}
LastKept = kept; LastDropped = dropped;
return result;
}
bool Underwater(Terrain t, Vector3 w)
{
for (int i = 0; i < _pools.Count; i++)
{
var p = _pools[i];
if (w.x < p.minX || w.x > p.maxX || w.z < p.minZ || w.z > p.maxZ) continue;
float h = t.SampleHeight(w) + t.transform.position.y;
if (h < p.surfaceY - _margin) return true;
}
return false;
}
}
}