174 lines
8.8 KiB
C#
174 lines
8.8 KiB
C#
|
|
// 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")
|
|||
|
|
+ "(R−B " + ((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);
|
|||
|
|
}
|
|||
|
|
}
|