Project_WL/AgentScripts/WL816r_Play2.cs

321 lines
17 KiB
C#

// WL-816r 2차 — PD 구도에서 「흙띠·모래띠」 후보 스윕 + 길/밭 머티리얼 프로브 역산.
public static class WL816r_Play2
{
public static void Start()
{
var go = UnityEngine.GameObject.Find("~WL816rPlay2");
if (go != null) UnityEngine.Object.DestroyImmediate(go);
go = new UnityEngine.GameObject("~WL816rPlay2");
go.AddComponent<WL816r_Runner2>();
}
}
public class WL816r_Runner2 : UnityEngine.MonoBehaviour
{
static System.Text.StringBuilder sb;
const int W = 1080, H = 1920;
static string Dir = "Screenshots_WL/WL816r";
// (모래 사분면, 흙 사분면) 후보 — 데모 흙 화면색 #A4A88B 목표
static readonly string[][] TopCand = {
new[]{"CCCBB5","807057"}, // 0 현행
new[]{"B5B69E","8F8F79"},
new[]{"A8A992","82836E"},
new[]{"C0C1A8","9A9B84"},
new[]{"AEAF98","6E6F5C"},
};
void Start() { StartCoroutine(Co()); }
System.Collections.IEnumerator Co()
{
sb = new System.Text.StringBuilder();
System.IO.Directory.CreateDirectory(Dir);
var cfg = WL.Look.Farm.WLIslandLookSettings.Instance;
var topMat = cfg.islandTopMaterial;
// ── 실태 보고 (비활성 포함) ─────────────────────────────────────────
var farms = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Farm>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
int soilAll = 0, soilActive = 0;
UnityEngine.Material soilMat = null;
foreach (var f in farms)
foreach (var s in f.GetComponentsInChildren<CryingSnow.FarmingIsland.Soil>(true))
{
soilAll++;
var r = s.GetComponent<UnityEngine.Renderer>();
if (r != null && r.gameObject.activeInHierarchy && r.enabled) soilActive++;
if (soilMat == null && r != null) soilMat = r.sharedMaterial;
}
var roadTfs = new System.Collections.Generic.List<UnityEngine.Transform>();
foreach (var t in UnityEngine.Object.FindObjectsByType<UnityEngine.Transform>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None))
if (t.name == "Road") roadTfs.Add(t);
int roadRendAll = 0, roadRendActive = 0;
UnityEngine.Material roadMat = null;
foreach (var t in roadTfs)
foreach (var r in t.GetComponentsInChildren<UnityEngine.Renderer>(true))
{
roadRendAll++;
if (r.gameObject.activeInHierarchy && r.enabled) roadRendActive++;
foreach (var m in r.sharedMaterials)
if (m != null && m.shader != null && m.shader.name.Contains("Toon") && roadMat == null) roadMat = m;
}
L("실태 — Farm=" + farms.Length + " Soil(전체/활성)=" + soilAll + "/" + soilActive
+ " · Road 트랜스폼=" + roadTfs.Count + " 렌더러(전체/활성)=" + roadRendAll + "/" + roadRendActive);
L(" Soil mat=" + (soilMat ? soilMat.name + " sh=" + soilMat.shader.name + " color=" + Hx(MatColor(soilMat).gamma) : "없음"));
L(" Road mat=" + (roadMat ? roadMat.name + " sh=" + roadMat.shader.name + " Dif=" + Hx(roadMat.GetColor("_DiffuseColor").gamma) + " Shd=" + Hx(roadMat.GetColor("_ShadowDiffuseColor").gamma) : "없음"));
// ── 섬 윗면 렌더러 ──────────────────────────────────────────────────
var topR = new System.Collections.Generic.List<UnityEngine.Renderer>();
foreach (var r in UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(UnityEngine.FindObjectsSortMode.None))
foreach (var m in r.sharedMaterials) if (m != null && m == topMat) { topR.Add(r); break; }
var camPd = MakePd();
// 띠 픽셀 = 섬윗면 그룹 중 「초록이 아닌」 픽셀 (전 기준으로 고정한다)
var mask = IdMask(camPd, W, H, topR);
var texB = Grab(camPd, W, H);
System.IO.File.WriteAllBytes(Dir + "/r2_before_pd.png", UnityEngine.ImageConversion.EncodeToPNG(texB));
var pxB = texB.GetPixels32();
var band = new byte[W * H];
int nb = 0;
for (int i = 0; i < mask.Length; i++)
{
if (mask[i] != 1) continue;
var p = pxB[i];
if (p.g > p.r + 10 && p.g > p.b + 10) continue; // 초록(풀밭 바닥) 제외
band[i] = 1; nb++;
}
L("섬윗면 그룹 px=" + Count(mask, 1) + " · 그중 띠(비초록) px=" + nb);
L("[전] 띠 " + Stat(pxB, band, 1));
UnityEngine.Object.DestroyImmediate(texB);
// ── 텍스처 후보 스윕 (초록 행 원본 바이트 유지) ─────────────────────
var srcBytes = System.IO.File.ReadAllBytes("Assets/WL/Look/Farm/Textures/WL_IslandTop_Demo.png");
for (int ci = 1; ci < TopCand.Length; ci++)
{
var tex = MakeTopTex(srcBytes, TopCand[ci][0], TopCand[ci][1]);
var m = new UnityEngine.Material(topMat); m.name = topMat.name + "_r" + ci;
m.SetTexture("_BaseMap", tex); m.SetTexture("_ShadowBaseMap", tex);
SwapMat(topR, topMat, m);
yield return null; yield return null;
var t2 = Grab(camPd, W, H);
var p2 = t2.GetPixels32();
L("[후보" + ci + " 모래#" + TopCand[ci][0] + " 흙#" + TopCand[ci][1] + "] 띠 " + Stat(p2, band, 1));
if (ci == 1) System.IO.File.WriteAllBytes(Dir + "/r2_cand1_pd.png", UnityEngine.ImageConversion.EncodeToPNG(t2));
UnityEngine.Object.DestroyImmediate(t2);
SwapMat(topR, m, topMat);
UnityEngine.Object.DestroyImmediate(m); UnityEngine.Object.DestroyImmediate(tex);
}
// ── 길·밭 머티리얼 프로브 (평평한 판 · 섬 위) ───────────────────────
var pc = UnityEngine.GameObject.FindGameObjectWithTag("Player");
var org = pc != null ? pc.transform.position : UnityEngine.Vector3.zero;
var cands = new[] { "D4D6BE", "C6C8B0", "B5B69E", "A8A992", "9A9B84", "CCCBB5" };
var camTopP = MakeTopProbe(org.x, org.z + 3f, 5f);
yield return ProbeRow(camTopP, roadMat, cands, org + new UnityEngine.Vector3(0f, 1.2f, 3f), "길(Toon)");
yield return ProbeRow(camTopP, soilMat, cands, org + new UnityEngine.Vector3(0f, 1.2f, 4.6f), "밭(Soil셰이더)");
Flush();
}
System.Collections.IEnumerator ProbeRow(UnityEngine.Camera cam, UnityEngine.Material baseMat, string[] cands, UnityEngine.Vector3 origin, string tag)
{
if (baseMat == null) { L(tag + " — 머티리얼 없음, 프로브 생략"); yield break; }
var root = new UnityEngine.GameObject("~816rP2");
var mats = new System.Collections.Generic.List<UnityEngine.Material>();
var rends = new System.Collections.Generic.List<UnityEngine.Renderer>();
var pos = new UnityEngine.Vector3[cands.Length];
bool toon = baseMat.HasProperty("_DiffuseColor");
var sr = toon && baseMat.HasProperty("_ShadowDiffuseColor")
? new UnityEngine.Color(0.3596f, 0.2741f, 0.2051f, 1f) : UnityEngine.Color.white; // 데모 흙 그림자비
for (int i = 0; i < cands.Length; i++)
{
var lin = Hex(cands[i]).linear;
var m = new UnityEngine.Material(baseMat); m.name = baseMat.name + "_p" + i;
if (toon)
{
m.SetTexture("_BaseMap", null); m.SetTexture("_ShadowBaseMap", null);
m.SetColor("_DiffuseColor", lin);
m.SetColor("_ShadowDiffuseColor", new UnityEngine.Color(lin.r * sr.r, lin.g * sr.g, lin.b * sr.b, 1f));
}
else SetMatColor(m, lin);
mats.Add(m);
var q = UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Quad);
q.transform.SetParent(root.transform);
q.transform.rotation = UnityEngine.Quaternion.Euler(90f, 0f, 0f);
q.transform.localScale = new UnityEngine.Vector3(1.1f, 1.1f, 1f);
pos[i] = origin + new UnityEngine.Vector3((i - (cands.Length - 1) * 0.5f) * 1.3f, 0f, 0f);
q.transform.position = pos[i];
var rr = q.GetComponent<UnityEngine.MeshRenderer>();
rr.sharedMaterial = m; rends.Add(rr);
UnityEngine.Object.DestroyImmediate(q.GetComponent<UnityEngine.Collider>());
}
yield return null; yield return null;
var tex = Grab(cam, 1024, 1024);
var px = tex.GetPixels32();
for (int i = 0; i < cands.Length; i++) L(" " + tag + " #" + cands[i] + " -> " + Patch(cam, px, pos[i], 1024, 8));
System.IO.File.WriteAllBytes(Dir + "/r2_probe_" + (toon ? "road" : "soil") + ".png", UnityEngine.ImageConversion.EncodeToPNG(tex));
UnityEngine.Object.DestroyImmediate(tex);
UnityEngine.Object.DestroyImmediate(root);
foreach (var m in mats) UnityEngine.Object.DestroyImmediate(m);
}
static UnityEngine.Color MatColor(UnityEngine.Material m)
{
if (m == null) return UnityEngine.Color.black;
if (m.HasProperty("_BaseColor")) return m.GetColor("_BaseColor");
if (m.HasProperty("_Color")) return m.GetColor("_Color");
return UnityEngine.Color.black;
}
static void SetMatColor(UnityEngine.Material m, UnityEngine.Color c)
{
if (m.HasProperty("_BaseColor")) m.SetColor("_BaseColor", c);
if (m.HasProperty("_Color")) m.SetColor("_Color", c);
}
static UnityEngine.Texture2D MakeTopTex(byte[] srcBytes, string sandHex, string dirtHex)
{
var tex = new UnityEngine.Texture2D(2, 2, UnityEngine.TextureFormat.RGBA32, false);
UnityEngine.ImageConversion.LoadImage(tex, srcBytes);
tex.filterMode = UnityEngine.FilterMode.Point; tex.wrapMode = UnityEngine.TextureWrapMode.Clamp;
var px = tex.GetPixels32();
var sand = Hex32c(sandHex); var dirt = Hex32c(dirtHex);
var sandSrc = new UnityEngine.Color32(0xCC, 0xCB, 0xB5, 255);
var dirtSrc = new UnityEngine.Color32(0x80, 0x70, 0x57, 255);
for (int i = 0; i < px.Length; i++)
{
if (Same(px[i], sandSrc)) px[i] = sand;
else if (Same(px[i], dirtSrc)) px[i] = dirt;
}
tex.SetPixels32(px); tex.Apply(false);
return tex;
}
static bool Same(UnityEngine.Color32 a, UnityEngine.Color32 b) { return a.r == b.r && a.g == b.g && a.b == b.b; }
static void SwapMat(System.Collections.Generic.List<UnityEngine.Renderer> rs, UnityEngine.Material from, UnityEngine.Material to)
{
foreach (var r in rs)
{
var ms = r.sharedMaterials; bool hit = false;
for (int i = 0; i < ms.Length; i++) if (ms[i] == from) { ms[i] = to; hit = true; }
if (hit) r.sharedMaterials = ms;
}
}
static byte[] IdMask(UnityEngine.Camera cam, int w, int h, System.Collections.Generic.List<UnityEngine.Renderer> top)
{
var unlit = UnityEngine.Shader.Find("Universal Render Pipeline/Unlit");
var saved = new System.Collections.Generic.Dictionary<UnityEngine.Renderer, UnityEngine.Material[]>();
var mats = new System.Collections.Generic.List<UnityEngine.Material>();
var black = new UnityEngine.Material(unlit); black.SetColor("_BaseColor", UnityEngine.Color.black); mats.Add(black);
var blue = new UnityEngine.Material(unlit); blue.SetColor("_BaseColor", new UnityEngine.Color(0f, 0f, 1f, 1f)); mats.Add(blue);
foreach (var r in UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(UnityEngine.FindObjectsSortMode.None))
{
if (r == null || !r.enabled) continue;
var use = top.Contains(r) ? blue : black;
saved[r] = r.sharedMaterials;
var arr = new UnityEngine.Material[r.sharedMaterials.Length];
for (int i = 0; i < arr.Length; i++) arr[i] = use;
r.sharedMaterials = arr;
}
var tex = Grab(cam, w, h);
var px = tex.GetPixels32();
var mask = new byte[w * h];
for (int i = 0; i < px.Length; i++) if (px[i].b > 150 && px[i].r < 90 && px[i].g < 90) mask[i] = 1;
UnityEngine.Object.DestroyImmediate(tex);
foreach (var kv in saved) if (kv.Key != null) kv.Key.sharedMaterials = kv.Value;
foreach (var m in mats) UnityEngine.Object.DestroyImmediate(m);
return mask;
}
static int Count(byte[] m, byte id) { int n = 0; for (int i = 0; i < m.Length; i++) if (m[i] == id) n++; return n; }
static string Stat(UnityEngine.Color32[] px, byte[] mask, byte id)
{
long r = 0, g = 0, b2 = 0; int n = 0;
var uniq = new System.Collections.Generic.Dictionary<int, int>();
for (int i = 0; i < mask.Length && i < px.Length; i++)
{
if (mask[i] != id) continue;
var p = px[i]; r += p.r; g += p.g; b2 += p.b; n++;
int k = (p.r << 16) | (p.g << 8) | p.b;
uniq[k] = uniq.ContainsKey(k) ? uniq[k] + 1 : 1;
}
if (n == 0) return "px0";
var list = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<int, int>>(uniq);
list.Sort((A, B) => B.Value.CompareTo(A.Value));
var top = new System.Text.StringBuilder();
for (int i = 0; i < System.Math.Min(4, list.Count); i++) top.Append(string.Format(" #{0:X6}x{1}", list[i].Key, list[i].Value));
return string.Format("n={0} avg=#{1:X2}{2:X2}{3:X2} uniq={4} top:{5}", n, r / n, g / n, b2 / n, uniq.Count, top);
}
static string Patch(UnityEngine.Camera cam, UnityEngine.Color32[] px, UnityEngine.Vector3 w, int size, int rad)
{
var v = cam.WorldToViewportPoint(w);
int cx = (int)(v.x * size), cy = (int)(v.y * size);
long r = 0, g = 0, b = 0; int n = 0;
for (int y = cy - rad; y <= cy + rad; y++)
for (int x = cx - rad; x <= cx + rad; x++)
{
if (x < 0 || y < 0 || x >= size || y >= size) continue;
var p = px[y * size + x]; r += p.r; g += p.g; b += p.b; n++;
}
return n == 0 ? "px0" : string.Format("#{0:X2}{1:X2}{2:X2} ({3},{4},{5})", r / n, g / n, b / n, r / n, g / n, b / n);
}
static UnityEngine.Color Hex(string h)
{
return new UnityEngine.Color(System.Convert.ToInt32(h.Substring(0, 2), 16) / 255f,
System.Convert.ToInt32(h.Substring(2, 2), 16) / 255f,
System.Convert.ToInt32(h.Substring(4, 2), 16) / 255f, 1f);
}
static UnityEngine.Color32 Hex32c(string h)
{
return new UnityEngine.Color32((byte)System.Convert.ToInt32(h.Substring(0, 2), 16),
(byte)System.Convert.ToInt32(h.Substring(2, 2), 16),
(byte)System.Convert.ToInt32(h.Substring(4, 2), 16), 255);
}
static string Hx(UnityEngine.Color c)
{
return string.Format("#{0:X2}{1:X2}{2:X2}", (int)(UnityEngine.Mathf.Clamp01(c.r) * 255), (int)(UnityEngine.Mathf.Clamp01(c.g) * 255), (int)(UnityEngine.Mathf.Clamp01(c.b) * 255));
}
static UnityEngine.Camera MakePd()
{
UnityEngine.Vector3 tgt = UnityEngine.Vector3.zero;
var pc = UnityEngine.GameObject.FindGameObjectWithTag("Player"); if (pc != null) tgt = pc.transform.position;
var go = UnityEngine.GameObject.Find("~816r2Pd"); if (go == null) go = new UnityEngine.GameObject("~816r2Pd");
var c = go.GetComponent<UnityEngine.Camera>(); if (c == null) c = go.AddComponent<UnityEngine.Camera>();
c.orthographic = false; c.fieldOfView = 60f; c.nearClipPlane = 0.1f; c.farClipPlane = 300f;
c.transform.rotation = UnityEngine.Quaternion.Euler(45f, 45f, 0f);
c.transform.position = tgt - c.transform.forward * 12f;
c.aspect = (float)W / H;
c.enabled = false; return c;
}
static UnityEngine.Camera MakeTopProbe(float x, float z, float size)
{
var go = UnityEngine.GameObject.Find("~816r2Tp"); if (go == null) go = new UnityEngine.GameObject("~816r2Tp");
var c = go.GetComponent<UnityEngine.Camera>(); if (c == null) c = go.AddComponent<UnityEngine.Camera>();
c.orthographic = true; c.orthographicSize = size; c.nearClipPlane = 0.1f; c.farClipPlane = 200f;
c.transform.rotation = UnityEngine.Quaternion.Euler(90f, 0f, 0f);
c.transform.position = new UnityEngine.Vector3(x, 40f, z);
c.aspect = 1f; c.enabled = false; return c;
}
static UnityEngine.Texture2D Grab(UnityEngine.Camera cam, int w, int h)
{
var rt = new UnityEngine.RenderTexture(w, h, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
rt.Create(); cam.targetTexture = rt; cam.Render();
var prev = UnityEngine.RenderTexture.active; UnityEngine.RenderTexture.active = rt;
var tex = new UnityEngine.Texture2D(w, h, UnityEngine.TextureFormat.RGB24, false);
tex.ReadPixels(new UnityEngine.Rect(0, 0, w, h), 0, 0); tex.Apply();
UnityEngine.RenderTexture.active = prev; cam.targetTexture = null;
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
return tex;
}
static void L(string s) { sb.AppendLine(s); Flush(); }
static void Flush()
{
System.IO.File.WriteAllText("AgentScripts/WL816r_PLAY2.txt", sb.ToString());
UnityEngine.Debug.Log("[816r play2]\n" + sb.ToString());
}
}