From 062d4b12aee837441522a626a3c367fde7b29758 Mon Sep 17 00:00:00 2001 From: swrring Date: Wed, 21 Oct 2026 18:56:06 +0900 Subject: [PATCH] =?UTF-8?q?WL=20#963=20=E2=91=A0=20=EB=82=A8=EC=9D=80=20?= =?UTF-8?q?=EC=9D=BC=20=E2=80=94=20=EB=B9=84=EC=88=98=201=C2=B72=ED=83=80?= =?UTF-8?q?=20=ED=98=B8=20=EB=85=B9=EC=83=89:=20=EA=B3=B5=EC=9A=A9=20?= =?UTF-8?q?=ED=98=B8=20=EC=85=B0=EC=9D=B4=EB=8D=94(SH=5FMaster=5Fimproved)?= =?UTF-8?q?=EA=B0=80=20=EC=9E=AC=EC=A7=88=20=5FUseCustomdata=5FColor=201?= =?UTF-8?q?=20=EC=9D=B4=EB=A9=B4=20=EC=A0=95=EC=A0=90=EC=83=89=20=EB=8C=80?= =?UTF-8?q?=EC=8B=A0=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=202(=EC=B2=AD=EB=A1=9D=20HDR=20=EA=B7=B8=EB=9D=BC?= =?UTF-8?q?=EB=94=94=EC=96=B8=ED=8A=B8)=EB=A5=BC=20=EC=83=89=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=8D=A8=EC=84=9C=20=EC=8B=9C=EC=9E=91=EC=83=89?= =?UTF-8?q?=EB=A7=8C=20=EB=B0=94=EA=BE=B8=EB=8D=98=20WLArcTint=20=EA=B0=80?= =?UTF-8?q?=20=EC=95=88=20=EB=A8=B9=ED=98=94=EC=9D=8C=20=E2=86=92=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20Col?= =?UTF-8?q?or=20=EB=AA=A8=EB=93=9C=20=EA=B7=B8=EB=9D=BC=EB=94=94=EC=96=B8?= =?UTF-8?q?=ED=8A=B8=EB=8F=84=20=EC=A7=81=EC=97=85=20=EC=83=89=EC=A1=B0?= =?UTF-8?q?=EB=A1=9C(=EB=AA=A8=EB=93=9C=20=EC=9C=A0=EC=A7=80)=20=C2=B7=20?= =?UTF-8?q?=EC=9B=90=EB=9E=98=20=EA=B0=92=20=EA=B9=8A=EC=9D=80=20=EB=B3=B5?= =?UTF-8?q?=EC=82=AC(GetColor=20=EA=B7=B8=EB=9D=BC=EB=94=94=EC=96=B8?= =?UTF-8?q?=ED=8A=B8=EA=B0=80=20=EB=AA=A8=EB=93=88=20=EA=B0=92=EC=9D=84=20?= =?UTF-8?q?=EA=B0=80=EB=A6=AC=EC=BC=9C=20=EB=AC=B5=EA=B4=91=20=EB=93=B1=20?= =?UTF-8?q?=EB=8B=A4=EB=A5=B8=20=EA=B7=BC=EC=A0=91=20=EC=A7=81=EC=97=85=20?= =?UTF-8?q?=ED=98=B8=EC=97=90=20=EB=85=B9=EC=83=89=EC=9D=B4=20=EB=82=A8?= =?UTF-8?q?=EB=8D=98=20=EB=B3=B5=EC=9B=90=20=EC=8B=A4=ED=8C=A8=20=EC=8B=A4?= =?UTF-8?q?=EC=B8=A1=20=E2=86=92=20=EB=B3=B5=EC=9B=90)=20=C2=B7=20?= =?UTF-8?q?=EC=A7=81=EC=97=85=2010202=20=EC=83=89=20colorAdditive=20(0.3,1?= =?UTF-8?q?.4,0.6)=E2=86=92(0.25,1.5,0.35)=20=C2=B7=20colorAlpha=20(0.15,0?= =?UTF-8?q?.95,0.45)=E2=86=92(0.12,0.95,0.2)(=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EB=AF=BC=ED=8A=B8=20152~163=C2=B0=20=E2=86=92=20=EB=85=B9?= =?UTF-8?q?=EC=83=89=20134=C2=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- Assets/WL/Combat/WLArcTint.cs | 52 +++++++++++++++++-- .../Resources/WL/SlashTrailSettings.asset | 4 +- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/Assets/WL/Combat/WLArcTint.cs b/Assets/WL/Combat/WLArcTint.cs index 0d117760a..a70bdb513 100644 --- a/Assets/WL/Combat/WLArcTint.cs +++ b/Assets/WL/Combat/WLArcTint.cs @@ -6,6 +6,8 @@ // 색은 입자 시작색이라 직업 궤적 색(SlashTrailSettings 직업 덮기 colorAdditive)이 닿지 않았다(Play 캡처 · 렌더러 목록). // ■ 처리 — WeaponTrailDriver 호 배치 직후 훅 1줄: 그 직업 덮기의 overrideLook 이 켜져 있으면 호 입자(살아 있는 것 + 다음 분출)의 색을 // colorAdditive 색조(명도 · 알파는 원래 값)로 · 아니면 이 인스턴스의 원래 시작색으로 되돌린다(풀 공유). +// ■ 2차(#963 남은 일) — 시작색만 바꾸니 화면은 녹청: 재질 _UseCustomdata_Color 1 이면 셰이더(SH_Master_improved Branch)가 정점색 대신 +// 사용자 데이터 2(Custom Data Color · 청록 HDR 그라디언트)를 색으로 쓴다 → 그 그라디언트도 같은 색조로 · 되돌릴 때 원래 값(깊은 복사). // 🔴 Debug.LogError 금지. // ───────────────────────────────────────────────────────────────────────────── using UnityEngine; @@ -16,8 +18,13 @@ namespace WL.Combat { public static int Tinted, Restored; static ParticleSystem.Particle[] s_buf = new ParticleSystem.Particle[256]; + static readonly ParticleSystemCustomData[] s_streams = { ParticleSystemCustomData.Custom1, ParticleSystemCustomData.Custom2 }; - sealed class Orig : MonoBehaviour { public ParticleSystem[] ps; public ParticleSystem.MinMaxGradient[] col; public bool tinted; } + sealed class Orig : MonoBehaviour + { + public ParticleSystem[] ps; public ParticleSystem.MinMaxGradient[] col; public bool tinted; + public ParticleSystem.MinMaxGradient[,] cd; public bool[,] hasCd; // [입자계, 사용자 데이터 1·2] Color 모드 원래 값 + } public static void Apply(GameObject arc, SlashTrailClassOverride cov) { @@ -28,7 +35,15 @@ namespace WL.Combat if (o == null) { o = arc.AddComponent(); o.ps = arc.GetComponentsInChildren(true); - o.col = new ParticleSystem.MinMaxGradient[o.ps.Length]; for (int i = 0; i < o.ps.Length; i++) o.col[i] = o.ps[i].main.startColor; + o.col = new ParticleSystem.MinMaxGradient[o.ps.Length]; + o.cd = new ParticleSystem.MinMaxGradient[o.ps.Length, 2]; o.hasCd = new bool[o.ps.Length, 2]; + for (int i = 0; i < o.ps.Length; i++) // 원래 값은 깊은 복사 — GetColor 그라디언트는 모듈 값을 그대로 가리켜 색조를 입히면 같이 바뀐다(묵광 복원 실패 실측) + { + o.col[i] = Copy(o.ps[i].main.startColor); + var cdm = o.ps[i].customData; if (!cdm.enabled) continue; + for (int k = 0; k < 2; k++) + if (cdm.GetMode(s_streams[k]) == ParticleSystemCustomDataMode.Color) { o.hasCd[i, k] = true; o.cd[i, k] = Copy(cdm.GetColor(s_streams[k])); } + } } bool want = cov != null && cov.overrideLook; if (!want && !o.tinted) return; @@ -38,6 +53,9 @@ namespace WL.Combat { var ps = o.ps[i]; if (ps == null) continue; var m = ps.main; + var cdm = ps.customData; // 사용자 데이터 색은 나이에 따라 매 프레임 계산 → 살아 있는 입자에도 바로 닿는다 + for (int k = 0; k < 2; k++) + if (o.hasCd[i, k]) cdm.SetColor(s_streams[k], want ? Retint(o.cd[i, k], th, ts) : o.cd[i, k]); if (!want) { m.startColor = o.col[i]; continue; } m.startColor = Retint(o.col[i], th, ts); int n = ps.GetParticles(s_buf); // 이미 나온 입자(호는 생성 순간 한 번에 분출) @@ -50,16 +68,40 @@ namespace WL.Combat } static Color Hue(Color c, float th, float ts) { float h, s, v; Color.RGBToHSV(c, out h, out s, out v); var r = Color.HSVToRGB(th, Mathf.Max(s, ts * 0.6f), v); r.a = c.a; return r; } + static Gradient Hue(Gradient g, float th, float ts) + { + if (g == null) return null; + var ng = new Gradient(); var ks = g.colorKeys; for (int k = 0; k < ks.Length; k++) ks[k].color = Hue(ks[k].color, th, ts); + ng.SetKeys(ks, g.alphaKeys); ng.mode = g.mode; ng.colorSpace = g.colorSpace; return ng; + } + static Gradient Clone(Gradient g) + { + if (g == null) return null; + var ng = new Gradient(); ng.SetKeys(g.colorKeys, g.alphaKeys); ng.mode = g.mode; ng.colorSpace = g.colorSpace; return ng; + } + static ParticleSystem.MinMaxGradient Copy(ParticleSystem.MinMaxGradient g) + { + switch (g.mode) + { + case ParticleSystemGradientMode.TwoGradients: return new ParticleSystem.MinMaxGradient(Clone(g.gradientMin), Clone(g.gradientMax)); + case ParticleSystemGradientMode.Gradient: + case ParticleSystemGradientMode.RandomColor: + var r = new ParticleSystem.MinMaxGradient(Clone(g.gradient)); r.mode = g.mode; return r; + default: return g; // 단색 · 두 색 = 값 + } + } static ParticleSystem.MinMaxGradient Retint(ParticleSystem.MinMaxGradient g, float th, float ts) { switch (g.mode) { case ParticleSystemGradientMode.Color: return new ParticleSystem.MinMaxGradient(Hue(g.color, th, ts)); case ParticleSystemGradientMode.TwoColors: return new ParticleSystem.MinMaxGradient(Hue(g.colorMin, th, ts), Hue(g.colorMax, th, ts)); - default: + case ParticleSystemGradientMode.TwoGradients: + if (g.gradientMin == null || g.gradientMax == null) return g; + return new ParticleSystem.MinMaxGradient(Hue(g.gradientMin, th, ts), Hue(g.gradientMax, th, ts)); + default: // Gradient · RandomColor(모드 유지) if (g.gradient == null) return g; - var ng = new Gradient(); var ks = g.gradient.colorKeys; for (int k = 0; k < ks.Length; k++) ks[k].color = Hue(ks[k].color, th, ts); - ng.SetKeys(ks, g.gradient.alphaKeys); return new ParticleSystem.MinMaxGradient(ng); + var r = new ParticleSystem.MinMaxGradient(Hue(g.gradient, th, ts)); r.mode = g.mode; return r; } } } diff --git a/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset b/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset index 1c566507e..542754782 100644 --- a/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset +++ b/Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset @@ -142,8 +142,8 @@ MonoBehaviour: - classId: 10202 mode: 0 overrideLook: 1 - colorAdditive: {r: 0.3, g: 1.4, b: 0.6, a: 1} - colorAlpha: {r: 0.15, g: 0.95, b: 0.45, a: 1} + colorAdditive: {r: 0.25, g: 1.5, b: 0.35, a: 1} + colorAlpha: {r: 0.12, g: 0.95, b: 0.2, a: 1} widthScale: 1 overrideWeaponSlots: 0 weaponSlotIndices: