151 lines
10 KiB
C#
151 lines
10 KiB
C#
// ─────────────────────────────────────────────────────────────────────────────
|
||
// WLEnvLookSettings.cs — Critter Environment 룩(툰 램프 + 1px 픽셀 외곽선 + 구름 그림자
|
||
// + 인스턴싱 잔디 + 거품 물)의 값 SOT. PD 지시 #814 · 발주서 WL-814c (2026-09-10)
|
||
//
|
||
// 🔴 코드 상수 0(C45) — 여기 있는 값만 바꾸면 룩이 바뀐다.
|
||
// 🔴 originals / toons 는 에디터 스크립트(AgentScripts/WL814c_Convert.cs)가 채우는 스왑 표다.
|
||
// 런타임은 이 표에 **있는 머티리얼만** 갈아끼운다 → 파티클·UI·이펙트는 절대 안 바뀐다.
|
||
// 🔴 원본 .mat 파일은 어떤 경로로도 수정되지 않는다(참조만 보관).
|
||
// ─────────────────────────────────────────────────────────────────────────────
|
||
|
||
using UnityEngine;
|
||
|
||
namespace WL.Look.Env
|
||
{
|
||
public sealed class WLEnvLookSettings : ScriptableObject
|
||
{
|
||
public const string kResourcePath = "WL/WLEnvLookSettings";
|
||
|
||
// ── C8 롤백 ──────────────────────────────────────────────────────────
|
||
[Tooltip("0 = 이 기능 전체 정지(러너 오브젝트 0 · 스왑 0 · 피처 0 · 잔디 0)")]
|
||
public bool enabled = true;
|
||
[Tooltip("적용/복원 1줄 로그")]
|
||
public bool verboseLog = false;
|
||
[Tooltip("🔴 WL-814e — 1 이면 814d 룩 토글 허브(LookModeHub.EnvLookOn)를 따른다: 맵 진입 자동 적용도 허브가 ON 일 때만 · [배경] 버튼으로 즉시 적용/원복. 0 이면 814c 원래 동작(맵 진입 자동 적용)")]
|
||
public bool followLookModeHub = true;
|
||
|
||
// ── 맵 경계 ──────────────────────────────────────────────────────────
|
||
[Tooltip("인게임 맵에서만 적용(로비/타이틀 제외)")]
|
||
public bool applyOnlyInBattleMap = true;
|
||
[Tooltip("맵 이탈·종료에서 원복")]
|
||
public bool restoreOnExit = true;
|
||
[Tooltip("맵 경계 폴링 주기(초)")]
|
||
public float pollSeconds = 0.5f;
|
||
[Tooltip("새로 스폰된 몹을 훑는 주기(초) · 0 이면 새 스폰 적용 안 함")]
|
||
public float respawnSweepSeconds = 0.5f;
|
||
|
||
// ── 스왑 대상 ────────────────────────────────────────────────────────
|
||
[Tooltip("맵 렌더러를 Toon 으로 스왑")]
|
||
public bool swapMap = true;
|
||
[Tooltip("캐릭터(PC·몹·보스) 렌더러를 Toon 으로 스왑 — PD 결정용(캡처 ⓔ/ⓕ 비교)")]
|
||
public bool swapCharacters = true;
|
||
|
||
// ── 스왑 표(에디터 스크립트가 채운다 · 손으로 만지지 말 것) ───────────
|
||
public Material[] originals;
|
||
public Material[] toons;
|
||
|
||
// ── 머티리얼 생성 값(에디터 스크립트가 읽는다) ────────────────────────
|
||
[Tooltip("캐릭터 머티리얼도 Toon 으로 만들 것인가(생성 단계)")]
|
||
public bool convertCharacters = true;
|
||
[Tooltip("툰 램프 단계 수 4~8 (데모 7 · 제안 5)")]
|
||
public int shades = 5;
|
||
public float brightness = 0.25f;
|
||
public float minimumDarkness = 0.2f;
|
||
public float ambientStrength = 0.1f;
|
||
[Tooltip("그림자 색 = 원본 색 × 이 계수(데모 머티리얼 관계 근사)")]
|
||
public Color shadowTint = new Color(0.42f, 0.40f, 0.55f, 1f);
|
||
|
||
// ── 1px 픽셀 외곽선(오브젝트 셰이더 내부 계산) ────────────────────────
|
||
public bool outlinesEnabled = true;
|
||
[Tooltip("🔴 캐릭터에도 외곽선을 줄 것인가. 실측: 스킨드 메시는 폴리곤이 촘촘해 270px 에서 노이즈가 된다 → 기본 off")]
|
||
public bool characterOutlines = false;
|
||
[Tooltip("깊이 외곽선 임계 = (외곽선을 낼 최소 단차 m) ÷ (직교 카메라 far − near). 데모 0.01 은 원근 카메라 기준")]
|
||
public float depthThreshold = 0.004f;
|
||
[Tooltip("노멀 외곽선 임계. 데모 1 · 낮출수록 면 안쪽까지 선이 생겨 노이즈가 된다")]
|
||
public float normalThreshold = 1f;
|
||
public Vector4 normalBias = new Vector4(1f, 1f, 1f, 0f);
|
||
public float depthEdgeStrength = 0.5f;
|
||
public float normalEdgeStrength = 0.3f;
|
||
public Color outlineColor = new Color(0f, 0f, 0f, 0f);
|
||
|
||
// ── 구름 그림자 ──────────────────────────────────────────────────────
|
||
// 🔴 실측: Critter Toon 셰이더에 `_CLOUDSENABLED` 키워드는 **없다**(데모 .mat 의 그 키워드는 구버전 잔재).
|
||
// on/off 는 `_Cloud_Strength` 로 한다(0 = 끔).
|
||
public bool cloudShadows = true;
|
||
public float cloudDensity = 0.01f;
|
||
public Vector4 cloudMovement = new Vector4(1f, 1f, 0f, 0f);
|
||
public float cloudStrength = 1f;
|
||
public float cloudCover = 0.5f;
|
||
public float cloudChange = 0.005f;
|
||
public Vector4 cloudStep = new Vector4(13f, 17f, 0f, 0f);
|
||
|
||
// ── 렌더러 피처(깊이·노멀 텍스처) ─────────────────────────────────────
|
||
[Tooltip("PixelOutlineSetupFeature 를 런타임에 켠다")]
|
||
public bool outlineFeature = true;
|
||
[Tooltip("인게임 맵에서만 피처 활성(타이틀·로비 비용 0)")]
|
||
public bool outlineFeatureOnlyInBattleMap = true;
|
||
|
||
// ── 잔디 인스턴싱 ────────────────────────────────────────────────────
|
||
public bool grassEnabled = true;
|
||
[Tooltip("데모 대비 밀도 비율. 1 = 데모(Critter Density 2.5) · 0.5 = 인스턴스 절반")]
|
||
public float grassDensity = 0.5f;
|
||
[Tooltip("데모 실측 Density(면적/인스턴스). 만지지 말 것")]
|
||
public float demoDensity = 2.5f;
|
||
[Tooltip("모바일 상한 — 이 수를 넘으면 밀도를 자동으로 낮춘다")]
|
||
public int maxInstances = 20000;
|
||
[Tooltip("지면 후보 판정: 수평 투영 면적(m²) 하한")]
|
||
public float minGroundFootprint = 100f;
|
||
[Tooltip("지면 후보 판정: 바운드 높이(m) 상한 — 배경 산·절벽을 뺀다(WL_Nature 실측 산 58~200 m · 지면 2~16 m)")]
|
||
public float maxGroundBoundsHeight = 30f;
|
||
[Tooltip("지면 후보 판정: 평평함 = 높이 ÷ 짧은 변. 실측 지면 0.02~0.15 · 나무/바위 0.65~0.90")]
|
||
public float groundFlatness = 0.35f;
|
||
[Tooltip("지면 후보 판정: 메시 면적 ÷ 수평 투영 면적. 실측 지면 ≈1.0 · 나무 수관 ≈0.3 (성긴 면은 지면이 아니다)")]
|
||
public float groundAreaRatio = 0.5f;
|
||
[Tooltip("지면 후보 최대 개수(플레이어에 가까운 순)")]
|
||
public int maxGroundMeshes = 4;
|
||
[Tooltip("잔디 한 포기의 목표 높이(m) — 메시 크기로 Scale 을 자동 계산한다(0 이면 아래 grassScale 을 그대로 쓴다)")]
|
||
public float grassHeightMeters = 0.3f;
|
||
[Tooltip("grassHeightMeters 가 0 일 때 쓰는 원시 Scale(데모 0.35)")]
|
||
public float grassScale = 0.35f;
|
||
public float grassNormalOffset = 0.04f;
|
||
[Tooltip("잔디 : 꽃 가중치(데모 100 : 1)")]
|
||
public float grassProbability = 100f;
|
||
public float flowerProbability = 1f;
|
||
[Tooltip("지면 메시가 읽기 불가일 때 레이캐스트로 만드는 대체 격자 한 변 분할 수")]
|
||
public int groundProbeGrid = 48;
|
||
|
||
// ── 물 ───────────────────────────────────────────────────────────────
|
||
[Tooltip("물 렌더러를 Critter Water 로 스왑(반사 카메라는 붙이지 않는다)")]
|
||
public bool waterEnabled = true;
|
||
public Material waterMaterial;
|
||
|
||
// ── 에셋 참조(에디터 스크립트가 채움) ─────────────────────────────────
|
||
public Mesh grassMesh;
|
||
public Material grassMaterial;
|
||
public Mesh flowerMesh;
|
||
public Material flowerMaterial;
|
||
|
||
// ─────────────────────────────────────────────────────────────────────
|
||
static WLEnvLookSettings s_ins;
|
||
static bool s_tried;
|
||
|
||
/// <summary>프로브·C8 용 런타임 강제 정지(에셋 파일은 건드리지 않는다).</summary>
|
||
public static bool RuntimeDisabled;
|
||
|
||
public static WLEnvLookSettings Instance
|
||
{
|
||
get
|
||
{
|
||
if (s_ins == null && !s_tried) { s_tried = true; s_ins = Resources.Load<WLEnvLookSettings>(kResourcePath); }
|
||
return s_ins;
|
||
}
|
||
}
|
||
|
||
/// <summary>기능이 살아 있는가 = 에셋 존재 · enabled · RuntimeDisabled off.</summary>
|
||
public static bool Enabled { get { var c = Instance; return c != null && c.enabled && !RuntimeDisabled; } }
|
||
|
||
/// <summary>프로브 전용 — 캐시를 비운다(SO 를 코드로 바꿔치기할 때).</summary>
|
||
public static void ClearCacheForProbe() { s_ins = null; s_tried = false; }
|
||
}
|
||
}
|