180 lines
11 KiB
C#
180 lines
11 KiB
C#
|
|
// WL-816a 캡처 — ⓐ원본 ⓑ통일 ⓒ좌우 ⓓ데모와 나란히 ⓔ텍스처 vs 단색 + 수치
|
||
|
|
// 전부 에디트 모드 오프스크린 렌더(UI 캔버스가 안 끼어든다) · 씬은 저장하지 않는다.
|
||
|
|
public static class WL816a_Cap
|
||
|
|
{
|
||
|
|
const string Dir = "Screenshots_WL/WL816a/";
|
||
|
|
const string Farm = "Assets/WL/Look/Farm/Scenes/WL_FarmLook.unity";
|
||
|
|
const string Orig = "Assets/FarmingIsland/Scenes/Level01.unity";
|
||
|
|
const string Demo = "Assets/3DPixelArtEnvironment/Demo/Demo.unity";
|
||
|
|
const int W = 1080, H = 1920;
|
||
|
|
|
||
|
|
public static void Run()
|
||
|
|
{
|
||
|
|
var sb = new System.Text.StringBuilder();
|
||
|
|
|
||
|
|
// ── ⓐ 원본 Level01 (저장 안 함) ──────────────────────────────────
|
||
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(Orig, UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||
|
|
Shot(FindCam("MainCamera"), Dir + "a_orig_level01.png");
|
||
|
|
Shot(DemoAngleCam(), Dir + "a_orig_demoangle.png");
|
||
|
|
Stats("원본 Level01", sb);
|
||
|
|
|
||
|
|
// ── ⓑ 통일본(텍스처 유지) ────────────────────────────────────────
|
||
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(Farm, UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||
|
|
Shot(FindCam("MainCamera"), Dir + "b_unified_tex.png");
|
||
|
|
Shot(DemoAngleCam(), Dir + "b_unified_tex_demoangle.png");
|
||
|
|
Stats("통일본(텍스처 유지)", sb);
|
||
|
|
|
||
|
|
// ── ⓔ 단색안 ─────────────────────────────────────────────────────
|
||
|
|
var comp = UnityEngine.Object.FindFirstObjectByType<WL.Look.Farm.WLFarmLook>(UnityEngine.FindObjectsInactive.Include);
|
||
|
|
if (comp != null) comp.Apply(2, 1);
|
||
|
|
Shot(FindCam("MainCamera"), Dir + "e_unified_flat.png");
|
||
|
|
Shot(DemoAngleCam(), Dir + "e_unified_flat_demoangle.png");
|
||
|
|
Stats("통일본(단색)", sb);
|
||
|
|
|
||
|
|
// ── 되돌리기 검증: enabled_=0 (원본 머티리얼 + 원본 조명) ─────────
|
||
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(Farm, UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||
|
|
comp = UnityEngine.Object.FindFirstObjectByType<WL.Look.Farm.WLFarmLook>(UnityEngine.FindObjectsInactive.Include);
|
||
|
|
if (comp != null) comp.Apply(0, 0);
|
||
|
|
Shot(FindCam("MainCamera"), Dir + "z_rollback_off.png");
|
||
|
|
Stats("되돌리기(enabled_=0)", sb);
|
||
|
|
|
||
|
|
// 씬을 디스크에서 다시 읽어 변경을 버린다(저장 금지)
|
||
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(Farm, UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||
|
|
|
||
|
|
// ── 데모 ─────────────────────────────────────────────────────────
|
||
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(Demo, UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||
|
|
Shot(FindCam("Main Camera"), Dir + "x_demo.png");
|
||
|
|
Stats("데모 Demo.unity", sb);
|
||
|
|
|
||
|
|
// ── 합성 ─────────────────────────────────────────────────────────
|
||
|
|
Side(Dir + "c_side_by_side.png", Dir + "a_orig_level01.png", Dir + "b_unified_tex.png");
|
||
|
|
Side(Dir + "d_demo_vs_unified.png", Dir + "x_demo.png", Dir + "b_unified_tex_demoangle.png");
|
||
|
|
Side(Dir + "e_tex_vs_flat.png", Dir + "b_unified_tex.png", Dir + "e_unified_flat.png");
|
||
|
|
Side(Dir + "z_rollback_vs_orig.png", Dir + "a_orig_level01.png", Dir + "z_rollback_off.png");
|
||
|
|
|
||
|
|
// ── 화면 고유색 수 ───────────────────────────────────────────────
|
||
|
|
sb.AppendLine("── 화면 고유색 수(1080x1920 · RGB24) ──");
|
||
|
|
string[] files = { "a_orig_level01.png", "b_unified_tex.png", "e_unified_flat.png", "x_demo.png",
|
||
|
|
"a_orig_demoangle.png", "b_unified_tex_demoangle.png", "z_rollback_off.png" };
|
||
|
|
for (int i = 0; i < files.Length; i++)
|
||
|
|
sb.AppendLine(string.Format(" {0,-32} {1,8:N0}", files[i], UniqueColors(Dir + files[i])));
|
||
|
|
UnityEngine.Debug.Log("[WL816a Cap]\n" + sb.ToString());
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── 데모와 같은 카메라 설정(직교 10 · euler 30,60,0)로 섬 중앙을 본다 ──
|
||
|
|
static UnityEngine.Camera DemoAngleCam()
|
||
|
|
{
|
||
|
|
var go = UnityEngine.GameObject.Find("__WL816aDemoAngle");
|
||
|
|
if (go == null) { go = new UnityEngine.GameObject("__WL816aDemoAngle"); go.hideFlags = UnityEngine.HideFlags.DontSave; }
|
||
|
|
var c = go.GetComponent<UnityEngine.Camera>();
|
||
|
|
if (c == null) c = go.AddComponent<UnityEngine.Camera>();
|
||
|
|
c.orthographic = true; c.orthographicSize = 10f;
|
||
|
|
c.nearClipPlane = 0.3f; c.farClipPlane = 500f;
|
||
|
|
c.clearFlags = UnityEngine.CameraClearFlags.Skybox;
|
||
|
|
c.backgroundColor = new UnityEngine.Color(0.192f, 0.302f, 0.475f, 0f);
|
||
|
|
var rot = UnityEngine.Quaternion.Euler(30f, 60f, 0f);
|
||
|
|
go.transform.rotation = rot;
|
||
|
|
go.transform.position = new UnityEngine.Vector3(0f, 0.6f, 0f) - rot * UnityEngine.Vector3.forward * 60f;
|
||
|
|
if (go.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() == null)
|
||
|
|
go.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
||
|
|
return c;
|
||
|
|
}
|
||
|
|
|
||
|
|
static UnityEngine.Camera FindCam(string name)
|
||
|
|
{
|
||
|
|
var cams = UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(
|
||
|
|
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||
|
|
for (int i = 0; i < cams.Length; i++) if (cams[i].name == name) return cams[i];
|
||
|
|
return cams.Length > 0 ? cams[0] : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void Shot(UnityEngine.Camera cam, string path)
|
||
|
|
{
|
||
|
|
if (cam == null) { UnityEngine.Debug.Log("[WL816a] 카메라 없음 " + path); return; }
|
||
|
|
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
||
|
|
rt.antiAliasing = 1;
|
||
|
|
var pT = cam.targetTexture; var pA = UnityEngine.RenderTexture.active;
|
||
|
|
cam.targetTexture = rt; cam.Render();
|
||
|
|
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 = pA; cam.targetTexture = pT;
|
||
|
|
var dir = System.IO.Path.GetDirectoryName(path);
|
||
|
|
if (!System.IO.Directory.Exists(dir)) System.IO.Directory.CreateDirectory(dir);
|
||
|
|
System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex));
|
||
|
|
UnityEngine.Object.DestroyImmediate(tex); UnityEngine.Object.DestroyImmediate(rt);
|
||
|
|
}
|
||
|
|
|
||
|
|
static UnityEngine.Texture2D Load(string path)
|
||
|
|
{
|
||
|
|
if (!System.IO.File.Exists(path)) return null;
|
||
|
|
var t = new UnityEngine.Texture2D(2, 2, UnityEngine.TextureFormat.RGB24, false, false);
|
||
|
|
return UnityEngine.ImageConversion.LoadImage(t, System.IO.File.ReadAllBytes(path)) ? t : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void Side(string outPath, string leftPath, string rightPath)
|
||
|
|
{
|
||
|
|
var a = Load(leftPath); var b = Load(rightPath);
|
||
|
|
if (a == null || b == null) { UnityEngine.Debug.Log("[WL816a] 합성 실패 " + outPath); return; }
|
||
|
|
int w = a.width + b.width, h = UnityEngine.Mathf.Max(a.height, b.height);
|
||
|
|
var o = new UnityEngine.Texture2D(w, h, UnityEngine.TextureFormat.RGB24, false);
|
||
|
|
var px = new UnityEngine.Color32[w * h];
|
||
|
|
for (int i = 0; i < px.Length; i++) px[i] = new UnityEngine.Color32(20, 20, 20, 255);
|
||
|
|
o.SetPixels32(px);
|
||
|
|
o.SetPixels(0, 0, a.width, a.height, a.GetPixels());
|
||
|
|
o.SetPixels(a.width, 0, b.width, b.height, b.GetPixels());
|
||
|
|
o.Apply();
|
||
|
|
System.IO.File.WriteAllBytes(outPath, UnityEngine.ImageConversion.EncodeToPNG(o));
|
||
|
|
UnityEngine.Object.DestroyImmediate(a); UnityEngine.Object.DestroyImmediate(b); UnityEngine.Object.DestroyImmediate(o);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int UniqueColors(string path)
|
||
|
|
{
|
||
|
|
var t = Load(path);
|
||
|
|
if (t == null) return -1;
|
||
|
|
var px = t.GetPixels32();
|
||
|
|
var set = new System.Collections.Generic.HashSet<int>();
|
||
|
|
for (int i = 0; i < px.Length; i++) set.Add((px[i].r << 16) | (px[i].g << 8) | px[i].b);
|
||
|
|
UnityEngine.Object.DestroyImmediate(t);
|
||
|
|
return set.Count;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void Stats(string label, System.Text.StringBuilder sb)
|
||
|
|
{
|
||
|
|
var rends = UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(
|
||
|
|
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||
|
|
var mats = new System.Collections.Generic.HashSet<UnityEngine.Material>();
|
||
|
|
var shaders = new System.Collections.Generic.Dictionary<string, int>();
|
||
|
|
long tris = 0; int slots = 0; int texMats = 0;
|
||
|
|
for (int i = 0; i < rends.Length; i++)
|
||
|
|
{
|
||
|
|
var r = rends[i];
|
||
|
|
if (r is UnityEngine.ParticleSystemRenderer) continue;
|
||
|
|
UnityEngine.Mesh mesh = null;
|
||
|
|
var mf = r.GetComponent<UnityEngine.MeshFilter>(); if (mf != null) mesh = mf.sharedMesh;
|
||
|
|
var sk = r as UnityEngine.SkinnedMeshRenderer; if (sk != null) mesh = sk.sharedMesh;
|
||
|
|
if (mesh != null) for (int s = 0; s < mesh.subMeshCount; s++) tris += mesh.GetIndexCount(s) / 3;
|
||
|
|
var ms = r.sharedMaterials;
|
||
|
|
for (int m = 0; m < ms.Length; m++)
|
||
|
|
{
|
||
|
|
if (ms[m] == null) continue;
|
||
|
|
slots++; mats.Add(ms[m]);
|
||
|
|
string sn = ms[m].shader != null ? ms[m].shader.name : "?";
|
||
|
|
int c; shaders.TryGetValue(sn, out c); shaders[sn] = c + 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
foreach (var m in mats)
|
||
|
|
if ((m.HasProperty("_BaseMap") && m.GetTexture("_BaseMap") != null) ||
|
||
|
|
(m.HasProperty("_MainTex") && m.GetTexture("_MainTex") != null)) texMats++;
|
||
|
|
var shs = new System.Text.StringBuilder();
|
||
|
|
foreach (var kv in shaders) shs.Append(kv.Key + " x" + kv.Value + " · ");
|
||
|
|
sb.AppendLine(string.Format("[{0}] 렌더러 {1} · 슬롯 {2} · 고유 머티리얼 {3}(텍스처 사용 {4}) · 삼각형 {5:N0}",
|
||
|
|
label, rends.Length, slots, mats.Count, texMats, tris));
|
||
|
|
sb.AppendLine(" 셰이더: " + shs.ToString());
|
||
|
|
sb.AppendLine(string.Format(" ambient={0} {1} · skybox={2} · 라이트 {3}",
|
||
|
|
UnityEngine.RenderSettings.ambientMode, UnityEngine.RenderSettings.ambientSkyColor,
|
||
|
|
UnityEngine.RenderSettings.skybox != null ? UnityEngine.RenderSettings.skybox.name : "없음",
|
||
|
|
UnityEngine.Object.FindObjectsByType<UnityEngine.Light>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None).Length));
|
||
|
|
}
|
||
|
|
}
|