89 lines
4.9 KiB
C#
89 lines
4.9 KiB
C#
// ─────────────────────────────────────────────────────────────────────────────
|
|
// WLWeaponGlowFx.cs — 무기 흰 빛 덧그림 도우미 (#916 · 2026-10-17)
|
|
//
|
|
// 해머 각성(WLHammerQuake #912)과 같은 방식: 소켓 아래 무기 메시마다 같은 메시를 쓰는 자식을 만들어 WL/WeaponGlow 재질(가산 · 테두리)을 씌우고,
|
|
// 세기 · 색 · 몸통 덮기 · 테두리를 렌더러별 프로퍼티 블록으로 쓴다(재질 인스턴스 0). End 에서 자식을 지운다.
|
|
// 🔴 Debug.LogError 금지(원본 팝업).
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace WL.Combat.Weapon
|
|
{
|
|
public sealed class WLWeaponGlowFx
|
|
{
|
|
static readonly Dictionary<string, Material> s_mats = new Dictionary<string, Material>();
|
|
static readonly int kGlow = Shader.PropertyToID("_Glow"), kColor = Shader.PropertyToID("_GlowColor"),
|
|
kFill = Shader.PropertyToID("_Fill"), kRim = Shader.PropertyToID("_RimPower");
|
|
|
|
readonly List<GameObject> _gos = new List<GameObject>();
|
|
readonly List<Renderer> _rs = new List<Renderer>();
|
|
MaterialPropertyBlock _mpb;
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
static void Reset() { s_mats.Clear(); }
|
|
|
|
public bool Active { get { return _rs.Count > 0; } }
|
|
|
|
/// <summary>socket 아래 켜진 MeshRenderer 마다 덧그림 자식을 만든다 — 만든 수.</summary>
|
|
public int Begin(Transform socket, string materialPath)
|
|
{
|
|
End();
|
|
if (socket == null || string.IsNullOrEmpty(materialPath)) return 0;
|
|
Material mat;
|
|
if (!s_mats.TryGetValue(materialPath, out mat)) { mat = Resources.Load<Material>(materialPath); s_mats[materialPath] = mat; }
|
|
if (mat == null) return 0;
|
|
foreach (var mf in socket.GetComponentsInChildren<MeshFilter>(false))
|
|
{
|
|
var mr = mf.GetComponent<MeshRenderer>();
|
|
if (mr == null || !mr.enabled || mf.sharedMesh == null || mf.name == "[WL] Glow") continue;
|
|
var go = new GameObject("[WL] Glow") { layer = mf.gameObject.layer };
|
|
go.transform.SetParent(mf.transform, false);
|
|
go.AddComponent<MeshFilter>().sharedMesh = mf.sharedMesh;
|
|
var r = go.AddComponent<MeshRenderer>();
|
|
var mats = new Material[Mathf.Max(1, mf.sharedMesh.subMeshCount)];
|
|
for (int i = 0; i < mats.Length; i++) mats[i] = mat;
|
|
r.sharedMaterials = mats; r.enabled = false;
|
|
r.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; r.receiveShadows = false;
|
|
r.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; r.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
|
|
_gos.Add(go); _rs.Add(r);
|
|
}
|
|
return _rs.Count;
|
|
}
|
|
|
|
public void Set(float glow, Color color, float fill, float rimPower)
|
|
{
|
|
if (_rs.Count == 0) return;
|
|
if (_mpb == null) _mpb = new MaterialPropertyBlock();
|
|
for (int i = 0; i < _rs.Count; i++)
|
|
{
|
|
var r = _rs[i]; if (r == null) continue;
|
|
r.enabled = glow > 0.001f;
|
|
_mpb.Clear(); _mpb.SetFloat(kGlow, glow); _mpb.SetColor(kColor, color); _mpb.SetFloat(kFill, fill); _mpb.SetFloat(kRim, rimPower);
|
|
r.SetPropertyBlock(_mpb);
|
|
}
|
|
}
|
|
|
|
public void End()
|
|
{
|
|
for (int i = 0; i < _gos.Count; i++) if (_gos[i] != null) Object.Destroy(_gos[i]);
|
|
_gos.Clear(); _rs.Clear();
|
|
}
|
|
|
|
/// <summary>socket 아래 가장 큰 메시의 경계 중심(socket 로컬) — 무기 가운데. 없으면 원점.</summary>
|
|
public static Vector3 CenterLocal(Transform socket)
|
|
{
|
|
if (socket == null) return Vector3.zero;
|
|
Vector3 best = Vector3.zero; float bestSize = -1f;
|
|
foreach (var mf in socket.GetComponentsInChildren<MeshFilter>(false))
|
|
{
|
|
var mr = mf.GetComponent<MeshRenderer>(); var mesh = mf.sharedMesh;
|
|
if (mr == null || !mr.enabled || mesh == null || mf.name == "[WL] Glow") continue;
|
|
float size = mesh.bounds.size.sqrMagnitude;
|
|
if (size > bestSize) { bestSize = size; best = socket.InverseTransformPoint(mf.transform.TransformPoint(mesh.bounds.center)); }
|
|
}
|
|
return best;
|
|
}
|
|
}
|
|
}
|