160 lines
11 KiB
C#
160 lines
11 KiB
C#
// WL788_Look.cs — #788 "tail 방식이 아니라 이전에 만든 고퀄리티 이펙트" : 힘민지 원본 슬래시(EricWang FX_Slash) 룩을 무기 추종 리본에 적용
|
|
// Edit : unity command run_script --file AgentScripts/WL788_Look.cs --entry WL788_Look.MakeAssets (스트릭 텍스처 + 리본 머티리얼 생성)
|
|
// Play : unity command run_script --file AgentScripts/WL788_Look.cs --entry WL788_Look.Apply --args '[1.6, 1, 1]' (emission, blend(1=One,6=OneMinusSrcAlpha), burst(1=ReuseShowEffect,0=None) · 메모리만)
|
|
// Edit : unity command run_script --file AgentScripts/WL788_Look.cs --entry WL788_Look.Bake --args '[1.6, 1, 1]' (설정 SO 굽기)
|
|
// Any : unity command run_script --file AgentScripts/WL788_Look.cs --entry WL788_Look.Dump
|
|
// 구성: ① 리본 머티리얼 = EricWang `Additive.shader`(원본 슬래시와 같은 셰이더) + 원본 `slash_L01.png` 스트릭을 리본 UV 에 맞게 전치(u=잔상축)·흑백화한 `T_WL_SlashStreak.png`
|
|
// ② 클래스별 색 = SlashTrailSettings 클래스 오버라이드 colorAdditive(HDR) — 정점색 경로(useGradients 0)
|
|
// ③ 원본 슬래시 프리팹의 플레어·글로우·링은 burstMode ReuseShowEffect + crescentRules(크레센트 스프라이트만 마스크) 로 그대로 재생
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
public static class WL788_Look
|
|
{
|
|
const string SrcTexPath = "Assets/ResWork/EricWang/GameVFX Collection(URP)/FX_Slash01/Textures/slash_L01.png";
|
|
const string ShaderPath = "Assets/ResWork/EricWang/GameVFX Collection(URP)/Shaders/Additive.shader";
|
|
const string TexPath = "Assets/WL/Combat/Textures/T_WL_SlashStreak.png";
|
|
const string MatPath = "Assets/WL/Combat/Materials/M_WL_SlashRibbon.mat";
|
|
const string SettingsPath = "Assets/WL/Settings/Resources/WL/SlashTrailSettings.asset";
|
|
|
|
// 클래스별 리본 색(HDR) — 원본 슬래시 프리팹 계열 색: 10101 Blue_Slash · 10102 Orange_Slash · 10501/10502 Lana(노랑·백금)
|
|
static readonly (int cid, Color col)[] ClassColors =
|
|
{
|
|
(10101, new Color(0.55f, 0.85f, 1.60f, 1f)),
|
|
(10102, new Color(1.60f, 0.85f, 0.35f, 1f)),
|
|
(10501, new Color(1.60f, 1.35f, 0.60f, 1f)),
|
|
(10502, new Color(1.30f, 1.20f, 0.80f, 1f)),
|
|
(10201, new Color(1.60f, 0.55f, 0.70f, 1f)),
|
|
(10202, new Color(1.60f, 0.55f, 0.70f, 1f)),
|
|
};
|
|
|
|
/// <summary>원본 스트릭을 전치(x↔y) + 흑백화해 리본용 텍스처로 굽는다. 리본 UV: u=잔상(1 머리) · v=칼날축.</summary>
|
|
public static object MakeAssets()
|
|
{
|
|
if (EditorApplication.isPlaying) return "ABORT: Play 중";
|
|
var src = AssetDatabase.LoadAssetAtPath<Texture2D>(SrcTexPath);
|
|
if (src == null) return "source tex null " + SrcTexPath;
|
|
// 읽기 불가 텍스처도 RenderTexture 경유로 픽셀을 얻는다
|
|
var rt = RenderTexture.GetTemporary(src.width, src.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
|
|
Graphics.Blit(src, rt);
|
|
var prev = RenderTexture.active; RenderTexture.active = rt;
|
|
var readable = new Texture2D(src.width, src.height, TextureFormat.RGBA32, false);
|
|
readable.ReadPixels(new Rect(0, 0, src.width, src.height), 0, 0); readable.Apply();
|
|
RenderTexture.active = prev; RenderTexture.ReleaseTemporary(rt);
|
|
|
|
int W = src.height, H = src.width; // 전치
|
|
var dst = new Texture2D(W, H, TextureFormat.RGBA32, false, false);
|
|
var sp = readable.GetPixels();
|
|
var dp = new Color[W * H];
|
|
for (int y = 0; y < H; y++)
|
|
for (int x = 0; x < W; x++)
|
|
{
|
|
// dst(x,y) = src(y,x) : src 의 세로(스트릭 방향)가 dst 의 가로(u=잔상축)가 된다
|
|
var c = sp[x * src.width + y];
|
|
float lum = Mathf.Clamp01(0.2126f * c.r + 0.7152f * c.g + 0.0722f * c.b);
|
|
float a = Mathf.Max(c.a, lum); // 원본이 가산용(알파 무의미)일 수 있어 밝기를 알파로도 쓴다
|
|
dp[y * W + x] = new Color(lum, lum, lum, a);
|
|
}
|
|
dst.SetPixels(dp); dst.Apply(false, false);
|
|
Directory.CreateDirectory(Path.GetDirectoryName(TexPath));
|
|
File.WriteAllBytes(TexPath, dst.EncodeToPNG());
|
|
Object.DestroyImmediate(readable); Object.DestroyImmediate(dst);
|
|
AssetDatabase.ImportAsset(TexPath, ImportAssetOptions.ForceUpdate);
|
|
var imp = AssetImporter.GetAtPath(TexPath) as TextureImporter;
|
|
if (imp != null)
|
|
{
|
|
imp.textureType = TextureImporterType.Default; imp.sRGBTexture = true; imp.alphaSource = TextureImporterAlphaSource.FromInput;
|
|
imp.mipmapEnabled = false; imp.wrapMode = TextureWrapMode.Clamp; imp.filterMode = FilterMode.Bilinear;
|
|
imp.maxTextureSize = 256; imp.textureCompression = TextureImporterCompression.Uncompressed; imp.isReadable = false;
|
|
imp.SaveAndReimport();
|
|
}
|
|
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(TexPath);
|
|
var shader = AssetDatabase.LoadAssetAtPath<Shader>(ShaderPath);
|
|
if (shader == null) return "shader null " + ShaderPath;
|
|
var mat = AssetDatabase.LoadAssetAtPath<Material>(MatPath);
|
|
if (mat == null) { mat = new Material(shader); AssetDatabase.CreateAsset(mat, MatPath); }
|
|
else mat.shader = shader;
|
|
mat.SetTexture("_MainTex", tex);
|
|
mat.SetColor("_Color", new Color(0.5f, 0.5f, 0.5f, 1f)); // 원본 슬래시 머티리얼 기본값과 동일
|
|
mat.SetFloat("_Emission", 1.6f);
|
|
mat.SetFloat("_Blend2", 1f); // One One = 원본과 같은 가산
|
|
mat.SetFloat("_CullMode", 0f);
|
|
mat.renderQueue = 3000;
|
|
EditorUtility.SetDirty(mat); AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
|
|
return "made " + TexPath + " (" + W + "x" + H + ") + " + MatPath + " shader=" + shader.name;
|
|
}
|
|
|
|
static string ApplyTo(WL.Combat.SlashTrailSettings s, Material mat, float emission, int blend, int burst)
|
|
{
|
|
s.materialAdditive = mat;
|
|
s.useGradients = false; // 정점색 = 클래스 오버라이드 colorAdditive
|
|
s.colorAdditive = new Color(1.2f, 1.2f, 1.2f, 1f); // 오버라이드 없는 클래스 기본(백색)
|
|
foreach (var cc in ClassColors)
|
|
{
|
|
var o = s.FindOverride(cc.cid);
|
|
if (o == null) continue;
|
|
// 이전 팀이 원본 슬래시 색을 실측해 넣어 둔 colorAdditive 가 있으면 그것을 쓴다(최대 채널 > 0.5 = 설정됨)
|
|
bool hasColor = Mathf.Max(o.colorAdditive.r, Mathf.Max(o.colorAdditive.g, o.colorAdditive.b)) > 0.5f
|
|
&& !(Mathf.Approximately(o.colorAdditive.r, 1f) && Mathf.Approximately(o.colorAdditive.g, 1f) && Mathf.Approximately(o.colorAdditive.b, 1f));
|
|
o.overrideLook = true; if (!hasColor) o.colorAdditive = cc.col; o.widthScale = 1f;
|
|
}
|
|
s.burstMode = (WL.Combat.BurstMode)burst; // 1 = ReuseShowEffect (원본 플레어·글로우 재생)
|
|
s.suppressMode = WL.Combat.SuppressMode.CrescentOnly; // crescentRules 에 적힌 크레센트 스프라이트만 마스크
|
|
if (mat != null) { mat.SetFloat("_Emission", emission); mat.SetFloat("_Blend2", blend); }
|
|
return "applied mat=" + (mat != null ? mat.name : "null") + " emission=" + emission + " blend=" + blend + " burst=" + s.burstMode + " suppress=" + s.suppressMode + " useGradients=0 classOverrides=" + ClassColors.Length;
|
|
}
|
|
|
|
public static object Apply(float emission, int blend, int burst)
|
|
{
|
|
if (!Application.isPlaying) return "not playing (Edit 모드에서는 Bake)";
|
|
var s = WL.Combat.SlashTrailSettings.Instance; if (s == null) return "settings null";
|
|
var mat = AssetDatabase.LoadAssetAtPath<Material>(MatPath); if (mat == null) return "mat null — MakeAssets 먼저";
|
|
string r = ApplyTo(s, mat, emission, blend, burst);
|
|
// BladeTrail 은 생성 시점에 머티리얼을 굽는다 → 이미 떠 있는 트레일의 렌더러를 직접 바꿔 준다(Play 검증용)
|
|
int swapped = 0;
|
|
foreach (var drv in Object.FindObjectsByType<WL.Combat.WeaponTrailDriver>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
var t = drv.GetTrail(i); if (t == null) continue;
|
|
var mr = t.GetComponent<MeshRenderer>(); if (mr == null) continue;
|
|
mr.sharedMaterials = new[] { mat }; swapped++;
|
|
}
|
|
return r + " · 런타임 트레일 렌더러 교체=" + swapped;
|
|
}
|
|
|
|
public static object Bake(float emission, int blend, int burst)
|
|
{
|
|
if (EditorApplication.isPlaying) return "ABORT: Play 중";
|
|
var s = AssetDatabase.LoadAssetAtPath<WL.Combat.SlashTrailSettings>(SettingsPath); if (s == null) return "settings null";
|
|
var mat = AssetDatabase.LoadAssetAtPath<Material>(MatPath); if (mat == null) return "mat null — MakeAssets 먼저";
|
|
string r = ApplyTo(s, mat, emission, blend, burst);
|
|
EditorUtility.SetDirty(s); EditorUtility.SetDirty(mat); AssetDatabase.SaveAssets();
|
|
return "baked: " + r;
|
|
}
|
|
|
|
/// <summary>Play: 버스트 모드만 바꾼다(0 None · 1 ReuseShowEffect = 원본 슬래시 프리팹의 플레어/글로우 재생 · 2 PrefabArc).</summary>
|
|
public static object Burst(int mode, int timing)
|
|
{
|
|
if (!Application.isPlaying) return "not playing";
|
|
var s = WL.Combat.SlashTrailSettings.Instance; if (s == null) return "settings null";
|
|
s.burstMode = (WL.Combat.BurstMode)mode;
|
|
s.burstTiming = (WL.Combat.BurstTiming)timing;
|
|
s.suppressMode = WL.Combat.SuppressMode.CrescentOnly;
|
|
return "burst=" + s.burstMode + " timing=" + s.burstTiming + " suppress=" + s.suppressMode;
|
|
}
|
|
|
|
public static object Dump()
|
|
{
|
|
var s = Application.isPlaying ? WL.Combat.SlashTrailSettings.Instance : AssetDatabase.LoadAssetAtPath<WL.Combat.SlashTrailSettings>(SettingsPath);
|
|
var sb = new StringBuilder();
|
|
if (s == null) return "settings null";
|
|
sb.AppendLine("mat=" + (s.materialAdditive != null ? s.materialAdditive.name + " / " + s.materialAdditive.shader.name : "null") + " useGradients=" + s.useGradients + " burst=" + s.burstMode + " suppress=" + s.suppressMode + " drawRibbon=" + s.drawRibbon + " fade=" + s.fadeSeconds);
|
|
foreach (var cc in ClassColors) { var o = s.FindOverride(cc.cid); sb.AppendLine(" " + cc.cid + " override=" + (o != null ? o.overrideLook + " col=" + o.colorAdditive : "none")); }
|
|
if (s.materialAdditive != null && s.materialAdditive.HasProperty("_Emission")) sb.AppendLine(" emission=" + s.materialAdditive.GetFloat("_Emission") + " blend2=" + s.materialAdditive.GetFloat("_Blend2") + " tex=" + (s.materialAdditive.GetTexture("_MainTex") != null ? s.materialAdditive.GetTexture("_MainTex").name : "none"));
|
|
return sb.ToString();
|
|
}
|
|
}
|