Project_WL/AgentScripts/WL816f_Cmp.cs

129 lines
6.8 KiB
C#
Raw Normal View History

[WL-816f] 바닥을 데모와 일치 — 잔디 단색 + 풀 대비↓ + 밀도 2.5→1.8 + 밭 칸 표시 톤↓ (#816) PD 「내가 실행할 때는 전혀 풀밭이 아니야 · 바닥이 완전히 같은 느낌이 나도록」 ■ ① PD 실행 경로 실측 = 훅은 실제로 돈다(버그 아님) InGame 활성 + Level01 Additive 재현: 머티리얼 1,575 렌더러 교체 · 풀 생성 · ReferenceLook on · 콘솔 error 0. 「안 나온다」가 아니라 「데모와 전혀 다르게 보인다」였다. 다만 이 경로에서만 생기는 실측 차이 2가지를 찾아 보고에 적었다 (세이브 파일이 활성 씬 이름으로 갈린다 · RenderSettings 가 InGame 소유). ■ ② 바닥 3요소 (같은 화각·같은 거리 캡처로 판정) 체크무늬 : 잔디 타일 텍스처는 단색(#A0E4A2) — 격자 0. 밭(Soil)의 칸 표시는 게임 기능이라 남기고 **색만** 데모 톤으로(soilTint·soilCheckerContrast). 바닥 색 : #AFEDAE → #A0E4A2 (화면색 평균 데모 #94BE81 ↔ 우리 #9AC37E) 풀 색 : 새 복사본 Farm_Grass_Demo.mat (_DiffuseColor #A6E39F · _ShadowDiffuseColor #95CC8F) → 풀이 바닥과 같은 색으로 깔려 「카펫」이 사라진다(에지% 8.09 → 1.96 · 데모 1.79) 밀도 : 2.5 → 1.8 (6.25 → 3.24 개/㎡) 🔴 Assets/FarmingIsland/** 0줄 · Assets/Script/** 0줄 · 3DPixelArtEnvironment 0줄 · ProjectSettings 0줄 · 전역 URP/품질 0. 되돌리기 = enabled_ = 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 05:19:39 +00:00
// WL-816f §2 — 「같은 화각·같은 거리」 바닥 비교용 렌더.
// 표준 바닥 카메라 = 직교 size 5 · euler(30,60,0) · 1080×1920 (814r/816a/816e 화각과 같은 방향)
// 데모는 에디트 모드에서 인스턴싱을 직접 발행해 그린다(데모 씬 Play 금지 · §9).
public static class WL816f_Cmp
{
public const string Dir = "Screenshots_WL/WL816f/";
public const int W = 1080, H = 1920;
// ── 데모 바닥 ──────────────────────────────────────────────────────
public static void Demo()
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/3DPixelArtEnvironment/Demo/Demo.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
var sb = new System.Text.StringBuilder();
// 평평한 풀밭 지점을 찾는다(경사가 작고 1층 스플랫이 지배적인 곳)
var terr = UnityEngine.Object.FindFirstObjectByType<UnityEngine.Terrain>();
UnityEngine.Vector3 spot = new UnityEngine.Vector3(130f, 0f, 90f);
if (terr != null)
{
var td = terr.terrainData;
float best = 999f;
for (float x = 40f; x < 180f; x += 10f)
for (float z = 40f; z < 180f; z += 10f)
{
float u = x / td.size.x, v = z / td.size.z;
var nrm = td.GetInterpolatedNormal(u, v);
float slope = 1f - nrm.y;
var c = td.alphamapTextures[0].GetPixelBilinear(u, v);
if (c.r < 0.9f) continue; // 1층(풀)이 지배적인 곳만
if (slope < best) { best = slope; spot = new UnityEngine.Vector3(x, td.GetInterpolatedHeight(u, v) + terr.transform.position.y, z); }
}
sb.AppendLine("데모 바닥 지점 " + spot.ToString("F2") + " slope=" + best.ToString("F4"));
}
var cam = GroundCam(spot, 6f);
int n = WL816f_Inst.Publish(sb);
Shoot(cam, Dir + "x_demo_ground.png", sb);
// 넓은 화각(ortho 10)도 하나
cam = GroundCam(spot, 10f);
WL816f_Inst.Publish(sb);
Shoot(cam, Dir + "x_demo_wide.png", sb);
sb.AppendLine("데모 인스턴싱 구성 " + n);
System.IO.File.WriteAllText("AgentScripts/WL816f_DEMO.txt", sb.ToString());
UnityEngine.Debug.Log(sb.ToString());
}
/// <summary>표준 바닥 카메라 — 지점 spot 을 데모 화각으로 본다.</summary>
public static UnityEngine.Camera GroundCam(UnityEngine.Vector3 spot, float size)
{
var go = UnityEngine.GameObject.Find("~WL816fGroundCam");
if (go == null) { go = new UnityEngine.GameObject("~WL816fGroundCam"); go.hideFlags = UnityEngine.HideFlags.DontSave; }
var c = go.GetComponent<UnityEngine.Camera>();
if (c == null) c = go.AddComponent<UnityEngine.Camera>();
c.orthographic = true; c.orthographicSize = size;
c.nearClipPlane = 0.3f; c.farClipPlane = 500f;
c.clearFlags = UnityEngine.CameraClearFlags.SolidColor;
c.backgroundColor = new UnityEngine.Color(0.192f, 0.302f, 0.475f, 1f);
c.cullingMask = ~0; c.depth = -100f;
var rot = UnityEngine.Quaternion.Euler(30f, 60f, 0f);
go.transform.rotation = rot;
go.transform.position = spot - rot * UnityEngine.Vector3.forward * 60f;
if (go.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() == null)
go.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
return c;
}
public static void Shoot(UnityEngine.Camera cam, string path, System.Text.StringBuilder sb)
{
if (cam == null) { if (sb != null) sb.AppendLine("카메라 없음 " + path); return; }
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var prevT = cam.targetTexture; var prevA = UnityEngine.RenderTexture.active;
cam.targetTexture = rt; cam.Render();
UnityEngine.RenderTexture.active = rt;
var tex = new UnityEngine.Texture2D(W, H, UnityEngine.TextureFormat.RGB24, false);
tex.ReadPixels(new UnityEngine.Rect(0, 0, W, H), 0, 0); tex.Apply();
System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex));
UnityEngine.RenderTexture.active = prevA; cam.targetTexture = prevT;
UnityEngine.Object.DestroyImmediate(tex);
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
WL816f_Inst.Free();
if (sb != null) sb.AppendLine("캡처 " + path);
}
}
/// <summary>에디트 모드에서 InstancesBehaviour 가 그릴 것을 이번 프레임에 직접 발행한다(Play 없이).</summary>
public static class WL816f_Inst
{
static readonly System.Collections.Generic.List<Environment.Instancing.InstancingConfiguration> s_pending
= new System.Collections.Generic.List<Environment.Instancing.InstancingConfiguration>();
public static int Publish(System.Text.StringBuilder sb)
{
int n = 0; long inst = 0;
var bs = UnityEngine.Object.FindObjectsByType<Environment.Instancing.InstancesBehaviour>(
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
for (int i = 0; i < bs.Length; i++)
{
var b = bs[i];
System.Collections.Generic.Dictionary<Environment.Instancing.InstancingSettings,
System.Collections.Generic.List<Environment.Instancing.InstanceData>> data = null;
try { data = b.GetInstanceData(); } catch { continue; }
if (data == null) continue;
var bounds = b.CalculateInstancesBounds();
var l2w = b.transform.localToWorldMatrix; l2w.m03 = 0; l2w.m13 = 0; l2w.m23 = 0;
foreach (var kv in data)
{
if (kv.Value == null || kv.Value.Count == 0) continue;
var cfg = new Environment.Instancing.InstancingConfiguration(kv.Key, kv.Value, "_InstanceData");
cfg.MaterialPropertyBlock.SetMatrix("_LocalToWorld", l2w);
UnityEngine.Graphics.DrawMeshInstancedIndirect(cfg.Mesh, 0, cfg.Material, bounds, cfg.CommandBuffer, 0,
cfg.MaterialPropertyBlock, UnityEngine.Rendering.ShadowCastingMode.Off, false, 0);
n++; inst += kv.Value.Count;
s_pending.Add(cfg);
}
}
if (sb != null) sb.AppendLine(" 인스턴스 " + inst + " (구성 " + n + ")");
return n;
}
public static void Free()
{
for (int i = 0; i < s_pending.Count; i++) s_pending[i].FreeMemory();
s_pending.Clear();
}
}