Project_WL/AgentScripts/WL814x3_Play.cs

519 lines
27 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.

// WL-814x2 — 🔴 **Play 모드에서만** 재는 색 측정/촬영 하니스
// 편집 모드 렌더는 스킨 메시가 갱신되지 않아 무의미하다(814x 에서 실측).
// run_script --file AgentScripts/WL814x2_Play.cs --entry WL814x2.Run (Play 중에 부른다)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using WL.Look.Arena;
using WL.Look.Character;
public static class WL814x3
{
public const string RAW = "Screenshots_WL/WL814x/3rd/raw/";
const int W = 1080, H = 1920;
static readonly StringBuilder sb = new StringBuilder();
static void L(string s) { sb.AppendLine(s); }
static GameObject s_root;
static Renderer[] s_rends;
static Material[][] s_orig;
static Camera s_cam;
static Vector3 s_camPos, s_center, s_pos;
static Quaternion s_rot, s_camRot;
static Animator s_an;
static float s_camSize, s_ts;
static void Setup()
{
s_root = GameObject.Find("PC_LH_M05");
if (s_root == null)
foreach (var g in UnityEngine.Object.FindObjectsByType<Animator>(FindObjectsSortMode.None))
if (g.name.Contains("LH_M05")) { s_root = g.gameObject; break; }
// 🔴 아레나에는 캐릭터를 걷게 하는 리그가 있다 — 샷마다 위치/포즈가 달라지면 색 비교가 무의미하다.
s_ts = Time.timeScale; Time.timeScale = 0f;
s_an = s_root.GetComponentInChildren<Animator>();
if (s_an != null) { s_an.speed = 0f; try { s_an.Play("idle", 0, 0.25f); s_an.Update(0f); } catch { } }
s_cam = Camera.main ?? UnityEngine.Object.FindObjectsByType<Camera>(FindObjectsSortMode.None).First(c => c.orthographic);
s_camPos = s_cam.transform.position; s_camSize = s_cam.orthographicSize; s_camRot = s_cam.transform.rotation;
s_root.transform.rotation = Quaternion.Euler(0, s_cam.transform.eulerAngles.y + 180f, 0);
s_pos = s_root.transform.position; s_rot = s_root.transform.rotation;
s_rends = s_root.GetComponentsInChildren<Renderer>(true).Where(r => r.enabled && r.gameObject.activeInHierarchy).ToArray();
s_orig = s_rends.Select(r => r.sharedMaterials).ToArray();
var b = new Bounds(s_root.transform.position, Vector3.zero);
foreach (var r in s_rends) b.Encapsulate(r.bounds);
s_center = b.center;
L("renderers " + string.Join(",", s_rends.Select(r => r.name)) + " · center " + s_center.ToString("F2") + " · h " + b.size.y.ToString("F3"));
foreach (var r in s_rends)
{
var m = r.sharedMaterial;
L(" " + r.name + " mat=" + m.name + " shader=" + m.shader.name
+ " base=" + (m.HasProperty("_BaseMap") && m.GetTexture("_BaseMap") ? m.GetTexture("_BaseMap").name : "-")
+ " diff=" + (m.HasProperty("_DiffuseColor") ? m.GetColor("_DiffuseColor").ToString("F3") : "-")
+ " shadow=" + (m.HasProperty("_ShadowDiffuseColor") ? m.GetColor("_ShadowDiffuseColor").ToString("F4") : "-")
+ " shades=" + (m.HasProperty("_Shades") ? m.GetFloat("_Shades").ToString("F0") : "-")
+ " minDark=" + (m.HasProperty("_MinimumDarkness") ? m.GetFloat("_MinimumDarkness").ToString("F2") : "-"));
}
var rc = WLReferenceLookSettings.Instance;
L("ReferenceLook: rimOn=" + rc.rimOn + " moodOn=" + rc.moodOn + " mood=" + rc.moodStrength.ToString("F2")
+ " contrast=" + rc.contrastOn + " minDark=" + rc.minimumDarkness.ToString("F2")
+ " shadowScale=" + rc.shadowColorScale.ToString("F2") + " shadowTintAmt=" + rc.shadowTintAmount.ToString("F2")
+ " shadowTint=" + rc.shadowTint.ToString("F3") + " charShades=" + rc.charShades
+ " key=" + rc.keyLightColor.ToString("F2") + "×" + rc.keyLightIntensity.ToString("F2") + " amb=" + rc.ambientColor.ToString("F2"));
}
static void Teardown()
{
for (int i = 0; i < s_rends.Length; i++) { s_rends[i].sharedMaterials = s_orig[i]; s_rends[i].enabled = true; }
s_cam.transform.SetPositionAndRotation(s_camPos, s_camRot); s_cam.orthographicSize = s_camSize;
Time.timeScale = s_ts;
}
static int[] s_layers; static int s_cull; static CameraClearFlags s_clear; static Color s_bg; static bool s_post, s_postSaved;
/// <summary>캐릭터만 남기고 배경·그림자·포스트를 모두 끈 렌더 상태(마스크·덩어리지도 전용).</summary>
static void Isolate(bool on)
{
var ts = s_root.GetComponentsInChildren<Transform>(true);
var ucd = s_cam.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
if (on)
{
s_layers = ts.Select(t => t.gameObject.layer).ToArray();
foreach (var t in ts) t.gameObject.layer = 31;
s_cull = s_cam.cullingMask; s_clear = s_cam.clearFlags; s_bg = s_cam.backgroundColor;
s_cam.cullingMask = 1 << 31; s_cam.clearFlags = CameraClearFlags.SolidColor; s_cam.backgroundColor = Color.black;
if (ucd != null) { s_post = ucd.renderPostProcessing; s_postSaved = true; ucd.renderPostProcessing = false; }
}
else
{
for (int i = 0; i < ts.Length && i < s_layers.Length; i++) ts[i].gameObject.layer = s_layers[i];
s_cam.cullingMask = s_cull; s_cam.clearFlags = s_clear; s_cam.backgroundColor = s_bg;
if (ucd != null && s_postSaved) { ucd.renderPostProcessing = s_post; s_postSaved = false; }
}
}
class Shot { public Color32[] px; }
static Shot Render(float ortho)
{
// 매 렌더마다 같은 위치·같은 포즈로 고정한다
s_root.transform.SetPositionAndRotation(s_pos, s_rot);
if (s_an != null) { s_an.speed = 0f; try { s_an.Play("idle", 0, 0.25f); s_an.Update(0f); } catch { } }
// 🔴 카메라도 매 프레임 따라다니는 스크립트가 있다 — 회전까지 고정해야 프레이밍이 같다.
s_cam.orthographicSize = ortho;
s_cam.transform.SetPositionAndRotation(s_center - (s_camRot * Vector3.forward) * 30f, s_camRot);
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.filterMode = FilterMode.Point; rt.Create();
var prev = s_cam.targetTexture; s_cam.targetTexture = rt; s_cam.Render(); s_cam.targetTexture = prev;
var pa = RenderTexture.active; RenderTexture.active = rt;
var t = new Texture2D(W, H, TextureFormat.RGBA32, false); t.ReadPixels(new Rect(0, 0, W, H), 0, 0); t.Apply();
RenderTexture.active = pa;
var s = new Shot { px = t.GetPixels32() };
UnityEngine.Object.Destroy(t); rt.Release(); UnityEngine.Object.Destroy(rt);
return s;
}
static void Save(Shot s, string name)
{
var t = new Texture2D(W, H, TextureFormat.RGBA32, false); t.SetPixels32(s.px); t.Apply();
Directory.CreateDirectory(RAW); File.WriteAllBytes(RAW + name + ".png", t.EncodeToPNG());
UnityEngine.Object.Destroy(t);
}
static void Shoot(string name, float ortho) { Render(ortho); Save(Render(ortho), name); }
static void SaveMask(string name, float ortho, params Renderer[] on)
{
Isolate(true);
foreach (var r in s_rends) r.enabled = on.Contains(r);
var a = Render(ortho);
foreach (var r in s_rends) r.enabled = true;
Isolate(false);
var t = new Texture2D(W, H, TextureFormat.RGBA32, false);
var px = new Color32[W * H]; int n = 0;
for (int i = 0; i < px.Length; i++)
{
int d = a.px[i].r + a.px[i].g + a.px[i].b;
bool hit = d > 12; if (hit) n++;
px[i] = hit ? new Color32(255, 255, 255, 255) : new Color32(0, 0, 0, 255);
}
t.SetPixels32(px); t.Apply();
Directory.CreateDirectory(RAW); File.WriteAllBytes(RAW + "mask_" + name + ".png", t.EncodeToPNG());
UnityEngine.Object.Destroy(t);
L("mask " + name + " @" + ortho.ToString("F2") + " = " + n + " px");
}
/// <summary>덩어리(팔레트 칸) 지도 — 빛 0. 부위별 색을 재기 위한 마스크.</summary>
static void ShootIdMap(string name, float ortho)
{
var pal = UnityEditor.AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/WL/Look/Character/Textures/WLPalette_FINAL.png");
int S = pal.width, G = S / 8;
var t = new Texture2D(S, S, TextureFormat.RGBA32, false) { filterMode = FilterMode.Point, wrapMode = TextureWrapMode.Clamp };
var px = new Color32[S * S];
for (int i = 0; i < px.Length; i++) px[i] = new Color32(0, 0, 0, 255);
for (int j = 0; j < G * G; j++)
{
int gx = j % G, gy = j / G;
var c = new Color32((byte)(9 + j * 15), (byte)(240 - j * 11), (byte)(40 + j * 7), 255);
for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) px[(gy * 8 + y) * S + gx * 8 + x] = c;
}
t.SetPixels32(px); t.Apply();
Isolate(true);
var sh = Shader.Find("Unlit/Texture");
var keep = new List<Renderer>();
for (int i = 0; i < s_rends.Length; i++)
{
if (s_rends[i].name == "Face") { s_rends[i].enabled = false; keep.Add(s_rends[i]); continue; }
var m = new Material(sh); m.SetTexture("_MainTex", t);
s_rends[i].sharedMaterials = Enumerable.Repeat(m, s_orig[i].Length).ToArray();
}
Shoot(name, ortho);
foreach (var r in keep) r.enabled = true;
for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i];
Isolate(false);
UnityEngine.Object.Destroy(t);
// 팔레트 칸 색도 적어 둔다(인덱스 → 팔레트 RGB)
var cols = pal.GetPixels32();
for (int j = 0; j < G * G; j++)
{
int gx = j % G, gy = j / G;
var c = cols[(gy * 8 + 4) * S + gx * 8 + 4];
L(string.Format("PAL {0,2} id={1},{2},{3} rgb={4},{5},{6}", j, 9 + j * 15, 240 - j * 11, 40 + j * 7, c.r, c.g, c.b));
}
}
/// <summary>ToonP 머티리얼의 그림자색만 바꾼 임시 복제본으로 교체.</summary>
static void SetShadow(Color shadow, float shades)
{
for (int i = 0; i < s_rends.Length; i++)
{
var mats = (Material[])s_orig[i].Clone();
for (int m = 0; m < mats.Length; m++)
{
if (mats[m] == null || mats[m].shader == null || mats[m].shader.name != "Shader Graphs/Toon") continue;
var c = new Material(mats[m]) { name = "TMP_" + mats[m].name };
c.SetColor("_ShadowDiffuseColor", shadow);
if (shades > 0) c.SetFloat("_Shades", shades);
mats[m] = c;
}
s_rends[i].sharedMaterials = mats;
}
}
static void ResetMats() { for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i]; }
static void Look(float mood, float shadowTintAmount, int rim)
{
var cfg = WLReferenceLookSettings.Instance;
var o = WLReferenceLook.Opt.FromSettings(cfg);
o.mood = mood > 0f; o.moodStrength = mood;
o.shadowTintAmount = shadowTintAmount;
o.rim = rim != 0;
WLReferenceLook.Apply(o, cfg);
}
public static string Run()
{
sb.Length = 0;
try
{
Setup();
SaveMask("all", 0.95f, s_rends);
foreach (var r in s_rends) SaveMask(r.name, 0.95f, r);
SaveMask("all10", 10f, s_rends);
foreach (var r in s_rends) SaveMask(r.name + "10", 10f, r);
ShootIdMap("idmap", 0.95f);
ShootIdMap("idmap10", 10f);
var cfg = WLReferenceLookSettings.Instance;
float mood0 = cfg.moodStrength, tint0 = cfg.shadowTintAmount;
Action<string, Color, float, float, float, int> V = (name, shadow, shades, mood, tintAmt, rim) =>
{
ResetMats();
WLReferenceLook.Restore();
if (shadow.a >= 0f && shadow != Color.clear) SetShadow(shadow, shades);
Look(mood, tintAmt, rim);
Shoot(name, 0.95f);
Shoot(name + "_g", 10f);
L("shot " + name + " shadow=" + shadow.ToString("F3") + " shades=" + shades + " mood=" + mood.ToString("F2") + " tintAmt=" + tintAmt.ToString("F2") + " · " + WLReferenceLook.LastLog);
};
var purple = new Color(0.2164f, 0.2092f, 0.3713f, 0f);
V("a_now", purple, 3f, mood0, tint0, 0);
V("b_neutral", new Color(0.45f, 0.45f, 0.45f, 0f), 3f, mood0, tint0, 0);
V("c_neutral_notint", new Color(0.45f, 0.45f, 0.45f, 0f), 3f, mood0, 0f, 0);
V("d_neutral_notint_mood0", new Color(0.45f, 0.45f, 0.45f, 0f), 3f, 0f, 0f, 0);
V("e_warm_notint", new Color(0.52f, 0.45f, 0.40f, 0f), 3f, mood0, 0f, 0);
V("f_neutral_notint_s7", new Color(0.45f, 0.45f, 0.45f, 0f), 7f, mood0, 0f, 0);
V("g_dark_notint", new Color(0.32f, 0.32f, 0.34f, 0f), 3f, mood0, 0f, 0);
ResetMats(); WLReferenceLook.Restore(); Look(mood0, tint0, 0);
L("DONE");
}
catch (Exception e) { L("EXCEPTION " + e); }
finally { try { Teardown(); } catch { } Directory.CreateDirectory("AgentScripts"); File.WriteAllText("AgentScripts/WL814x3_PLAY.txt", sb.ToString(), new UTF8Encoding(true)); }
return sb.ToString();
}
/// <summary>아레나 씬을 연다(Play 진입 전 · 편집 모드에서 1회).</summary>
public static string Open()
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene("Assets/WL/Look/Arena/Scenes/WL_ArenaProto.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
return "opened " + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
}
/// <summary>무드(포스트 그레이딩·앰비언트·키라이트)가 화면 색을 얼마나 틀어놓는지 — 에셋 수정 0(런타임 프로파일 인스턴스).</summary>
public static string Mood()
{
sb.Length = 0;
try
{
Setup();
SaveMask("all", 0.95f, s_rends);
foreach (var r in s_rends) SaveMask(r.name, 0.95f, r);
SaveMask("all10", 10f, s_rends);
ShootIdMap("idmap", 0.95f);
var cfg = WLReferenceLookSettings.Instance;
Action<string, float, bool, bool> V = (name, mood, killWB, killSMH) =>
{
WLReferenceLook.Restore();
var o = WLReferenceLook.Opt.FromSettings(cfg);
o.rim = false; o.mood = mood > 0f; o.moodStrength = mood;
WLReferenceLook.Apply(o, cfg);
var vgo = GameObject.Find("WL814t_ReferenceLook_Volume");
// killWB = 포스트 그레이딩 Volume 의 weight 만 0 으로 (조명 무드는 그대로 둔다)
if (vgo != null && killWB) vgo.GetComponent<UnityEngine.Rendering.Volume>().weight = 0f;
Shoot(name, 0.95f); Shoot(name + "_g", 10f);
L("mood shot " + name + " mood=" + mood.ToString("F2") + " killWB=" + killWB + " killSMH=" + killSMH);
};
V("m30", 0.30f, false, false);
V("m15", 0.15f, false, false);
V("m00", 0.00f, false, false);
V("n_novol30", 0.30f, true, false);
V("n_novol15", 0.15f, true, false);
WLReferenceLook.Restore();
var o2 = WLReferenceLook.Opt.FromSettings(cfg); o2.rim = false;
WLReferenceLook.Apply(o2, cfg);
L("DONE");
}
catch (Exception e) { L("EXCEPTION " + e); }
finally { try { Teardown(); } catch { } File.WriteAllText("AgentScripts/WL814x3_MOOD.txt", sb.ToString(), new UTF8Encoding(true)); }
return sb.ToString();
}
/// <summary>🔴 캐릭터 전용 광원 색조 상쇄 — _DiffuseColor 에 휘도보존 역이득을 넣는다.
/// 씬·조명·814t 설정·ProjectSettings 는 하나도 안 건드린다.</summary>
public static string SetTint()
{
var g = new Color(0.994f, 1.024f, 0.894f, 1f);
var sb2 = new StringBuilder();
foreach (var n in new[] { "M05_ToonP", "Skin_ToonP", "Hair05_ToonP" })
{
var p = "Assets/WL/Look/Character/Materials/" + n + ".mat";
var m = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(p);
if (m == null) { sb2.AppendLine("!! " + p); continue; }
m.SetColor("_DiffuseColor", g);
UnityEditor.EditorUtility.SetDirty(m);
sb2.AppendLine(n + " _DiffuseColor = " + g.ToString("F3"));
}
UnityEditor.AssetDatabase.SaveAssets();
return sb2.ToString();
}
/// <summary>3차 — 앰비언트/키라이트 색조 3+1안. 🔴 SO·씬·에셋은 안 건드린다(런타임 RenderSettings·Light.color 만).</summary>
public static string Amb()
{
sb.Length = 0;
try
{
Setup();
SaveMask("all", 0.95f, s_rends);
foreach (var r in s_rends) SaveMask(r.name, 0.95f, r);
SaveMask("all10", 10f, s_rends);
ShootIdMap("idmap", 0.95f);
var cfg = WLReferenceLookSettings.Instance;
var lights = UnityEngine.Object.FindObjectsByType<Light>(FindObjectsSortMode.None)
.Where(l => l.type == LightType.Directional).ToArray();
// 측정은 «보정 없는» 상태에서 — _DiffuseColor 를 흰색으로 되돌린 임시 복제본
Action white = () =>
{
for (int i = 0; i < s_rends.Length; i++)
{
var mats = (Material[])s_orig[i].Clone();
for (int m = 0; m < mats.Length; m++)
{
if (mats[m] == null || mats[m].shader == null || mats[m].shader.name != "Shader Graphs/Toon") continue;
var c = new Material(mats[m]) { name = "TMP_w" };
c.SetColor("_DiffuseColor", Color.white);
mats[m] = c;
}
s_rends[i].sharedMaterials = mats;
}
};
Action<string, Color, Color> V = (name, amb, key) =>
{
for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i];
WLReferenceLook.Restore();
var o = WLReferenceLook.Opt.FromSettings(cfg); o.rim = false;
WLReferenceLook.Apply(o, cfg);
if (amb.a > 0f) RenderSettings.ambientLight = new Color(amb.r, amb.g, amb.b, 1f);
if (key.a > 0f) foreach (var l in lights) l.color = new Color(key.r, key.g, key.b, 1f);
white();
Shoot(name, 0.95f);
Shoot(name + "_g", 10f);
L(string.Format("amb shot {0} ambient={1} key={2}", name, RenderSettings.ambientLight.ToString("F3"),
lights.Length > 0 ? lights[0].color.ToString("F3") : "-"));
};
Color no = new Color(0, 0, 0, 0);
// 현재 무드가 만드는 앰비언트 = lerp(원래, (0.28,0.17,0.40), 0.30) → 그대로 두면 v0
V("v0_purple", no, no);
V("v1_gray", new Color(0.229f, 0.229f, 0.229f, 1f), no);
V("v2_cool", new Color(0.205f, 0.228f, 0.262f, 1f), no);
V("v3_warm", new Color(0.262f, 0.226f, 0.193f, 1f), no);
V("v4_gray_keysoft", new Color(0.229f, 0.229f, 0.229f, 1f), new Color(1f, 0.95f, 0.90f, 1f));
V("v5_gray_keywhite", new Color(0.229f, 0.229f, 0.229f, 1f), new Color(1f, 1f, 1f, 1f));
// 배경 포함 넓은 구도(게임 실제 카메라 위치·직교 10) — 배경이 얼마나 바뀌는지
for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i];
Action<string, Color, Color> WIDE = (name, amb, key) =>
{
WLReferenceLook.Restore();
var o = WLReferenceLook.Opt.FromSettings(cfg); o.rim = false;
WLReferenceLook.Apply(o, cfg);
if (amb.a > 0f) RenderSettings.ambientLight = new Color(amb.r, amb.g, amb.b, 1f);
if (key.a > 0f) foreach (var l in lights) l.color = new Color(key.r, key.g, key.b, 1f);
s_cam.orthographicSize = 10f;
s_cam.transform.SetPositionAndRotation(s_camPos, s_camRot);
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.filterMode = FilterMode.Point; rt.Create();
var pv = s_cam.targetTexture; s_cam.targetTexture = rt; s_cam.Render(); s_cam.Render(); s_cam.targetTexture = pv;
var pa = RenderTexture.active; RenderTexture.active = rt;
var t = new Texture2D(W, H, TextureFormat.RGBA32, false); t.ReadPixels(new Rect(0, 0, W, H), 0, 0); t.Apply();
RenderTexture.active = pa;
Directory.CreateDirectory(RAW); File.WriteAllBytes(RAW + name + ".png", t.EncodeToPNG());
UnityEngine.Object.Destroy(t); rt.Release(); UnityEngine.Object.Destroy(rt);
L("wide " + name);
};
WIDE("w0_purple", no, no);
WIDE("w1_gray", new Color(0.229f, 0.229f, 0.229f, 1f), no);
WIDE("w4_gray_keysoft", new Color(0.229f, 0.229f, 0.229f, 1f), new Color(1f, 0.95f, 0.90f, 1f));
WIDE("w5_gray_keywhite", new Color(0.229f, 0.229f, 0.229f, 1f), new Color(1f, 1f, 1f, 1f));
for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i];
WLReferenceLook.Restore();
var o2 = WLReferenceLook.Opt.FromSettings(cfg); o2.rim = false; WLReferenceLook.Apply(o2, cfg);
L("DONE");
}
catch (Exception e) { L("EXCEPTION " + e); }
finally { try { Teardown(); } catch { } File.WriteAllText("AgentScripts/WL814x3_AMB.txt", sb.ToString(), new UTF8Encoding(true)); }
return sb.ToString();
}
/// <summary>3차 채택값 쓰기 — 앰비언트 중성화(814t SO) + 캐릭터 _DiffuseColor 흰색 복귀.</summary>
public static string Adopt()
{
var sb2 = new StringBuilder();
var rc = UnityEditor.AssetDatabase.LoadAssetAtPath<WLReferenceLookSettings>("Assets/WL/Look/Arena/Resources/WL/WLReferenceLookSettings.asset");
sb2.AppendLine("ambientColor " + rc.ambientColor.ToString("F3") + " → 중성 (0.229,0.229,0.229)");
rc.ambientColor = new Color(0.229f, 0.229f, 0.229f, 1f);
UnityEditor.EditorUtility.SetDirty(rc);
foreach (var n in new[] { "M05_ToonP", "Skin_ToonP", "Hair05_ToonP" })
{
var m = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>("Assets/WL/Look/Character/Materials/" + n + ".mat");
var dc = new Color(0.993f, 1.028f, 0.874f, 1f);
m.SetColor("_DiffuseColor", dc);
UnityEditor.EditorUtility.SetDirty(m);
sb2.AppendLine(n + " _DiffuseColor → " + dc.ToString("F3"));
}
UnityEditor.AssetDatabase.ImportAsset("Assets/WL/Look/Character/Textures/WLPalette_FINAL.png", UnityEditor.ImportAssetOptions.ForceUpdate);
UnityEditor.AssetDatabase.SaveAssets();
return sb2.ToString();
}
/// <summary>최종 = 실제 배선된 머티리얼 그대로(보정 포함) 근접·게임크기·넓은 구도.</summary>
public static string Final()
{
sb.Length = 0;
try
{
Setup();
var cfg = WLReferenceLookSettings.Instance;
L("ambient(SO)=" + cfg.ambientColor.ToString("F3") + " diffuse=" + s_rends[0].sharedMaterial.GetColor("_DiffuseColor").ToString("F3"));
WLReferenceLook.Restore();
var o = WLReferenceLook.Opt.FromSettings(cfg); o.rim = false;
WLReferenceLook.Apply(o, cfg);
Shoot("f_final", 0.95f);
Shoot("f_final_g", 10f);
s_cam.orthographicSize = 10f;
s_cam.transform.SetPositionAndRotation(s_camPos, s_camRot);
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.filterMode = FilterMode.Point; rt.Create();
var pv = s_cam.targetTexture; s_cam.targetTexture = rt; s_cam.Render(); s_cam.Render(); s_cam.targetTexture = pv;
var pa = RenderTexture.active; RenderTexture.active = rt;
var t = new Texture2D(W, H, TextureFormat.RGBA32, false); t.ReadPixels(new Rect(0, 0, W, H), 0, 0); t.Apply();
RenderTexture.active = pa;
Directory.CreateDirectory(RAW); File.WriteAllBytes(RAW + "f_wide.png", t.EncodeToPNG());
UnityEngine.Object.Destroy(t); rt.Release(); UnityEngine.Object.Destroy(rt);
L("DONE");
}
catch (Exception e) { L("EXCEPTION " + e); }
finally { try { Teardown(); } catch { } File.WriteAllText("AgentScripts/WL814x3_FINAL.txt", sb.ToString(), new UTF8Encoding(true)); }
return sb.ToString();
}
/// <summary>어두운 면(피부)의 잔여 색조 — 그림자 알베도 색을 바꿔 비교(에셋 무수정·임시 복제본).</summary>
public static string Shad()
{
sb.Length = 0;
try
{
Setup();
SaveMask("all", 0.95f, s_rends);
foreach (var r in s_rends) SaveMask(r.name, 0.95f, r);
ShootIdMap("idmap", 0.95f);
var cfg = WLReferenceLookSettings.Instance;
Action<string, Color> V = (name, sh) =>
{
for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i];
WLReferenceLook.Restore();
if (sh.a > 0f)
for (int i = 0; i < s_rends.Length; i++)
{
var mats = (Material[])s_orig[i].Clone();
for (int m = 0; m < mats.Length; m++)
{
if (mats[m] == null || mats[m].shader == null || mats[m].shader.name != "Shader Graphs/Toon") continue;
var c = new Material(mats[m]) { name = "TMP_s" };
c.SetColor("_ShadowDiffuseColor", new Color(sh.r, sh.g, sh.b, 0f));
mats[m] = c;
}
s_rends[i].sharedMaterials = mats;
}
var o = WLReferenceLook.Opt.FromSettings(cfg); o.rim = false;
WLReferenceLook.Apply(o, cfg);
Shoot(name, 0.95f); Shoot(name + "_g", 10f);
L("shadow shot " + name + " = " + sh.ToString("F3"));
};
V("s0_now", new Color(0, 0, 0, 0));
V("s1_gray", new Color(0.38f, 0.38f, 0.38f, 1f));
V("s2_warm", new Color(0.42f, 0.38f, 0.32f, 1f));
V("s3_graylight", new Color(0.50f, 0.50f, 0.50f, 1f));
V("s4_warmlight", new Color(0.55f, 0.50f, 0.42f, 1f));
for (int i = 0; i < s_rends.Length; i++) s_rends[i].sharedMaterials = s_orig[i];
WLReferenceLook.Restore();
var o2 = WLReferenceLook.Opt.FromSettings(cfg); o2.rim = false; WLReferenceLook.Apply(o2, cfg);
L("DONE");
}
catch (Exception e) { L("EXCEPTION " + e); }
finally { try { Teardown(); } catch { } File.WriteAllText("AgentScripts/WL814x3_SHAD.txt", sb.ToString(), new UTF8Encoding(true)); }
return sb.ToString();
}
}