Project_WL/AgentScripts/WL816q_Iter.cs

141 lines
7.3 KiB
C#
Raw Permalink Normal View History

// WL-816q 회차 — 풀이 「띠 안쪽에서 바닥과 같은 픽셀」이 되도록 풀 색을 수렴시킨다.
// 바닥만 찍은 기준 이미지와 같은 자리를 비교해 채널별 배율을 뉴턴식으로 갱신.
// 에셋 무변경(런타임 복제본만).
public static class WL816q_Iter
{
public static void Start()
{
var go = UnityEngine.GameObject.Find("~WL816qIter");
if (go != null) UnityEngine.Object.DestroyImmediate(go);
go = new UnityEngine.GameObject("~WL816qIter");
go.AddComponent<WL816q_IterRunner>();
}
}
public class WL816q_IterRunner : UnityEngine.MonoBehaviour
{
static System.Text.StringBuilder sb;
const int TS = 768;
static string Dir = "Screenshots_WL/WL816q";
void Start() { StartCoroutine(Co()); }
System.Collections.IEnumerator Co()
{
sb = new System.Text.StringBuilder();
System.IO.Directory.CreateDirectory(Dir);
if (UnityEngine.SceneManagement.SceneManager.sceneCount < 2)
{
var op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Level01", UnityEngine.SceneManagement.LoadSceneMode.Additive);
while (op != null && !op.isDone) yield return null;
}
for (int i = 0; i < 5; i++) yield return new UnityEngine.WaitForSeconds(1f);
var g = UnityEngine.Object.FindFirstObjectByType<WL.Look.Farm.WLIslandGrass>(UnityEngine.FindObjectsInactive.Include);
if (g == null) { L("WLIslandGrass 없음"); Flush(); yield break; }
var rt = UnityEngine.Object.Instantiate(WL.Look.Farm.WLIslandLookSettings.Instance);
var arr = new WL.Look.Farm.WLScatterDef[rt.scatter.Length];
for (int i = 0; i < arr.Length; i++)
{
var s = rt.scatter[i];
arr[i] = new WL.Look.Farm.WLScatterDef { enabled_ = s.enabled_, label = s.label, mesh = s.mesh, material = s.material,
probability = s.probability, scale = s.scale, normalOffset = s.normalOffset, density = s.density };
}
rt.scatter = arr; g.cfg = rt;
var baseMat = arr[0].material;
var dif0 = baseMat.GetColor("_DiffuseColor");
var shd0 = baseMat.GetColor("_ShadowDiffuseColor");
var clone = new UnityEngine.Material(baseMat); clone.name = baseMat.name + "_iter";
for (int i = 0; i < arr.Length; i++) if (arr[i].material == baseMat) arr[i].material = clone;
var b = g.CalculateInstancesBounds();
var cam = MakeTop(b.center.x, b.center.z, 6f);
// 시간을 멈춘다 — 구름이 흐르면 회차마다 바닥이 달라져 비교가 무효가 된다
float ts = UnityEngine.Time.timeScale;
UnityEngine.Time.timeScale = 0f;
yield return null;
// 기준 = 바닥만
rt.grassEnabled = 0; g.Rebuild(); yield return null; yield return null;
var A = Grab(cam, TS, TS);
System.IO.File.WriteAllBytes(Dir + "/iter_A_ground.png", UnityEngine.ImageConversion.EncodeToPNG(A));
var apx = A.GetPixels32();
rt.grassEnabled = 1;
float kr = 1f, kg = 1f, kb = 1f;
for (int it = 0; it < 5; it++)
{
clone.SetColor("_DiffuseColor", new UnityEngine.Color(dif0.r * kr, dif0.g * kg, dif0.b * kb, dif0.a));
clone.SetColor("_ShadowDiffuseColor", new UnityEngine.Color(shd0.r * kr, shd0.g * kg, shd0.b * kb, shd0.a));
g.Rebuild(); yield return null; yield return null;
var Bt = Grab(cam, TS, TS);
var bpx = Bt.GetPixels32();
double rr, rg, rb; int cov;
Ratio(apx, bpx, out rr, out rg, out rb, out cov);
L(string.Format("회차{0} k=({1:F4},{2:F4},{3:F4}) → 풀/바닥 비=({4:F4},{5:F4},{6:F4}) 덮임={7:F1}% Dif=({8:F3},{9:F3},{10:F3})",
it, kr, kg, kb, rr, rg, rb, cov * 100.0 / (TS * TS), dif0.r * kr, dif0.g * kg, dif0.b * kb));
System.IO.File.WriteAllBytes(Dir + "/iter_" + it + ".png", UnityEngine.ImageConversion.EncodeToPNG(Bt));
UnityEngine.Object.DestroyImmediate(Bt);
if (System.Math.Abs(rr - 1) < 0.004 && System.Math.Abs(rg - 1) < 0.004 && System.Math.Abs(rb - 1) < 0.004) { L("수렴"); break; }
kr = (float)UnityEngine.Mathf.Clamp((float)(kr / System.Math.Max(0.5, rr)), 0.5f, 2.5f);
kg = (float)UnityEngine.Mathf.Clamp((float)(kg / System.Math.Max(0.5, rg)), 0.5f, 2.5f);
kb = (float)UnityEngine.Mathf.Clamp((float)(kb / System.Math.Max(0.5, rb)), 0.5f, 2.5f);
}
L(string.Format("채택 _DiffuseColor = {0:F4} {1:F4} {2:F4}", dif0.r * kr, dif0.g * kg, dif0.b * kb));
L(string.Format("채택 _ShadowDiffuseColor = {0:F4} {1:F4} {2:F4}", shd0.r * kr, shd0.g * kg, shd0.b * kb));
UnityEngine.Object.DestroyImmediate(A);
UnityEngine.Time.timeScale = ts;
Flush();
}
// 바닥만 이미지와 다른 픽셀 = 풀. 그 자리의 바닥색 대비 평균비.
static void Ratio(UnityEngine.Color32[] a, UnityEngine.Color32[] b, out double rr, out double rg, out double rb, out int cov)
{
double sa = 0, sb = 0, sa2 = 0, sb2 = 0, sa3 = 0, sb3 = 0; int n = 0;
for (int i = 0; i < a.Length; i++)
{
var p = a[i]; var q = b[i];
if (!(p.g > p.b + 8 && p.g > 45)) continue; // 초록 지면만
int d = System.Math.Abs(p.r - q.r) + System.Math.Abs(p.g - q.g) + System.Math.Abs(p.b - q.b);
if (d <= 6) continue; // 안 바뀐 = 풀 없음
if (q.g <= q.b + 4) continue; // 꽃(노랑)·자갈 제외
sa += p.r; sb += q.r; sa2 += p.g; sb2 += q.g; sa3 += p.b; sb3 += q.b; n++;
}
cov = n;
rr = n == 0 ? 1 : sb / sa; rg = n == 0 ? 1 : sb2 / sa2; rb = n == 0 ? 1 : sb3 / sa3;
}
static UnityEngine.Camera MakeTop(float cx, float cz, float size)
{
var go = UnityEngine.GameObject.Find("~816qTop");
if (go == null) go = new UnityEngine.GameObject("~816qTop");
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(cx, 60f, cz);
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/WL816q_ITER.txt", sb.ToString());
UnityEngine.Debug.Log("[816q iter]\n" + sb.ToString());
}
}