Project_WL/AgentScripts/WL816n_Play.cs

154 lines
8.2 KiB
C#

// WL-816n — PD 구도(12 m · 45° · fov 60)에서 섬 전/후 캡처 + 화면색·성능 실측.
// 에셋은 건드리지 않는다 (cfg 는 Instantiate 복제본 · 816f 방식).
public static class WL816n_Play
{
public static void Start()
{
var go = UnityEngine.GameObject.Find("~WL816nPlay");
if (go != null) UnityEngine.Object.DestroyImmediate(go);
go = new UnityEngine.GameObject("~WL816nPlay");
go.AddComponent<WL816n_PlayRunner>();
}
}
public class WL816n_PlayRunner : UnityEngine.MonoBehaviour
{
static System.Text.StringBuilder sb;
const int W = 1080, H = 1920;
const string TOP_A = "Assets/WL/Look/Farm/Materials/Farm_IslandTop_Arena.mat";
const string GR_A = "Assets/WL/Look/Farm/Materials/Farm_Grass_Arena.mat";
void Start() { StartCoroutine(Co()); }
System.Collections.IEnumerator Co()
{
sb = new System.Text.StringBuilder();
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 < 7; 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 src = WL.Look.Farm.WLIslandLookSettings.Instance;
var rt = UnityEngine.Object.Instantiate(src); // 에셋 무변경
g.cfg = rt;
var cam = MakeCam();
L("카메라 " + cam.transform.position + " euler=" + cam.transform.eulerAngles + " fov=" + cam.fieldOfView + " (타깃까지 12 m · 45°)");
// ── BEFORE (현재 값: 밀도 1.8 · Demo 머티리얼) ─────────────
g.Rebuild(); yield return null; yield return null;
L(Shot(cam, "a_before", "BEFORE 밀도=" + Dens(rt) + " 풀mat=" + MatName(rt)));
L(" 인스턴스=" + WL.Look.Farm.WLIslandGrass.Instances + " 삼각형=" + WL.Look.Farm.WLIslandGrass.Triangles
+ " 드로우콜+" + WL.Look.Farm.WLIslandGrass.DrawnConfigs + " " + Bench(cam, 60).ToString("F3") + " ms/frame");
// ── AFTER (밀도 2.5 = 데모 FirstLayer 값 · *_Arena 머티리얼) ─
var topA = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(TOP_A);
var graA = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(GR_A);
if (topA == null || graA == null) { L("🔴 *_Arena 머티리얼 없음 — Apply 먼저"); Flush(); yield break; }
for (int i = 0; i < rt.scatter.Length; i++)
if (rt.scatter[i] != null && (rt.scatter[i].label.Contains("풀") || rt.scatter[i].label.Contains("꽃")))
{ rt.scatter[i].density = 2.5f; if (rt.scatter[i].label.Contains("풀")) rt.scatter[i].material = graA; }
var topD = rt.islandTopMaterial;
rt.islandTopMaterial = topA;
for (int i = 0; i < rt.materialRemap.Length; i++)
if (rt.materialRemap[i] != null && rt.materialRemap[i].to == topD) rt.materialRemap[i].to = topA;
WL.Look.Farm.WLIslandLook.SwapMaterials(rt, UnityEngine.SceneManagement.SceneManager.GetSceneByName("Level01"));
g.Rebuild();
yield return new UnityEngine.WaitForSeconds(1.5f);
L(Shot(cam, "b_after", "AFTER 밀도=" + Dens(rt) + " 풀mat=" + MatName(rt)));
L(" 인스턴스=" + WL.Look.Farm.WLIslandGrass.Instances + " 삼각형=" + WL.Look.Farm.WLIslandGrass.Triangles
+ " 드로우콜+" + WL.Look.Farm.WLIslandGrass.DrawnConfigs + " " + Bench(cam, 60).ToString("F3") + " ms/frame");
// 구름 띠가 시간에 따라 움직이는가 (같은 카메라 · 3초 간격 두 장의 차이)
var t0 = Grab(cam);
yield return new UnityEngine.WaitForSeconds(3f);
var t1 = Grab(cam);
L("[구름 이동] 3초 간격 두 프레임의 평균 채널차 = " + Diff(t0, t1).ToString("F2") + " (0 이면 정지)");
Flush();
}
// ─────────────────────────────────────────── helpers
static string Dens(WL.Look.Farm.WLIslandLookSettings c)
{ for (int i = 0; i < c.scatter.Length; i++) if (c.scatter[i] != null && c.scatter[i].label.Contains("풀")) return c.scatter[i].density.ToString("F2"); return "?"; }
static string MatName(WL.Look.Farm.WLIslandLookSettings c)
{ for (int i = 0; i < c.scatter.Length; i++) if (c.scatter[i] != null && c.scatter[i].label.Contains("풀")) return c.scatter[i].material ? c.scatter[i].material.name : "-"; return "?"; }
static UnityEngine.Camera MakeCam()
{
UnityEngine.Vector3 tgt = UnityEngine.Vector3.zero;
var pc = UnityEngine.GameObject.FindGameObjectWithTag("Player");
if (pc != null) tgt = pc.transform.position;
var go = new UnityEngine.GameObject("~816nCam");
var c = go.AddComponent<UnityEngine.Camera>();
c.fieldOfView = 60f; c.orthographic = false;
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.enabled = false;
return c;
}
static UnityEngine.Texture2D Grab(UnityEngine.Camera cam)
{
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 float Diff(UnityEngine.Texture2D a, UnityEngine.Texture2D b)
{
var pa = a.GetPixels32(); var pb = b.GetPixels32();
long s = 0; int n = 0;
for (int i = 0; i < pa.Length; i += 7)
{ s += System.Math.Abs(pa[i].r - pb[i].r) + System.Math.Abs(pa[i].g - pb[i].g) + System.Math.Abs(pa[i].b - pb[i].b); n += 3; }
UnityEngine.Object.DestroyImmediate(a); UnityEngine.Object.DestroyImmediate(b);
return n == 0 ? 0f : (float)s / n;
}
static string Shot(UnityEngine.Camera cam, string name, string tag)
{
var tex = Grab(cam);
System.IO.Directory.CreateDirectory("Screenshots_WL/WL816n");
System.IO.File.WriteAllBytes("Screenshots_WL/WL816n/" + name + ".png", UnityEngine.ImageConversion.EncodeToPNG(tex));
// 초록(풀밭) 픽셀 통계 + 풀 실루엣 커버%
var px = tex.GetPixels32();
long r = 0, gg = 0, b = 0; int n = 0;
for (int i = 0; i < px.Length; i++)
{
var p = px[i];
if (p.g > p.b + 12 && p.g > p.r + 8 && p.g > 60) { r += p.r; gg += p.g; b += p.b; n++; }
}
UnityEngine.Object.DestroyImmediate(tex);
if (n == 0) return tag + " : 초록 픽셀 0";
return string.Format("{0} : 풀밭 초록 픽셀 {1} ({2:F1}%) 평균 #{3:X2}{4:X2}{5:X2}", tag, n, 100f * n / px.Length, r / n, gg / n, b / n);
}
static float Bench(UnityEngine.Camera cam, int frames)
{
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
rt.Create(); 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 = null;
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
return (float)sw.Elapsed.TotalMilliseconds / frames;
}
static void L(string s) { sb.AppendLine(s); }
static void Flush()
{
System.IO.File.WriteAllText("AgentScripts/WL816n_PLAY.txt", sb.ToString());
UnityEngine.Debug.Log("[816n play]\n" + sb.ToString());
}
}