140 lines
7.6 KiB
C#
140 lines
7.6 KiB
C#
// WL-816e 캡처 — 데모 씬(에디트 모드에서 풀 인스턴싱을 직접 그려서) vs 우리 섬 · 좌우 비교 합성
|
|
// 🔴 데모 씬은 **Play 하지 않는다**(CLAUDE.md §9 상시 제약). 인스턴싱을 스크립트로 직접 발행해 렌더만 한다.
|
|
public static class WL816e_Cap
|
|
{
|
|
const string Dir = "Screenshots_WL/WL816e/";
|
|
const int W = 1080, H = 1920;
|
|
|
|
// ── 데모 씬을 에디트 모드에서 「풀까지 보이게」 렌더 ────────────────
|
|
public static void Demo()
|
|
{
|
|
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
|
|
"Assets/3DPixelArtEnvironment/Demo/Demo.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
|
|
|
|
var cam = DemoAngleCam();
|
|
var sb = new System.Text.StringBuilder();
|
|
int n = DrawInstancing(sb);
|
|
Shot(cam, Dir + "x_demo_demoangle.png", sb);
|
|
var mainCam = FindMainCam();
|
|
int n2 = DrawInstancing(sb);
|
|
Shot(mainCam, Dir + "x_demo_main.png", sb);
|
|
sb.AppendLine("데모 인스턴싱 구성 " + n + "/" + n2);
|
|
UnityEngine.Debug.Log("[WL816e Cap Demo]\n" + sb.ToString());
|
|
}
|
|
|
|
/// <summary>씬의 InstancesBehaviour 들이 그릴 것을 이번 프레임에 직접 발행한다(Play 없이).</summary>
|
|
static int DrawInstancing(System.Text.StringBuilder sb)
|
|
{
|
|
int n = 0;
|
|
var bs = UnityEngine.Object.FindObjectsByType<Environment.Instancing.InstancesBehaviour>(
|
|
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
|
long inst = 0;
|
|
for (int i = 0; i < bs.Length; i++)
|
|
{
|
|
var b = bs[i];
|
|
System.Collections.Generic.Dictionary<Environment.Instancing.InstancingSettings,
|
|
System.Collections.Generic.List<Environment.Instancing.InstanceData>> data = null;
|
|
try { data = b.GetInstanceData(); } catch { continue; }
|
|
if (data == null) continue;
|
|
var bounds = b.CalculateInstancesBounds();
|
|
var l2w = b.transform.localToWorldMatrix;
|
|
l2w.m03 = 0; l2w.m13 = 0; l2w.m23 = 0;
|
|
foreach (var kv in data)
|
|
{
|
|
if (kv.Value == null || kv.Value.Count == 0) continue;
|
|
var cfg = new Environment.Instancing.InstancingConfiguration(kv.Key, kv.Value, "_InstanceData");
|
|
cfg.MaterialPropertyBlock.SetMatrix("_LocalToWorld", l2w);
|
|
UnityEngine.Graphics.DrawMeshInstancedIndirect(cfg.Mesh, 0, cfg.Material, bounds, cfg.CommandBuffer, 0,
|
|
cfg.MaterialPropertyBlock, UnityEngine.Rendering.ShadowCastingMode.Off, false, 0);
|
|
n++; inst += kv.Value.Count;
|
|
s_pending.Add(cfg);
|
|
}
|
|
}
|
|
sb.AppendLine(" 데모 인스턴스 총 " + inst + " (구성 " + n + ")");
|
|
return n;
|
|
}
|
|
|
|
static readonly System.Collections.Generic.List<Environment.Instancing.InstancingConfiguration> s_pending
|
|
= new System.Collections.Generic.List<Environment.Instancing.InstancingConfiguration>();
|
|
|
|
static void FreePending()
|
|
{
|
|
for (int i = 0; i < s_pending.Count; i++) s_pending[i].FreeMemory();
|
|
s_pending.Clear();
|
|
}
|
|
|
|
static UnityEngine.Camera FindMainCam()
|
|
{
|
|
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 == "Main Camera" || cams[i].CompareTag("MainCamera")) return cams[i];
|
|
return cams.Length > 0 ? cams[0] : null;
|
|
}
|
|
|
|
static UnityEngine.Camera DemoAngleCam()
|
|
{
|
|
var go = UnityEngine.GameObject.Find("__WL816eDemoAngle");
|
|
if (go == null) { go = new UnityEngine.GameObject("__WL816eDemoAngle"); 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);
|
|
c.depth = -100f;
|
|
var rot = UnityEngine.Quaternion.Euler(30f, 60f, 0f);
|
|
go.transform.rotation = rot;
|
|
// 데모는 지형 중앙(약 130, 5, 90) 근처가 풀밭이다
|
|
go.transform.position = new UnityEngine.Vector3(130f, 5.3f, 90f) - rot * UnityEngine.Vector3.forward * 60f;
|
|
if (go.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() == null)
|
|
go.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
|
return c;
|
|
}
|
|
|
|
static void Shot(UnityEngine.Camera cam, string path, System.Text.StringBuilder sb)
|
|
{
|
|
if (cam == null) { sb.AppendLine(" 카메라 없음 " + path); return; }
|
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
|
|
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
|
rt.antiAliasing = 1; rt.Create();
|
|
var prevT = cam.targetTexture; var prevA = 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();
|
|
System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex));
|
|
UnityEngine.RenderTexture.active = prevA; cam.targetTexture = prevT;
|
|
UnityEngine.Object.DestroyImmediate(tex);
|
|
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
|
|
FreePending();
|
|
sb.AppendLine(" 캡처 " + path);
|
|
}
|
|
|
|
// ── 좌우 합성 ──────────────────────────────────────────────────────
|
|
public static void Compose()
|
|
{
|
|
Side(Dir + "a_play_main.png", Dir + "b_play_main.png", Dir + "c_side_by_side.png");
|
|
Side(Dir + "x_demo_demoangle.png", Dir + "b_play_demoangle.png", Dir + "d_demo_vs_island.png");
|
|
UnityEngine.Debug.Log("[WL816e Cap Compose] c_side_by_side.png(좌 지금/우 풀밭) · d_demo_vs_island.png(좌 데모/우 섬)");
|
|
}
|
|
|
|
public static void Side(string left, string right, string outPath)
|
|
{
|
|
if (!System.IO.File.Exists(left) || !System.IO.File.Exists(right)) { UnityEngine.Debug.Log("합성 건너뜀 " + outPath); return; }
|
|
var a = new UnityEngine.Texture2D(2, 2); UnityEngine.ImageConversion.LoadImage(a, System.IO.File.ReadAllBytes(left));
|
|
var b = new UnityEngine.Texture2D(2, 2); UnityEngine.ImageConversion.LoadImage(b, System.IO.File.ReadAllBytes(right));
|
|
int h = UnityEngine.Mathf.Max(a.height, b.height);
|
|
int w = a.width + b.width + 8;
|
|
var o = new UnityEngine.Texture2D(w, h, UnityEngine.TextureFormat.RGB24, false);
|
|
var fill = new UnityEngine.Color[w * h];
|
|
for (int i = 0; i < fill.Length; i++) fill[i] = UnityEngine.Color.black;
|
|
o.SetPixels(fill);
|
|
o.SetPixels(0, h - a.height, a.width, a.height, a.GetPixels());
|
|
o.SetPixels(a.width + 8, h - b.height, 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);
|
|
}
|
|
}
|