[WL-814b] Critter 픽셀 카메라 리그: 직교 저해상도 RT · 원본 카메라 미러 · 인게임 조립/복원 · 룩 캡처 (#814)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
a4043647db
commit
e4d69ead8c
|
|
@ -0,0 +1,78 @@
|
|||
// WL-814b — Assets/3DPixelCamera/URP.unitypackage 해제(BuiltIn 은 절대 건드리지 않는다).
|
||||
// 게임 코드 아님. run_script 전용.
|
||||
public static class WL814b_Import
|
||||
{
|
||||
const string Pkg = "Assets/3DPixelCamera/URP.unitypackage";
|
||||
const string Dir = "Assets/3DPixelCamera/URP";
|
||||
|
||||
/// <summary>1단계 — 스냅샷을 찍고 비동기 임포트를 시작한다.</summary>
|
||||
public static string Run()
|
||||
{
|
||||
if (!System.IO.File.Exists(Pkg)) return "FAIL 패키지 없음: " + Pkg;
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("[WL814b-import] before: URP 폴더 존재=" + System.IO.Directory.Exists(Dir));
|
||||
UnityEditor.AssetDatabase.ImportPackage(Pkg, false); // false = 대화상자 없이 전부
|
||||
sb.AppendLine("[WL814b-import] ImportPackage 호출됨(비동기) — 다음 단계에서 Verify");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>2단계 — 생긴 파일 목록·GUID 를 뱉는다.</summary>
|
||||
public static string Verify()
|
||||
{
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
var sb = new System.Text.StringBuilder();
|
||||
if (!System.IO.Directory.Exists(Dir)) { sb.AppendLine("FAIL URP 폴더 없음"); return sb.ToString(); }
|
||||
|
||||
var files = System.IO.Directory.GetFiles(Dir, "*", System.IO.SearchOption.AllDirectories);
|
||||
System.Array.Sort(files);
|
||||
int n = 0;
|
||||
foreach (var f in files)
|
||||
{
|
||||
var rel = f.Replace('\\', '/');
|
||||
int i = rel.IndexOf("Assets/");
|
||||
if (i >= 0) rel = rel.Substring(i);
|
||||
if (rel.EndsWith(".meta")) { sb.AppendLine(" meta " + rel); continue; }
|
||||
n++;
|
||||
var guid = UnityEditor.AssetDatabase.AssetPathToGUID(rel);
|
||||
var t = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(rel);
|
||||
sb.AppendLine(" ASSET " + rel + " | guid=" + guid + " | type=" + (t == null ? "?" : t.Name)
|
||||
+ " | " + new System.IO.FileInfo(f).Length + " B");
|
||||
}
|
||||
sb.AppendLine("[WL814b-import] 에셋 " + n + "개(+meta) · BuiltIn 해제 0");
|
||||
|
||||
// 프리팹 구조 표
|
||||
var pf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(Dir + "/PixelCameraSystem.prefab");
|
||||
if (pf == null) sb.AppendLine("FAIL PixelCameraSystem.prefab 로드 실패");
|
||||
else { sb.AppendLine("[구조]"); Dump(pf.transform, 0, sb); }
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
static void Dump(UnityEngine.Transform t, int depth, System.Text.StringBuilder sb)
|
||||
{
|
||||
sb.Append(' ', depth * 2).Append("- ").Append(t.name).Append(" layer=").Append(t.gameObject.layer);
|
||||
var comps = t.GetComponents<UnityEngine.Component>();
|
||||
sb.Append(" [");
|
||||
for (int i = 0; i < comps.Length; i++)
|
||||
{
|
||||
if (comps[i] == null) { sb.Append("<missing> "); continue; }
|
||||
sb.Append(comps[i].GetType().Name).Append(' ');
|
||||
}
|
||||
sb.Append("]");
|
||||
var cam = t.GetComponent<UnityEngine.Camera>();
|
||||
if (cam != null)
|
||||
sb.Append(" cam(ortho=").Append(cam.orthographic ? 1 : 0).Append(" size=").Append(cam.orthographicSize)
|
||||
.Append(" depth=").Append(cam.depth).Append(" mask=").Append(cam.cullingMask)
|
||||
.Append(" clear=").Append((int)cam.clearFlags).Append(" near=").Append(cam.nearClipPlane)
|
||||
.Append(" far=").Append(cam.farClipPlane).Append(")");
|
||||
var ucd = t.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
||||
if (ucd != null) sb.Append(" urp(type=").Append(ucd.renderType).Append(" post=").Append(ucd.renderPostProcessing ? 1 : 0).Append(")");
|
||||
var mr = t.GetComponent<UnityEngine.MeshRenderer>();
|
||||
if (mr != null) sb.Append(" mat=").Append(mr.sharedMaterial == null ? "null" : mr.sharedMaterial.name);
|
||||
var lp = t.localPosition; var ls = t.localScale;
|
||||
sb.Append(" lp=(").Append(lp.x.ToString("0.####")).Append(',').Append(lp.y.ToString("0.####")).Append(',').Append(lp.z.ToString("0.####")).Append(')');
|
||||
sb.Append(" ls=(").Append(ls.x.ToString("0.####")).Append(',').Append(ls.y.ToString("0.####")).Append(',').Append(ls.z.ToString("0.####")).Append(')');
|
||||
sb.AppendLine();
|
||||
for (int i = 0; i < t.childCount; i++) Dump(t.GetChild(i), depth + 1, sb);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,637 @@
|
|||
// PD 지시 #814 · 발주서 WL-814b — Critter 픽셀 카메라 리그 검증 프로브 + 룩 캡처
|
||||
// (에디트 모드 전용 · Play 0 · 로그인 0 · 디스크 에셋 무수정)
|
||||
//
|
||||
// 실행 (CLAUDE.md §1: using 금지 · 네임스페이스 풀어 쓰기)
|
||||
// unity command run_script --file AgentScripts/WL814b_Probe.cs --entry WL814b_Probe.MakeAsset --timeout 300
|
||||
// unity command run_script --file AgentScripts/WL814b_Probe.cs --entry WL814b_Probe.Edit --timeout 1800
|
||||
//
|
||||
// 무엇을 재는가
|
||||
// A. 표 ① 보조 — 원본 Main Camera.prefab 값 · NewGameUI 캔버스 렌더 모드/카메라 · UICamera 스택
|
||||
// B. 리그 — 임시 씬(추가 로드 · 저장 0)에 맵 + PC + 잡몹 + 원본 카메라 → 조립 → 구조 표
|
||||
// C. 복원 — 원본 카메라 값 스냅샷 == 복원값(문자열 동일) · 리그 오브젝트 0 · RT 해제
|
||||
// D. 매핑오차 — Camera.main 투영(WorldToViewportPoint) vs 실제 RT→쿼드→뷰 카메라 화면 좌표(5점 · px)
|
||||
// E. GC — 프록시 미러 · 회전 스냅 판정 200k 회 할당 증가분(0 B 목표)
|
||||
// F. C8 — RuntimeDisabled = true → Tick 이 즉시 복원 · 조립 0
|
||||
// G. 캡처 — 1080×1920 4장(ortho 3.8×480 · 3.8×360 · 4.6×480 · 대조 원근 원본)
|
||||
public static class WL814b_Probe
|
||||
{
|
||||
const string kOutDir = @"E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b";
|
||||
const string kMap = "Assets/Res_Addr/Map/WL_Nature.prefab";
|
||||
const string kPc = "Assets/Res_Addr/PC/Ai01.prefab";
|
||||
const string kCam = "Assets/ResWork/Prefabs/Ingame/Main Camera.prefab";
|
||||
const string kRig = "Assets/3DPixelCamera/URP/PixelCameraSystem.prefab";
|
||||
const string kSo = "Assets/WL/Combat/Settings/Resources/WL/WLPixelCameraSettings.asset";
|
||||
const string kSnap = "AgentScripts/staging/WL814b/EDIT_PROBE.txt";
|
||||
|
||||
const int W = 1080, H = 1920;
|
||||
|
||||
static System.Text.StringBuilder sb;
|
||||
static int pass, fail;
|
||||
static UnityEngine.Vector3 s_lookAtWorld;
|
||||
|
||||
static void L(string s) { sb.Append(s).Append('\n'); }
|
||||
static void Chk(bool ok, string label, string detail)
|
||||
{
|
||||
if (ok) pass++; else fail++;
|
||||
sb.Append(ok ? " PASS " : " FAIL ").Append(label);
|
||||
if (!string.IsNullOrEmpty(detail)) sb.Append(" ").Append(detail);
|
||||
sb.Append('\n');
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// SO 에셋 생성 (1회) — 손으로 YAML 쓰지 않고 에디터가 만들게 한다
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
public static string MakeAsset()
|
||||
{
|
||||
sb = new System.Text.StringBuilder();
|
||||
var dir = System.IO.Path.GetDirectoryName(kSo).Replace('\\', '/');
|
||||
if (!System.IO.Directory.Exists(dir)) { L("FAIL 폴더 없음 " + dir); return sb.ToString(); }
|
||||
|
||||
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<WL.PixelArt.WLPixelCameraSettings>(kSo);
|
||||
bool created = false;
|
||||
if (so == null)
|
||||
{
|
||||
so = UnityEngine.ScriptableObject.CreateInstance<WL.PixelArt.WLPixelCameraSettings>();
|
||||
UnityEditor.AssetDatabase.CreateAsset(so, kSo);
|
||||
created = true;
|
||||
}
|
||||
|
||||
var rig = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kRig);
|
||||
so.pixelCameraSystemPrefab = rig;
|
||||
UnityEditor.EditorUtility.SetDirty(so);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
|
||||
L((created ? "생성" : "갱신") + " " + kSo);
|
||||
L(" prefab=" + (rig == null ? "null(패키지 해제 확인)" : UnityEditor.AssetDatabase.GetAssetPath(rig)));
|
||||
L(" guid=" + UnityEditor.AssetDatabase.AssetPathToGUID(kSo));
|
||||
L(" enabled=" + so.enabled + " orthoSize=" + so.orthoSize + " pixelHeight=" + so.pixelHeight
|
||||
+ " rigLayer=" + so.rigLayer + " proxyMode=" + so.proxyMode
|
||||
+ " compensateViewZoom=" + so.compensateViewZoom);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 본 프로브
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
public static string Edit()
|
||||
{
|
||||
sb = new System.Text.StringBuilder();
|
||||
pass = fail = 0;
|
||||
System.IO.Directory.CreateDirectory(kOutDir);
|
||||
|
||||
L("# WL-814b 프로브 — " + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
L("unity=" + UnityEngine.Application.unityVersion + " · isPlaying=" + UnityEngine.Application.isPlaying);
|
||||
|
||||
SectionA();
|
||||
|
||||
// 배치모드 에디터의 현재(무제목·빈) 씬에 직접 짓는다 — 추가 씬 생성은 무제목 씬이 열려 있으면 금지된다.
|
||||
// 모든 인스턴스는 HideAndDontSave + DestroyImmediate 이므로 씬에 남지도, 저장되지도 않는다(811o 방식).
|
||||
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
||||
L("현재 씬 = '" + scene.name + "' path='" + scene.path + "' dirty(before)=" + scene.isDirty
|
||||
+ " rootCount=" + scene.rootCount);
|
||||
|
||||
UnityEngine.GameObject mapGo = null, pcGo = null, camGo = null, lightGo = null;
|
||||
var mobs = new System.Collections.Generic.List<UnityEngine.GameObject>();
|
||||
try
|
||||
{
|
||||
BuildScene(ref mapGo, ref pcGo, ref camGo, ref lightGo, mobs);
|
||||
if (camGo == null) { L("FAIL 카메라 인스턴스 실패 — 중단"); }
|
||||
else
|
||||
{
|
||||
var cam = camGo.GetComponent<UnityEngine.Camera>();
|
||||
SectionBCD(cam, pcGo);
|
||||
SectionE(cam);
|
||||
SectionF(cam);
|
||||
SectionG(cam);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex) { L("EXCEPTION " + ex.GetType().Name + " " + ex.Message); L(ex.StackTrace); fail++; }
|
||||
finally
|
||||
{
|
||||
WL.PixelArt.PixelCameraRig.Teardown("probe end");
|
||||
WL.PixelArt.WLPixelCameraSettings.RuntimeDisabled = false;
|
||||
for (int i = 0; i < mobs.Count; i++) if (mobs[i] != null) UnityEngine.Object.DestroyImmediate(mobs[i]);
|
||||
if (pcGo != null) UnityEngine.Object.DestroyImmediate(pcGo);
|
||||
if (camGo != null) UnityEngine.Object.DestroyImmediate(camGo);
|
||||
if (mapGo != null) UnityEngine.Object.DestroyImmediate(mapGo);
|
||||
if (lightGo != null) UnityEngine.Object.DestroyImmediate(lightGo);
|
||||
var after = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
||||
L("씬 정리 후: dirty=" + after.isDirty + " rootCount=" + after.rootCount + " (저장 0)");
|
||||
}
|
||||
|
||||
L("");
|
||||
L("RESULT " + (fail == 0 ? "PASS" : "FAIL") + " " + pass + "/" + (pass + fail));
|
||||
var outPath = kSnap;
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outPath));
|
||||
System.IO.File.WriteAllText(outPath, sb.ToString(), new System.Text.UTF8Encoding(false));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// ── A. 표 ① 보조 실측 ────────────────────────────────────────────────────
|
||||
static void SectionA()
|
||||
{
|
||||
L("");
|
||||
L("## A. 원본 카메라 · UI 캔버스 실측");
|
||||
var camPf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kCam);
|
||||
if (camPf == null) { L("FAIL Main Camera.prefab 로드 실패"); fail++; return; }
|
||||
var c = camPf.GetComponent<UnityEngine.Camera>();
|
||||
var rc = camPf.GetComponent("RealCamera");
|
||||
var al = camPf.GetComponent<UnityEngine.AudioListener>();
|
||||
var mrv = camPf.GetComponent("MeshRendererVisibility");
|
||||
var ucd = camPf.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
||||
L("Main Camera.prefab: tag=" + camPf.tag + " layer=" + camPf.layer + " parent=" + (camPf.transform.parent == null ? "none" : camPf.transform.parent.name)
|
||||
+ " children=" + camPf.transform.childCount);
|
||||
L(" Camera: ortho=" + c.orthographic + " fov=" + c.fieldOfView + " size=" + c.orthographicSize
|
||||
+ " near=" + c.nearClipPlane + " far=" + c.farClipPlane + " depth=" + c.depth
|
||||
+ " mask=" + c.cullingMask + " clear=" + c.clearFlags + " hdr=" + c.allowHDR + " msaa=" + c.allowMSAA
|
||||
+ " occlusionCulling=" + c.useOcclusionCulling);
|
||||
if (ucd != null)
|
||||
L(" URP: type=" + ucd.renderType + " post=" + ucd.renderPostProcessing + " shadows=" + ucd.renderShadows
|
||||
+ " volumeMask=" + ucd.volumeLayerMask.value + " aa=" + ucd.antialiasing
|
||||
+ " stack=" + (ucd.cameraStack == null ? -1 : ucd.cameraStack.Count));
|
||||
L(" 컴포넌트: RealCamera=" + (rc != null) + " AudioListener=" + (al != null) + " MeshRendererVisibility=" + (mrv != null));
|
||||
Chk(rc != null && al != null, "원본 카메라 = RealCamera + AudioListener 보유(재부모화·비활성 금지 근거)", "");
|
||||
|
||||
var uiPf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>("Assets/Res_Addr/MainUI/NewGameUI.prefab");
|
||||
if (uiPf != null)
|
||||
{
|
||||
var canvases = uiPf.GetComponentsInChildren<UnityEngine.Canvas>(true);
|
||||
L("NewGameUI.prefab 캔버스 " + canvases.Length + "개");
|
||||
for (int i = 0; i < canvases.Length; i++)
|
||||
{
|
||||
var cv = canvases[i];
|
||||
L(" [" + i + "] " + cv.name + " renderMode=" + cv.renderMode
|
||||
+ " worldCamera=" + (cv.worldCamera == null ? "null" : cv.worldCamera.name)
|
||||
+ " planeDistance=" + cv.planeDistance + " sortingOrder=" + cv.sortingOrder + " layer=" + cv.gameObject.layer);
|
||||
}
|
||||
var cams = uiPf.GetComponentsInChildren<UnityEngine.Camera>(true);
|
||||
for (int i = 0; i < cams.Length; i++)
|
||||
L(" UI camera: " + cams[i].name + " ortho=" + cams[i].orthographic + " depth=" + cams[i].depth
|
||||
+ " mask=" + cams[i].cullingMask + " clear=" + cams[i].clearFlags);
|
||||
bool ssc = false;
|
||||
for (int i = 0; i < canvases.Length; i++) if (canvases[i].renderMode == UnityEngine.RenderMode.ScreenSpaceCamera) ssc = true;
|
||||
Chk(ssc, "인게임 UI 캔버스 = Screen Space - Camera(UICamera) → 원본 카메라를 끄면 UI 가 사라진다", "");
|
||||
}
|
||||
else { L("FAIL NewGameUI.prefab 로드 실패"); fail++; }
|
||||
}
|
||||
|
||||
// ── 씬 조립 ──────────────────────────────────────────────────────────────
|
||||
static void BuildScene(ref UnityEngine.GameObject mapGo, ref UnityEngine.GameObject pcGo,
|
||||
ref UnityEngine.GameObject camGo, ref UnityEngine.GameObject lightGo,
|
||||
System.Collections.Generic.List<UnityEngine.GameObject> mobs)
|
||||
{
|
||||
L("");
|
||||
L("## B. 임시 씬(추가 로드 · 저장 0)");
|
||||
|
||||
var mapPf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kMap);
|
||||
if (mapPf != null) { mapGo = UnityEngine.Object.Instantiate(mapPf); mapGo.name = "__WL814b_Map"; mapGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave; }
|
||||
L("맵 " + (mapGo == null ? "실패" : mapGo.name + " renderers=" + mapGo.GetComponentsInChildren<UnityEngine.Renderer>(true).Length));
|
||||
|
||||
// 지면 y 찾기 + 소품이 가장 많은 앵커 고르기(룩 캡처라 배경이 비어 있으면 안 된다)
|
||||
UnityEngine.Physics.SyncTransforms();
|
||||
var rends = mapGo == null ? new UnityEngine.Renderer[0] : mapGo.GetComponentsInChildren<UnityEngine.Renderer>(true);
|
||||
// 소품이 실제로 모여 있는 곳을 찾는다 — 소품 중심들 중 반경 10 m 이웃이 가장 많은 지점
|
||||
var cands = new System.Collections.Generic.List<UnityEngine.Vector3>();
|
||||
for (int r = 0; r < rends.Length; r++)
|
||||
{
|
||||
if (rends[r] == null) continue;
|
||||
var b = rends[r].bounds;
|
||||
if (b.size.y < 1.0f || b.size.y > 20f) continue; // 지형/바닥/거대 오브젝트 제외
|
||||
if (b.center.y > 6f) continue; // 언덕 위·공중 제외
|
||||
cands.Add(b.center);
|
||||
}
|
||||
UnityEngine.Vector3 pcPos = new UnityEngine.Vector3(139f, 0.8f, -20f);
|
||||
int bestCount = -1;
|
||||
for (int i = 0; i < cands.Count; i++)
|
||||
{
|
||||
int n = 0;
|
||||
for (int j = 0; j < cands.Count; j++)
|
||||
if ((cands[j] - cands[i]).sqrMagnitude < 100f) n++; // 반경 10 m
|
||||
if (n > bestCount) { bestCount = n; pcPos = cands[i]; }
|
||||
}
|
||||
string bestHit = "미검출";
|
||||
UnityEngine.RaycastHit gh;
|
||||
if (UnityEngine.Physics.Raycast(new UnityEngine.Vector3(pcPos.x, pcPos.y + 100f, pcPos.z), UnityEngine.Vector3.down, out gh, 400f))
|
||||
{ pcPos.y = gh.point.y; bestHit = gh.collider.name; }
|
||||
L(" 소품 후보 " + cands.Count + "개 · 가장 밀집한 지점 반경 10 m 이웃 " + bestCount + "개");
|
||||
L("PC 위치 " + pcPos.ToString("F2") + " · 반경 10 m 소품 " + bestCount + "개 (지면 " + bestHit + ")");
|
||||
|
||||
var pcPf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kPc);
|
||||
if (pcPf != null)
|
||||
{
|
||||
pcGo = UnityEngine.Object.Instantiate(pcPf);
|
||||
pcGo.name = "__WL814b_PC";
|
||||
pcGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
|
||||
pcGo.transform.position = pcPos;
|
||||
pcGo.transform.rotation = UnityEngine.Quaternion.Euler(0f, 200f, 0f);
|
||||
StripBehaviours(pcGo);
|
||||
L("PC 포즈: " + PoseIdle(pcGo));
|
||||
}
|
||||
L("PC " + (pcGo == null ? "실패" : "ok"));
|
||||
|
||||
// 잡몹 3
|
||||
string[] mobPaths = {
|
||||
"Assets/Res_Addr/Mobs/Mob/Anto_A.prefab",
|
||||
"Assets/Res_Addr/Mobs/Mob/Anto_B.prefab",
|
||||
"Assets/Res_Addr/Mobs/Mob/Angez_A.prefab",
|
||||
};
|
||||
UnityEngine.Vector3[] mobOff = {
|
||||
new UnityEngine.Vector3(2.2f, 0f, 1.6f),
|
||||
new UnityEngine.Vector3(-2.4f, 0f, 0.8f),
|
||||
new UnityEngine.Vector3(0.2f, 0f, 3.0f),
|
||||
};
|
||||
for (int i = 0; i < mobPaths.Length; i++)
|
||||
{
|
||||
var pf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(mobPaths[i]);
|
||||
if (pf == null) continue;
|
||||
var g = UnityEngine.Object.Instantiate(pf);
|
||||
g.name = "__WL814b_Mob" + i;
|
||||
g.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
|
||||
var p = pcPos + mobOff[i];
|
||||
UnityEngine.RaycastHit mh;
|
||||
if (UnityEngine.Physics.Raycast(new UnityEngine.Vector3(p.x, 200f, p.z), UnityEngine.Vector3.down, out mh, 500f)) p.y = mh.point.y;
|
||||
g.transform.position = p;
|
||||
g.transform.rotation = UnityEngine.Quaternion.Euler(0f, 20f + i * 90f, 0f);
|
||||
StripBehaviours(g);
|
||||
PoseIdle(g);
|
||||
mobs.Add(g);
|
||||
}
|
||||
L("잡몹 " + mobs.Count + "체");
|
||||
|
||||
lightGo = new UnityEngine.GameObject("__WL814b_Sun");
|
||||
lightGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
|
||||
var lt = lightGo.AddComponent<UnityEngine.Light>();
|
||||
lt.type = UnityEngine.LightType.Directional;
|
||||
lt.intensity = 1.1f;
|
||||
lt.color = new UnityEngine.Color(1f, 0.97f, 0.92f);
|
||||
lightGo.transform.rotation = UnityEngine.Quaternion.Euler(48f, 35f, 0f);
|
||||
|
||||
// 원본 카메라 인스턴스 — 811o 구도(h 76 · d 3.0 · up 2.4)를 RealCamera 수식으로 직접 계산
|
||||
var camPf = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kCam);
|
||||
if (camPf == null) return;
|
||||
camGo = UnityEngine.Object.Instantiate(camPf);
|
||||
camGo.name = "__WL814b_MainCamera";
|
||||
camGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
|
||||
StripBehaviours(camGo); // RealCamera·MeshRendererVisibility 정지(트랜스폼은 우리가 잡는다)
|
||||
var cam = camGo.GetComponent<UnityEngine.Camera>();
|
||||
cam.aspect = (float)W / H;
|
||||
|
||||
const float camHeight = 76f, rotateAround = 347.21f, distanceAway = 3.0f, distanceUp = 2.4f;
|
||||
var lookAt = new UnityEngine.Vector3(0f, 1.06f, 0f);
|
||||
var rotv = UnityEngine.Quaternion.Euler(camHeight, rotateAround, 0f) * UnityEngine.Vector3.one;
|
||||
var camPosition = pcPos + UnityEngine.Vector3.up * distanceUp - rotv * distanceAway;
|
||||
camGo.transform.position = camPosition;
|
||||
s_lookAtWorld = pcPos + lookAt;
|
||||
camGo.transform.LookAt(s_lookAtWorld);
|
||||
float dist = UnityEngine.Vector3.Distance(camPosition, pcPos + lookAt);
|
||||
L("카메라(811o 구도) pos=" + camPosition.ToString("F3") + " euler=" + camGo.transform.eulerAngles.ToString("F2"));
|
||||
L(" PC 주시점까지 거리 = " + dist.ToString("F3") + " m → 원근 fov 60 의 반높이 = " + (dist * UnityEngine.Mathf.Tan(30f * UnityEngine.Mathf.Deg2Rad)).ToString("F3") + " m");
|
||||
}
|
||||
|
||||
/// <summary>에디트 모드에서는 Animator 가 돌지 않아 T 포즈가 된다 → idle 클립을 1프레임 샘플링한다.</summary>
|
||||
static string PoseIdle(UnityEngine.GameObject go)
|
||||
{
|
||||
var anim = go.GetComponentInChildren<UnityEngine.Animator>(true);
|
||||
if (anim == null || anim.runtimeAnimatorController == null) return "Animator 없음(T 포즈)";
|
||||
var clips = anim.runtimeAnimatorController.animationClips;
|
||||
if (clips == null || clips.Length == 0) return "클립 0(T 포즈)";
|
||||
UnityEngine.AnimationClip pick = null;
|
||||
for (int i = 0; i < clips.Length; i++)
|
||||
{
|
||||
if (clips[i] == null) continue;
|
||||
var n = clips[i].name.ToLower();
|
||||
if (n.Contains("idle") || n.Contains("wait") || n.Contains("stand")) { pick = clips[i]; break; }
|
||||
}
|
||||
if (pick == null) pick = clips[0];
|
||||
pick.SampleAnimation(anim.gameObject, 0.4f);
|
||||
return pick.name + " @0.4s (" + clips.Length + "클립)";
|
||||
}
|
||||
|
||||
/// <summary>임시 씬에서 원본 로직이 돌지 않게 MonoBehaviour 를 전부 끈다(에셋 무변경 · 인스턴스만).</summary>
|
||||
static void StripBehaviours(UnityEngine.GameObject go)
|
||||
{
|
||||
var all = go.GetComponentsInChildren<UnityEngine.MonoBehaviour>(true);
|
||||
for (int i = 0; i < all.Length; i++)
|
||||
{
|
||||
if (all[i] == null) continue;
|
||||
if (all[i] is UnityEngine.Rendering.Universal.UniversalAdditionalCameraData) continue;
|
||||
try { all[i].enabled = false; } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
// ── B/C/D. 조립 · 복원 · 매핑 오차 ──────────────────────────────────────
|
||||
static void SectionBCD(UnityEngine.Camera cam, UnityEngine.GameObject pcGo)
|
||||
{
|
||||
L("");
|
||||
L("## B. 리그 조립");
|
||||
var cfg = MakeCfg(3.8f, 480, false);
|
||||
if (cfg == null) { L("FAIL SO/프리팹 없음 — 중단"); fail++; return; }
|
||||
|
||||
string before = WL.PixelArt.PixelCameraRig.CurrentSummary(cam);
|
||||
int origMask = cam.cullingMask;
|
||||
L("조립 전 원본 카메라: " + before);
|
||||
|
||||
bool ok = WL.PixelArt.PixelCameraRig.Assemble(cfg, cam);
|
||||
Chk(ok && WL.PixelArt.PixelCameraRig.IsAssembled, "조립 성공", WL.PixelArt.PixelCameraRig.LastLog);
|
||||
if (!ok) return;
|
||||
|
||||
var rig = WL.PixelArt.PixelCameraRig.RigRoot;
|
||||
var gameCam = WL.PixelArt.PixelCameraRig.GameCamera;
|
||||
var viewCam = WL.PixelArt.PixelCameraRig.ViewCamera;
|
||||
var mgr = WL.PixelArt.PixelCameraRig.Manager;
|
||||
var proxy = WL.PixelArt.PixelCameraRig.Proxy;
|
||||
|
||||
L("리그 구조:");
|
||||
Dump(rig.transform, 1);
|
||||
L("프록시: " + (proxy == null ? "null" : proxy.name + " parent=" + (proxy.parent == null ? "none" : proxy.parent.name)
|
||||
+ " worldPos=" + proxy.position.ToString("F4") + " camPos=" + cam.transform.position.ToString("F4")));
|
||||
Chk(proxy != null && (proxy.position - cam.transform.position).sqrMagnitude < 1e-8f,
|
||||
"프록시 월드 위치 == 원본 카메라 위치(지연 0)", "");
|
||||
Chk(proxy != null && UnityEngine.Quaternion.Angle(proxy.rotation, cam.transform.rotation) < 1e-3f,
|
||||
"프록시 회전 == 원본 카메라 회전", "");
|
||||
|
||||
string after = WL.PixelArt.PixelCameraRig.CurrentSummary(cam);
|
||||
L("조립 후 원본 카메라: " + after);
|
||||
Chk(cam.orthographic, "원본 카메라 직교 전환", "size=" + cam.orthographicSize);
|
||||
Chk(cam.cullingMask == 0, "원본 카메라 월드 미렌더(cullingMask 0)", "mask=" + cam.cullingMask);
|
||||
Chk(cam.tag == "MainCamera" && cam.enabled, "MainCamera 태그·enabled 유지(Camera.main 보존)", "tag=" + cam.tag);
|
||||
|
||||
// Critter 를 1프레임 강제로 돌린다(에디트 모드에는 LateUpdate 가 안 올 수 있다)
|
||||
viewCam.aspect = (float)W / H;
|
||||
mgr.SendMessage("LateUpdate", UnityEngine.SendMessageOptions.DontRequireReceiver);
|
||||
|
||||
var rt = gameCam.targetTexture;
|
||||
L("게임 카메라: ortho=" + gameCam.orthographic + " size=" + gameCam.orthographicSize.ToString("F4")
|
||||
+ " mask=" + gameCam.cullingMask + " depth=" + gameCam.depth
|
||||
+ " RT=" + (rt == null ? "null" : rt.width + "×" + rt.height + " filter=" + rt.filterMode + " fmt=" + rt.format));
|
||||
L("뷰 카메라: ortho=" + viewCam.orthographic + " size=" + viewCam.orthographicSize.ToString("F4")
|
||||
+ " mask=" + viewCam.cullingMask + " near=" + viewCam.nearClipPlane + " far=" + viewCam.farClipPlane
|
||||
+ " localPos=" + viewCam.transform.localPosition.ToString("F5"));
|
||||
L("Critter: GameResolution=" + mgr.GameResolution + " zoom=" + mgr.GameCameraZoom.ToString("F5")
|
||||
+ " viewZoom=" + mgr.ViewCameraZoom + " grid=" + mgr.VoxelGridMovement + " sub=" + mgr.SubpixelAdjustments
|
||||
+ " followRot=" + mgr.FollowRotation);
|
||||
Chk(rt != null && rt.height == 480 && rt.filterMode == UnityEngine.FilterMode.Point,
|
||||
"저해상도 RT 480줄 · 포인트 필터", rt == null ? "null" : rt.width + "×" + rt.height);
|
||||
Chk(gameCam.cullingMask == (origMask & ~(1 << cfg.rigLayer)),
|
||||
"게임 카메라 = 원본 cullingMask 승계", "orig=" + origMask + " game=" + gameCam.cullingMask);
|
||||
Chk((gameCam.cullingMask & (1 << cfg.rigLayer)) == 0, "게임 카메라가 픽셀 쿼드를 다시 그리지 않는다(리그 레이어 제외)", "");
|
||||
Chk(viewCam.cullingMask == (1 << cfg.rigLayer), "뷰 카메라는 픽셀 쿼드만 그린다", "mask=" + viewCam.cullingMask);
|
||||
|
||||
// ── D. 매핑 오차
|
||||
L("");
|
||||
L("## D. 매핑 오차 — Camera.main 투영 vs 실제 화면(1080×1920 · px)");
|
||||
MappingTable(cam, gameCam, viewCam, mgr, pcGo);
|
||||
|
||||
// ── C. 복원
|
||||
L("");
|
||||
L("## C. 복원");
|
||||
var rtRef = gameCam.targetTexture;
|
||||
WL.PixelArt.PixelCameraRig.Teardown("probe C");
|
||||
string restored = WL.PixelArt.PixelCameraRig.CurrentSummary(cam);
|
||||
L("복원 후 원본 카메라: " + restored);
|
||||
Chk(restored == before, "원본 카메라 값 스냅샷 == 복원값(문자열 완전 일치)", restored == before ? "" : "\n before=" + before + "\n after =" + restored);
|
||||
Chk(!WL.PixelArt.PixelCameraRig.IsAssembled, "리그 오브젝트 0", "");
|
||||
Chk(rtRef == null, "RT 참조 해제(Release + Destroy)", "rt=" + (rtRef == null ? "null" : "alive"));
|
||||
int strays = 0;
|
||||
var left = UnityEngine.Object.FindObjectsByType<PixelCamera.PixelCameraManager>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
|
||||
strays = left == null ? 0 : left.Length;
|
||||
Chk(strays == 0, "씬에 PixelCameraManager 잔재 0", "found=" + strays);
|
||||
int proxyLeft = 0;
|
||||
for (int i = 0; i < cam.transform.childCount; i++) if (cam.transform.GetChild(i).name == WL.PixelArt.PixelCameraRig.ProxyName) proxyLeft++;
|
||||
Chk(proxyLeft == 0, "원본 카메라 자식 프록시 0", "found=" + proxyLeft);
|
||||
|
||||
var mat = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Material>("Assets/3DPixelCamera/URP/UpscaleMaterialURP.mat");
|
||||
bool matClean = mat == null || !mat.HasProperty("_LowResTexture") || mat.GetTexture("_LowResTexture") == null;
|
||||
Chk(matClean, "디스크 UpscaleMaterialURP.mat 의 _LowResTexture 오염 0(런타임 인스턴스 사용)",
|
||||
mat == null ? "mat=null" : ("tex=" + (mat.GetTexture("_LowResTexture") == null ? "null" : mat.GetTexture("_LowResTexture").name)));
|
||||
}
|
||||
|
||||
static void MappingTable(UnityEngine.Camera src, UnityEngine.Camera gameCam, UnityEngine.Camera viewCam,
|
||||
PixelCamera.PixelCameraManager mgr, UnityEngine.GameObject pcGo)
|
||||
{
|
||||
var quad = FindQuad();
|
||||
if (quad == null) { L("FAIL 픽셀 쿼드를 못 찾음"); fail++; return; }
|
||||
var rt = gameCam.targetTexture;
|
||||
if (rt == null) { L("FAIL RT 없음"); fail++; return; }
|
||||
|
||||
var basePos = pcGo != null ? pcGo.transform.position : src.transform.position + src.transform.forward * 6f;
|
||||
var pts = new UnityEngine.Vector3[]
|
||||
{
|
||||
basePos,
|
||||
basePos + new UnityEngine.Vector3(0f, 1.7f, 0f),
|
||||
basePos + new UnityEngine.Vector3(1.8f, 0.2f, 1.4f),
|
||||
basePos + new UnityEngine.Vector3(-2.1f, 1.0f, 1.0f),
|
||||
basePos + new UnityEngine.Vector3(0.4f, 0.6f, 2.6f),
|
||||
};
|
||||
|
||||
L(" # | world | Camera.main px | 실제 화면 px | 오차 px | RT양자화 포함 오차 px");
|
||||
float maxErr = 0f, maxErrQ = 0f, sumErr = 0f, sumErrQ = 0f;
|
||||
for (int i = 0; i < pts.Length; i++)
|
||||
{
|
||||
var p = pts[i];
|
||||
var vSrc = src.WorldToViewportPoint(p);
|
||||
var expect = new UnityEngine.Vector2(vSrc.x * W, vSrc.y * H);
|
||||
|
||||
var vGame = gameCam.WorldToViewportPoint(p);
|
||||
var actual = ViewportToScreen(vGame.x, vGame.y, quad, viewCam);
|
||||
|
||||
float qx = (UnityEngine.Mathf.Floor(vGame.x * rt.width) + 0.5f) / rt.width;
|
||||
float qy = (UnityEngine.Mathf.Floor(vGame.y * rt.height) + 0.5f) / rt.height;
|
||||
var actualQ = ViewportToScreen(qx, qy, quad, viewCam);
|
||||
|
||||
float e = UnityEngine.Vector2.Distance(expect, actual);
|
||||
float eq = UnityEngine.Vector2.Distance(expect, actualQ);
|
||||
maxErr = UnityEngine.Mathf.Max(maxErr, e); maxErrQ = UnityEngine.Mathf.Max(maxErrQ, eq);
|
||||
sumErr += e; sumErrQ += eq;
|
||||
L(" " + (i + 1) + " | " + p.ToString("F2")
|
||||
+ " | (" + expect.x.ToString("F1") + "," + expect.y.ToString("F1") + ")"
|
||||
+ " | (" + actual.x.ToString("F1") + "," + actual.y.ToString("F1") + ")"
|
||||
+ " | " + e.ToString("F2")
|
||||
+ " | " + eq.ToString("F2"));
|
||||
}
|
||||
L(" 최대 " + maxErr.ToString("F2") + " px · 평균 " + (sumErr / pts.Length).ToString("F2")
|
||||
+ " px (연속) / 최대 " + maxErrQ.ToString("F2") + " px · 평균 " + (sumErrQ / pts.Length).ToString("F2") + " px (RT 양자화 포함)");
|
||||
L(" 참고: 1 RT 픽셀 = 화면 " + ((float)H / rt.height).ToString("F2") + " px(세로) · " + ((float)W / rt.width).ToString("F2") + " px(가로)");
|
||||
Chk(maxErr <= 2.0f, "연속 매핑 오차 ≤ 2 px (compensateViewZoom 보정 확인)", "max=" + maxErr.ToString("F2") + " px");
|
||||
Chk(maxErrQ <= (float)H / rt.height, "RT 양자화 포함 오차 ≤ 업스케일 1픽셀", "max=" + maxErrQ.ToString("F2") + " px");
|
||||
}
|
||||
|
||||
static UnityEngine.Vector2 ViewportToScreen(float vx, float vy, UnityEngine.Transform quad, UnityEngine.Camera viewCam)
|
||||
{
|
||||
var quadLocal = new UnityEngine.Vector3(vx - 0.5f, vy - 0.5f, 0f);
|
||||
var quadWorld = quad.TransformPoint(quadLocal);
|
||||
var vView = viewCam.WorldToViewportPoint(quadWorld);
|
||||
return new UnityEngine.Vector2(vView.x * W, vView.y * H);
|
||||
}
|
||||
|
||||
static UnityEngine.Transform FindQuad()
|
||||
{
|
||||
var rig = WL.PixelArt.PixelCameraRig.RigRoot;
|
||||
if (rig == null) return null;
|
||||
var uc = rig.GetComponentInChildren<PixelCamera.UpscaledCanvas>(true);
|
||||
return uc == null ? null : uc.transform;
|
||||
}
|
||||
|
||||
static void Dump(UnityEngine.Transform t, int depth)
|
||||
{
|
||||
var line = new System.Text.StringBuilder();
|
||||
line.Append(' ', depth * 2).Append("- ").Append(t.name).Append(" layer=").Append(t.gameObject.layer);
|
||||
var comps = t.GetComponents<UnityEngine.Component>();
|
||||
line.Append(" [");
|
||||
for (int i = 0; i < comps.Length; i++) if (comps[i] != null) line.Append(comps[i].GetType().Name).Append(' ');
|
||||
line.Append("]");
|
||||
line.Append(" lp=").Append(t.localPosition.ToString("F4")).Append(" ls=").Append(t.localScale.ToString("F4"));
|
||||
L(line.ToString());
|
||||
for (int i = 0; i < t.childCount; i++) Dump(t.GetChild(i), depth + 1);
|
||||
}
|
||||
|
||||
// ── E. GC ────────────────────────────────────────────────────────────────
|
||||
static void SectionE(UnityEngine.Camera cam)
|
||||
{
|
||||
L("");
|
||||
L("## E. GC (200k 회)");
|
||||
var probeGo = new UnityEngine.GameObject("__WL814b_MirrorProbe");
|
||||
probeGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
|
||||
var mirror = probeGo.AddComponent<WL.PixelArt.PixelCameraProxyMirror>();
|
||||
mirror.Source = cam.transform;
|
||||
|
||||
System.GC.Collect();
|
||||
long m0 = System.GC.GetAllocatedBytesForCurrentThread();
|
||||
long t0 = System.GC.GetTotalMemory(false);
|
||||
int g0 = System.GC.CollectionCount(0);
|
||||
for (int i = 0; i < 200000; i++) mirror.Mirror();
|
||||
long m1 = System.GC.GetAllocatedBytesForCurrentThread();
|
||||
long t1 = System.GC.GetTotalMemory(false);
|
||||
int g1 = System.GC.CollectionCount(0);
|
||||
L("프록시 미러 ×200k: thread Δ" + (m1 - m0) + " B · total Δ" + (t1 - t0) + " B · gen0 " + (g1 - g0));
|
||||
Chk(m1 - m0 == 0, "프록시 미러 GC 0 B", "Δ=" + (m1 - m0));
|
||||
UnityEngine.Object.DestroyImmediate(probeGo);
|
||||
|
||||
var cfg = MakeCfg(3.8f, 480, false);
|
||||
WL.PixelArt.PixelCameraRig.Assemble(cfg, cam);
|
||||
System.GC.Collect();
|
||||
long s0 = System.GC.GetAllocatedBytesForCurrentThread();
|
||||
for (int i = 0; i < 200000; i++) WL.PixelArt.PixelCameraRig.ProbeSnapTick();
|
||||
long s1 = System.GC.GetAllocatedBytesForCurrentThread();
|
||||
L("회전 스냅 판정 ×200k: thread Δ" + (s1 - s0) + " B");
|
||||
Chk(s1 - s0 == 0, "회전 스냅 판정 GC 0 B", "Δ=" + (s1 - s0));
|
||||
WL.PixelArt.PixelCameraRig.Teardown("probe E");
|
||||
}
|
||||
|
||||
// ── F. C8 ────────────────────────────────────────────────────────────────
|
||||
static void SectionF(UnityEngine.Camera cam)
|
||||
{
|
||||
L("");
|
||||
L("## F. C8 롤백");
|
||||
var so = WL.PixelArt.WLPixelCameraSettings.Instance;
|
||||
Chk(so != null, "SO 로드(Resources/WL/WLPixelCameraSettings)", so == null ? "null" : "enabled=" + so.enabled);
|
||||
|
||||
string before = WL.PixelArt.PixelCameraRig.CurrentSummary(cam);
|
||||
var cfg = MakeCfg(3.8f, 480, false);
|
||||
WL.PixelArt.PixelCameraRig.Assemble(cfg, cam);
|
||||
Chk(WL.PixelArt.PixelCameraRig.IsAssembled, "조립됨(C8 전)", "");
|
||||
|
||||
WL.PixelArt.WLPixelCameraSettings.RuntimeDisabled = true;
|
||||
Chk(!WL.PixelArt.WLPixelCameraSettings.Enabled, "RuntimeDisabled → Enabled=false", "");
|
||||
WL.PixelArt.PixelCameraRig.Tick(); // Active=false → 즉시 Teardown
|
||||
Chk(!WL.PixelArt.PixelCameraRig.IsAssembled, "Tick 1회에 리그 해체", "");
|
||||
string after = WL.PixelArt.PixelCameraRig.CurrentSummary(cam);
|
||||
Chk(after == before, "C8 복원값 == 원값", after == before ? "" : "\n before=" + before + "\n after =" + after);
|
||||
|
||||
WL.PixelArt.PixelCameraRig.Tick(); // 재호출해도 조립 0
|
||||
Chk(!WL.PixelArt.PixelCameraRig.IsAssembled, "C8 상태에서 재조립 0", "");
|
||||
WL.PixelArt.WLPixelCameraSettings.RuntimeDisabled = false;
|
||||
}
|
||||
|
||||
// ── G. 캡처 ──────────────────────────────────────────────────────────────
|
||||
static void SectionG(UnityEngine.Camera cam)
|
||||
{
|
||||
L("");
|
||||
L("## G. 룩 캡처 1080×1920 → " + kOutDir);
|
||||
L(CaptureControl(cam, "look_00_persp_original"));
|
||||
L(CaptureRig(cam, 3.8f, 480, "look_01_ortho38_px480"));
|
||||
L(CaptureRig(cam, 3.8f, 360, "look_02_ortho38_px360"));
|
||||
L(CaptureRig(cam, 4.6f, 480, "look_03_ortho46_px480"));
|
||||
// 보너스 — 811o 구도의 실측 거리(카메라→주시점)에서 원근 fov 60 과 PC 평면 크기가 정확히 같아지는 ortho
|
||||
float matched = UnityEngine.Vector3.Distance(cam.transform.position, s_lookAtWorld) * UnityEngine.Mathf.Tan(30f * UnityEngine.Mathf.Deg2Rad);
|
||||
L(CaptureRig(cam, matched, 480, "look_04_orthoMatched_px480") + " ← 실측 정합값 ortho " + matched.ToString("F3"));
|
||||
}
|
||||
|
||||
static string CaptureControl(UnityEngine.Camera cam, string tag)
|
||||
{
|
||||
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32);
|
||||
var prevTarget = cam.targetTexture;
|
||||
float prevAspect = cam.aspect;
|
||||
cam.aspect = (float)W / H;
|
||||
cam.targetTexture = rt;
|
||||
cam.Render();
|
||||
cam.targetTexture = prevTarget;
|
||||
cam.aspect = prevAspect;
|
||||
string path = WritePng(rt, tag);
|
||||
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
|
||||
return " 대조(원근 fov " + cam.fieldOfView + ") → " + path;
|
||||
}
|
||||
|
||||
static string CaptureRig(UnityEngine.Camera cam, float orthoSize, int pixelHeight, string tag)
|
||||
{
|
||||
var cfg = MakeCfg(orthoSize, pixelHeight, false); // viewCameraInMainStack=false → 뷰 카메라를 Base 로 직접 렌더
|
||||
if (cfg == null) return " FAIL cfg";
|
||||
if (!WL.PixelArt.PixelCameraRig.Assemble(cfg, cam)) return " FAIL assemble " + tag;
|
||||
|
||||
var gameCam = WL.PixelArt.PixelCameraRig.GameCamera;
|
||||
var viewCam = WL.PixelArt.PixelCameraRig.ViewCamera;
|
||||
var mgr = WL.PixelArt.PixelCameraRig.Manager;
|
||||
|
||||
var cap = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32);
|
||||
viewCam.aspect = (float)W / H;
|
||||
viewCam.targetTexture = cap;
|
||||
mgr.SendMessage("LateUpdate", UnityEngine.SendMessageOptions.DontRequireReceiver);
|
||||
mgr.SendMessage("LateUpdate", UnityEngine.SendMessageOptions.DontRequireReceiver); // RT 생성 후 위치·줌 확정
|
||||
|
||||
var lowRt = gameCam.targetTexture;
|
||||
gameCam.Render(); // 저해상도 RT 를 채운다
|
||||
viewCam.Render(); // 쿼드를 1080×1920 으로 업스케일
|
||||
|
||||
string path = WritePng(cap, tag);
|
||||
string info = " ortho " + orthoSize.ToString("0.##") + " × px " + pixelHeight
|
||||
+ " → RT " + (lowRt == null ? "null" : lowRt.width + "×" + lowRt.height)
|
||||
+ " · gameZoom " + mgr.GameCameraZoom.ToString("F4")
|
||||
+ " · viewSize " + viewCam.orthographicSize.ToString("F4")
|
||||
+ " → " + path;
|
||||
|
||||
viewCam.targetTexture = null;
|
||||
cap.Release(); UnityEngine.Object.DestroyImmediate(cap);
|
||||
WL.PixelArt.PixelCameraRig.Teardown("capture " + tag);
|
||||
return info;
|
||||
}
|
||||
|
||||
static string WritePng(UnityEngine.RenderTexture rt, string tag)
|
||||
{
|
||||
var prev = UnityEngine.RenderTexture.active;
|
||||
UnityEngine.RenderTexture.active = rt;
|
||||
var tex = new UnityEngine.Texture2D(rt.width, rt.height, UnityEngine.TextureFormat.RGB24, false);
|
||||
tex.ReadPixels(new UnityEngine.Rect(0, 0, rt.width, rt.height), 0, 0);
|
||||
tex.Apply();
|
||||
UnityEngine.RenderTexture.active = prev;
|
||||
var path = System.IO.Path.Combine(kOutDir, tag + ".png");
|
||||
System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex));
|
||||
UnityEngine.Object.DestroyImmediate(tex);
|
||||
return path;
|
||||
}
|
||||
|
||||
// ── 임시 설정(디스크 SO 를 절대 건드리지 않는다) ─────────────────────────
|
||||
static WL.PixelArt.WLPixelCameraSettings MakeCfg(float orthoSize, int pixelHeight, bool inStack)
|
||||
{
|
||||
var rig = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kRig);
|
||||
if (rig == null) return null;
|
||||
var cfg = UnityEngine.ScriptableObject.CreateInstance<WL.PixelArt.WLPixelCameraSettings>();
|
||||
cfg.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
|
||||
cfg.pixelCameraSystemPrefab = rig;
|
||||
cfg.orthoSize = orthoSize;
|
||||
cfg.pixelHeight = pixelHeight;
|
||||
cfg.viewCameraInMainStack = inStack;
|
||||
cfg.verboseLog = false;
|
||||
return cfg;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
# WL-814b 프로브 — 2026-09-10 23:27:24
|
||||
unity=6000.3.23f1 · isPlaying=False
|
||||
|
||||
## A. 원본 카메라 · UI 캔버스 실측
|
||||
Main Camera.prefab: tag=MainCamera layer=0 parent=none children=0
|
||||
Camera: ortho=False fov=60 size=5 near=0.3 far=1000 depth=5 mask=95 clear=Skybox hdr=True msaa=True occlusionCulling=False
|
||||
URP: type=Base post=True shadows=False volumeMask=1 aa=None stack=0
|
||||
컴포넌트: RealCamera=True AudioListener=True MeshRendererVisibility=False
|
||||
PASS 원본 카메라 = RealCamera + AudioListener 보유(재부모화·비활성 금지 근거)
|
||||
NewGameUI.prefab 캔버스 1개
|
||||
[0] NewGameUI renderMode=ScreenSpaceCamera worldCamera=Camera planeDistance=100 sortingOrder=0 layer=5
|
||||
UI camera: Camera ortho=True depth=6 mask=32 clear=Nothing
|
||||
PASS 인게임 UI 캔버스 = Screen Space - Camera(UICamera) → 원본 카메라를 끄면 UI 가 사라진다
|
||||
현재 씬 = '' path='' dirty(before)=False rootCount=0
|
||||
|
||||
## B. 임시 씬(추가 로드 · 저장 0)
|
||||
맵 __WL814b_Map renderers=1299
|
||||
소품 후보 799개 · 가장 밀집한 지점 반경 10 m 이웃 36개
|
||||
PC 위치 (192.32, 1.99, -46.40) · 반경 10 m 소품 36개 (지면 Collider)
|
||||
PC 포즈: Idle @0.4s (26클립)
|
||||
PC ok
|
||||
잡몹 3체
|
||||
카메라(811o 구도) pos=(190.198, 6.579, -50.608) euler=(36.79, 26.73, 0.00)
|
||||
PC 주시점까지 거리 = 5.887 m → 원근 fov 60 의 반높이 = 3.399 m
|
||||
|
||||
## B. 리그 조립
|
||||
조립 전 원본 카메라: ortho=0 size=5 fov=60 near=0.3 far=1000 depth=5 mask=95 clear=1 bg=0,0,0,1 hdr=1 msaa=1 occ=0 rt=0 type=0 post=1 shadow=0 vmask=1 aa=0 stack=0
|
||||
PASS 조립 성공 조립 — ortho 3.8 · RT 640×480 · zoom 3.8159 · layer 31
|
||||
리그 구조:
|
||||
- WL_PixelCameraRig layer=31 [Transform ] lp=(190.1982, 6.5791, -50.6082) ls=(1.0000, 1.0000, 1.0000)
|
||||
- PixelCameraTransform layer=31 [Transform ] lp=(0.0000, 0.0000, 0.0000) ls=(1.0000, 1.0000, 1.0000)
|
||||
- PixelCamera layer=31 [Transform Camera PixelCameraManager UniversalAdditionalCameraData ] lp=(0.0000, 0.0000, 0.0000) ls=(1.0000, 1.0000, 1.0000)
|
||||
- UpscaledDisplay layer=31 [Transform ] lp=(0.0000, 0.0000, -1.0000) ls=(1.0000, 1.0000, 1.0000)
|
||||
- ViewCamera layer=31 [Transform Camera UniversalAdditionalCameraData CanvasViewCamera ] lp=(0.0000, 0.0086, -1.0000) ls=(1.0000, 1.0000, 1.0000)
|
||||
- QuadCanvas layer=31 [Transform MeshFilter MeshRenderer UpscaledCanvas ] lp=(0.0000, 0.0000, 0.0000) ls=(19.8022, 10.0556, 1.0000)
|
||||
프록시: WL_PixelFollow parent=__WL814b_MainCamera worldPos=(190.1982, 6.5791, -50.6082) camPos=(190.1982, 6.5791, -50.6082)
|
||||
PASS 프록시 월드 위치 == 원본 카메라 위치(지연 0)
|
||||
PASS 프록시 회전 == 원본 카메라 회전
|
||||
조립 후 원본 카메라: ortho=1 size=3.8 fov=60 near=0.3 far=1000 depth=5 mask=0 clear=2 bg=0,0,0,1 hdr=1 msaa=1 occ=0 rt=0 type=0 post=0 shadow=0 vmask=1 aa=0 stack=0
|
||||
PASS 원본 카메라 직교 전환 size=3.8
|
||||
PASS 원본 카메라 월드 미렌더(cullingMask 0) mask=0
|
||||
PASS MainCamera 태그·enabled 유지(Camera.main 보존) tag=MainCamera
|
||||
게임 카메라: ortho=True size=3.8159 mask=95 depth=4 RT=270×480 filter=Point fmt=ARGB32
|
||||
뷰 카메라: ortho=True size=3.8000 mask=-2147483648 near=0 far=1001 localPos=(-0.00383, 0.00197, -1.00000)
|
||||
Critter: GameResolution=(270, 480) zoom=3.81590 viewZoom=1 grid=True sub=True followRot=True
|
||||
PASS 저해상도 RT 480줄 · 포인트 필터 270×480
|
||||
PASS 게임 카메라 = 원본 cullingMask 승계 orig=95 game=95
|
||||
PASS 게임 카메라가 픽셀 쿼드를 다시 그리지 않는다(리그 레이어 제외)
|
||||
PASS 뷰 카메라는 픽셀 쿼드만 그린다 mask=-2147483648
|
||||
|
||||
## D. 매핑 오차 — Camera.main 투영 vs 실제 화면(1080×1920 · px)
|
||||
# | world | Camera.main px | 실제 화면 px | 오차 px | RT양자화 포함 오차 px
|
||||
1 | (192.32, 1.99, -46.40) | (540.0,745.5) | (540.0,745.5) | 0.00 | 1.40
|
||||
2 | (192.32, 3.69, -46.40) | (540.0,1089.5) | (540.0,1089.5) | 0.00 | 1.19
|
||||
3 | (194.12, 2.19, -45.00) | (787.1,1097.7) | (787.1,1097.7) | 0.00 | 1.03
|
||||
4 | (190.22, 2.99, -45.40) | (-47.5,940.1) | (-47.5,940.1) | 0.00 | 1.35
|
||||
5 | (192.72, 2.59, -43.80) | (334.8,1245.5) | (334.8,1245.5) | 0.00 | 1.43
|
||||
최대 0.00 px · 평균 0.00 px (연속) / 최대 1.43 px · 평균 1.28 px (RT 양자화 포함)
|
||||
참고: 1 RT 픽셀 = 화면 4.00 px(세로) · 4.00 px(가로)
|
||||
PASS 연속 매핑 오차 ≤ 2 px (compensateViewZoom 보정 확인) max=0.00 px
|
||||
PASS RT 양자화 포함 오차 ≤ 업스케일 1픽셀 max=1.43 px
|
||||
|
||||
## C. 복원
|
||||
복원 후 원본 카메라: ortho=0 size=5 fov=60 near=0.3 far=1000 depth=5 mask=95 clear=1 bg=0,0,0,1 hdr=1 msaa=1 occ=0 rt=0 type=0 post=1 shadow=0 vmask=1 aa=0 stack=0
|
||||
PASS 원본 카메라 값 스냅샷 == 복원값(문자열 완전 일치)
|
||||
PASS 리그 오브젝트 0
|
||||
PASS RT 참조 해제(Release + Destroy) rt=null
|
||||
PASS 씬에 PixelCameraManager 잔재 0 found=0
|
||||
PASS 원본 카메라 자식 프록시 0 found=0
|
||||
PASS 디스크 UpscaleMaterialURP.mat 의 _LowResTexture 오염 0(런타임 인스턴스 사용) tex=null
|
||||
|
||||
## E. GC (200k 회)
|
||||
프록시 미러 ×200k: thread Δ0 B · total Δ0 B · gen0 0
|
||||
PASS 프록시 미러 GC 0 B Δ=0
|
||||
회전 스냅 판정 ×200k: thread Δ0 B
|
||||
PASS 회전 스냅 판정 GC 0 B Δ=0
|
||||
|
||||
## F. C8 롤백
|
||||
PASS SO 로드(Resources/WL/WLPixelCameraSettings) enabled=True
|
||||
PASS 조립됨(C8 전)
|
||||
PASS RuntimeDisabled → Enabled=false
|
||||
PASS Tick 1회에 리그 해체
|
||||
PASS C8 복원값 == 원값
|
||||
PASS C8 상태에서 재조립 0
|
||||
|
||||
## G. 룩 캡처 1080×1920 → E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b
|
||||
대조(원근 fov 60) → E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b\look_00_persp_original.png
|
||||
ortho 3.8 × px 480 → RT 270×480 · gameZoom 3.8159 · viewSize 3.8000 → E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b\look_01_ortho38_px480.png
|
||||
ortho 3.8 × px 360 → RT 202×360 · gameZoom 3.8212 · viewSize 3.8000 → E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b\look_02_ortho38_px360.png
|
||||
ortho 4.6 × px 480 → RT 270×480 · gameZoom 4.6192 · viewSize 4.6000 → E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b\look_03_ortho46_px480.png
|
||||
ortho 3.4 × px 480 → RT 270×480 · gameZoom 3.4128 · viewSize 3.3986 → E:\NerdNavis\nn_himminji\Screenshots_WL\WL814b\look_04_orthoMatched_px480.png ← 실측 정합값 ortho 3.399
|
||||
씬 정리 후: dirty=False rootCount=0 (저장 0)
|
||||
|
||||
RESULT PASS 28/28
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 89ba2272d61bfaf4f8e60603c1027381
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67fa8744e3c0f97478b2a6fd3292b65d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,496 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1532677598533230704
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7303396614074331432}
|
||||
m_Layer: 0
|
||||
m_Name: PixelCameraTransform
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &7303396614074331432
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1532677598533230704}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 3132409262940554809}
|
||||
m_RootOrder: -1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2255326839739188927
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3132409262940554809}
|
||||
m_Layer: 0
|
||||
m_Name: PixelCameraSystem
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3132409262940554809
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2255326839739188927}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 7303396614074331432}
|
||||
- {fileID: 8788124287499514057}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3474214803470865388
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1813454538314249935}
|
||||
- component: {fileID: 5422343619921320258}
|
||||
- component: {fileID: 418977516687070584}
|
||||
- component: {fileID: 5593218058142784318}
|
||||
m_Layer: 0
|
||||
m_Name: QuadCanvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1813454538314249935
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3474214803470865388}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 19.802168, y: 10.055555, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8987800775158610402}
|
||||
m_RootOrder: -1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &5422343619921320258
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3474214803470865388}
|
||||
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!23 &418977516687070584
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3474214803470865388}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 1af8e993bbdb2f547989713359c47b1c, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!114 &5593218058142784318
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3474214803470865388}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: ab692ebf91361b44cbd447f7d7b5fddf, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!1 &4231759119073248400
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8788124287499514057}
|
||||
- component: {fileID: 9205371885998440386}
|
||||
- component: {fileID: 6298985930916582049}
|
||||
- component: {fileID: 4103191127918928509}
|
||||
m_Layer: 0
|
||||
m_Name: PixelCamera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8788124287499514057
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4231759119073248400}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 8987800775158610402}
|
||||
m_Father: {fileID: 3132409262940554809}
|
||||
m_RootOrder: -1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!20 &9205371885998440386
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4231759119073248400}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 2
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 1
|
||||
orthographic size: 5
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!114 &6298985930916582049
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4231759119073248400}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a6fe4c3a8238df440bdf10c687b2537f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
FollowedTransform: {fileID: 7303396614074331432}
|
||||
VoxelGridMovement: 1
|
||||
SubpixelAdjustments: 1
|
||||
FollowRotation: 1
|
||||
resolutionSynchronizationMode: 0
|
||||
GameResolution: {x: 640, y: 360}
|
||||
ControlGameZoom: 1
|
||||
GameCameraZoom: 5
|
||||
ViewCameraZoom: 1
|
||||
--- !u!114 &4103191127918928509
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4231759119073248400}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_RenderShadows: 1
|
||||
m_RequiresDepthTextureOption: 2
|
||||
m_RequiresOpaqueTextureOption: 2
|
||||
m_CameraType: 0
|
||||
m_Cameras: []
|
||||
m_RendererIndex: -1
|
||||
m_VolumeLayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 1
|
||||
m_VolumeTrigger: {fileID: 0}
|
||||
m_VolumeFrameworkUpdateModeOption: 2
|
||||
m_RenderPostProcessing: 0
|
||||
m_Antialiasing: 0
|
||||
m_AntialiasingQuality: 2
|
||||
m_StopNaN: 0
|
||||
m_Dithering: 0
|
||||
m_ClearDepth: 1
|
||||
m_AllowXRRendering: 1
|
||||
m_AllowHDROutput: 1
|
||||
m_UseScreenCoordOverride: 0
|
||||
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_RequiresDepthTexture: 0
|
||||
m_RequiresColorTexture: 0
|
||||
m_Version: 2
|
||||
m_TaaSettings:
|
||||
quality: 3
|
||||
frameInfluence: 0.1
|
||||
jitterScale: 1
|
||||
mipBias: 0
|
||||
varianceClampScale: 0.9
|
||||
contrastAdaptiveSharpening: 0
|
||||
--- !u!1 &6842119547268722464
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2475294716756555193}
|
||||
- component: {fileID: 1798342755243477739}
|
||||
- component: {fileID: 439820793684178854}
|
||||
- component: {fileID: 3231981177195013634}
|
||||
- component: {fileID: 1032179972197267321}
|
||||
m_Layer: 0
|
||||
m_Name: ViewCamera
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &2475294716756555193
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6842119547268722464}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0.008579807, z: -1}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8987800775158610402}
|
||||
m_RootOrder: -1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!20 &1798342755243477739
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6842119547268722464}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 2
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0
|
||||
far clip plane: 1001
|
||||
field of view: 60
|
||||
orthographic: 1
|
||||
orthographic size: 5
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!81 &439820793684178854
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6842119547268722464}
|
||||
m_Enabled: 1
|
||||
--- !u!114 &3231981177195013634
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6842119547268722464}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_RenderShadows: 0
|
||||
m_RequiresDepthTextureOption: 2
|
||||
m_RequiresOpaqueTextureOption: 2
|
||||
m_CameraType: 0
|
||||
m_Cameras: []
|
||||
m_RendererIndex: -1
|
||||
m_VolumeLayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 1
|
||||
m_VolumeTrigger: {fileID: 0}
|
||||
m_VolumeFrameworkUpdateModeOption: 2
|
||||
m_RenderPostProcessing: 0
|
||||
m_Antialiasing: 0
|
||||
m_AntialiasingQuality: 2
|
||||
m_StopNaN: 0
|
||||
m_Dithering: 0
|
||||
m_ClearDepth: 1
|
||||
m_AllowXRRendering: 1
|
||||
m_AllowHDROutput: 1
|
||||
m_UseScreenCoordOverride: 0
|
||||
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_RequiresDepthTexture: 0
|
||||
m_RequiresColorTexture: 0
|
||||
m_Version: 2
|
||||
m_TaaSettings:
|
||||
quality: 3
|
||||
frameInfluence: 0.1
|
||||
jitterScale: 1
|
||||
mipBias: 0
|
||||
varianceClampScale: 0.9
|
||||
contrastAdaptiveSharpening: 0
|
||||
--- !u!114 &1032179972197267321
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6842119547268722464}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: de5b95231816236418041ca173b33a29, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!1 &7295925279294691889
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8987800775158610402}
|
||||
m_Layer: 0
|
||||
m_Name: UpscaledDisplay
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8987800775158610402
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7295925279294691889}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -1}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2475294716756555193}
|
||||
- {fileID: 1813454538314249935}
|
||||
m_Father: {fileID: 8788124287499514057}
|
||||
m_RootOrder: -1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e96cffa9d00b6b545adfeb26165952cc
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UpscaleMaterialURP
|
||||
m_Shader: {fileID: -6465566751694194690, guid: c63d04c1c20ea83498addf7813ae3dc5,
|
||||
type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DownscaledTexture:
|
||||
m_Texture: {fileID: 8400000, guid: b341653440931de4ba25940d113f4375, type: 2}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _LowResTexture:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendOp: 0
|
||||
- _BumpScale: 1
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _QueueControl: 0
|
||||
- _QueueOffset: 0
|
||||
- _SampleGI: 0
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &4363459520997935123
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 10
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1af8e993bbdb2f547989713359c47b1c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,693 @@
|
|||
{
|
||||
"m_SGVersion": 3,
|
||||
"m_Type": "UnityEditor.ShaderGraph.GraphData",
|
||||
"m_ObjectId": "4b4aee54c62b40958070f4140352fba7",
|
||||
"m_Properties": [
|
||||
{
|
||||
"m_Id": "3ba9df8d7b064813844ee1a01ff30884"
|
||||
}
|
||||
],
|
||||
"m_Keywords": [],
|
||||
"m_Dropdowns": [],
|
||||
"m_CategoryData": [
|
||||
{
|
||||
"m_Id": "5b7e26a64997477b8fceed79720cbe18"
|
||||
}
|
||||
],
|
||||
"m_Nodes": [
|
||||
{
|
||||
"m_Id": "e89eafddf99b406dba0daa5373d685ee"
|
||||
},
|
||||
{
|
||||
"m_Id": "54acbcd866754623a9971b65c87753b5"
|
||||
},
|
||||
{
|
||||
"m_Id": "3a3ed0c7f46f423bb7e2448b2a885805"
|
||||
},
|
||||
{
|
||||
"m_Id": "b646594906c747a4a535fe5a190c267e"
|
||||
},
|
||||
{
|
||||
"m_Id": "8346d6ed11034b1785db95ef2e8bf371"
|
||||
},
|
||||
{
|
||||
"m_Id": "8d0d097456884c839b0e1bccbd948c83"
|
||||
}
|
||||
],
|
||||
"m_GroupDatas": [],
|
||||
"m_StickyNoteDatas": [
|
||||
{
|
||||
"m_Id": "2bcf8277985449668ed3ecc75283b25f"
|
||||
}
|
||||
],
|
||||
"m_Edges": [
|
||||
{
|
||||
"m_OutputSlot": {
|
||||
"m_Node": {
|
||||
"m_Id": "8346d6ed11034b1785db95ef2e8bf371"
|
||||
},
|
||||
"m_SlotId": 0
|
||||
},
|
||||
"m_InputSlot": {
|
||||
"m_Node": {
|
||||
"m_Id": "8d0d097456884c839b0e1bccbd948c83"
|
||||
},
|
||||
"m_SlotId": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"m_OutputSlot": {
|
||||
"m_Node": {
|
||||
"m_Id": "8d0d097456884c839b0e1bccbd948c83"
|
||||
},
|
||||
"m_SlotId": 0
|
||||
},
|
||||
"m_InputSlot": {
|
||||
"m_Node": {
|
||||
"m_Id": "b646594906c747a4a535fe5a190c267e"
|
||||
},
|
||||
"m_SlotId": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"m_VertexContext": {
|
||||
"m_Position": {
|
||||
"x": 878.666748046875,
|
||||
"y": -616.0001220703125
|
||||
},
|
||||
"m_Blocks": [
|
||||
{
|
||||
"m_Id": "e89eafddf99b406dba0daa5373d685ee"
|
||||
},
|
||||
{
|
||||
"m_Id": "54acbcd866754623a9971b65c87753b5"
|
||||
},
|
||||
{
|
||||
"m_Id": "3a3ed0c7f46f423bb7e2448b2a885805"
|
||||
}
|
||||
]
|
||||
},
|
||||
"m_FragmentContext": {
|
||||
"m_Position": {
|
||||
"x": 879.3333740234375,
|
||||
"y": -363.3334655761719
|
||||
},
|
||||
"m_Blocks": [
|
||||
{
|
||||
"m_Id": "b646594906c747a4a535fe5a190c267e"
|
||||
}
|
||||
]
|
||||
},
|
||||
"m_PreviewData": {
|
||||
"serializedMesh": {
|
||||
"m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}",
|
||||
"m_Guid": ""
|
||||
},
|
||||
"preventRotation": false
|
||||
},
|
||||
"m_Path": "Shader Graphs",
|
||||
"m_GraphPrecision": 0,
|
||||
"m_PreviewMode": 2,
|
||||
"m_OutputNode": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_ActiveTargets": [
|
||||
{
|
||||
"m_Id": "0d38844c2de34d5ba592090e3a320f9d"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
|
||||
"m_ObjectId": "012c063cd77b4055a5d02d510505e55e",
|
||||
"m_Id": 5,
|
||||
"m_DisplayName": "G",
|
||||
"m_SlotType": 1,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "G",
|
||||
"m_StageCapability": 2,
|
||||
"m_Value": 0.0,
|
||||
"m_DefaultValue": 0.0,
|
||||
"m_Labels": []
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 1,
|
||||
"m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget",
|
||||
"m_ObjectId": "0d38844c2de34d5ba592090e3a320f9d",
|
||||
"m_Datas": [],
|
||||
"m_ActiveSubTarget": {
|
||||
"m_Id": "82a2f491e31c4a83a8bfa01a377c3b68"
|
||||
},
|
||||
"m_AllowMaterialOverride": false,
|
||||
"m_SurfaceType": 0,
|
||||
"m_ZTestMode": 4,
|
||||
"m_ZWriteControl": 0,
|
||||
"m_AlphaMode": 0,
|
||||
"m_RenderFace": 2,
|
||||
"m_AlphaClip": false,
|
||||
"m_CastShadows": true,
|
||||
"m_ReceiveShadows": true,
|
||||
"m_SupportsLODCrossFade": false,
|
||||
"m_CustomEditorGUI": "",
|
||||
"m_SupportVFX": false
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
|
||||
"m_ObjectId": "1bd6c17f30d843c5bded4563c487ef31",
|
||||
"m_Id": 6,
|
||||
"m_DisplayName": "B",
|
||||
"m_SlotType": 1,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "B",
|
||||
"m_StageCapability": 2,
|
||||
"m_Value": 0.0,
|
||||
"m_DefaultValue": 0.0,
|
||||
"m_Labels": []
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.StickyNoteData",
|
||||
"m_ObjectId": "2bcf8277985449668ed3ecc75283b25f",
|
||||
"m_Title": "Hello!",
|
||||
"m_Content": "This shader is intended to display the game on a quad. The 'LowResTexture' is a low-resolution rendertexture of the game. A full-resolution camera then looks at said quad and performs adjustments to create subpixel movement.\n\nThis way you can have your FX, post-processing, gameobjects, and virtually everything rendered on low-resolution which creates significant boost in performance for GPU. \n\n*** Add \"post-post-processing\" here *** \n\nBecause this shader displays the final result of your game, you can adjust this shader to create your own effects on top of all that.",
|
||||
"m_TextSize": 0,
|
||||
"m_Theme": 0,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": 360.6666564941406,
|
||||
"y": -648.0,
|
||||
"width": 366.66668701171877,
|
||||
"height": 226.00003051757813
|
||||
},
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
|
||||
"m_ObjectId": "3a3ed0c7f46f423bb7e2448b2a885805",
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_Name": "VertexDescription.Tangent",
|
||||
"m_DrawState": {
|
||||
"m_Expanded": true,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"width": 0.0,
|
||||
"height": 0.0
|
||||
}
|
||||
},
|
||||
"m_Slots": [
|
||||
{
|
||||
"m_Id": "95d25e4d952f48c38ba5e62dc3fab9cd"
|
||||
}
|
||||
],
|
||||
"synonyms": [],
|
||||
"m_Precision": 0,
|
||||
"m_PreviewExpanded": true,
|
||||
"m_DismissedVersion": 0,
|
||||
"m_PreviewMode": 0,
|
||||
"m_CustomColors": {
|
||||
"m_SerializableColors": []
|
||||
},
|
||||
"m_SerializedDescriptor": "VertexDescription.Tangent"
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Internal.Texture2DShaderProperty",
|
||||
"m_ObjectId": "3ba9df8d7b064813844ee1a01ff30884",
|
||||
"m_Guid": {
|
||||
"m_GuidSerialized": "cdef0278-d3f3-407a-9b37-d7731b76ad2c"
|
||||
},
|
||||
"m_Name": "LowResTexture",
|
||||
"m_DefaultRefNameVersion": 0,
|
||||
"m_RefNameGeneratedByDisplayName": "",
|
||||
"m_DefaultReferenceName": "Texture2D_3ba9df8d7b064813844ee1a01ff30884",
|
||||
"m_OverrideReferenceName": "_LowResTexture",
|
||||
"m_GeneratePropertyBlock": true,
|
||||
"m_UseCustomSlotLabel": false,
|
||||
"m_CustomSlotLabel": "",
|
||||
"m_DismissedVersion": 0,
|
||||
"m_Precision": 0,
|
||||
"overrideHLSLDeclaration": false,
|
||||
"hlslDeclarationOverride": 0,
|
||||
"m_Hidden": false,
|
||||
"m_Value": {
|
||||
"m_SerializedTexture": "{\"texture\":{\"fileID\":8400000,\"guid\":\"dc06a050ca5352e469850f311104ce88\",\"type\":2}}",
|
||||
"m_Guid": ""
|
||||
},
|
||||
"isMainTexture": false,
|
||||
"useTilingAndOffset": false,
|
||||
"m_Modifiable": true,
|
||||
"m_DefaultType": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
|
||||
"m_ObjectId": "3e6a598eb5204f6287316d0d3809b215",
|
||||
"m_Id": 7,
|
||||
"m_DisplayName": "A",
|
||||
"m_SlotType": 1,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "A",
|
||||
"m_StageCapability": 2,
|
||||
"m_Value": 0.0,
|
||||
"m_DefaultValue": 0.0,
|
||||
"m_Labels": []
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot",
|
||||
"m_ObjectId": "4da2c55cfe2e4cf9a6659081084573f0",
|
||||
"m_Id": 0,
|
||||
"m_DisplayName": "Position",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "Position",
|
||||
"m_StageCapability": 1,
|
||||
"m_Value": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_DefaultValue": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_Labels": [],
|
||||
"m_Space": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.SamplerStateMaterialSlot",
|
||||
"m_ObjectId": "5186d854ec8f4e55a948afefab209f95",
|
||||
"m_Id": 3,
|
||||
"m_DisplayName": "Sampler",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "Sampler",
|
||||
"m_StageCapability": 3,
|
||||
"m_BareResource": false
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
|
||||
"m_ObjectId": "54acbcd866754623a9971b65c87753b5",
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_Name": "VertexDescription.Normal",
|
||||
"m_DrawState": {
|
||||
"m_Expanded": true,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"width": 0.0,
|
||||
"height": 0.0
|
||||
}
|
||||
},
|
||||
"m_Slots": [
|
||||
{
|
||||
"m_Id": "bdebc5a760f846638151adf9af8840ef"
|
||||
}
|
||||
],
|
||||
"synonyms": [],
|
||||
"m_Precision": 0,
|
||||
"m_PreviewExpanded": true,
|
||||
"m_DismissedVersion": 0,
|
||||
"m_PreviewMode": 0,
|
||||
"m_CustomColors": {
|
||||
"m_SerializableColors": []
|
||||
},
|
||||
"m_SerializedDescriptor": "VertexDescription.Normal"
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.CategoryData",
|
||||
"m_ObjectId": "5b7e26a64997477b8fceed79720cbe18",
|
||||
"m_Name": "",
|
||||
"m_ChildObjectList": [
|
||||
{
|
||||
"m_Id": "3ba9df8d7b064813844ee1a01ff30884"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot",
|
||||
"m_ObjectId": "5c5be1888bc54fd2b3729d265949c03d",
|
||||
"m_Id": 0,
|
||||
"m_DisplayName": "Base Color",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "BaseColor",
|
||||
"m_StageCapability": 2,
|
||||
"m_Value": {
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 0.5
|
||||
},
|
||||
"m_DefaultValue": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_Labels": [],
|
||||
"m_ColorMode": 0,
|
||||
"m_DefaultColor": {
|
||||
"r": 0.5,
|
||||
"g": 0.5,
|
||||
"b": 0.5,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Vector4MaterialSlot",
|
||||
"m_ObjectId": "65e0744788694ef2a6997127e52e86df",
|
||||
"m_Id": 0,
|
||||
"m_DisplayName": "RGBA",
|
||||
"m_SlotType": 1,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "RGBA",
|
||||
"m_StageCapability": 2,
|
||||
"m_Value": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0,
|
||||
"w": 0.0
|
||||
},
|
||||
"m_DefaultValue": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0,
|
||||
"w": 0.0
|
||||
},
|
||||
"m_Labels": []
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 2,
|
||||
"m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalUnlitSubTarget",
|
||||
"m_ObjectId": "82a2f491e31c4a83a8bfa01a377c3b68"
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.PropertyNode",
|
||||
"m_ObjectId": "8346d6ed11034b1785db95ef2e8bf371",
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_Name": "Property",
|
||||
"m_DrawState": {
|
||||
"m_Expanded": true,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": 397.9999694824219,
|
||||
"y": -323.3333435058594,
|
||||
"width": 166.66665649414063,
|
||||
"height": 33.99998474121094
|
||||
}
|
||||
},
|
||||
"m_Slots": [
|
||||
{
|
||||
"m_Id": "9314c3adf5944d85aecd153224b0d052"
|
||||
}
|
||||
],
|
||||
"synonyms": [],
|
||||
"m_Precision": 0,
|
||||
"m_PreviewExpanded": true,
|
||||
"m_DismissedVersion": 0,
|
||||
"m_PreviewMode": 0,
|
||||
"m_CustomColors": {
|
||||
"m_SerializableColors": []
|
||||
},
|
||||
"m_Property": {
|
||||
"m_Id": "3ba9df8d7b064813844ee1a01ff30884"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.SampleTexture2DNode",
|
||||
"m_ObjectId": "8d0d097456884c839b0e1bccbd948c83",
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_Name": "Sample Texture 2D",
|
||||
"m_DrawState": {
|
||||
"m_Expanded": true,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": 579.9999389648438,
|
||||
"y": -363.9999694824219,
|
||||
"width": 186.66668701171876,
|
||||
"height": 250.66668701171876
|
||||
}
|
||||
},
|
||||
"m_Slots": [
|
||||
{
|
||||
"m_Id": "65e0744788694ef2a6997127e52e86df"
|
||||
},
|
||||
{
|
||||
"m_Id": "fc04b5e5ba934388a44813680a77fbcc"
|
||||
},
|
||||
{
|
||||
"m_Id": "012c063cd77b4055a5d02d510505e55e"
|
||||
},
|
||||
{
|
||||
"m_Id": "1bd6c17f30d843c5bded4563c487ef31"
|
||||
},
|
||||
{
|
||||
"m_Id": "3e6a598eb5204f6287316d0d3809b215"
|
||||
},
|
||||
{
|
||||
"m_Id": "c81c4d76704d4e9abb6058defef68892"
|
||||
},
|
||||
{
|
||||
"m_Id": "dffb325305ee488f981ffcfee4bbe1fa"
|
||||
},
|
||||
{
|
||||
"m_Id": "5186d854ec8f4e55a948afefab209f95"
|
||||
}
|
||||
],
|
||||
"synonyms": [],
|
||||
"m_Precision": 0,
|
||||
"m_PreviewExpanded": false,
|
||||
"m_DismissedVersion": 0,
|
||||
"m_PreviewMode": 0,
|
||||
"m_CustomColors": {
|
||||
"m_SerializableColors": []
|
||||
},
|
||||
"m_TextureType": 0,
|
||||
"m_NormalMapSpace": 1,
|
||||
"m_EnableGlobalMipBias": true,
|
||||
"m_MipSamplingMode": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Texture2DMaterialSlot",
|
||||
"m_ObjectId": "9314c3adf5944d85aecd153224b0d052",
|
||||
"m_Id": 0,
|
||||
"m_DisplayName": "LowResTexture",
|
||||
"m_SlotType": 1,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "Out",
|
||||
"m_StageCapability": 3,
|
||||
"m_BareResource": false
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot",
|
||||
"m_ObjectId": "95d25e4d952f48c38ba5e62dc3fab9cd",
|
||||
"m_Id": 0,
|
||||
"m_DisplayName": "Tangent",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "Tangent",
|
||||
"m_StageCapability": 1,
|
||||
"m_Value": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_DefaultValue": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_Labels": [],
|
||||
"m_Space": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
|
||||
"m_ObjectId": "b646594906c747a4a535fe5a190c267e",
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_Name": "SurfaceDescription.BaseColor",
|
||||
"m_DrawState": {
|
||||
"m_Expanded": true,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"width": 0.0,
|
||||
"height": 0.0
|
||||
}
|
||||
},
|
||||
"m_Slots": [
|
||||
{
|
||||
"m_Id": "5c5be1888bc54fd2b3729d265949c03d"
|
||||
}
|
||||
],
|
||||
"synonyms": [],
|
||||
"m_Precision": 0,
|
||||
"m_PreviewExpanded": true,
|
||||
"m_DismissedVersion": 0,
|
||||
"m_PreviewMode": 0,
|
||||
"m_CustomColors": {
|
||||
"m_SerializableColors": []
|
||||
},
|
||||
"m_SerializedDescriptor": "SurfaceDescription.BaseColor"
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot",
|
||||
"m_ObjectId": "bdebc5a760f846638151adf9af8840ef",
|
||||
"m_Id": 0,
|
||||
"m_DisplayName": "Normal",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "Normal",
|
||||
"m_StageCapability": 1,
|
||||
"m_Value": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_DefaultValue": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"m_Labels": [],
|
||||
"m_Space": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Texture2DInputMaterialSlot",
|
||||
"m_ObjectId": "c81c4d76704d4e9abb6058defef68892",
|
||||
"m_Id": 1,
|
||||
"m_DisplayName": "Texture",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "Texture",
|
||||
"m_StageCapability": 3,
|
||||
"m_BareResource": false,
|
||||
"m_Texture": {
|
||||
"m_SerializedTexture": "{\"texture\":{\"instanceID\":0}}",
|
||||
"m_Guid": ""
|
||||
},
|
||||
"m_DefaultType": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.UVMaterialSlot",
|
||||
"m_ObjectId": "dffb325305ee488f981ffcfee4bbe1fa",
|
||||
"m_Id": 2,
|
||||
"m_DisplayName": "UV",
|
||||
"m_SlotType": 0,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "UV",
|
||||
"m_StageCapability": 3,
|
||||
"m_Value": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"m_DefaultValue": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"m_Labels": [],
|
||||
"m_Channel": 0
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
|
||||
"m_ObjectId": "e89eafddf99b406dba0daa5373d685ee",
|
||||
"m_Group": {
|
||||
"m_Id": ""
|
||||
},
|
||||
"m_Name": "VertexDescription.Position",
|
||||
"m_DrawState": {
|
||||
"m_Expanded": true,
|
||||
"m_Position": {
|
||||
"serializedVersion": "2",
|
||||
"x": -81.33334350585938,
|
||||
"y": -847.3334350585938,
|
||||
"width": 200.0,
|
||||
"height": 40.66668701171875
|
||||
}
|
||||
},
|
||||
"m_Slots": [
|
||||
{
|
||||
"m_Id": "4da2c55cfe2e4cf9a6659081084573f0"
|
||||
}
|
||||
],
|
||||
"synonyms": [],
|
||||
"m_Precision": 0,
|
||||
"m_PreviewExpanded": true,
|
||||
"m_DismissedVersion": 0,
|
||||
"m_PreviewMode": 0,
|
||||
"m_CustomColors": {
|
||||
"m_SerializableColors": []
|
||||
},
|
||||
"m_SerializedDescriptor": "VertexDescription.Position"
|
||||
}
|
||||
|
||||
{
|
||||
"m_SGVersion": 0,
|
||||
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
|
||||
"m_ObjectId": "fc04b5e5ba934388a44813680a77fbcc",
|
||||
"m_Id": 4,
|
||||
"m_DisplayName": "R",
|
||||
"m_SlotType": 1,
|
||||
"m_Hidden": false,
|
||||
"m_ShaderOutputName": "R",
|
||||
"m_StageCapability": 2,
|
||||
"m_Value": 0.0,
|
||||
"m_DefaultValue": 0.0,
|
||||
"m_Labels": []
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c63d04c1c20ea83498addf7813ae3dc5
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: aedb96845e568d44889723065b993c14, type: 3}
|
||||
m_Name: WLPixelCameraSettings
|
||||
m_EditorClassIdentifier: Assembly-CSharp::WL.PixelArt.WLPixelCameraSettings
|
||||
enabled: 1
|
||||
verboseLog: 0
|
||||
assembleOnMapEnter: 1
|
||||
assembleInLobby: 0
|
||||
pollSeconds: 0.25
|
||||
pixelCameraSystemPrefab: {fileID: 2255326839739188927, guid: e96cffa9d00b6b545adfeb26165952cc,
|
||||
type: 3}
|
||||
rigLayer: 31
|
||||
proxyMode: 0
|
||||
orthoSize: 3.8
|
||||
pixelHeight: 480
|
||||
compensateViewZoom: 1
|
||||
voxelGridMovement: 1
|
||||
subpixelAdjustments: 1
|
||||
followRotation: 1
|
||||
controlGameZoom: 1
|
||||
viewCameraZoom: 1
|
||||
viewCameraInMainStack: 1
|
||||
disableSnapWhileRotating: 1
|
||||
rotationSnapOffDegPerSec: 30
|
||||
rotationSnapResumeSeconds: 0.25
|
||||
mainCameraCullingMask: 0
|
||||
mainCameraPostProcessingOff: 1
|
||||
copyPostProcessingToGameCamera: 1
|
||||
mainCameraSolidBlack: 1
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b6db3e9a69baba4381dc38c3c2c414f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7bcfe795ab749ec4bad536c992cb5e70
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,711 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// PixelCameraRig.cs — Critter 3D Pixel Camera 를 인게임에서 런타임 조립/복원하는 WL 리그
|
||||
//
|
||||
// PD 지시 #814(「Critter 3D Pixel Art Toolkit 으로 도트 게임처럼」) · 발주서 WL-814b §1-3
|
||||
//
|
||||
// ■ 왜 이렇게 만들었나 (실측 근거 — 보고서 표 ①)
|
||||
// · 원본 인게임 카메라는 `Assets/ResWork/Prefabs/Ingame/Main Camera.prefab`(tag MainCamera · fov 60 · 원근)이고
|
||||
// `Assets/Script/Util/RealCamera.cs` 가 **LateUpdate 에서** 트랜스폼을 쓴다. CamStatus 1/2 는
|
||||
// `Vector3.Lerp(transform.position, …)` = **현재 위치에서 보간**이라 누가 카메라 트랜스폼에 되쓰면
|
||||
// 그 값이 다음 프레임의 입력이 된다(피드백 루프). → 리그는 카메라 트랜스폼에 **절대 쓰지 않는다**.
|
||||
// · `RealCamera.Shaking()` 은 `transform.localPosition` 을 쓴다(811gh 셰이크). 원본 카메라를 **재부모화하면
|
||||
// 셰이크 기준이 깨진다** → 재부모화 0. 대신 **원본 카메라의 자식**으로 빈 프록시를 하나 달아
|
||||
// Critter 가 그것을 따라가게 한다(지연 0 · 프레임당 비용 0 · 셰이크도 그대로 미러된다).
|
||||
// · `MyValue.m_RealCamera` 는 `Camera.main.GetComponent<RealCamera>()` 다 → 원본 카메라가 **계속
|
||||
// MainCamera 태그를 달고 enabled 여야** 한다(`Camera.main` 은 활성 카메라만 돌려준다).
|
||||
// · 인게임 UI 캔버스는 **Screen Space - Camera(UICamera)** 이고 `NewGameUI.cs:38` 이 그 UICamera 를
|
||||
// **`Camera.main` 의 URP 카메라 스택에 Overlay 로** 넣는다 → 원본 카메라를 끄면 UI 가 사라진다.
|
||||
// 그래서 원본 카메라는 화면 Base 로 남기고, Critter 뷰 카메라를 같은 스택의 **0번 Overlay** 로 끼운다.
|
||||
// 스택 = [원본 Main Camera(Base · 월드 미렌더)] → [ViewCamera(Overlay · 픽셀 쿼드)] → [UICamera(Overlay · UI)]
|
||||
// · `HUDBase.cs:28,55`(HP 바 · 데미지 숫자)와 `DSUtil.cs:859`·`InGameTouchInfo.cs:37` 은 전부
|
||||
// `Camera.main` 의 투영을 쓴다 → 원본 카메라를 **직교로 바꿔** 픽셀 카메라와 같은 투영을 갖게 한다.
|
||||
//
|
||||
// ■ 리그 구조 (Assemble 이 만든다 · 디스크 에셋 수정 0)
|
||||
// WL_PixelCameraRig = PixelCameraSystem.prefab 인스턴스(루트 이름만 바꿈)
|
||||
// ├─ PixelCameraTransform 프리팹 기본 followed(ChildOfCamera 모드에서는 쓰지 않는다 · 삭제하면
|
||||
// │ Critter 의 `parent.childCount` 권고에서 벗어나므로 그대로 둔다)
|
||||
// └─ PixelCamera 직교 카메라 + PixelCameraManager · 저해상도 RT 로 월드를 그린다
|
||||
// └─ UpscaledDisplay
|
||||
// ├─ QuadCanvas RT 를 붙인 쿼드(UpscaledCanvas) · rigLayer
|
||||
// └─ ViewCamera 직교 · CanvasViewCamera(서브픽셀 보정) · rigLayer 만 그린다
|
||||
// Main Camera (원본 · 트랜스폼 무변경)
|
||||
// └─ WL_PixelFollow 프록시(빈 오브젝트 · localPos 0 · localRot identity)
|
||||
//
|
||||
// ■ C8 롤백
|
||||
// `WLPixelCameraSettings.enabled = 0`(또는 `RuntimeDisabled`) → 다음 틱에 Teardown → 원본 카메라 값
|
||||
// (직교/사이즈/컬링/클리어/배경/near·far/fov/depth/포스트/스택)이 **스냅샷 그대로** 복원되고 리그 오브젝트 0 · RT 해제.
|
||||
//
|
||||
// 🔴 이 파일은 Debug.LogError / Debug.LogException 을 쓰지 않는다(813z · ErrorLogHookManager 팝업).
|
||||
// 🔴 Assets/WL/ 에 .asmdef 를 만들지 말 것.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using PixelCamera;
|
||||
|
||||
namespace WL.PixelArt
|
||||
{
|
||||
/// <summary>Critter 픽셀 카메라 리그의 조립·복원. 정적 · 전용 러너 1개.</summary>
|
||||
public static class PixelCameraRig
|
||||
{
|
||||
public const string RigName = "WL_PixelCameraRig";
|
||||
public const string ProxyName = "WL_PixelFollow";
|
||||
|
||||
// ───────────────────────────────────────── 진단(프로브가 읽는다)
|
||||
public static int Boundaries, Assembled, Restored, SkippedLobby, SkippedNoCam, SkippedNoPrefab, Faults;
|
||||
public static string LastReason = "", LastLog = "";
|
||||
|
||||
/// <summary>지금 리그가 조립돼 있는가.</summary>
|
||||
public static bool IsAssembled { get { return s_rigRoot != null; } }
|
||||
|
||||
/// <summary>조립된 리그의 핵심 참조(프로브 전용).</summary>
|
||||
public static GameObject RigRoot { get { return s_rigRoot; } }
|
||||
public static Camera SourceCamera { get { return s_src; } }
|
||||
public static Camera GameCamera { get { return s_gameCam; } }
|
||||
public static Camera ViewCamera { get { return s_viewCam; } }
|
||||
public static Transform Proxy { get { return s_proxy; } }
|
||||
public static PixelCameraManager Manager { get { return s_mgr; } }
|
||||
|
||||
/// <summary>지금 회전 때문에 스냅이 꺼져 있는가(진단).</summary>
|
||||
public static bool SnapSuspended { get { return s_snapSuspended; } }
|
||||
|
||||
// ───────────────────────────────────────── 내부 상태
|
||||
static Camera s_src;
|
||||
static GameObject s_rigRoot, s_proxyGo;
|
||||
static Transform s_proxy;
|
||||
static Camera s_gameCam, s_viewCam;
|
||||
static PixelCameraManager s_mgr;
|
||||
static UpscaledCanvas s_canvas;
|
||||
static Material s_matInstance;
|
||||
static MeshRenderer s_quadRenderer;
|
||||
static Material s_quadSharedMat;
|
||||
|
||||
static CamSnapshot s_snap;
|
||||
static bool s_faulted;
|
||||
|
||||
static PCActor s_lastPc;
|
||||
static int s_lastMapId = int.MinValue;
|
||||
static float s_nextPoll;
|
||||
|
||||
static bool s_snapSuspended;
|
||||
static float s_snapResumeAt;
|
||||
static Quaternion s_lastSrcRot = Quaternion.identity;
|
||||
static bool s_hasLastRot;
|
||||
|
||||
static WLPixelCameraSettings Cfg { get { return WLPixelCameraSettings.Instance; } }
|
||||
static bool Active { get { return WLPixelCameraSettings.Enabled; } }
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// 틱 (러너가 매 프레임 부른다 · 에디트 모드에서는 프로브가 직접 부를 수 있다)
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>1프레임. (프로브가 별도 어셈블리에서 부르므로 public)</summary>
|
||||
public static void Tick()
|
||||
{
|
||||
if (s_faulted) return;
|
||||
|
||||
// C8 — 기능이 꺼지면 즉시 원상복구.
|
||||
if (!Active) { if (IsAssembled) Teardown("off"); return; }
|
||||
|
||||
try
|
||||
{
|
||||
var cfg = Cfg;
|
||||
UpdateSnapSuspension(cfg);
|
||||
|
||||
float now = Time.unscaledTime;
|
||||
if (now < s_nextPoll) return;
|
||||
s_nextPoll = now + Mathf.Max(0.02f, cfg.pollSeconds);
|
||||
if (cfg.assembleOnMapEnter) PollBoundary(cfg);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
s_faulted = true; Faults++;
|
||||
LastLog = "중단(예외) — " + ex.Message;
|
||||
Log(LastLog); // 🔴 LogError 금지(813z)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>맵 진입/이탈 경계 — 811q EffectWarmup · 811o CameraFramingOverride 와 같은 규칙.</summary>
|
||||
static void PollBoundary(WLPixelCameraSettings cfg)
|
||||
{
|
||||
if (!Application.isPlaying) return; // 에디트 모드 오염 0(프로브는 ProbeAssemble 로 들어온다)
|
||||
|
||||
var pc = MyValue.MyPC;
|
||||
if (DSUtil.CheckNull(pc))
|
||||
{
|
||||
// 맵 이탈 — PC 가 사라졌다. 리그를 걷는다.
|
||||
if (s_lastPc != null && IsAssembled) Teardown("맵 이탈");
|
||||
s_lastPc = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var info = InGameInfo.Ins;
|
||||
if (DSUtil.CheckNull(info)) return; // 인게임 정보가 아직 없다 — 경계를 소비하지 않는다
|
||||
|
||||
int map = MyValue.MyChoiceMapData != null ? MyValue.MyChoiceMapData.n_MapID : int.MinValue;
|
||||
bool pcChanged = !ReferenceEquals(pc, s_lastPc);
|
||||
bool mapChanged = map != s_lastMapId;
|
||||
if (!pcChanged && !mapChanged) return;
|
||||
|
||||
bool lobby = info.Get_GameMode() == eGameMode.Lobby;
|
||||
if (!cfg.assembleInLobby && lobby)
|
||||
{
|
||||
s_lastPc = pc; s_lastMapId = map;
|
||||
Boundaries++; SkippedLobby++;
|
||||
LastReason = "lobby";
|
||||
if (IsAssembled) Teardown("로비 진입");
|
||||
return;
|
||||
}
|
||||
|
||||
var cam = Camera.main;
|
||||
if (cam == null) { SkippedNoCam++; return; } // 경계를 소비하지 않는다 — 다음 폴링에서 다시 본다
|
||||
|
||||
s_lastPc = pc; s_lastMapId = map;
|
||||
Boundaries++;
|
||||
LastReason = pcChanged ? "pc" : ("map " + map);
|
||||
|
||||
if (IsAssembled) Teardown("경계 재조립");
|
||||
Assemble(cfg, cam);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// 조립
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>리그를 조립한다. 성공 시 true.</summary>
|
||||
public static bool Assemble(WLPixelCameraSettings cfg, Camera src)
|
||||
{
|
||||
if (cfg == null || src == null) return false;
|
||||
if (IsAssembled) return true;
|
||||
|
||||
var prefab = cfg.pixelCameraSystemPrefab;
|
||||
if (prefab == null)
|
||||
{
|
||||
SkippedNoPrefab++;
|
||||
LastLog = "PixelCameraSystem 프리팹 미설정 — 조립 안 함(URP.unitypackage 해제 확인)";
|
||||
Log(LastLog);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 이전 잔재(에디트 모드 재실행 등) 제거 — Critter 의 FindAnyObjectByType 가 엉뚱한 걸 잡지 않게.
|
||||
DestroyStrays();
|
||||
|
||||
s_src = src;
|
||||
s_snap.Capture(src);
|
||||
|
||||
// ── 리그 인스턴스. 프리팹이 followed/뷰/캔버스를 이미 배선해 두었으므로 활성 상태로 만들어
|
||||
// Critter Initialize() 의 LogError 경로(부모 없음 · followed null · 뷰/캔버스 못 찾음)를 전부 피한다.
|
||||
// 값 보정은 같은 프레임 안에서 끝나므로(LateUpdate 이전) 잘못된 프레임이 그려지지 않는다.
|
||||
s_rigRoot = Object.Instantiate(prefab);
|
||||
s_rigRoot.name = RigName;
|
||||
s_rigRoot.transform.SetPositionAndRotation(src.transform.position, src.transform.rotation);
|
||||
|
||||
s_mgr = s_rigRoot.GetComponentInChildren<PixelCameraManager>(true);
|
||||
var view = s_rigRoot.GetComponentInChildren<CanvasViewCamera>(true);
|
||||
s_canvas = s_rigRoot.GetComponentInChildren<UpscaledCanvas>(true);
|
||||
if (s_mgr == null || view == null || s_canvas == null)
|
||||
{
|
||||
LastLog = "리그 프리팹 구조가 예상과 다르다 — 조립 취소";
|
||||
Log(LastLog);
|
||||
Teardown("구조 불일치");
|
||||
Faults++;
|
||||
return false;
|
||||
}
|
||||
|
||||
s_gameCam = s_mgr.GetComponent<Camera>();
|
||||
s_viewCam = view.GetComponent<Camera>();
|
||||
if (s_gameCam == null || s_viewCam == null)
|
||||
{
|
||||
LastLog = "리그 카메라 컴포넌트 없음 — 조립 취소";
|
||||
Log(LastLog);
|
||||
Teardown("카메라 없음");
|
||||
Faults++;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 🔴 Critter 프리팹의 ViewCamera 에는 AudioListener 가 달려 있다(실측). 원본 Main Camera 의 것과
|
||||
// 겹치면 Unity 가 "There are 2 audio listeners in the scene" 경고를 매 프레임 낸다 → 리그 것은 끈다.
|
||||
var listeners = s_rigRoot.GetComponentsInChildren<AudioListener>(true);
|
||||
for (int i = 0; i < listeners.Length; i++) if (listeners[i] != null) DestroyObj(listeners[i]);
|
||||
|
||||
int layer = Mathf.Clamp(cfg.rigLayer, 0, 31);
|
||||
SetLayerRecursive(s_rigRoot.transform, layer);
|
||||
s_rigRoot.tag = "Untagged";
|
||||
s_gameCam.gameObject.tag = "Untagged";
|
||||
s_viewCam.gameObject.tag = "Untagged";
|
||||
|
||||
// ── 쿼드 머티리얼을 런타임 인스턴스로 갈아 끼운다.
|
||||
// Critter 의 UpscaledCanvas 는 sharedMaterial 에 _LowResTexture 를 직접 SetTexture 한다 →
|
||||
// 그대로 두면 **디스크의 .mat 에셋이 더러워진다**(에디트 모드에서 특히). 인스턴스로 바꾸고
|
||||
// OnEnable 을 다시 돌려 캐시를 갱신한다.
|
||||
s_quadRenderer = s_canvas.GetComponent<MeshRenderer>();
|
||||
if (s_quadRenderer != null && s_quadRenderer.sharedMaterial != null)
|
||||
{
|
||||
s_quadSharedMat = s_quadRenderer.sharedMaterial;
|
||||
s_matInstance = new Material(s_quadSharedMat);
|
||||
s_matInstance.name = s_quadSharedMat.name + " (WL rig runtime)";
|
||||
s_quadRenderer.sharedMaterial = s_matInstance;
|
||||
s_canvas.enabled = false; s_canvas.enabled = true; // OnEnable 재실행 → 인스턴스 캐시
|
||||
}
|
||||
|
||||
// ── 프록시
|
||||
if (cfg.proxyMode == PixelProxyMode.ChildOfCamera)
|
||||
{
|
||||
s_proxyGo = new GameObject(ProxyName);
|
||||
s_proxyGo.layer = layer;
|
||||
s_proxyGo.transform.SetParent(src.transform, false);
|
||||
s_proxyGo.transform.localPosition = Vector3.zero;
|
||||
s_proxyGo.transform.localRotation = Quaternion.identity;
|
||||
s_proxyGo.transform.localScale = Vector3.one;
|
||||
s_proxy = s_proxyGo.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_proxyGo = new GameObject(ProxyName);
|
||||
s_proxyGo.layer = layer;
|
||||
s_proxyGo.transform.SetPositionAndRotation(src.transform.position, src.transform.rotation);
|
||||
var mirror = s_proxyGo.AddComponent<PixelCameraProxyMirror>();
|
||||
mirror.Source = src.transform;
|
||||
s_proxy = s_proxyGo.transform;
|
||||
}
|
||||
|
||||
// ── 저해상도 게임 카메라 = 원본이 보던 월드를 그대로 본다(리그 레이어만 뺀다)
|
||||
s_gameCam.orthographic = true;
|
||||
s_gameCam.nearClipPlane = s_snap.near;
|
||||
s_gameCam.farClipPlane = s_snap.far;
|
||||
s_gameCam.cullingMask = s_snap.cullingMask & ~(1 << layer);
|
||||
s_gameCam.clearFlags = s_snap.clearFlags;
|
||||
s_gameCam.backgroundColor = s_snap.background;
|
||||
s_gameCam.allowHDR = s_snap.allowHDR;
|
||||
s_gameCam.allowMSAA = s_snap.allowMSAA;
|
||||
s_gameCam.useOcclusionCulling = s_snap.occlusionCulling;
|
||||
s_gameCam.depth = s_snap.depth - 1f; // 원본(화면 Base)보다 먼저 RT 를 채운다
|
||||
s_gameCam.targetTexture = null; // Critter 가 만든다
|
||||
|
||||
var srcData = s_src.GetUniversalAdditionalCameraData();
|
||||
var gameData = s_gameCam.GetUniversalAdditionalCameraData();
|
||||
if (gameData != null)
|
||||
{
|
||||
gameData.renderType = CameraRenderType.Base;
|
||||
if (gameData.cameraStack != null) gameData.cameraStack.Clear();
|
||||
if (srcData != null)
|
||||
{
|
||||
gameData.renderShadows = srcData.renderShadows;
|
||||
gameData.volumeLayerMask = srcData.volumeLayerMask;
|
||||
gameData.volumeTrigger = srcData.volumeTrigger;
|
||||
gameData.renderPostProcessing = cfg.copyPostProcessingToGameCamera && srcData.renderPostProcessing;
|
||||
gameData.antialiasing = srcData.antialiasing;
|
||||
gameData.antialiasingQuality = srcData.antialiasingQuality;
|
||||
gameData.stopNaN = srcData.stopNaN;
|
||||
gameData.dithering = srcData.dithering;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Critter 값
|
||||
float aspect = ScreenAspect();
|
||||
int px = Mathf.Max(3, cfg.pixelHeight);
|
||||
s_mgr.FollowedTransform = s_proxy;
|
||||
s_mgr.VoxelGridMovement = cfg.voxelGridMovement;
|
||||
s_mgr.SubpixelAdjustments = cfg.subpixelAdjustments;
|
||||
s_mgr.FollowRotation = cfg.followRotation;
|
||||
s_mgr.resolutionSynchronizationMode = ResolutionSynchronizationMode.SetHeight;
|
||||
s_mgr.GameResolution = new Vector2Int(Mathf.Max(2, Mathf.RoundToInt(px * aspect)), px);
|
||||
s_mgr.ControlGameZoom = cfg.controlGameZoom;
|
||||
s_mgr.GameCameraZoom = GameZoomFor(cfg);
|
||||
s_mgr.ViewCameraZoom = cfg.viewCameraZoom;
|
||||
|
||||
// ── 뷰 카메라 = 픽셀 쿼드만 그린다
|
||||
s_viewCam.orthographic = true;
|
||||
s_viewCam.cullingMask = 1 << layer;
|
||||
s_viewCam.allowHDR = s_snap.allowHDR;
|
||||
s_viewCam.allowMSAA = false;
|
||||
s_viewCam.useOcclusionCulling = false;
|
||||
var viewData = s_viewCam.GetUniversalAdditionalCameraData();
|
||||
if (viewData != null)
|
||||
{
|
||||
viewData.renderPostProcessing = false;
|
||||
viewData.renderShadows = false;
|
||||
viewData.renderType = cfg.viewCameraInMainStack ? CameraRenderType.Overlay : CameraRenderType.Base;
|
||||
if (viewData.cameraStack != null && viewData.renderType == CameraRenderType.Base) viewData.cameraStack.Clear();
|
||||
}
|
||||
if (!cfg.viewCameraInMainStack) s_viewCam.depth = s_snap.depth + 1f;
|
||||
|
||||
// ── 원본 카메라 = 화면 Base 로 남되 월드는 그리지 않는다(투영만 픽셀 카메라와 맞춘다)
|
||||
s_src.orthographic = true;
|
||||
s_src.orthographicSize = cfg.orthoSize;
|
||||
s_src.cullingMask = cfg.mainCameraCullingMask;
|
||||
if (cfg.mainCameraSolidBlack)
|
||||
{
|
||||
s_src.clearFlags = CameraClearFlags.SolidColor;
|
||||
s_src.backgroundColor = Color.black;
|
||||
}
|
||||
if (srcData != null)
|
||||
{
|
||||
if (cfg.mainCameraPostProcessingOff) srcData.renderPostProcessing = false;
|
||||
srcData.renderShadows = false;
|
||||
if (cfg.viewCameraInMainStack && srcData.cameraStack != null)
|
||||
srcData.cameraStack.Insert(0, s_viewCam); // ViewCamera → UICamera 순서
|
||||
}
|
||||
|
||||
Assembled++;
|
||||
s_hasLastRot = false;
|
||||
s_snapSuspended = false;
|
||||
LastLog = "조립 — ortho " + cfg.orthoSize.ToString("0.###")
|
||||
+ " · RT " + s_mgr.GameResolution.x + "×" + s_mgr.GameResolution.y
|
||||
+ " · zoom " + s_mgr.GameCameraZoom.ToString("0.####")
|
||||
+ " · layer " + layer;
|
||||
Log(LastLog);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>SO 값으로 Critter 게임 카메라 줌(= 캔버스 반높이)을 계산한다.</summary>
|
||||
public static float GameZoomFor(WLPixelCameraSettings cfg)
|
||||
{
|
||||
if (cfg == null) return 5f;
|
||||
if (!cfg.compensateViewZoom) return cfg.orthoSize;
|
||||
return cfg.orthoSize / CanvasOnScreenLimit(cfg.pixelHeight);
|
||||
}
|
||||
|
||||
/// <summary>Critter 가 캔버스 가장자리를 넘지 않으려고 쓰는 줌 한계 = 1 − 2/pixelHeight.</summary>
|
||||
public static float CanvasOnScreenLimit(int pixelHeight)
|
||||
{
|
||||
int py = Mathf.Max(3, pixelHeight);
|
||||
return 1f - (2f / py);
|
||||
}
|
||||
|
||||
static float ScreenAspect()
|
||||
{
|
||||
float w = Screen.width, h = Screen.height;
|
||||
if (w <= 0f || h <= 0f) return 9f / 16f;
|
||||
return w / h;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// 복원
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>리그를 걷고 원본 카메라를 스냅샷 그대로 되돌린다.</summary>
|
||||
public static void Teardown(string why)
|
||||
{
|
||||
bool had = s_rigRoot != null || s_proxyGo != null;
|
||||
|
||||
// 원본 카메라 복원 — 스택에서 뷰 카메라부터 뺀다.
|
||||
if (s_src != null)
|
||||
{
|
||||
var srcData = s_src.GetUniversalAdditionalCameraData();
|
||||
if (srcData != null && srcData.cameraStack != null)
|
||||
{
|
||||
srcData.cameraStack.Clear();
|
||||
if (s_snap.stack != null)
|
||||
for (int i = 0; i < s_snap.stack.Length; i++)
|
||||
if (s_snap.stack[i] != null) srcData.cameraStack.Add(s_snap.stack[i]);
|
||||
}
|
||||
s_snap.Restore(s_src);
|
||||
}
|
||||
|
||||
// RT 해제 — Critter 가 만든 것을 우리가 반납한다.
|
||||
if (s_gameCam != null)
|
||||
{
|
||||
var rt = s_gameCam.targetTexture;
|
||||
s_gameCam.targetTexture = null;
|
||||
if (rt != null) { rt.Release(); DestroyObj(rt); }
|
||||
}
|
||||
|
||||
// 쿼드 머티리얼 인스턴스 반납 + 원본 sharedMaterial 복귀(디스크 에셋 무변경 보장)
|
||||
if (s_quadRenderer != null && s_quadSharedMat != null) s_quadRenderer.sharedMaterial = s_quadSharedMat;
|
||||
if (s_matInstance != null) { DestroyObj(s_matInstance); s_matInstance = null; }
|
||||
|
||||
if (s_rigRoot != null) { DestroyObj(s_rigRoot); s_rigRoot = null; }
|
||||
if (s_proxyGo != null) { DestroyObj(s_proxyGo); s_proxyGo = null; }
|
||||
DestroyStrays();
|
||||
|
||||
s_proxy = null; s_gameCam = null; s_viewCam = null; s_mgr = null; s_canvas = null;
|
||||
s_quadRenderer = null; s_quadSharedMat = null;
|
||||
s_snapSuspended = false; s_hasLastRot = false;
|
||||
s_src = null;
|
||||
|
||||
if (had)
|
||||
{
|
||||
Restored++;
|
||||
LastLog = "복원 — " + why;
|
||||
Log(LastLog);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>이름으로 남은 리그·프록시 잔재를 지운다(도메인 리로드·에디트 모드 재실행 대비).</summary>
|
||||
static void DestroyStrays()
|
||||
{
|
||||
var all = Object.FindObjectsByType<PixelCameraManager>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
for (int i = 0; i < all.Length; i++)
|
||||
{
|
||||
if (all[i] == null) continue;
|
||||
var root = all[i].transform.parent != null ? all[i].transform.parent.gameObject : all[i].gameObject;
|
||||
if (root == s_rigRoot) continue;
|
||||
if (root.name == RigName) DestroyObj(root);
|
||||
}
|
||||
|
||||
// 프록시(원본 카메라의 자식)도 이름으로 정리
|
||||
var cam = Camera.main;
|
||||
if (cam != null)
|
||||
{
|
||||
for (int i = cam.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var c = cam.transform.GetChild(i);
|
||||
if (c != null && c.gameObject != s_proxyGo && c.name == ProxyName) DestroyObj(c.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DestroyObj(Object o)
|
||||
{
|
||||
if (o == null) return;
|
||||
if (Application.isPlaying) Object.Destroy(o);
|
||||
else Object.DestroyImmediate(o);
|
||||
}
|
||||
|
||||
static void SetLayerRecursive(Transform t, int layer)
|
||||
{
|
||||
t.gameObject.layer = layer;
|
||||
for (int i = 0; i < t.childCount; i++) SetLayerRecursive(t.GetChild(i), layer);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// 회전 중 스냅 해제 (Critter 문서 권고 · 811o 구도 전환 · 보스 연출)
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
static void UpdateSnapSuspension(WLPixelCameraSettings cfg)
|
||||
{
|
||||
if (s_mgr == null || s_src == null) { s_hasLastRot = false; return; }
|
||||
if (!cfg.disableSnapWhileRotating)
|
||||
{
|
||||
if (s_snapSuspended) { s_mgr.VoxelGridMovement = cfg.voxelGridMovement; s_mgr.SubpixelAdjustments = cfg.subpixelAdjustments; s_snapSuspended = false; }
|
||||
return;
|
||||
}
|
||||
|
||||
var rot = s_src.transform.rotation;
|
||||
float dt = Mathf.Max(1e-4f, Time.unscaledDeltaTime);
|
||||
if (!s_hasLastRot) { s_lastSrcRot = rot; s_hasLastRot = true; return; }
|
||||
|
||||
float degPerSec = Quaternion.Angle(s_lastSrcRot, rot) / dt;
|
||||
s_lastSrcRot = rot;
|
||||
|
||||
float now = Time.unscaledTime;
|
||||
if (degPerSec >= Mathf.Max(0f, cfg.rotationSnapOffDegPerSec))
|
||||
{
|
||||
s_snapResumeAt = now + Mathf.Max(0f, cfg.rotationSnapResumeSeconds);
|
||||
if (!s_snapSuspended)
|
||||
{
|
||||
s_snapSuspended = true;
|
||||
s_mgr.VoxelGridMovement = false;
|
||||
s_mgr.SubpixelAdjustments = false;
|
||||
}
|
||||
}
|
||||
else if (s_snapSuspended && now >= s_snapResumeAt)
|
||||
{
|
||||
s_snapSuspended = false;
|
||||
s_mgr.VoxelGridMovement = cfg.voxelGridMovement;
|
||||
s_mgr.SubpixelAdjustments = cfg.subpixelAdjustments;
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// 프로브 진입점
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>프로브·에디트 모드: 경계 폴링을 건너뛰고 지금 바로 조립한다.</summary>
|
||||
public static bool ProbeAssemble(Camera src)
|
||||
{
|
||||
var cfg = Cfg;
|
||||
if (cfg == null) return false;
|
||||
if (IsAssembled) Teardown("probe 재조립");
|
||||
return Assemble(cfg, src);
|
||||
}
|
||||
|
||||
/// <summary>프로브: 지금 바로 복원한다.</summary>
|
||||
public static void ProbeTeardown() { Teardown("probe"); }
|
||||
|
||||
/// <summary>프로브: 회전 스냅 판정을 1회 돌린다(에디트 모드).</summary>
|
||||
public static void ProbeSnapTick() { var c = Cfg; if (c != null) UpdateSnapSuspension(c); }
|
||||
|
||||
/// <summary>프로브: 원본 카메라 스냅샷을 한 줄로.</summary>
|
||||
public static string SnapshotSummary() { return s_snap.Summary(); }
|
||||
|
||||
/// <summary>프로브: 지금 원본 카메라 상태를 스냅샷과 같은 형식으로.</summary>
|
||||
public static string CurrentSummary(Camera cam) { var s = new CamSnapshot(); s.Capture(cam); return s.Summary(); }
|
||||
|
||||
public static void ResetAll()
|
||||
{
|
||||
Teardown("reset");
|
||||
Boundaries = Assembled = Restored = SkippedLobby = SkippedNoCam = SkippedNoPrefab = Faults = 0;
|
||||
LastReason = LastLog = "";
|
||||
s_faulted = false;
|
||||
s_lastPc = null; s_lastMapId = int.MinValue; s_nextPoll = 0f;
|
||||
}
|
||||
|
||||
static void Log(string msg)
|
||||
{
|
||||
var cfg = Cfg;
|
||||
if (cfg != null && cfg.verboseLog) Debug.Log("[PixelCameraRig] " + msg);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// 러너
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
static GameObject s_runner;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
static void Boot()
|
||||
{
|
||||
if (s_runner != null) return;
|
||||
if (!Active) return; // C8 — 러너 자체가 뜨지 않는다
|
||||
s_runner = new GameObject("[WL814b] PixelCameraRigRunner");
|
||||
s_runner.hideFlags = HideFlags.HideAndDontSave;
|
||||
s_runner.AddComponent<PixelCameraRigRunner>();
|
||||
Object.DontDestroyOnLoad(s_runner);
|
||||
}
|
||||
|
||||
internal static void OnRunnerQuit() { Teardown("quit"); }
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>에디터: Play 진입/이탈 경계에서 반드시 복원한다(에디트 모드 프로브 잔재 0).</summary>
|
||||
[UnityEditor.InitializeOnLoadMethod]
|
||||
static void EditorHook()
|
||||
{
|
||||
UnityEditor.EditorApplication.playModeStateChanged -= OnPlayModeChanged;
|
||||
UnityEditor.EditorApplication.playModeStateChanged += OnPlayModeChanged;
|
||||
}
|
||||
|
||||
static void OnPlayModeChanged(UnityEditor.PlayModeStateChange s)
|
||||
{
|
||||
if (s == UnityEditor.PlayModeStateChange.ExitingEditMode || s == UnityEditor.PlayModeStateChange.ExitingPlayMode)
|
||||
Teardown("playmode " + s);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>매 프레임 리그 틱. Critter(기본 실행 순서 0)보다 먼저 돌아야 회전 스냅 해제가 그 프레임에 반영된다.</summary>
|
||||
[DefaultExecutionOrder(-100)]
|
||||
internal sealed class PixelCameraRigRunner : MonoBehaviour
|
||||
{
|
||||
void Update() { PixelCameraRig.Tick(); }
|
||||
void OnApplicationQuit() { PixelCameraRig.OnRunnerQuit(); }
|
||||
void OnDestroy() { PixelCameraRig.OnRunnerQuit(); }
|
||||
}
|
||||
|
||||
/// <summary>MirrorScript 모드용 프록시. 원본 카메라 트랜스폼을 읽기만 한다(역방향 쓰기 0 = 피드백 루프 0).</summary>
|
||||
[DefaultExecutionOrder(-100)]
|
||||
public sealed class PixelCameraProxyMirror : MonoBehaviour
|
||||
{
|
||||
public Transform Source;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (Source == null) return;
|
||||
transform.SetPositionAndRotation(Source.position, Source.rotation);
|
||||
}
|
||||
|
||||
/// <summary>프로브: 1회 미러(에디트 모드).</summary>
|
||||
public void Mirror() { LateUpdate(); }
|
||||
}
|
||||
|
||||
/// <summary>원본 Camera + URP 데이터의 되돌릴 값 전부.</summary>
|
||||
internal struct CamSnapshot
|
||||
{
|
||||
public bool valid;
|
||||
public bool ortho;
|
||||
public float orthoSize, fov, near, far, depth;
|
||||
public int cullingMask;
|
||||
public CameraClearFlags clearFlags;
|
||||
public Color background;
|
||||
public bool allowHDR, allowMSAA, occlusionCulling;
|
||||
public RenderTexture target;
|
||||
|
||||
public bool hasData;
|
||||
public CameraRenderType renderType;
|
||||
public bool renderPost, renderShadows;
|
||||
public LayerMask volumeMask;
|
||||
public Transform volumeTrigger;
|
||||
public AntialiasingMode aa;
|
||||
public AntialiasingQuality aaQuality;
|
||||
public Camera[] stack;
|
||||
|
||||
public void Capture(Camera c)
|
||||
{
|
||||
valid = c != null;
|
||||
if (!valid) return;
|
||||
ortho = c.orthographic; orthoSize = c.orthographicSize; fov = c.fieldOfView;
|
||||
near = c.nearClipPlane; far = c.farClipPlane; depth = c.depth;
|
||||
cullingMask = c.cullingMask; clearFlags = c.clearFlags; background = c.backgroundColor;
|
||||
allowHDR = c.allowHDR; allowMSAA = c.allowMSAA; occlusionCulling = c.useOcclusionCulling;
|
||||
target = c.targetTexture;
|
||||
|
||||
var d = c.GetUniversalAdditionalCameraData();
|
||||
hasData = d != null;
|
||||
if (!hasData) { stack = null; return; }
|
||||
renderType = d.renderType;
|
||||
renderPost = d.renderPostProcessing;
|
||||
renderShadows = d.renderShadows;
|
||||
volumeMask = d.volumeLayerMask;
|
||||
volumeTrigger = d.volumeTrigger;
|
||||
aa = d.antialiasing;
|
||||
aaQuality = d.antialiasingQuality;
|
||||
|
||||
var st = d.cameraStack;
|
||||
if (st == null) { stack = null; return; }
|
||||
stack = new Camera[st.Count];
|
||||
for (int i = 0; i < st.Count; i++) stack[i] = st[i];
|
||||
}
|
||||
|
||||
public void Restore(Camera c)
|
||||
{
|
||||
if (!valid || c == null) return;
|
||||
c.orthographic = ortho; c.orthographicSize = orthoSize; c.fieldOfView = fov;
|
||||
c.nearClipPlane = near; c.farClipPlane = far; c.depth = depth;
|
||||
c.cullingMask = cullingMask; c.clearFlags = clearFlags; c.backgroundColor = background;
|
||||
c.allowHDR = allowHDR; c.allowMSAA = allowMSAA; c.useOcclusionCulling = occlusionCulling;
|
||||
c.targetTexture = target;
|
||||
|
||||
if (!hasData) return;
|
||||
var d = c.GetUniversalAdditionalCameraData();
|
||||
if (d == null) return;
|
||||
d.renderType = renderType;
|
||||
d.renderPostProcessing = renderPost;
|
||||
d.renderShadows = renderShadows;
|
||||
d.volumeLayerMask = volumeMask;
|
||||
d.volumeTrigger = volumeTrigger;
|
||||
d.antialiasing = aa;
|
||||
d.antialiasingQuality = aaQuality;
|
||||
}
|
||||
|
||||
/// <summary>비교용 한 줄 요약(프로브가 조립 전/후를 문자열로 대조한다).</summary>
|
||||
public string Summary()
|
||||
{
|
||||
if (!valid) return "(none)";
|
||||
var sb = new System.Text.StringBuilder(160);
|
||||
sb.Append("ortho=").Append(ortho ? 1 : 0)
|
||||
.Append(" size=").Append(orthoSize.ToString("0.####"))
|
||||
.Append(" fov=").Append(fov.ToString("0.###"))
|
||||
.Append(" near=").Append(near.ToString("0.###"))
|
||||
.Append(" far=").Append(far.ToString("0.#"))
|
||||
.Append(" depth=").Append(depth.ToString("0.##"))
|
||||
.Append(" mask=").Append(cullingMask)
|
||||
.Append(" clear=").Append((int)clearFlags)
|
||||
.Append(" bg=").Append(background.r.ToString("0.###")).Append(',').Append(background.g.ToString("0.###")).Append(',').Append(background.b.ToString("0.###")).Append(',').Append(background.a.ToString("0.###"))
|
||||
.Append(" hdr=").Append(allowHDR ? 1 : 0)
|
||||
.Append(" msaa=").Append(allowMSAA ? 1 : 0)
|
||||
.Append(" occ=").Append(occlusionCulling ? 1 : 0)
|
||||
.Append(" rt=").Append(target == null ? 0 : 1);
|
||||
if (hasData)
|
||||
{
|
||||
sb.Append(" type=").Append((int)renderType)
|
||||
.Append(" post=").Append(renderPost ? 1 : 0)
|
||||
.Append(" shadow=").Append(renderShadows ? 1 : 0)
|
||||
.Append(" vmask=").Append(volumeMask.value)
|
||||
.Append(" aa=").Append((int)aa)
|
||||
.Append(" stack=").Append(stack == null ? 0 : stack.Length);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 861b4bf4226c29b438df6f1367a332b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// WLPixelCameraSettings.cs — Critter 3D Pixel Camera 리그 값의 SOT (C45)
|
||||
//
|
||||
// PD 지시 #814(「도트 게임처럼」) · 발주서 WL-814b §1-3 (2026-09-10)
|
||||
//
|
||||
// 값의 SOT = Assets/WL/Combat/Settings/Resources/WL/WLPixelCameraSettings.asset
|
||||
// → Resources.Load<WLPixelCameraSettings>("WL/WLPixelCameraSettings") 1회 로드 후 캐시(기존 WL 설정 SO 관례).
|
||||
//
|
||||
// 🔴 C8 — enabled = 0 (또는 RuntimeDisabled = true) 이면 리그가 아예 조립되지 않고,
|
||||
// 이미 조립돼 있으면 다음 틱에 원본 카메라 값이 100 % 복원된다(원본 동작과 동일).
|
||||
//
|
||||
// 🔴 원본 스크립트 0 · 원본 프리팹/씬 디스크 수정 0. 이 SO 와 PixelCameraRig.cs 만이 WL 신규 파일이다.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace WL.PixelArt
|
||||
{
|
||||
/// <summary>Followed 프록시를 어떻게 원본 카메라에 붙일지.</summary>
|
||||
public enum PixelProxyMode
|
||||
{
|
||||
/// <summary>원본 Main Camera 의 자식(localPos 0 · localRot identity). 지연 0 · 프레임당 비용 0 · GC 0. 권장.</summary>
|
||||
ChildOfCamera = 0,
|
||||
/// <summary>독립 오브젝트 + 미러 스크립트([DefaultExecutionOrder(-100)] LateUpdate). 1프레임 지연.</summary>
|
||||
MirrorScript = 1,
|
||||
}
|
||||
|
||||
/// <summary>Critter 픽셀 카메라 리그 값. 전부 여기서만 바꾼다(코드 상수 0).</summary>
|
||||
[CreateAssetMenu(fileName = "WLPixelCameraSettings", menuName = "WL/Pixel Camera Settings", order = 814)]
|
||||
public sealed class WLPixelCameraSettings : ScriptableObject
|
||||
{
|
||||
public const string ResourcesPath = "WL/WLPixelCameraSettings";
|
||||
|
||||
static WLPixelCameraSettings s_cached;
|
||||
static bool s_lookupDone;
|
||||
|
||||
/// <summary>Resources 에서 1회 로드 후 캐시. 없으면 null(= 기능 off).</summary>
|
||||
public static WLPixelCameraSettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!s_lookupDone)
|
||||
{
|
||||
s_lookupDone = true;
|
||||
s_cached = Resources.Load<WLPixelCameraSettings>(ResourcesPath);
|
||||
}
|
||||
return s_cached;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>진단·A/B 전용 런타임 스위치(WLHitFeel.RuntimeDisabled 선례). 에셋을 안 건드리고 이 기능만 끈다.</summary>
|
||||
public static bool RuntimeDisabled;
|
||||
|
||||
/// <summary>이 기능이 살아 있는가(에셋 존재 + enabled + !RuntimeDisabled).</summary>
|
||||
public static bool Enabled
|
||||
{
|
||||
get { var i = Instance; return i != null && i.enabled && !RuntimeDisabled; }
|
||||
}
|
||||
|
||||
/// <summary>테스트용: 캐시를 비워 다음 접근 때 다시 Resources.Load 한다.</summary>
|
||||
public static void ClearCache() { s_cached = null; s_lookupDone = false; }
|
||||
|
||||
// ───────────────────────────────────────── 마스터
|
||||
[Header("마스터 (C8)")]
|
||||
[Tooltip("0 이면 리그를 만들지 않고, 이미 만들었으면 원본 카메라를 100 % 복원한다.")]
|
||||
public bool enabled = true;
|
||||
|
||||
[Tooltip("1 이면 조립/복원 로그를 1줄씩 남긴다. LogError 는 쓰지 않는다(813z).")]
|
||||
public bool verboseLog = false;
|
||||
|
||||
// ───────────────────────────────────────── 조립 경계
|
||||
[Header("조립 경계 (811q EffectWarmup / 811o CameraFramingOverride 와 같은 판정)")]
|
||||
[Tooltip("맵 진입 경계(메인 PC 교체 또는 맵 ID 변경)에서 자동 조립한다. 0 이면 프로브만 조립할 수 있다.")]
|
||||
public bool assembleOnMapEnter = true;
|
||||
|
||||
[Tooltip("로비에서도 조립할지. 기본 0 = 인게임 맵에서만.")]
|
||||
public bool assembleInLobby = false;
|
||||
|
||||
[Tooltip("경계 폴링 주기(초).")]
|
||||
public float pollSeconds = 0.25f;
|
||||
|
||||
// ───────────────────────────────────────── 리그 원본
|
||||
[Header("Critter 리그")]
|
||||
[Tooltip("Assets/3DPixelCamera/URP/PixelCameraSystem.prefab (URP.unitypackage 해제로 생긴 프리팹).")]
|
||||
public GameObject pixelCameraSystemPrefab;
|
||||
|
||||
[Tooltip("리그 전용 레이어 인덱스. 게임 카메라는 이 레이어를 빼고, 뷰 카메라는 이 레이어만 그린다. 프로젝트 미명명 레이어를 쓴다(TagManager 수정 0).")]
|
||||
[Range(0, 31)] public int rigLayer = 31;
|
||||
|
||||
[Tooltip("프록시 방식. ChildOfCamera = 원본 카메라의 자식(지연 0 · 권장).")]
|
||||
public PixelProxyMode proxyMode = PixelProxyMode.ChildOfCamera;
|
||||
|
||||
// ───────────────────────────────────────── 투영·해상도
|
||||
[Header("직교 투영 · 픽셀 해상도")]
|
||||
[Tooltip("원본 Main Camera 에 적용할 orthographicSize(= 화면 세로 절반의 월드 단위). "
|
||||
+ "기본 3.8 = 원근 fov 60 · 카메라 거리 6.58 m 의 반높이(tan30° × 6.58).")]
|
||||
[Range(1f, 12f)] public float orthoSize = 3.8f;
|
||||
|
||||
[Tooltip("저해상도 RT 의 세로 픽셀 수(SetHeight). 가로는 화면 비율로 자동(9:16 · 480 → 270×480).")]
|
||||
[Range(60, 1080)] public int pixelHeight = 480;
|
||||
|
||||
[Tooltip("Critter 뷰 카메라가 캔버스 가장자리를 넘지 않으려고 (1 − 2/pixelHeight) 만큼 줌아웃하는 것을 보정한다. "
|
||||
+ "1 이면 GameCameraZoom = orthoSize / (1 − 2/pixelHeight) 로 올려 화면 매핑을 orthoSize 와 정확히 맞춘다.")]
|
||||
public bool compensateViewZoom = true;
|
||||
|
||||
// ───────────────────────────────────────── Critter 값
|
||||
[Header("Critter PixelCameraManager 값")]
|
||||
[Tooltip("픽셀 격자(voxel grid) 스냅. 정지 물체의 픽셀이 떨리지 않게 한다.")]
|
||||
public bool voxelGridMovement = true;
|
||||
|
||||
[Tooltip("서브픽셀 보정. 격자 스냅의 뚝뚝 끊김을 뷰 카메라 오프셋으로 되돌린다.")]
|
||||
public bool subpixelAdjustments = true;
|
||||
|
||||
[Tooltip("followed 트랜스폼의 회전도 따라간다.")]
|
||||
public bool followRotation = true;
|
||||
|
||||
[Tooltip("Critter 가 게임 카메라의 orthographicSize 를 직접 제어한다.")]
|
||||
public bool controlGameZoom = true;
|
||||
|
||||
[Tooltip("뷰 카메라 줌(−1~1). 1 = 캔버스를 화면에 꽉 채운다.")]
|
||||
[Range(-1f, 1f)] public float viewCameraZoom = 1f;
|
||||
|
||||
[Tooltip("뷰 카메라를 원본 Main Camera 의 URP 카메라 스택에 Overlay 로 끼운다(권장). "
|
||||
+ "0 이면 Base 로 두고 depth 를 원본보다 1 높인다.")]
|
||||
public bool viewCameraInMainStack = true;
|
||||
|
||||
// ───────────────────────────────────────── 회전 중 스냅 해제
|
||||
[Header("회전 중 스냅 해제 (Critter 문서 권고)")]
|
||||
[Tooltip("카메라가 빠르게 돌 때 격자 스냅·서브픽셀 보정을 잠시 끈다(811o 구도 전환 · 보스 연출).")]
|
||||
public bool disableSnapWhileRotating = true;
|
||||
|
||||
[Tooltip("이 각속도(도/초)를 넘으면 회전 중으로 본다.")]
|
||||
public float rotationSnapOffDegPerSec = 30f;
|
||||
|
||||
[Tooltip("회전이 멎고 이 시간(초)이 지나면 스냅을 다시 켠다.")]
|
||||
public float rotationSnapResumeSeconds = 0.25f;
|
||||
|
||||
// ───────────────────────────────────────── 원본 카메라 처리
|
||||
[Header("원본 Main Camera 처리 (MainCamera 태그·RealCamera·AudioListener 전부 유지)")]
|
||||
[Tooltip("원본 카메라가 그릴 레이어. 기본 0 = 월드를 그리지 않는다(인게임 UI 캔버스는 UICamera Overlay 가 그린다).")]
|
||||
public int mainCameraCullingMask = 0;
|
||||
|
||||
[Tooltip("원본 카메라의 포스트프로세싱을 끈다(픽셀 결과를 다시 후처리하지 않게). 게임 카메라 쪽에서 처리한다.")]
|
||||
public bool mainCameraPostProcessingOff = true;
|
||||
|
||||
[Tooltip("원본 카메라의 포스트프로세싱 설정을 저해상도 게임 카메라로 복사한다(블룸 등이 픽셀 해상도로 들어간다).")]
|
||||
public bool copyPostProcessingToGameCamera = true;
|
||||
|
||||
[Tooltip("원본 카메라의 배경을 단색 검정으로 바꾼다(스카이박스 클리어 비용 제거). 복원 시 원값으로 되돌린다.")]
|
||||
public bool mainCameraSolidBlack = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aedb96845e568d44889723065b993c14
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue