232 lines
12 KiB
C#
232 lines
12 KiB
C#
|
|
// WL-816k — ⑤ 대안 ⓑ: 지금 물(ToonWaterU · 814t 톤 유지)에 **얕은 물 그라데이션**을 되살린다.
|
|||
|
|
// 816j2 는 깊이 거품을 껐다(FoamColor=WaterColor) → 섬과 만나는 선에 아무 반응이 없어 「통과하는 느낌」.
|
|||
|
|
// 흰 거품(=PD 가 「안개 같다」) 대신 **물색을 밝힌 색**으로 되살려 얕은 물처럼 보이게 한다. 둘레 띠는 off.
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Text;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.Rendering.Universal;
|
|||
|
|
using UnityEngine.SceneManagement;
|
|||
|
|
using WL.Look.Farm;
|
|||
|
|
|
|||
|
|
public static class WL816k_AltB
|
|||
|
|
{
|
|||
|
|
public const string D = "Screenshots_WL/WL816k/";
|
|||
|
|
public const int PW = 1280, PH = 720;
|
|||
|
|
public const string MatDir = "Assets/WL/Look/Farm/Materials/";
|
|||
|
|
public const string C_Foam = "Color_e1f155248d144786a62fc1585ca21e9a";
|
|||
|
|
public const string R_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5";
|
|||
|
|
public const string R_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e";
|
|||
|
|
|
|||
|
|
public static void Open()
|
|||
|
|
{
|
|||
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
|
|||
|
|
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
|
|||
|
|
}
|
|||
|
|
public static void Start()
|
|||
|
|
{
|
|||
|
|
var go = GameObject.Find("~WL816kB");
|
|||
|
|
if (go != null) Object.DestroyImmediate(go);
|
|||
|
|
go = new GameObject("~WL816kB");
|
|||
|
|
go.AddComponent<WL816k_AltBRunner>();
|
|||
|
|
}
|
|||
|
|
public static Texture2D Grab(Camera cam, int w, int h)
|
|||
|
|
{
|
|||
|
|
var rt = new RenderTexture(w, h, 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(w, h, TextureFormat.RGB24, false);
|
|||
|
|
t.ReadPixels(new Rect(0, 0, w, h), 0, 0); t.Apply();
|
|||
|
|
RenderTexture.active = pA; cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt);
|
|||
|
|
return t;
|
|||
|
|
}
|
|||
|
|
static float Lum(Color32 c) { return (0.299f * c.r + 0.587f * c.g + 0.114f * c.b) / 255f; }
|
|||
|
|
|
|||
|
|
public static string Shot(Camera cam, string path, int w, int h, bool shoreMetric, out float shore, out int rmb)
|
|||
|
|
{
|
|||
|
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
|
|||
|
|
var t = Grab(cam, w, h);
|
|||
|
|
System.IO.File.WriteAllBytes(path, t.EncodeToPNG());
|
|||
|
|
var px = t.GetPixels32();
|
|||
|
|
long r = 0, g = 0, b = 0; int n = 0; double sum = 0, sum2 = 0;
|
|||
|
|
int y0 = 20, y1s = shoreMetric ? 200 : Mathf.Min(320, h);
|
|||
|
|
int x0 = shoreMetric ? 100 : 20, x1s = shoreMetric ? w - 100 : Mathf.Min(340, w);
|
|||
|
|
for (int y = y0; y < y1s; y += 2)
|
|||
|
|
for (int x = x0; x < x1s; x += 2)
|
|||
|
|
{ var c = px[y * w + x]; r += c.r; g += c.g; b += c.b; n++; float l = Lum(c); sum += l; sum2 += l * l; }
|
|||
|
|
double mean = n > 0 ? sum / n : 0;
|
|||
|
|
double sd = n > 0 ? System.Math.Sqrt(System.Math.Max(0, sum2 / n - mean * mean)) : 0;
|
|||
|
|
shore = 0f;
|
|||
|
|
string extra = "";
|
|||
|
|
if (shoreMetric)
|
|||
|
|
{
|
|||
|
|
double a = 0, b2 = 0; int an = 0, bn = 0;
|
|||
|
|
for (int y = 300; y < 350; y++) for (int x = 100; x < w - 100; x += 2) { a += Lum(px[y * w + x]); an++; }
|
|||
|
|
for (int y = 20; y < 70; y++) for (int x = 100; x < w - 100; x += 2) { b2 += Lum(px[y * w + x]); bn++; }
|
|||
|
|
shore = (float)((an > 0 ? a / an : 0) - (bn > 0 ? b2 / bn : 0));
|
|||
|
|
extra = " · 물가Δ " + shore.ToString("F4");
|
|||
|
|
}
|
|||
|
|
// 밝은 픽셀 R−B (분홍 방지 · 816j2 ②)
|
|||
|
|
long fr = 0, fb = 0; int fn = 0, tot = 0;
|
|||
|
|
int yh = (int)(h * 0.55f);
|
|||
|
|
for (int y = 0; y < yh; y++) for (int x = 0; x < w; x += 2)
|
|||
|
|
{ var c = px[y * w + x]; tot++; if (c.r > 200 && c.g > 195 && c.b > 195) { fr += c.r; fb += c.b; fn++; } }
|
|||
|
|
rmb = fn == 0 ? 0 : (int)(fr / fn) - (int)(fb / fn);
|
|||
|
|
Object.DestroyImmediate(t);
|
|||
|
|
return "바다 #" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(b / n)).ToString("X2")
|
|||
|
|
+ " σ=" + sd.ToString("F4") + " · 밝음 " + (100f * fn / tot).ToString("F2") + "%(R−B " + rmb + ")" + extra;
|
|||
|
|
}
|
|||
|
|
public static void Strip(string[] paths, string outPath, int div)
|
|||
|
|
{
|
|||
|
|
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 / div); h += ts[i].height / div;
|
|||
|
|
}
|
|||
|
|
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 yo = h;
|
|||
|
|
for (int i = 0; i < ts.Length; i++)
|
|||
|
|
{
|
|||
|
|
int sw = ts[i].width / div, sh2 = ts[i].height / div;
|
|||
|
|
var src = ts[i].GetPixels32(); int fw = ts[i].width;
|
|||
|
|
var dst = new Color32[sw * sh2];
|
|||
|
|
for (int y = 0; y < sh2; y++) for (int x = 0; x < sw; x++)
|
|||
|
|
{
|
|||
|
|
int rr = 0, gg = 0, bb = 0;
|
|||
|
|
for (int dy = 0; dy < div; dy++) for (int dx = 0; dx < div; dx++)
|
|||
|
|
{ var c = src[(y * div + dy) * fw + (x * div + dx)]; rr += c.r; gg += c.g; bb += c.b; }
|
|||
|
|
int q = div * div;
|
|||
|
|
dst[y * sw + x] = new Color32((byte)(rr / q), (byte)(gg / q), (byte)(bb / q), 255);
|
|||
|
|
}
|
|||
|
|
yo -= sh2; o.SetPixels32(0, yo, sw, sh2, dst);
|
|||
|
|
}
|
|||
|
|
o.Apply();
|
|||
|
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outPath));
|
|||
|
|
System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG());
|
|||
|
|
Object.DestroyImmediate(o);
|
|||
|
|
for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class WL816k_AltBRunner : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
static StringBuilder sb;
|
|||
|
|
static void L(string s) { sb.AppendLine(s); }
|
|||
|
|
const string D = WL816k_AltB.D;
|
|||
|
|
const int PW = WL816k_AltB.PW, PH = WL816k_AltB.PH;
|
|||
|
|
Camera live, zoom; Renderer water; MeshRenderer band;
|
|||
|
|
|
|||
|
|
void Start() { StartCoroutine(Co()); }
|
|||
|
|
|
|||
|
|
IEnumerator Co()
|
|||
|
|
{
|
|||
|
|
sb = new StringBuilder();
|
|||
|
|
L("=== WL-816k ⑤ 대안 ⓑ — 지금 물 + 얕은 물 그라데이션 (PD 구도 15 m · 띠 off) ===");
|
|||
|
|
var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive);
|
|||
|
|
while (op != null && !op.isDone) yield return null;
|
|||
|
|
for (int i = 0; i < 8; i++) yield return new WaitForSeconds(1f);
|
|||
|
|
|
|||
|
|
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|||
|
|
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
|
|||
|
|
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);
|
|||
|
|
band = foam != null ? foam.GetComponent<MeshRenderer>() : null;
|
|||
|
|
if (water == null || live == null) { L("🔴 물/카메라 없음"); Done(); yield break; }
|
|||
|
|
|
|||
|
|
foreach (var mb in live.GetComponents<MonoBehaviour>())
|
|||
|
|
if (mb != null && mb.GetType().Name.Contains("Cinemachine")) mb.enabled = false;
|
|||
|
|
float d = 15f, k = d * 0.70710678f;
|
|||
|
|
live.transform.position = new Vector3(0f, k, -k);
|
|||
|
|
live.transform.rotation = Quaternion.Euler(45f, 0f, 0f);
|
|||
|
|
live.fieldOfView = 60f;
|
|||
|
|
yield return null; yield return new WaitForSeconds(0.3f);
|
|||
|
|
L("카메라 거리 " + live.transform.position.magnitude.ToString("F1") + " m · 각 " + live.transform.eulerAngles.ToString("F0"));
|
|||
|
|
|
|||
|
|
var E = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(WL816k_AltB.MatDir + "Farm_Water_WL_E.mat");
|
|||
|
|
if (E == null) { L("🔴 E 없음"); Done(); yield break; }
|
|||
|
|
|
|||
|
|
var zgo = new GameObject("~WL816kBZ"); zgo.hideFlags = HideFlags.DontSave;
|
|||
|
|
zoom = zgo.AddComponent<Camera>();
|
|||
|
|
zoom.fieldOfView = 34f; zoom.nearClipPlane = 0.1f; zoom.farClipPlane = 2000f;
|
|||
|
|
zoom.clearFlags = CameraClearFlags.Skybox; zoom.cullingMask = ~0; zoom.depth = -100f;
|
|||
|
|
zgo.AddComponent<UniversalAdditionalCameraData>().renderPostProcessing = true;
|
|||
|
|
Bounds bb = band != null ? band.bounds : new Bounds(Vector3.zero, new Vector3(16, 1, 16));
|
|||
|
|
zgo.transform.position = new Vector3(bb.center.x, 3.2f, bb.min.z - 9f);
|
|||
|
|
zgo.transform.LookAt(new Vector3(bb.center.x, -1f, bb.min.z + 2f));
|
|||
|
|
|
|||
|
|
float sh; int rmb;
|
|||
|
|
L("");
|
|||
|
|
water.sharedMaterial = E; if (band != null) band.enabled = true;
|
|||
|
|
yield return null; yield return new WaitForSeconds(0.35f);
|
|||
|
|
L("[전] 지금(물 E · 띠 on) 물가 " + WL816k_AltB.Shot(zoom, D + "b_before_zoom.png", PW, PH, true, out sh, out rmb));
|
|||
|
|
if (band != null) band.enabled = false;
|
|||
|
|
yield return null; yield return new WaitForSeconds(0.3f);
|
|||
|
|
L("[전] 띠만 off 물가 " + WL816k_AltB.Shot(zoom, D + "b_bandoff_zoom.png", PW, PH, true, out sh, out rmb));
|
|||
|
|
|
|||
|
|
// 얕은 물 그라데이션 3안 (흰 거품 아님 — 물색을 밝힌 색)
|
|||
|
|
var fc = new[] { new Color(0.62f, 0.82f, 0.90f, 1f), new Color(0.62f, 0.82f, 0.90f, 1f), new Color(0.78f, 0.90f, 0.95f, 1f) };
|
|||
|
|
var fd = new[] { 1.2f, 2.2f, 1.6f };
|
|||
|
|
var fe = new[] { 6f, 3f, 4f };
|
|||
|
|
var zp = new string[3]; var shores = new float[3];
|
|||
|
|
L("");
|
|||
|
|
L("[얕은 물 그라데이션 3안] FoamColor = 물색을 밝힌 색 · 띠 off");
|
|||
|
|
for (int i = 0; i < 3; i++)
|
|||
|
|
{
|
|||
|
|
var m = new Material(E);
|
|||
|
|
m.SetColor(WL816k_AltB.C_Foam, fc[i]);
|
|||
|
|
m.SetFloat(WL816k_AltB.R_FoamDistance, fd[i]);
|
|||
|
|
m.SetFloat(WL816k_AltB.R_FoamEdge, fe[i]);
|
|||
|
|
water.sharedMaterial = m;
|
|||
|
|
yield return null; yield return new WaitForSeconds(0.3f);
|
|||
|
|
zp[i] = D + "b_w" + (i + 1) + "_zoom.png";
|
|||
|
|
L(" w" + (i + 1) + " FoamColor" + fc[i].ToString("F2") + " Dist " + fd[i] + " Edge " + fe[i]);
|
|||
|
|
L(" " + WL816k_AltB.Shot(zoom, zp[i], PW, PH, true, out sh, out rmb));
|
|||
|
|
shores[i] = sh;
|
|||
|
|
L(" PD " + WL816k_AltB.Shot(live, D + "b_w" + (i + 1) + ".png", PW, PH, false, out _, out _));
|
|||
|
|
}
|
|||
|
|
WL816k_AltB.Strip(zp, D + "b_w3_zoom.png", 3);
|
|||
|
|
int best = 0; float bd = -9f;
|
|||
|
|
for (int i = 0; i < 3; i++) if (shores[i] > bd && shores[i] <= 0.09f) { bd = shores[i]; best = i; }
|
|||
|
|
L("");
|
|||
|
|
L("🔴 ⓑ 채택 = w" + (best + 1) + " · FoamColor " + fc[best].ToString("F3") + " · FoamDistance " + fd[best] + " · FoamEdge " + fe[best]
|
|||
|
|
+ " · 물가Δ " + shores[best].ToString("F4"));
|
|||
|
|
System.IO.File.WriteAllText("AgentScripts/WL816k_PICKB.txt",
|
|||
|
|
fc[best].r + "," + fc[best].g + "," + fc[best].b + "|" + fd[best] + "|" + fe[best]);
|
|||
|
|
|
|||
|
|
// 후 = 채택안 PD 구도
|
|||
|
|
var win = new Material(E);
|
|||
|
|
win.SetColor(WL816k_AltB.C_Foam, fc[best]);
|
|||
|
|
win.SetFloat(WL816k_AltB.R_FoamDistance, fd[best]);
|
|||
|
|
win.SetFloat(WL816k_AltB.R_FoamEdge, fe[best]);
|
|||
|
|
water.sharedMaterial = win;
|
|||
|
|
yield return null; yield return new WaitForSeconds(0.35f);
|
|||
|
|
L("[후] PD " + WL816k_AltB.Shot(live, D + "zb_after_pd.png", PW, PH, false, out _, out _));
|
|||
|
|
L("[후] 물가 " + WL816k_AltB.Shot(zoom, D + "zb_after_zoom.png", PW, PH, true, out sh, out rmb));
|
|||
|
|
// 전 PD (띠 on) 도 같은 자리에서
|
|||
|
|
water.sharedMaterial = E; if (band != null) band.enabled = true;
|
|||
|
|
yield return null; yield return new WaitForSeconds(0.35f);
|
|||
|
|
L("[전] PD " + WL816k_AltB.Shot(live, D + "zb_before_pd.png", PW, PH, false, out _, out _));
|
|||
|
|
WL816k_AltB.Strip(new[] { D + "zb_before_pd.png", D + "zb_after_pd.png" }, D + "z_pd_before_after.png", 1);
|
|||
|
|
WL816k_AltB.Strip(new[] { D + "b_before_zoom.png", D + "zb_after_zoom.png" }, D + "z_zoom_shore.png", 1);
|
|||
|
|
|
|||
|
|
Object.DestroyImmediate(zgo);
|
|||
|
|
Done();
|
|||
|
|
}
|
|||
|
|
void Done()
|
|||
|
|
{
|
|||
|
|
System.IO.File.WriteAllText("AgentScripts/WL816k_ALTB.txt", sb.ToString());
|
|||
|
|
Debug.Log("[816k altB]\n" + sb);
|
|||
|
|
}
|
|||
|
|
}
|