Project_WL/AgentScripts/WL816j2_Tune.cs

174 lines
8.8 KiB
C#
Raw 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-816j2 — ④ PD 구도에서 마지막 조율: 무늬 선을 데모만큼 은은하게 · 띠 폭/비용 · 최종 전후
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using WL.Look.Farm;
public static class WL816j2_Tune
{
public const string D = "Screenshots_WL/WL816j2/";
public const int PW = 1280, PH = 720;
public const string C_Light = "Color_1ec6cccf8ead489ebb917674f7e8b3b1";
public const string C_FoamShadow = "Color_2323d69962e04c499c5d5f0925432b55";
public static void Start()
{
var go = GameObject.Find("~WL816j2T");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816j2T");
go.AddComponent<WL816j2_TuneRunner>();
}
public static string Shot(Camera cam, string path)
{
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(PW, PH, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; var pA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var t = new Texture2D(PW, PH, TextureFormat.RGB24, false);
t.ReadPixels(new Rect(0, 0, PW, PH), 0, 0); t.Apply();
RenderTexture.active = pA; cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt);
System.IO.File.WriteAllBytes(path, t.EncodeToPNG());
var px = t.GetPixels32();
double sum = 0, sum2 = 0; int n = 0;
for (int y = 20; y < 320; y += 2)
for (int x = 20; x < 340; x += 2)
{ var c = px[y * PW + x]; float l = (0.299f * c.r + 0.587f * c.g + 0.114f * c.b) / 255f; sum += l; sum2 += l * l; n++; }
double mean = sum / n, sd = System.Math.Sqrt(System.Math.Max(0, sum2 / n - mean * mean));
long fr = 0, fg = 0, fb = 0; int fn = 0, tot = 0;
int y1 = (int)(PH * 0.55f);
for (int y = 0; y < y1; y++)
for (int x = 0; x < PW; x += 2)
{ var c = px[y * PW + x]; tot++; if (c.r > 200 && c.g > 195 && c.b > 195) { fr += c.r; fg += c.g; fb += c.b; fn++; } }
Object.DestroyImmediate(t);
string foam = fn == 0 ? "거품 0%" : "거품 " + (100f * fn / tot).ToString("F2") + "% #"
+ ((int)(fr / fn)).ToString("X2") + ((int)(fg / fn)).ToString("X2") + ((int)(fb / fn)).ToString("X2")
+ "(RB " + ((int)(fr / fn) - (int)(fb / fn)) + ")";
return "σ=" + sd.ToString("F4") + " · " + foam + " → " + path;
}
public static float Ms(Camera cam, int frames)
{
var rt = new RenderTexture(PW, PH, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; cam.targetTexture = rt;
for (int i = 0; i < 10; i++) cam.Render();
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < frames; i++) cam.Render();
sw.Stop();
cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt);
return (float)sw.Elapsed.TotalMilliseconds / frames;
}
public static void Strip(string[] paths, string outPath)
{
var ts = new Texture2D[paths.Length]; int w = 0, h = 0;
for (int i = 0; i < paths.Length; i++)
{
if (!System.IO.File.Exists(paths[i])) return;
ts[i] = new Texture2D(2, 2, TextureFormat.RGB24, false);
ts[i].LoadImage(System.IO.File.ReadAllBytes(paths[i]));
w = Mathf.Max(w, ts[i].width); h += ts[i].height;
}
var o = new Texture2D(w, h, TextureFormat.RGB24, false);
var f = new Color32[w * h];
for (int i = 0; i < f.Length; i++) f[i] = new Color32(24, 24, 28, 255);
o.SetPixels32(f);
int y = h;
for (int i = 0; i < ts.Length; i++) { y -= ts[i].height; o.SetPixels32(0, y, ts[i].width, ts[i].height, ts[i].GetPixels32()); }
o.Apply();
System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG());
Object.DestroyImmediate(o);
for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]);
}
}
public class WL816j2_TuneRunner : MonoBehaviour
{
static StringBuilder sb;
static void L(string s) { sb.AppendLine(s); }
const string D = WL816j2_Tune.D;
const string MatDir = "Assets/WL/Look/Farm/Materials/";
void Start() { StartCoroutine(Co()); }
IEnumerator Co()
{
sb = new StringBuilder();
L("=== WL-816j2 ④ 마지막 조율 (PD 구도 1280×720) ===");
Renderer water = null;
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
Camera live = null;
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue;
if (c.name.StartsWith("~WL816")) continue;
if (live == null || c.depth > live.depth) live = c;
}
var foam = Object.FindFirstObjectByType<WLShoreFoam>(FindObjectsInactive.Include);
if (water == null || live == null || foam == null) { L("🔴 없음"); Done(); yield break; }
var E = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(MatDir + "Farm_Water_WL_E.mat");
var mr = foam.GetComponent<MeshRenderer>();
// ── 1) 무늬 선을 데모만큼 은은하게 (기준 데모 σ=0.0024 · 지금 D σ=0.0823) ──
L("");
L("1) 무늬 선 3단 — LightColor + FoamShadowColor(무늬의 어두운 쪽). 목표 = 데모(σ 0.0024)에 가깝게");
var lc = new[] { new Color(0.45f, 0.74f, 0.86f), new Color(0.42f, 0.72f, 0.845f), new Color(0.385f, 0.705f, 0.83f) };
var fs = new[] { new Color(0.78f, 0.86f, 0.92f), new Color(0.93f, 0.96f, 0.98f), new Color(1f, 1f, 1f) };
var ps = new string[3];
for (int i = 0; i < 3; i++)
{
var m = new Material(E);
m.SetColor(WL816j2_Tune.C_Light, lc[i]);
m.SetColor(WL816j2_Tune.C_FoamShadow, fs[i]);
water.sharedMaterial = m; yield return null; yield return new WaitForSeconds(0.2f);
ps[i] = D + "h_soft" + (i + 1) + ".png";
L(" Light " + lc[i] + " Shadow " + fs[i] + " " + WL816j2_Tune.Shot(live, ps[i]));
}
WL816j2_Tune.Strip(ps, D + "h_soft_steps.png");
// 채택 후보 = 가운데
var adopt = new Material(E);
adopt.SetColor(WL816j2_Tune.C_Light, lc[1]);
adopt.SetColor(WL816j2_Tune.C_FoamShadow, fs[1]);
water.sharedMaterial = adopt; yield return null;
// ── 2) 띠 폭 3단 (고친 텍스처로 다시) + 폭별 비용 ────────────
L("");
L("2) 띠 폭 3단 + 폭별 비용 (60프레임 × 2회)");
var ws = new string[4]; float[] wid = { 0.9f, 1.6f, 2.6f };
mr.enabled = false; yield return null; yield return null;
ws[0] = D + "i_w0_off.png";
L(" [띠 off] " + WL816j2_Tune.Shot(live, ws[0]) + " · " + WL816j2_Tune.Ms(live, 60).ToString("F3") + " ms");
mr.enabled = true;
for (int i = 0; i < 3; i++)
{
foam.widthOverride = wid[i]; foam.Rebuild();
yield return null; yield return new WaitForSeconds(0.2f);
ws[i + 1] = D + "i_w" + (i + 1) + ".png";
float a = WL816j2_Tune.Ms(live, 60), b = WL816j2_Tune.Ms(live, 60);
L(" [폭 " + wid[i] + " m · 삼각형 " + WLShoreFoam.Tris + "] " + WL816j2_Tune.Shot(live, ws[i + 1])
+ " · " + a.ToString("F3") + " / " + b.ToString("F3") + " ms");
}
WL816j2_Tune.Strip(ws, D + "i_band_steps.png");
foam.widthOverride = 0f; foam.Rebuild(); yield return null;
// ── 3) 최종 전/후 (PD 구도) ─────────────────────────────────
var Dm = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(MatDir + "Farm_Water_WL_D.mat");
L("");
L("3) 최종 전/후 (PD 구도)");
mr.enabled = false; water.sharedMaterial = Dm; yield return null; yield return new WaitForSeconds(0.3f);
L(" [전] main(물 D · 띠 없음) " + WL816j2_Tune.Shot(live, D + "z_before_pd.png"));
mr.enabled = true; water.sharedMaterial = adopt; yield return null; yield return new WaitForSeconds(0.3f);
L(" [후] 816j2(물 E · 띠 on) " + WL816j2_Tune.Shot(live, D + "z_after_pd.png"));
WL816j2_Tune.Strip(new[] { D + "z_before_pd.png", D + "z_after_pd.png" }, D + "z_pd_before_after.png");
Done();
}
void Done()
{
System.IO.File.WriteAllText("AgentScripts/WL816j2_TUNE.txt", sb.ToString());
Debug.Log("[816j2 tune]\n" + sb);
}
}