Merge branch 'wl/gameplay/WL-814x4-shadows'
This commit is contained in:
commit
8bc3d53dde
|
|
@ -0,0 +1,34 @@
|
||||||
|
renderers Arm_m05,Body_m05,Face,Hair05,Head,Leg_M05 · center (-0.01, 0.57, 0.00) · h 1.220
|
||||||
|
Arm_m05 mat=M05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Body_m05 mat=M05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Face mat=face02_ToonP shader=Unlit/Transparent base=- diff=- shadow=- shades=- minDark=-
|
||||||
|
Hair05 mat=Hair05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Head mat=Skin_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Leg_M05 mat=M05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
ReferenceLook: rimOn=False moodOn=True mood=0.30 contrast=True minDark=0.12 shadowScale=0.85 shadowTintAmt=0.30 shadowTint=RGBA(0.243, 0.106, 0.353, 1.000) charShades=0 key=RGBA(1.00, 0.78, 0.46, 1.00)×1.45 amb=RGBA(0.23, 0.23, 0.23, 1.00)
|
||||||
|
mask all @0.95 = 330746 px
|
||||||
|
mask Arm_m05 @0.95 = 36600 px
|
||||||
|
mask Body_m05 @0.95 = 107658 px
|
||||||
|
mask Face @0.95 = 7136 px
|
||||||
|
mask Hair05 @0.95 = 127668 px
|
||||||
|
mask Head @0.95 = 116073 px
|
||||||
|
mask Leg_M05 @0.95 = 80860 px
|
||||||
|
mask all10 @10.00 = 2959 px
|
||||||
|
PAL 0 id=9,240,40 rgb=226,175,169
|
||||||
|
PAL 1 id=24,229,47 rgb=115,78,58
|
||||||
|
PAL 2 id=39,218,54 rgb=199,199,198
|
||||||
|
PAL 3 id=54,207,61 rgb=126,57,54
|
||||||
|
PAL 4 id=69,196,68 rgb=207,173,129
|
||||||
|
PAL 5 id=84,185,75 rgb=164,73,67
|
||||||
|
PAL 6 id=99,174,82 rgb=185,131,97
|
||||||
|
PAL 7 id=114,163,89 rgb=130,122,118
|
||||||
|
PAL 8 id=129,152,96 rgb=215,186,139
|
||||||
|
PAL 9 id=144,141,103 rgb=194,161,131
|
||||||
|
PAL 10 id=159,130,110 rgb=116,92,78
|
||||||
|
PAL 11 id=174,119,117 rgb=133,84,73
|
||||||
|
PAL 12 id=189,108,124 rgb=224,205,153
|
||||||
|
PAL 13 id=204,97,131 rgb=152,123,103
|
||||||
|
PAL 14 id=219,86,138 rgb=177,173,172
|
||||||
|
PAL 15 id=234,75,145 rgb=94,61,45
|
||||||
|
diffuse Skin=RGBA(0.993, 1.028, 0.874, 1.000) M05=RGBA(0.993, 1.028, 0.874, 1.000) Hair=RGBA(0.993, 1.028, 0.874, 1.000)
|
||||||
|
DONE
|
||||||
|
|
@ -0,0 +1,669 @@
|
||||||
|
// 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 WL814x4
|
||||||
|
{
|
||||||
|
public const string RAW = "Screenshots_WL/WL814x/4th/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 GameObject s_ovr;
|
||||||
|
static Vector4 s_shad0; static bool s_shadOv0, s_shadSaved;
|
||||||
|
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/WL814x4_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/WL814x4_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/WL814x4_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/WL814x4_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/WL814x4_SHAD.txt", sb.ToString(), new UTF8Encoding(true)); }
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>4차 — WL_ArenaMood 의 ShadowsMidtonesHighlights.shadows 를 런타임 프로파일 복제본에서 조정.
|
||||||
|
/// 🔴 프로파일 에셋은 안 건드린다(Volume.profile 은 인스턴스 복제본).</summary>
|
||||||
|
static void RestoreShadows()
|
||||||
|
{
|
||||||
|
var cfg = WLReferenceLookSettings.Instance;
|
||||||
|
UnityEngine.Rendering.Universal.ShadowsMidtonesHighlights smh;
|
||||||
|
if (s_shadSaved && cfg != null && cfg.profile != null && cfg.profile.asset != null && cfg.profile.asset.TryGet(out smh))
|
||||||
|
{ smh.shadows.value = s_shad0; smh.shadows.overrideState = s_shadOv0; s_shadSaved = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Shadows()
|
||||||
|
{
|
||||||
|
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 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, Vector4, bool> V = (name, sh, useWhite) =>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
string applied = "-";
|
||||||
|
// 🔴 Volume 오버라이드(우선순위/인스턴스)는 둘 다 실패했다(전자는 안 먹고, 후자는 프로파일 전체를
|
||||||
|
// weight 1 로 얹어 버린다). → 프로파일 «에셋의 값»을 직접 바꾸고 끝에 되돌린다(SaveAssets 0).
|
||||||
|
UnityEngine.Rendering.Universal.ShadowsMidtonesHighlights smh;
|
||||||
|
if (cfg.profile != null && cfg.profile.asset != null && cfg.profile.asset.TryGet(out smh))
|
||||||
|
{
|
||||||
|
if (!s_shadSaved) { s_shad0 = smh.shadows.value; s_shadOv0 = smh.shadows.overrideState; s_shadSaved = true; }
|
||||||
|
smh.shadows.overrideState = true;
|
||||||
|
smh.shadows.value = (sh.w > -900f) ? sh : s_shad0;
|
||||||
|
applied = smh.shadows.value.ToString("F2");
|
||||||
|
}
|
||||||
|
if (useWhite) white();
|
||||||
|
Shoot(name, 0.95f);
|
||||||
|
Shoot(name + "_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 + "wide_" + name + ".png", t.EncodeToPNG());
|
||||||
|
UnityEngine.Object.Destroy(t); rt.Release(); UnityEngine.Object.Destroy(rt);
|
||||||
|
L("shadows " + name + " = " + applied);
|
||||||
|
};
|
||||||
|
|
||||||
|
var none = new Vector4(0, 0, 0, -1000f);
|
||||||
|
V("a_now", none, true); // 지금 (0.78,0.58,1.25)
|
||||||
|
V("b_g075", new Vector4(0.78f, 0.75f, 1.25f, -0.06f), true);
|
||||||
|
V("c_g085", new Vector4(0.78f, 0.85f, 1.25f, -0.06f), true);
|
||||||
|
V("d_g095", new Vector4(0.78f, 0.95f, 1.25f, -0.06f), true);
|
||||||
|
V("e_g085b110", new Vector4(0.82f, 0.85f, 1.10f, -0.06f), true);
|
||||||
|
V("f_g095b100", new Vector4(0.85f, 0.95f, 1.00f, -0.06f), true);
|
||||||
|
V("g_neutral", new Vector4(0.92f, 0.92f, 1.00f, -0.06f), true);
|
||||||
|
V("z_sanity", new Vector4(0.78f, 1.80f, 1.25f, -0.06f), true); // 오버라이드가 먹는지 확인용(극단값)
|
||||||
|
|
||||||
|
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 { RestoreShadows(); Teardown(); } catch { } File.WriteAllText("AgentScripts/WL814x4_SHADOWS.txt", sb.ToString(), new UTF8Encoding(true)); }
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>4차 채택 — 부위 그룹별 _DiffuseColor 역이득(전역 1개로는 피부를 못 맞춘다).</summary>
|
||||||
|
public static string Adopt4()
|
||||||
|
{
|
||||||
|
var sb2 = new StringBuilder();
|
||||||
|
var g = new System.Collections.Generic.Dictionary<string, Color> {
|
||||||
|
{ "Skin_ToonP", new Color(0.993f, 1.028f, 0.874f, 1f) },
|
||||||
|
{ "M05_ToonP", new Color(0.993f, 1.028f, 0.874f, 1f) },
|
||||||
|
{ "Hair05_ToonP", new Color(0.993f, 1.028f, 0.874f, 1f) },
|
||||||
|
};
|
||||||
|
foreach (var kv in g)
|
||||||
|
{
|
||||||
|
var m = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>("Assets/WL/Look/Character/Materials/" + kv.Key + ".mat");
|
||||||
|
m.SetColor("_DiffuseColor", kv.Value);
|
||||||
|
UnityEditor.EditorUtility.SetDirty(m);
|
||||||
|
sb2.AppendLine(kv.Key + " _DiffuseColor = " + kv.Value.ToString("F3"));
|
||||||
|
}
|
||||||
|
UnityEditor.AssetDatabase.SaveAssets();
|
||||||
|
return sb2.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>최종 촬영 — 실제 배선 그대로(근접 · 게임 크기 · 넓은 구도).</summary>
|
||||||
|
public static string Final4()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
WLReferenceLook.Restore();
|
||||||
|
var o = WLReferenceLook.Opt.FromSettings(cfg); o.rim = false;
|
||||||
|
WLReferenceLook.Apply(o, cfg);
|
||||||
|
L("diffuse Skin=" + s_rends.First(r => r.name == "Head").sharedMaterial.GetColor("_DiffuseColor").ToString("F3")
|
||||||
|
+ " M05=" + s_rends.First(r => r.name == "Body_m05").sharedMaterial.GetColor("_DiffuseColor").ToString("F3")
|
||||||
|
+ " Hair=" + s_rends.First(r => r.name == "Hair05").sharedMaterial.GetColor("_DiffuseColor").ToString("F3"));
|
||||||
|
Shoot("fin", 0.95f); Shoot("fin_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 + "fin_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/WL814x4_FINAL.txt", sb.ToString(), new UTF8Encoding(true)); }
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
renderers Arm_m05,Body_m05,Face,Hair05,Head,Leg_M05 · center (-0.01, 0.57, 0.00) · h 1.220
|
||||||
|
Arm_m05 mat=M05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Body_m05 mat=M05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Face mat=face02_ToonP shader=Unlit/Transparent base=- diff=- shadow=- shades=- minDark=-
|
||||||
|
Hair05 mat=Hair05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Head mat=Skin_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
Leg_M05 mat=M05_ToonP_814t shader=Shader Graphs/Toon base=WLPalette_FINAL diff=RGBA(0.993, 1.028, 0.874, 1.000) shadow=RGBA(0.1430, 0.1307, 0.2416, 0.0000) shades=3 minDark=0.12
|
||||||
|
ReferenceLook: rimOn=False moodOn=True mood=0.30 contrast=True minDark=0.12 shadowScale=0.85 shadowTintAmt=0.30 shadowTint=RGBA(0.243, 0.106, 0.353, 1.000) charShades=0 key=RGBA(1.00, 0.78, 0.46, 1.00)×1.45 amb=RGBA(0.23, 0.23, 0.23, 1.00)
|
||||||
|
mask all @0.95 = 330746 px
|
||||||
|
mask Arm_m05 @0.95 = 36600 px
|
||||||
|
mask Body_m05 @0.95 = 107658 px
|
||||||
|
mask Face @0.95 = 7136 px
|
||||||
|
mask Hair05 @0.95 = 127668 px
|
||||||
|
mask Head @0.95 = 116073 px
|
||||||
|
mask Leg_M05 @0.95 = 80860 px
|
||||||
|
mask all10 @10.00 = 2959 px
|
||||||
|
PAL 0 id=9,240,40 rgb=226,175,169
|
||||||
|
PAL 1 id=24,229,47 rgb=115,78,58
|
||||||
|
PAL 2 id=39,218,54 rgb=199,199,198
|
||||||
|
PAL 3 id=54,207,61 rgb=126,57,54
|
||||||
|
PAL 4 id=69,196,68 rgb=207,173,129
|
||||||
|
PAL 5 id=84,185,75 rgb=164,73,67
|
||||||
|
PAL 6 id=99,174,82 rgb=185,131,97
|
||||||
|
PAL 7 id=114,163,89 rgb=130,122,118
|
||||||
|
PAL 8 id=129,152,96 rgb=215,186,139
|
||||||
|
PAL 9 id=144,141,103 rgb=194,161,131
|
||||||
|
PAL 10 id=159,130,110 rgb=116,92,78
|
||||||
|
PAL 11 id=174,119,117 rgb=133,84,73
|
||||||
|
PAL 12 id=189,108,124 rgb=224,205,153
|
||||||
|
PAL 13 id=204,97,131 rgb=152,123,103
|
||||||
|
PAL 14 id=219,86,138 rgb=177,173,172
|
||||||
|
PAL 15 id=234,75,145 rgb=94,61,45
|
||||||
|
shadows a_now = (0.78, 1.80, 1.25, -0.06)
|
||||||
|
shadows b_g075 = (0.78, 0.75, 1.25, -0.06)
|
||||||
|
shadows c_g085 = (0.78, 0.85, 1.25, -0.06)
|
||||||
|
shadows d_g095 = (0.78, 0.95, 1.25, -0.06)
|
||||||
|
shadows e_g085b110 = (0.82, 0.85, 1.10, -0.06)
|
||||||
|
shadows f_g095b100 = (0.85, 0.95, 1.00, -0.06)
|
||||||
|
shadows g_neutral = (0.92, 0.92, 1.00, -0.06)
|
||||||
|
shadows z_sanity = (0.78, 1.80, 1.25, -0.06)
|
||||||
|
DONE
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
# WL-814x3 평가기 — 안별로 ① 부위 dHue ② 최적 _DiffuseColor 역이득(예측) ③ 게임 크기 고유색
|
||||||
|
import json, sys
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image
|
||||||
|
RAW='Screenshots_WL/WL814x/4th/raw'
|
||||||
|
def L(n): return np.asarray(Image.open(RAW+'/'+n+'.png').convert('RGB'),dtype=np.uint8)
|
||||||
|
def hue(c):
|
||||||
|
r,g,b=[float(x) for x in c]; mx,mn=max(r,g,b),min(r,g,b); d=mx-mn
|
||||||
|
if d<1e-6: return 0.0
|
||||||
|
if mx==r: h=((g-b)/d)%6
|
||||||
|
elif mx==g: h=(b-r)/d+2
|
||||||
|
else: h=(r-g)/d+4
|
||||||
|
return h*60.0
|
||||||
|
def sat(c):
|
||||||
|
mx=max(c); return (mx-min(c))/mx if mx>1e-6 else 0
|
||||||
|
def dh(a,b): return (b-a+540)%360-180
|
||||||
|
idm=L('idmap'); maF=L('mask_Face')[:,:,0]>127; ma=(L('mask_all')[:,:,0]>127)&~maF
|
||||||
|
G=np.array(Image.open('Assets/WL/Look/Character/Textures/WLPalette_FINAL.png')).shape[0]//8
|
||||||
|
idref=np.array([[9+j*15,240-j*11,40+j*7] for j in range(G*G)],np.float32)
|
||||||
|
fl=idm.reshape(-1,3).astype(np.float32); d2=((fl[:,None,:]-idref[None,:,:])**2).sum(2)
|
||||||
|
kid=np.where((d2.min(1).reshape(idm.shape[:2])<400)&(idm.sum(2)>12), d2.argmin(1).reshape(idm.shape[:2]), -1)
|
||||||
|
tgt={int(k):np.array(v,np.float32) for k,v in json.load(open('AgentScripts/WL814x2_target.json')).items()}
|
||||||
|
NAME={8:'머리칼(주)',4:'머리칼(밝)',2:'흰튜닉',1:'가죽갑옷',15:'붉은바지',0:'머리피부',5:'다리피부',14:'부츠흰면',11:'팔소매',10:'벨트',12:'머리칼(하)',3:'부츠갈색',13:'가죽(어두운)',9:'붉은천'}
|
||||||
|
cells=[]
|
||||||
|
for j in range(G*G):
|
||||||
|
sel=ma&(kid==j); n=int(sel.sum())
|
||||||
|
if n<800: continue
|
||||||
|
cells.append((j,n,sel,tgt[j]))
|
||||||
|
m10=L('mask_all10')[:,:,0]>127
|
||||||
|
def cellmeans(im):
|
||||||
|
return [(j,n,o,im[sel].mean(0).astype(np.float64)) for j,n,sel,o in cells]
|
||||||
|
def errs(cm,g):
|
||||||
|
return [(j,n,o,np.clip(s*g,0,255),dh(hue(o),hue(np.clip(s*g,0,255))),sat(o)) for j,n,o,s in cm]
|
||||||
|
def wavg(out):
|
||||||
|
ch=[(n,abs(e)) for j,n,o,s,e,so in out if so>0.12]
|
||||||
|
w=np.array([c[0] for c in ch],float); e=np.array([c[1] for c in ch])
|
||||||
|
return (e*w).sum()/w.sum(), e.max()
|
||||||
|
print('%-18s %7s %7s | %-22s %7s %7s | %6s %6s'%('안','dHue','최대','최적 _DiffuseColor','dHue*','최대*','고유색','비율%'))
|
||||||
|
best={}
|
||||||
|
for v in sys.argv[1:]:
|
||||||
|
cm=cellmeans(L(v))
|
||||||
|
o0=errs(cm,np.ones(3)); a0,m0=wavg(o0)
|
||||||
|
bb=None
|
||||||
|
for gr in np.arange(0.80,1.25,0.015):
|
||||||
|
for gb in np.arange(0.70,1.35,0.015):
|
||||||
|
gg=(1.0-0.299*gr-0.114*gb)/0.587
|
||||||
|
if gg<0.7 or gg>1.4: continue
|
||||||
|
g=np.array([gr,gg,gb]); a,m=wavg(errs(cm,g))
|
||||||
|
sc=a+0.35*m
|
||||||
|
if bb is None or sc<bb[0]: bb=(sc,g,a,m)
|
||||||
|
g=L(v+'_g')[m10]; k=(g[:,0].astype(np.int32)<<16)|(g[:,1].astype(np.int32)<<8)|g[:,2].astype(np.int32)
|
||||||
|
uc=len(np.unique(k))
|
||||||
|
print('%-18s %7.1f %7.1f | %-22s %7.1f %7.1f | %6d %6.1f'%(v,a0,m0,str(np.round(bb[1],3)),bb[2],bb[3],uc,100.0*uc/m10.sum()))
|
||||||
|
best[v]=bb[1]
|
||||||
|
json.dump({k:[float(x) for x in v] for k,v in best.items()}, open('AgentScripts/WL814x4_gains.json','w'))
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"a_now": [1.1750000000000003, 0.9691226575809199, 0.7], "fin": [1.2350000000000003, 0.9385604770017035, 0.7]}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"Skin": [
|
||||||
|
1.06,
|
||||||
|
0.9985689948892675,
|
||||||
|
0.8500000000000001
|
||||||
|
],
|
||||||
|
"M05": [
|
||||||
|
0.9900000000000001,
|
||||||
|
1.0050936967632027,
|
||||||
|
1.0000000000000002
|
||||||
|
],
|
||||||
|
"Hair": [
|
||||||
|
1.0150000000000001,
|
||||||
|
0.9904173764906303,
|
||||||
|
1.0100000000000002
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
# WL-814x4 — 부위 그룹(M05/Skin/Hair)별로 _DiffuseColor 역이득을 따로 탐색한다.
|
||||||
|
# 전역 이득 1개로는 못 맞추는 이유 = 부위마다 밝기 분포가 달라 그레이딩 회전량이 다르기 때문.
|
||||||
|
import json, sys
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image
|
||||||
|
RAW='Screenshots_WL/WL814x/4th/raw'
|
||||||
|
REN=sys.argv[1] if len(sys.argv)>1 else 'a_now'
|
||||||
|
def L(n): return np.asarray(Image.open(RAW+'/'+n+'.png').convert('RGB'),dtype=np.uint8)
|
||||||
|
def lum(c): return 0.299*c[0]+0.587*c[1]+0.114*c[2]
|
||||||
|
def hue(c):
|
||||||
|
r,g,b=[float(x) for x in c]; mx,mn=max(r,g,b),min(r,g,b); d=mx-mn
|
||||||
|
if d<1e-6: return 0.0
|
||||||
|
if mx==r: h=((g-b)/d)%6
|
||||||
|
elif mx==g: h=(b-r)/d+2
|
||||||
|
else: h=(r-g)/d+4
|
||||||
|
return h*60.0
|
||||||
|
def sat(c):
|
||||||
|
mx=max(c); return (mx-min(c))/mx if mx>1e-6 else 0
|
||||||
|
def dh(a,b): return (b-a+540)%360-180
|
||||||
|
idm=L('idmap'); maF=L('mask_Face')[:,:,0]>127; ma=(L('mask_all')[:,:,0]>127)&~maF
|
||||||
|
G=np.array(Image.open('Assets/WL/Look/Character/Textures/WLPalette_FINAL.png')).shape[0]//8
|
||||||
|
idref=np.array([[9+j*15,240-j*11,40+j*7] for j in range(G*G)],np.float32)
|
||||||
|
fl=idm.reshape(-1,3).astype(np.float32); d2=((fl[:,None,:]-idref[None,:,:])**2).sum(2)
|
||||||
|
kid=np.where((d2.min(1).reshape(idm.shape[:2])<400)&(idm.sum(2)>12), d2.argmin(1).reshape(idm.shape[:2]), -1)
|
||||||
|
tgt={int(k):np.array(v,np.float32) for k,v in json.load(open('AgentScripts/WL814x2_target.json')).items()}
|
||||||
|
PART={'Body_m05':'M05','Arm_m05':'M05','Leg_M05':'M05','Head':'Skin','Hair05':'Hair'}
|
||||||
|
pm={p:(L('mask_'+p)[:,:,0]>127) for p in PART}
|
||||||
|
im=L(REN)
|
||||||
|
cells={}
|
||||||
|
for j in range(G*G):
|
||||||
|
sel=ma&(kid==j); n=int(sel.sum())
|
||||||
|
if n<800: continue
|
||||||
|
grp=PART[max(((k,int((sel&v).sum())) for k,v in pm.items()),key=lambda t:t[1])[0]]
|
||||||
|
cells.setdefault(grp,[]).append((j,n,tgt[j].astype(np.float64),im[sel].mean(0).astype(np.float64)))
|
||||||
|
best={}
|
||||||
|
print('%-6s %-24s %8s %8s (칸 %d)'%('그룹','최적 _DiffuseColor','dHue','최대',0))
|
||||||
|
for grp,cs in cells.items():
|
||||||
|
def ev(g, full=False):
|
||||||
|
e=[];w=[];pen=0.0;pw=0.0
|
||||||
|
for j,n,o,s in cs:
|
||||||
|
c=np.clip(s*g,0,255)
|
||||||
|
if sat(o)>0.12:
|
||||||
|
e.append(abs(dh(hue(o),hue(c)))); w.append(n)
|
||||||
|
# 채도 보존: 보정으로 채도가 줄면(색이 빠지면) 벌점
|
||||||
|
pen += n*max(0.0, sat(s)-sat(c))*260.0; pw += n
|
||||||
|
else:
|
||||||
|
# 무채색 목표(흰옷·부츠)는 화면에서도 무채여야 한다
|
||||||
|
pen += n*max(0.0, sat(c)-0.14)*700.0; pw += n
|
||||||
|
if not e: return 0.0,0.0,0.0
|
||||||
|
e=np.array(e);w=np.array(w,float)
|
||||||
|
return (e*w).sum()/w.sum(), e.max(), pen/max(pw,1)
|
||||||
|
bb=None
|
||||||
|
for gr in np.arange(0.88,1.145,0.005):
|
||||||
|
for gb in np.arange(0.80,1.145,0.005):
|
||||||
|
gg=(1.0-0.299*gr-0.114*gb)/0.587
|
||||||
|
if gg<0.88 or gg>1.15: continue
|
||||||
|
g=np.array([gr,gg,gb]); a,m,pn=ev(g)
|
||||||
|
sc=a+0.4*m+pn
|
||||||
|
if bb is None or sc<bb[0]: bb=(sc,g,a,m)
|
||||||
|
a0,m0,_=ev(np.ones(3))
|
||||||
|
print('%-6s %-24s %8.1f %8.1f (보정 전 %.1f / 최대 %.1f · 칸 %d)'%(grp,str(np.round(bb[1],3)),bb[2],bb[3],a0,m0,len(cs)))
|
||||||
|
best[grp]=[float(x) for x in bb[1]]
|
||||||
|
for j,n,o,s in cs:
|
||||||
|
c=np.clip(s*bb[1],0,255)
|
||||||
|
print(' 칸%2d n=%6d 원본%-16s 지금%-16s → %-16s dHue %+6.1f → %+6.1f'%(j,n,
|
||||||
|
tuple(int(x) for x in o),tuple(int(x) for x in s),tuple(int(x) for x in c),dh(hue(o),hue(s)),dh(hue(o),hue(c))))
|
||||||
|
json.dump(best,open('AgentScripts/WL814x4_pergroup.json','w'),indent=1)
|
||||||
|
# 전체 가중 평균 예측
|
||||||
|
e=[];w=[]
|
||||||
|
for grp,cs in cells.items():
|
||||||
|
g=np.array(best[grp])
|
||||||
|
for j,n,o,s in cs:
|
||||||
|
if sat(o)<=0.12: continue
|
||||||
|
e.append(abs(dh(hue(o),hue(np.clip(s*g,0,255))))); w.append(n)
|
||||||
|
e=np.array(e);w=np.array(w,float)
|
||||||
|
print('예상 전체 유채 가중 dHue %.1f° (최대 %.1f°)'%((e*w).sum()/w.sum(),e.max()))
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
RAW='Screenshots_WL/WL814x/4th/raw'; OUT='Screenshots_WL/WL814x/4th'
|
||||||
|
import os; os.makedirs(OUT,exist_ok=True)
|
||||||
|
ma=np.asarray(Image.open(RAW+'/mask_all.png').convert('L'))>127
|
||||||
|
mf=np.asarray(Image.open(RAW+'/mask_Face.png').convert('L'))>127
|
||||||
|
ys,xs=np.where(ma|mf); x0,x1,y0,y1=xs.min()-24,xs.max()+25,ys.min()-24,ys.max()+25
|
||||||
|
def crop(n,s=1.0):
|
||||||
|
im=Image.open(RAW+'/'+n+'.png').convert('RGB').crop((x0,y0,x1,y1))
|
||||||
|
return im.resize((int(im.width*s),int(im.height*s)),Image.NEAREST) if s!=1.0 else im
|
||||||
|
def grid(out,items,fn):
|
||||||
|
ims=[(t,fn(n)) for t,n in items]
|
||||||
|
W=sum(i.width for _,i in ims)+18*(len(ims)-1); H=ims[0][1].height+26
|
||||||
|
o=Image.new('RGB',(W,H),(22,22,26)); d=ImageDraw.Draw(o); x=0
|
||||||
|
for t,im in ims:
|
||||||
|
o.paste(im,(x,26)); d.text((x+3,7),t,fill=(240,232,190)); x+=im.width+18
|
||||||
|
o.save(OUT+'/'+out); print('saved',out,o.size)
|
||||||
|
grid('e_final_close.png',[('3차 상태 (4차 시작)','a_now'),('4차 최종 (부위별 색조 보정)','fin')],lambda n:crop(n))
|
||||||
|
grid('e_shadow_steps.png',[('지금 G0.58','a_now'),('G0.75','b_g075'),('G0.85','c_g085'),('G0.95','d_g095'),('G.95 B1.0','f_g095b100'),('거의 중성','g_neutral')],lambda n:crop(n,0.55))
|
||||||
|
def wide(n,s=0.42):
|
||||||
|
im=Image.open(RAW+'/'+n+'.png').convert('RGB'); return im.resize((int(im.width*s),int(im.height*s)),Image.BILINEAR)
|
||||||
|
grid('e_final_wide.png',[('3차 상태','wide_a_now'),('4차 최종','fin_wide'),('참고: 그레이딩 G0.95','wide_d_g095')],wide)
|
||||||
|
rows=[('항목','1차 시작(원본 텍스처)','4차 최종','합격선','판정'),
|
||||||
|
('서로 다른 색 비율','89.3 %','3.9 %','≤ 25 %','PASS'),
|
||||||
|
('캐릭터 영역 고유색','2,676','115','≤ 200','PASS'),
|
||||||
|
('부위(덩어리)당 색 단계','41','평균 2.8 (13/14칸이 2~3)','≤ 4','PASS'),
|
||||||
|
('눈이 어두운 덩어리로','10 px','36 px (눈 1개 7×5)','36 px 이상','PASS'),
|
||||||
|
('화면 Hue 오차(유채 가중)','–','10.7° (벨트칸 제외 8.4°)','≤ 8°','거의'),
|
||||||
|
(' 부위 최대','–','벨트 61.1° / 그 외 ≤ 28.8°','≤ 20°','미달 2칸'),
|
||||||
|
('실루엣 외곽선','1 px','1 px (설정 무변경)','유지','PASS'),
|
||||||
|
('배경 룩','PD 승인','무변경(그레이딩 미채택)','유지','PASS')]
|
||||||
|
cw=[210,170,220,90,80]; rh=32; W=sum(cw)+40; H=rh*len(rows)+64
|
||||||
|
img=Image.new('RGB',(W,H),(22,22,26)); d=ImageDraw.Draw(img)
|
||||||
|
d.text((20,12),'WL-814x 1~4차 최종 요약 (인게임 Play · 포스트 포함 · 게임 크기 · 캐릭터 2,959 px)',fill=(255,235,160))
|
||||||
|
for r,row in enumerate(rows):
|
||||||
|
y=44+r*rh
|
||||||
|
bg=(40,40,48) if r==0 else ((30,30,36) if r%2 else (26,26,31))
|
||||||
|
d.rectangle([16,y,W-16,y+rh-2],fill=bg)
|
||||||
|
x=20
|
||||||
|
for c,cell in enumerate(row):
|
||||||
|
col=(235,235,235)
|
||||||
|
if r>0 and c==4: col=(130,230,150) if cell=='PASS' else (245,200,120)
|
||||||
|
if r>0 and c==2: col=(150,210,255)
|
||||||
|
d.text((x+6,y+8),str(cell),fill=col); x+=cw[c]
|
||||||
|
img.save(OUT+'/e_metrics.png'); print('saved e_metrics.png',img.size)
|
||||||
Loading…
Reference in New Issue