Project_WL/Assets/WL/Look/Character/WLCharacterBacklightSetting...

167 lines
12 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.

// ─────────────────────────────────────────────────────────────────────────────
// WLCharacterBacklightSettings.cs — 캐릭터 역광(림·라이트 랩·피부 투과) + 번짐(Bloom) 값 (C45 · 코드 상수 금지)
//
// 2026-09-17 PD 「캐릭터가 조금 더 돋보이게」 + 팁(차가운 역광 · SSS · Bloom).
// enabled_ = 0 → 아무 것도 덧붙이지 않는다(캐릭터 재질 배열 원래대로) · bloomEnabled = 0 → 카메라/볼륨 0 변경.
// 🔴 Debug.LogError / Debug.LogException 을 쓰지 않는다(813z 규칙).
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Look.Character
{
public class WLCharacterBacklightSettings : ScriptableObject
{
[Header("스위치")]
[Tooltip("0 = 역광 패스 전체 off(재질 배열 원래대로).")]
public int enabled_ = 1;
[Tooltip("1 이면 적용 내역을 로그로 남긴다.")]
public int verboseLog = 0;
[Header("대상")]
[Tooltip("이 셰이더 이름의 재질을 가진 렌더러에만 덧붙인다(얼굴 Unlit/Transparent · 파티클 제외). 비우면 파티클 외 전부.")]
public string shaderNameFilter = "Shader Graphs/Toon";
[Tooltip("재질 이름에 이 글자가 들어 있으면 피부로 보고 피부 투과(SSS)를 켠 재질을 물린다.")]
public string[] skinMaterialHints = { "Skin" };
[Header("⓪ 본체 밝히기 — 2026-09-17 PD 「캐릭터가 어둡게 보인다 · 원한 건 더 밝고 화사하게」")]
[Tooltip("1 = 캐릭터 본체(Toon) 재질 값을 렌더러별 프로퍼티 블록으로 덮는다(재질 에셋 0줄 · 0 = 덮지 않음).")]
public int baseBrighten = 1;
[Tooltip("그늘의 최소 밝기(원본 0.2). 클수록 그늘이 밝다.")]
[Range(0f, 1f)] public float baseMinimumDarkness = 0.38f;
[Tooltip("그늘 색(원본 (0.216,0.209,0.371) = 어두운 남색). 밝고 따뜻하게.")]
public Color baseShadowColor = new Color(0.46f, 0.38f, 0.44f, 0f);
[Tooltip("구름 그늘 세기(원본은 지형과 같은 값). 0 = 캐릭터는 구름 그늘을 안 받는다(항상 화사). 음수 = 재질 값 그대로.")]
public float baseCloudStrength = 0f;
[Header("① 역광 림 — 2026-09-17 PD 「너무 푸른색 느낌」 → 태양색 계열의 따뜻한 흰빛(차가운 하늘색 (0.28,0.62,1) 에서 변경) · 「라이팅이 과하다」 → 약하게")]
[ColorUsage(false, true)] public Color rimColor = new Color(1f, 0.96f, 0.88f, 1f);
[Tooltip("림 밝기 배수(1 초과 = HDR · Bloom 이 집어낸다).")]
public float rimStrength = 1.0f;
[Header("①-b 화면 공간 깊이 림(기본) — 실루엣 바깥쪽에만 · 화면 픽셀 굵기 일정")]
[Tooltip("1 = 깊이 림 사용(URP 에셋의 Depth Texture 가 꺼져 있으면 자동으로 프레넬만 쓴다). 실측: 프레넬만 쓰면 머리카락 안쪽 가닥마다 줄이 생긴다.")]
public int rimUseDepth = 1;
[Tooltip("띠 굵기 = 화면 짧은 변 × 이 값(0.0045 → 1080 기준 ≈ 5 px).")]
[Range(0f, 0.02f)] public float rimWidth = 0.003f;
[Tooltip("역광 쪽 이웃 픽셀이 이만큼(m) 더 멀면 실루엣으로 본다(작으면 머리카락 가닥에도 생긴다).")]
public float rimDepthThreshold = 0.12f;
[Tooltip("깊이 림에 섞는 프레넬 림의 양 — 가까울 때(두께감).")]
[Range(0f, 1f)] public float rimFresnelNear = 0.25f;
[Tooltip("깊이 림에 섞는 프레넬 림의 양 — 멀 때(0 = 깊이 림만 · 가닥 줄 없음).")]
[Range(0f, 1f)] public float rimFresnelFar = 0f;
[Header("①-a 프레넬 림(보조 · 깊이 텍스처가 없을 때는 이것만)")]
[Tooltip("가까울 때(rimNearDistance 이하)의 띠 굵기 — 클수록 가는 띠(0.4 = 굵게 · 0.7 = 가늘게).")]
[Range(0f, 1f)] public float rimThreshold = 0.52f;
[Tooltip("멀 때(rimFarDistance 이상)의 띠 굵기 — 작게 줘서 굵게. 게임 카메라(섬 12 m · 던전 11 m)에서 캐릭터가 ~70 px 라 가는 띠는 1 px 로 사라진다(실측).")]
[Range(0f, 1f)] public float rimThresholdFar = 0.36f;
[Tooltip("이 거리(m) 이하 = 가까움.")]
public float rimNearDistance = 3f;
[Tooltip("이 거리(m) 이상 = 멂.")]
public float rimFarDistance = 12f;
[Tooltip("띠 가장자리 부드러움(작을수록 셀 느낌).")]
[Range(0.001f, 0.5f)] public float rimSoftness = 0.05f;
[Tooltip("0 = 둘레 전부 · 1 = 가상 역광 쪽 윤곽만.")]
[Range(0f, 1f)] public float rimDirectional = 0.85f;
[Tooltip("림이 바탕을 덮는 정도(1 = 림 색 그대로 · 0 = 순수 가산). 실측: 순수 가산은 노란 머리·살색 위에서 흰 테가 돼 차가운 색이 안 보였다.")]
[Range(0f, 1f)] public float rimOpacity = 0.5f;
[Header("가상 역광 위치(카메라 기준) — 캐릭터 뒤 + 위 + 옆")]
[Tooltip("위쪽 성분(클수록 머리·어깨 윗선에 맺힌다).")]
public float backlightUp = 0.7f;
[Tooltip("옆 성분(+ = 화면 오른쪽 · − = 왼쪽). 메인 조명이 왼쪽 앞에서 오므로 오른쪽 뒤가 자연스럽다.")]
public float backlightSide = 0.8f;
[Header("② 라이트 랩 — 빛이 안쪽으로 스며드는 옅은 번짐")]
[ColorUsage(false, true)] public Color wrapColor = new Color(1f, 0.95f, 0.88f, 1f);
public float wrapStrength = 0.06f;
public float wrapPower = 1.6f;
[Header("③ 피부 투과(SSS 흉내) — 피부 재질에만")]
[ColorUsage(false, true)] public Color sssColor = new Color(1f, 0.32f, 0.22f, 1f);
public float sssStrength = 1.0f;
public float sssPower = 1.7f;
[Header("④ 얼굴 포인트 라이트 — 얼굴 주변만 살짝 밝히는 빛(2026-09-17 PD 「얼굴 쪽을 살짝 포인트로 하이라이트」)")]
[Tooltip("0 = 끔.")]
public int faceEnabled = 1;
[ColorUsage(false, true)] public Color faceColor = new Color(1f, 0.93f, 0.85f, 1f);
[Tooltip("밝기(가산). 0.2 = 은은 · 0.5 = 뚜렷.")]
public float faceStrength = 0.16f;
[Tooltip("빛이 닿는 반지름 = 얼굴(머리) 렌더러 경계 크기 × 이 값. 3 = 얼굴에서 가장 밝고 발끝으로 갈수록 옅어지는 몸 전체 채움빛(「밝고 화사」).")]
public float faceRadiusScale = 3.0f;
[Tooltip("0 = 빛 방향을 향한 면만 · 1 = 둥글게 감싸는 빛.")]
[Range(0f, 1f)] public float faceWrap = 0.8f;
[Tooltip("빛 위치(카메라 기준): 위쪽 성분.")]
public float faceLightUp = 0.6f;
[Tooltip("빛 위치(카메라 기준): 옆 성분(− = 화면 왼쪽 · 역광의 반대쪽).")]
public float faceLightSide = -0.4f;
[Tooltip("얼굴 중심으로 쓸 렌더러 이름 힌트(앞에서부터 찾는다 · 못 찾으면 얼굴 빛 없음).")]
public string[] faceRendererHints = { "Face", "Head" };
[Header("등급 — 2026-09-17 PD 「톤은 전체 공유 · 플레이어 1등급 · 몬스터와 NPC 2등급 · 배경(프랍) 3등급」")]
[Tooltip("1 = 2·3등급도 적용한다. 0 = 플레이어(1등급)만.")]
public int tiersEnabled = 1;
[Tooltip("2등급(몬스터·NPC·동료) — 림 세기/불투명도(1등급보다 약하게).")]
public float tier2RimStrength = 0.7f;
[Range(0f, 1f)] public float tier2RimOpacity = 0.35f;
[Tooltip("2등급 — 몸 전체 채움빛 세기(얼굴 중심 없음).")]
public float tier2FillStrength = 0.07f;
[Tooltip("2등급 — 본체가 Toon 그래프일 때: 그늘 최소 밝기에 더하는 양 · 그늘 색을 공유 그늘 색 쪽으로 섞는 비율(재질마다 원래 값이 달라 상대값으로).")]
[Range(0f, 0.5f)] public float tier2MinimumDarknessAdd = 0.10f;
[Range(0f, 1f)] public float tier2ShadowBlend = 0.6f;
public Color tier2ShadowColor = new Color(0.36f, 0.31f, 0.40f, 0f);
[Tooltip("2등급 — 본체가 MK Toon(힘민지 몬스터)일 때 그늘 색 `_GoochDarkColor`(원본 검정). 전체가 공유하는 따뜻한 보랏빛 그늘 계열.")]
public Color tier2MkShadowColor = new Color(0.30f, 0.25f, 0.34f, 1f);
[Tooltip("2등급 대상 역할(원본 eRole 이름). PC 는 1등급이라 제외.")]
public string[] tier2Roles = { "Mob", "Pet", "Worker", "Fairy", "EnemyPC", "Farmer", "Summon", "BattleNPC", "EnemyPet", "EnemySummon" };
[Tooltip("2등급 재검색 주기(s) — 새로 나온 몬스터에 붙인다.")]
public float tier2ScanSeconds = 1.5f;
[Tooltip("3등급(배경 프랍) — 덧그리기 없음(비용 0) · 공유 재질의 런타임 복사본에 그늘 값만 살짝: 그늘 최소 밝기에 더하는 양 · 공유 그늘 색 쪽으로 섞는 비율.")]
[Range(0f, 0.5f)] public float tier3MinimumDarknessAdd = 0.06f;
[Range(0f, 1f)] public float tier3ShadowBlend = 0.35f;
public Color tier3ShadowColor = new Color(0.29f, 0.27f, 0.39f, 0f);
[Tooltip("3등급 대상 셰이더 이름(이 셰이더를 쓰는 MeshRenderer · 캐릭터/몬스터/지형/풀 제외).")]
public string[] tier3ShaderNames = { "Shader Graphs/Toon" };
[Tooltip("3등급 재검색 주기(s) — 섬 확장·설치물처럼 나중에 생기는 프랍.")]
public float tier3ScanSeconds = 5f;
[Header("⑤ 번짐(Bloom) — 역광이 화사하게 번지게(전체 화면 패스 · 모바일 비용 있음)")]
[Tooltip("0 = 카메라·볼륨을 건드리지 않는다.")]
public int bloomEnabled = 1;
[Tooltip("이 씬이 떠 있을 때만 켠다(전투 맵의 기존 후처리는 그대로).")]
public string[] bloomScenes = { "Level01" };
[Tooltip("이 밝기 이상만 번진다(HDR 1 초과 = 림·반짝임만).")]
public float bloomThreshold = 1.2f;
public float bloomIntensity = 0.4f;
[Range(0f, 1f)] public float bloomScatter = 0.55f;
[Tooltip("1 = 카메라 HDR 을 켠다(림만 골라 번지게 · 끄면 흰 거품·밝은 모래도 같이 번진다).")]
public int bloomHdr = 1;
[Tooltip("1 = 1/4 해상도에서 시작(모바일 권장).")]
public int bloomQuarter = 1;
[Tooltip("블러 단계 수(작을수록 쌈).")]
public int bloomMaxIterations = 4;
// ───────────────────────────────────────── 싱글턴(Resources)
public const string ResourcePath = "WL/WLCharacterBacklightSettings";
static WLCharacterBacklightSettings s_inst;
static bool s_tried;
public static WLCharacterBacklightSettings Instance
{
get
{
if (s_inst == null && !s_tried)
{
s_tried = true;
s_inst = Resources.Load<WLCharacterBacklightSettings>(ResourcePath);
}
return s_inst;
}
}
public static void Invalidate() { s_inst = null; s_tried = false; }
}
}