[WL-816r] 후속 A/B 실측 — 풀 회귀 없음(816q 12.44% vs 816r 10.69%) · 공정 캡처 재작성 (#816)
- 같은 PD 구도·같은 구름 위상·풀 인스턴스 1155 동일에서 816q(원본 mat/텍스처) vs 816r(Arena2) A/B - 보이는 풀 12.44% -> 10.69% · 에지% 1.65 -> 1.69(노이즈) · HF 1.58 -> 1.43 · 바닥초록 #89B074 -> #89B375 - 원인 후보 전부 실측 기각: 머티리얼 값 차이 0건 · 텍스처 임포트 동일(8x8/RGB24/Point/mip1) · 풀 인스턴스 동일 - 기존 a_demo_vs_island.png 이 서로 다른 프레임(구름 위상)을 나란히 붙여 불공정했던 것 -> 같은 프레임쌍으로 재작성 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
75f1333583
commit
09e067af02
|
|
@ -0,0 +1,217 @@
|
|||
// WL-816r 후속 — 816q 상태(원본 mat/텍스처) vs 816r 상태(Arena2) 를 **같은 조건**에서 A/B.
|
||||
// 지표 = 816q 정의: 보이는 풀 %(풀 ON vs OFF 픽셀 차) · 에지 % · HF · 바닥 초록 화면색.
|
||||
public static class WL816r_Ab
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
var go = UnityEngine.GameObject.Find("~WL816rAb");
|
||||
if (go != null) UnityEngine.Object.DestroyImmediate(go);
|
||||
go = new UnityEngine.GameObject("~WL816rAb");
|
||||
go.AddComponent<WL816r_AbRun>();
|
||||
}
|
||||
}
|
||||
|
||||
public class WL816r_AbRun : UnityEngine.MonoBehaviour
|
||||
{
|
||||
static System.Text.StringBuilder sb;
|
||||
const int W = 1080, H = 1920;
|
||||
static string Dir = "Screenshots_WL/WL816r";
|
||||
|
||||
static int s_instQ, s_instR;
|
||||
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 < 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); // 에셋 무변경 — 런타임 복제본
|
||||
if (rt.scatter != null)
|
||||
{
|
||||
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 matR = src.islandTopMaterial; // 816r (Arena2)
|
||||
var matQ = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(
|
||||
"Assets/WL/Look/Farm/Materials/Farm_IslandTop_Arena.mat"); // 816q (원본)
|
||||
L("816r mat=" + (matR ? matR.name : "-") + " tex=" + TexName(matR) + " | 816q mat=" + (matQ ? matQ.name : "-") + " tex=" + TexName(matQ));
|
||||
if (matQ == null) { L("원본 머티리얼 로드 실패 — 중단"); Flush(); yield break; }
|
||||
L("머티리얼 값 대조 " + Cmp(matQ, matR));
|
||||
|
||||
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 == matR) { topR.Add(r); break; }
|
||||
L("섬윗면 렌더러=" + topR.Count);
|
||||
|
||||
var cam = MakePd();
|
||||
|
||||
// ── A: 816q 상태 ──────────────────────────────────────────────────
|
||||
SwapMat(topR, matR, matQ);
|
||||
yield return null; yield return null;
|
||||
rt.grassEnabled = 1; g.Rebuild(); yield return null; yield return null; yield return null;
|
||||
var qOn = Shot(cam); s_instQ = WL.Look.Farm.WLIslandGrass.Instances;
|
||||
rt.grassEnabled = 0; g.Rebuild(); yield return null; yield return null; yield return null;
|
||||
var qOff = Shot(cam);
|
||||
L("[816q] " + Metrics(qOn, qOff) + " · 풀 인스턴스(ON시)=" + s_instQ);
|
||||
System.IO.File.WriteAllBytes(Dir + "/ab_816q.png", UnityEngine.ImageConversion.EncodeToPNG(ToTex(qOn)));
|
||||
|
||||
// ── B: 816r 상태 ──────────────────────────────────────────────────
|
||||
SwapMat(topR, matQ, matR);
|
||||
yield return null; yield return null;
|
||||
rt.grassEnabled = 1; g.Rebuild(); yield return null; yield return null; yield return null;
|
||||
var rOn = Shot(cam); s_instR = WL.Look.Farm.WLIslandGrass.Instances;
|
||||
rt.grassEnabled = 0; g.Rebuild(); yield return null; yield return null; yield return null;
|
||||
var rOff = Shot(cam);
|
||||
L("[816r] " + Metrics(rOn, rOff) + " · 풀 인스턴스(ON시)=" + s_instR);
|
||||
System.IO.File.WriteAllBytes(Dir + "/ab_816r.png", UnityEngine.ImageConversion.EncodeToPNG(ToTex(rOn)));
|
||||
|
||||
// 풀 다시 켜고 마무리
|
||||
rt.grassEnabled = 1; g.Rebuild();
|
||||
Flush();
|
||||
}
|
||||
|
||||
UnityEngine.Color32[] Shot(UnityEngine.Camera cam)
|
||||
{
|
||||
var tex = Grab(cam, W, H);
|
||||
var px = tex.GetPixels32();
|
||||
UnityEngine.Object.DestroyImmediate(tex);
|
||||
return px;
|
||||
}
|
||||
static UnityEngine.Texture2D ToTex(UnityEngine.Color32[] px)
|
||||
{
|
||||
var t = new UnityEngine.Texture2D(W, H, UnityEngine.TextureFormat.RGB24, false);
|
||||
t.SetPixels32(px); t.Apply();
|
||||
return t;
|
||||
}
|
||||
|
||||
// 816q 지표
|
||||
static bool Ground(UnityEngine.Color32 p) { return p.g > p.b + 8 && p.g > 45; }
|
||||
static float Lum(UnityEngine.Color32 p) { return 0.299f * p.r + 0.587f * p.g + 0.114f * p.b; }
|
||||
|
||||
static string Metrics(UnityEngine.Color32[] on, UnityEngine.Color32[] off)
|
||||
{
|
||||
int gn = 0, vis = 0;
|
||||
long rr = 0, gg = 0, bb = 0; int cn = 0;
|
||||
for (int i = 0; i < off.Length; i++)
|
||||
{
|
||||
if (!Ground(off[i])) continue;
|
||||
gn++;
|
||||
rr += off[i].r; gg += off[i].g; bb += off[i].b; cn++;
|
||||
if (System.Math.Abs(Lum(on[i]) - Lum(off[i])) > 8f) vis++;
|
||||
}
|
||||
// 에지 % (풀 ON · 지면 픽셀)
|
||||
int ed = 0, edn = 0;
|
||||
double hf = 0; int hfn = 0;
|
||||
for (int y = 0; y < H - 1; y++)
|
||||
for (int x = 0; x < W - 1; x++)
|
||||
{
|
||||
int i = y * W + x;
|
||||
if (!Ground(on[i])) continue;
|
||||
edn++;
|
||||
var r0 = on[i + 1]; var d0 = on[i + W];
|
||||
if ((Ground(r0) && System.Math.Abs(Lum(on[i]) - Lum(r0)) > 8) || (Ground(d0) && System.Math.Abs(Lum(on[i]) - Lum(d0)) > 8)) ed++;
|
||||
}
|
||||
// HF = 8×8 블록 내 편차 평균
|
||||
int bs = 8;
|
||||
for (int by = 0; by + bs <= H; by += bs)
|
||||
for (int bx = 0; bx + bs <= W; bx += bs)
|
||||
{
|
||||
double s = 0; int n = 0;
|
||||
for (int y = 0; y < bs; y++) for (int x = 0; x < bs; x++)
|
||||
{ var p = on[(by + y) * W + bx + x]; if (!Ground(p)) continue; s += Lum(p); n++; }
|
||||
if (n < bs * bs / 2) continue;
|
||||
double mean = s / n;
|
||||
for (int y = 0; y < bs; y++) for (int x = 0; x < bs; x++)
|
||||
{ var p = on[(by + y) * W + bx + x]; if (!Ground(p)) continue; hf += System.Math.Abs(Lum(p) - mean); hfn++; }
|
||||
}
|
||||
string col = cn == 0 ? "-" : string.Format("#{0:X2}{1:X2}{2:X2}", rr / cn, gg / cn, bb / cn);
|
||||
return string.Format("지면px(풀off)={0} · 보이는 풀={1:F2}% · 에지%={2:F2} · HF={3:F2} · 바닥초록={4}",
|
||||
gn, gn == 0 ? 0f : 100f * vis / gn, edn == 0 ? 0f : 100f * ed / edn, hfn == 0 ? 0 : hf / hfn, col);
|
||||
}
|
||||
|
||||
static UnityEngine.Material FindMat(string name)
|
||||
{
|
||||
foreach (var m in UnityEngine.Resources.FindObjectsOfTypeAll<UnityEngine.Material>())
|
||||
if (m != null && m.name == name) return m;
|
||||
return null;
|
||||
}
|
||||
static string TexName(UnityEngine.Material m)
|
||||
{
|
||||
if (m == null) return "-";
|
||||
var t = m.GetTexture("_BaseMap");
|
||||
return t ? t.name : "-";
|
||||
}
|
||||
static string Cmp(UnityEngine.Material a, UnityEngine.Material b)
|
||||
{
|
||||
string[] fs = { "_Shades", "_Brightness", "_MinimumDarkness", "_Cloud_Strength", "_Cloud_Density", "_Cloud_Cover", "_Cloud_Change" };
|
||||
string[] cs = { "_DiffuseColor", "_ShadowDiffuseColor" };
|
||||
var s = new System.Text.StringBuilder();
|
||||
int diff = 0;
|
||||
foreach (var f in fs) { float x = a.GetFloat(f), y = b.GetFloat(f); if (UnityEngine.Mathf.Abs(x - y) > 0.0001f) { diff++; s.Append(" " + f + " " + x + "→" + y); } }
|
||||
foreach (var c in cs) { var x = a.GetColor(c); var y = b.GetColor(c); if (x != y) { diff++; s.Append(" " + c + " " + x + "→" + y); } }
|
||||
var ka = string.Join(",", a.shaderKeywords); var kb = string.Join(",", b.shaderKeywords);
|
||||
if (ka != kb) { diff++; s.Append(" kw [" + ka + "]→[" + kb + "]"); }
|
||||
// 텍스처 임포트 성질
|
||||
var ta = a.GetTexture("_BaseMap") as UnityEngine.Texture2D;
|
||||
var tb = b.GetTexture("_BaseMap") as UnityEngine.Texture2D;
|
||||
if (ta != null && tb != null)
|
||||
s.Append(" | tex A " + ta.width + "x" + ta.height + "/" + ta.format + "/" + ta.filterMode + "/mip" + ta.mipmapCount
|
||||
+ " B " + tb.width + "x" + tb.height + "/" + tb.format + "/" + tb.filterMode + "/mip" + tb.mipmapCount);
|
||||
return (diff == 0 ? "값 차이 0" : "차이 " + diff + "건:") + s;
|
||||
}
|
||||
|
||||
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 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("~816rAbPd"); if (go == null) go = new UnityEngine.GameObject("~816rAbPd");
|
||||
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.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_AB.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log("[816r ab]\n" + sb.ToString());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue