Project_WL/Assets/WL/Look/WLPixelLookSettings.cs

127 lines
7.3 KiB
C#
Raw Permalink 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.

// ─────────────────────────────────────────────────────────────────────────────
// WLPixelLookSettings.cs — 도트(픽셀아트) 룩 스위치 값의 단일 출처 (SOT · C45)
//
// PD 지시 #814(「Critter 3D Pixel Art Toolkit 으로 우리 게임을 도트 게임처럼 보이게」)
// 발주서 WL-814a §1-2 (2026-09-10)
//
// ■ 왜 URP 기본 기능인가 (실측)
// 임포트된 것은 `Assets/Critter 3D Pixel Art Toolkit/README.pdf` **1개뿐**이다
// (번들 3종 = Critter 3D Pixel Camera · Environment · Volumetric Lighting 은 Asset Store 에서 별도 다운로드).
// → 에셋이 도착하기 전까지 URP 17.3 이 이미 가진 두 값만으로 「도트 룩」 1차 시안을 만든다:
// UniversalRenderPipelineAsset.renderScale … 낮은 해상도로 그린다(= 픽셀이 커진다)
// UniversalRenderPipelineAsset.upscalingFilter … Point(Nearest-Neighbor) 로 확대한다(= 뭉개지지 않는다)
// 이 둘은 **파이프라인 에셋의 런타임 프로퍼티**라 코드에서 켜고 끌 수 있다(셰이더·머티리얼·포스트 0).
//
// ■ 🔴 절대 규칙 — 디스크에 쓰지 않는다
// 파이프라인 에셋은 프로젝트 에셋이다. 에디터에서 그 오브젝트의 값을 바꾸면 **메모리에 남고**,
// PD 가 「Save Project」 를 누르면 `Assets/Settings/URP-*.asset` 에 그대로 기록된다.
// 그래서 이 기능은
// · `EditorUtility.SetDirty` 를 **부르지 않는다**(호출 0)
// · 맵 이탈 · `OnApplicationQuit` · 에디터 플레이모드 종료에서 **원래 값으로 되돌린다**
// · 되돌릴 값(에셋 경로 + renderScale + filter)을 에디터 `SessionState` 에도 적어 둬서
// 도메인 리로드로 static 이 날아가도 다음 로드에서 복원한다(§PixelLook.EditorSafetyNet)
//
// ■ C8 롤백
// `enabled = 0` → 러너 오브젝트가 아예 뜨지 않고 파이프라인 에셋을 한 번도 건드리지 않는다(원본 100 %).
//
// 에셋 경로(고정): Assets/WL/Combat/Settings/Resources/WL/WLPixelLookSettings.asset
// → Resources.Load<WLPixelLookSettings>("WL/WLPixelLookSettings") 1회 로드 후 캐시(기존 WL 설정 SO 관례).
//
// 🔴 어셈블리 주의: Assets/WL/Look/ 에 .asmdef 를 만들지 말 것(MyValue·InGameInfo 가 Assembly-CSharp 에 있다).
// 🔴 이 파일은 Debug.LogError / Debug.LogException 을 쓰지 않는다(813z 규칙).
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Look
{
/// <summary>낮은 해상도를 화면 크기로 확대할 때 쓰는 필터. URP UpscalingFilterSelection 으로 매핑된다.</summary>
public enum PixelUpscaleFilter
{
/// <summary>Nearest-Neighbor — 픽셀이 네모로 남는다(도트 룩의 핵심).</summary>
Point = 0,
/// <summary>Bilinear — 뭉개진다(비교용).</summary>
Linear = 1,
/// <summary>URP 자동 선택(렌더 스케일·해상도에 따라 Point 또는 Linear).</summary>
Auto = 2,
/// <summary>AMD FSR 1.0(선명하게 복원 = 도트 룩과 반대 방향 · 비교용).</summary>
FSR = 3,
}
[CreateAssetMenu(fileName = "WLPixelLookSettings", menuName = "WL/Pixel Look Settings", order = 324)]
public sealed class WLPixelLookSettings : ScriptableObject
{
public const string ResourcesPath = "WL/WLPixelLookSettings";
static WLPixelLookSettings s_cached;
static bool s_lookupDone;
/// <summary>설정 에셋(1회 로드 후 캐시). 없으면 null = 기능 전체 무동작.</summary>
public static WLPixelLookSettings Instance
{
get
{
if (!s_lookupDone)
{
s_cached = Resources.Load<WLPixelLookSettings>(ResourcesPath);
s_lookupDone = true;
}
return s_cached;
}
}
/// <summary>진단·A/B 전용 런타임 스위치(WLCameraFramingSettings.RuntimeDisabled 선례).</summary>
public static bool RuntimeDisabled;
/// <summary>기능이 살아 있는가 = 에셋 존재 · enabled · 런타임 스위치 off.</summary>
public static bool Enabled
{
get { var i = Instance; return i != null && i.enabled && !RuntimeDisabled; }
}
/// <summary>테스트용: 캐시를 비워 다음 접근 때 다시 Resources.Load 한다.</summary>
public static void ClearCache() { s_cached = null; s_lookupDone = false; }
// ─────────────────────────────────────────── 전체 스위치
[Header("전체 스위치 (C8)")]
[Tooltip("0 이면 러너 오브젝트도 뜨지 않고 파이프라인 에셋을 한 번도 건드리지 않는다 = 원본 100 %.")]
public bool enabled = true;
[Tooltip("적용/복원 1줄 로그. 프레임당 로그는 없다(경계에서만).")]
public bool verboseLog = false;
// ─────────────────────────────────────────── 픽셀 크기
[Header("픽셀 크기")]
[Tooltip("세로로 몇 픽셀을 그릴 것인가. renderScale = targetHeightPx ÷ Screen.height.\n" +
"1080×1920 기준: 1920=원본 · 640≈0.333 · 480=0.25 · 360≈0.1875")]
[Range(64, 4096)]
public int targetHeightPx = 480;
[Tooltip("확대 필터. 도트 룩은 Point(Nearest-Neighbor).")]
public PixelUpscaleFilter filter = PixelUpscaleFilter.Point;
[Tooltip("renderScale 하한(URP 자체 하한도 0.1). 0.1 미만은 URP 가 어차피 0.1 로 잘라낸다.")]
[Range(0.05f, 1f)]
public float minRenderScale = 0.1f;
[Tooltip("renderScale 상한. 1 이면 「원본보다 크게 그리는 것」을 막는다(=슈퍼샘플링 방지).")]
[Range(0.5f, 3f)]
public float maxRenderScale = 1f;
// ─────────────────────────────────────────── 적용 범위
[Header("적용 범위 (인게임 한정)")]
[Tooltip("1 이면 전투 맵(Stage/Dungeon)에서만 켠다. 로비·타이틀·농장은 선명하게 둔다.")]
public bool applyOnlyInBattleMap = true;
[Tooltip("1 이면 맵 이탈(타이틀/로비 복귀) · 종료 · 플레이모드 종료에서 원래 값으로 되돌린다. 🔴 0 으로 두지 말 것.")]
public bool restoreOnExit = true;
[Tooltip("맵 진입/이탈 경계를 보는 주기(초). 프레임당 비용 0(시간 비교 1회).")]
[Range(0.05f, 2f)]
public float pollSeconds = 0.25f;
[Tooltip("1 이면 해상도가 바뀌었을 때(회전·창 크기) renderScale 을 다시 계산한다.")]
public bool trackScreenSize = true;
}
}