Project_WL/AgentScripts/WL814q_Capture.cs

183 lines
9.3 KiB
C#
Raw Normal View History

// WL-814q — 캡처 4장(+개요) · 1080×1920 · Screenshots_WL/WL814q/
public static class WL814q_Capture
{
const string Out = "Screenshots_WL/WL814q/";
const string ScenePath = "Assets/WL/Look/Arena/Scenes/WL_ArenaProto.unity";
const string DemoPath = "Assets/3DPixelArtEnvironment/Demo/Demo.unity";
const int W = 1080, H = 1920;
static UnityEngine.Texture2D Shot(UnityEngine.Camera cam, int w, int h)
{
var rt = new UnityEngine.RenderTexture(w, h, 24, UnityEngine.RenderTextureFormat.ARGB32,
UnityEngine.RenderTextureReadWrite.sRGB);
rt.filterMode = UnityEngine.FilterMode.Point;
rt.antiAliasing = 1;
rt.Create();
var prev = cam.targetTexture;
cam.targetTexture = rt;
cam.Render();
var oldActive = 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 = oldActive;
cam.targetTexture = prev;
rt.Release();
UnityEngine.Object.DestroyImmediate(rt);
return tex;
}
/// <summary>점(Point) 확대 — 도트 격자를 그대로 키운다.</summary>
static UnityEngine.Texture2D Upscale(UnityEngine.Texture2D src, int w, int h)
{
var d = new UnityEngine.Texture2D(w, h, UnityEngine.TextureFormat.RGB24, false);
var sp = src.GetPixels32();
var dp = new UnityEngine.Color32[w * h];
for (int y = 0; y < h; y++)
{
int sy = y * src.height / h; if (sy >= src.height) sy = src.height - 1;
for (int x = 0; x < w; x++)
{
int sx = x * src.width / w; if (sx >= src.width) sx = src.width - 1;
dp[y * w + x] = sp[sy * src.width + sx];
}
}
d.SetPixels32(dp); d.Apply();
return d;
}
static void Save(UnityEngine.Texture2D t, string name)
{
var dir = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), Out);
System.IO.Directory.CreateDirectory(dir);
System.IO.File.WriteAllBytes(System.IO.Path.Combine(dir, name), UnityEngine.ImageConversion.EncodeToPNG(t));
UnityEngine.Object.DestroyImmediate(t);
}
/// <summary>도트A: pixelHeight 240 저해상도 렌더 → 점 확대.</summary>
static UnityEngine.Texture2D DotA(UnityEngine.Camera cam, float orthoSize)
{
bool o = cam.orthographic; float os = cam.orthographicSize;
cam.orthographic = true; cam.orthographicSize = orthoSize;
int ph = 240, pw = UnityEngine.Mathf.RoundToInt(240f * W / H); // 135×240
var small = Shot(cam, pw, ph);
var big = Upscale(small, W, H);
UnityEngine.Object.DestroyImmediate(small);
cam.orthographic = o; cam.orthographicSize = os;
return big;
}
static UnityEngine.Texture2D SideBySide(UnityEngine.Texture2D a, UnityEngine.Texture2D b, int gap)
{
int w = a.width + gap + b.width, h = UnityEngine.Mathf.Max(a.height, b.height);
var d = 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(18, 18, 22, 255);
d.SetPixels32(px); d.Apply();
UnityEngine.Graphics.CopyTexture(a, 0, 0, 0, 0, a.width, a.height, d, 0, 0, 0, 0);
UnityEngine.Graphics.CopyTexture(b, 0, 0, 0, 0, b.width, b.height, d, 0, 0, a.width + gap, 0);
return d;
}
public static string Run()
{
var sb = new System.Text.StringBuilder();
var scene = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(ScenePath,
UnityEditor.SceneManagement.OpenSceneMode.Single);
// 🔴 Water_Plane 프리팹의 PlanarReflectionProbe 도 Camera 다 — 이름으로 고른다
UnityEngine.Camera cam = null;
foreach (var c in UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(
UnityEngine.FindObjectsSortMode.None))
if (c.gameObject.name == "Main Camera") cam = c;
if (cam == null) return "NO CAMERA";
var camPos = cam.transform.position;
var camRot = cam.transform.rotation;
// ⓐ 일반 모드 — 같은 위치·각도 · 퍼스펙티브 · 풀해상도(도트 없음)
cam.orthographic = false;
// 주시점까지 거리에서 세로 화각이 ortho 3.4 와 같아지도록 FOV 를 맞춘다(같은 구도 유지)
float dist = UnityEngine.Vector3.Distance(camPos, new UnityEngine.Vector3(0f, 1.06f, 0f));
cam.fieldOfView = 2f * UnityEngine.Mathf.Atan2(3.4f, dist) * UnityEngine.Mathf.Rad2Deg;
var a = Shot(cam, W, H);
Save(a, "a_normal_1080x1920.png");
sb.AppendLine("a_normal: perspective fov=" + cam.fieldOfView.ToString("F2") + " dist=" + dist.ToString("F3"));
cam.orthographic = true; cam.orthographicSize = 3.4f;
// ⓑ 도트A — 같은 구도 · orthoSize 3.4 · pixelHeight 240
Save(DotA(cam, 3.4f), "b_dotA_1080x1920.png");
sb.AppendLine("b_dotA: ortho 3.4 · 135x240 -> point x8");
// ⓒ 캐릭터가 보이는 눈높이 구도(도트A) — 더 가깝고 낮게
cam.transform.position = new UnityEngine.Vector3(0f, 1.15f, 0f)
+ UnityEngine.Quaternion.Euler(0f, 205f, 0f) * new UnityEngine.Vector3(0f, 0f, -4.2f)
+ UnityEngine.Vector3.up * 0.55f;
cam.transform.LookAt(new UnityEngine.Vector3(0f, 0.75f, 0f));
Save(DotA(cam, 2.0f), "c_dotA_eye_1080x1920.png");
sb.AppendLine("c_dotA_eye: ortho 2.0 · 135x240 -> point x8 · pos=" + cam.transform.position);
// 개요(참고) — 아레나 전체 + 연못 + 풍차 (퍼스펙티브 3/4 뷰)
cam.orthographic = false;
cam.fieldOfView = 40f;
cam.transform.position = new UnityEngine.Vector3(30f, 20f, -33f);
cam.transform.LookAt(new UnityEngine.Vector3(1f, 1.5f, -1f));
Save(Shot(cam, W, H), "e_overview_1080x1920.png");
sb.AppendLine("e_overview: perspective fov40 @" + cam.transform.position);
cam.orthographic = true; cam.orthographicSize = 3.4f;
// ⓓ 비교용 — 새 아레나(도트A) 렌더를 먼저 잡아 둔다
cam.transform.position = camPos; cam.transform.rotation = camRot;
cam.orthographic = true; cam.orthographicSize = 3.4f;
var mine = DotA(cam, 3.4f);
var mineHalf = Upscale(mine, W / 2, H / 2);
UnityEngine.Object.DestroyImmediate(mine);
// 텍스처를 씬 전환에서 지키기
mineHalf.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
// 데모 씬 — 같은 규격(도트A)으로. 🔴 저장하지 않는다.
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(DemoPath,
UnityEditor.SceneManagement.OpenSceneMode.Single);
UnityEngine.Camera demoCam = null;
foreach (var c in UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(
UnityEngine.FindObjectsSortMode.None))
if (c.gameObject.name == "Main Camera") demoCam = c;
UnityEngine.Texture2D demoHalf = null;
if (demoCam != null)
{
// 데모의 마을 중심(House 2채 + Light_Post 일대)을 우리와 같은 내림각 43.61°·도트A 규격으로
var dt = UnityEngine.Object.FindFirstObjectByType<UnityEngine.Terrain>();
var fxz = new UnityEngine.Vector3(94f, 0f, 78f);
float fy = dt != null ? dt.SampleHeight(fxz) + dt.transform.position.y : 4f;
var focus = new UnityEngine.Vector3(fxz.x, fy, fxz.z);
float camUp = 5.4335f, camHoriz = 4.5911f;
float yaw = 215f;
var dir = new UnityEngine.Vector3(UnityEngine.Mathf.Sin(yaw * UnityEngine.Mathf.Deg2Rad), 0f,
UnityEngine.Mathf.Cos(yaw * UnityEngine.Mathf.Deg2Rad));
demoCam.transform.position = focus + UnityEngine.Vector3.up * camUp - dir * camHoriz;
demoCam.transform.LookAt(focus + UnityEngine.Vector3.up * 1.06f);
demoCam.orthographic = true; demoCam.orthographicSize = 3.4f;
var d = DotA(demoCam, 3.4f);
demoHalf = Upscale(d, W / 2, H / 2);
demoHalf.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
UnityEngine.Object.DestroyImmediate(d);
sb.AppendLine("demo shot ok @" + demoCam.transform.position);
}
else sb.AppendLine("DEMO CAMERA NOT FOUND");
if (demoHalf != null)
{
var cmp = SideBySide(demoHalf, mineHalf, 16);
Save(cmp, "d_compare_demo_vs_arena.png");
sb.AppendLine("d_compare: left=Critter Demo · right=WL_ArenaProto (both dotA 240p)");
UnityEngine.Object.DestroyImmediate(demoHalf);
}
UnityEngine.Object.DestroyImmediate(mineHalf);
// 🔴 데모 씬은 저장하지 않고 원래 씬으로 되돌린다
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(ScenePath,
UnityEditor.SceneManagement.OpenSceneMode.Single);
sb.AppendLine("OUT " + System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), Out));
return sb.ToString();
}
}