Merge branch 'wl/gameplay/WL-816h-sky-water'

This commit is contained in:
깃 관리자 2026-09-13 16:16:25 +09:00
commit 3bc5358aaa
30 changed files with 2049 additions and 9 deletions

View File

@ -0,0 +1,6 @@
원본 Assets/WL/Materials/WL_Water_Ocean.mat shader=Shader Graphs/ToonWaterU
복사 Assets/WL/Look/Farm/Materials/Farm_Water_WL_A.mat = Shader Graphs/ToonWaterU
복사 Assets/WL/Look/Farm/Materials/Farm_Water_WL_B.mat = Shader Graphs/ToonWaterU
복사 Assets/WL/Look/Farm/Materials/Farm_Water_WL_C.mat = Shader Graphs/ToonWaterU
FI 원본 물 = Assets/FarmingIsland/Materials/Environments/SimpleWater.mat
SO 배선 완료 — waterMode=1 waterTo=Farm_Water_WL_B skyScopeEnabled=1 skyScenes=Level01,WL_FarmLook,WL_Dungeon01,WL_Dungeon02

View File

@ -0,0 +1,133 @@
// WL-816h — ③ WL 워터 복사본 3단(A/B/C) 만들기 + SO 배선 (에디트 모드)
// 🔴 `Assets/WL/Materials/WL_Water_Ocean.mat` 원본은 **복사만** 한다(0줄 수정).
// 🔴 `Assets/FarmingIsland/**` 0줄.
using UnityEngine;
using UnityEditor;
public static class WL816h_Build
{
const string SrcOcean = "Assets/WL/Materials/WL_Water_Ocean.mat";
const string Dir = "Assets/WL/Look/Farm/Materials/";
const string SO = "Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset";
const string FiWater = "Assets/FarmingIsland/Materials/SimpleWater.mat"; // 확인 후 대체
// ToonWaterU 프로퍼티 참조 이름 (shadergraph 실측)
const string P_Size = "Vector1_07238257334b4a149e675e2451801030";
const string P_FoamDistance = "Vector1_101dc4546b684d40bc2ff2fc59ab43d5";
const string P_FoamScale = "Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f";
const string P_FoamSpeed = "Vector1_3089b6a325a44c1686907af4ee3b0776";
const string P_FoamEdge = "Vector1_34f757bec6b8422b9aef3b9d97117a6e";
const string P_DeepDistance = "Vector1_566e288f42864b8e9432d81fbdb83f38";
const string P_Height = "Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9";
const string P_WaweSpeed = "Vector1_ff7a2780aaa94ddd86e156c4707e39a2";
const string P_Strength = "Vector1_99cc56b5c6fd474082f07f00a6df94f9";
const string P_Speed = "Vector1_8e22a98f75c94b218c49e6c4805e799d";
const string P_Alpha = "Vector1_7090c8ca8ea84e2d85858ae4beb5be38";
const string P_WaterColor = "Color_9af4ad59934f40d1ae6565e6ab22c45e";
const string P_DarkColor = "Color_ca031ae309ff42bdb95f777248fb961d";
const string P_FoamColor = "Color_e1f155248d144786a62fc1585ca21e9a";
const string P_FoamShadow = "Color_2323d69962e04c499c5d5f0925432b55";
public static void Run()
{
var sb = new System.Text.StringBuilder();
var src = AssetDatabase.LoadAssetAtPath<Material>(SrcOcean);
if (src == null) { sb.AppendLine("🔴 원본 없음 " + SrcOcean); Dump(sb); return; }
sb.AppendLine("원본 " + SrcOcean + " shader=" + src.shader.name);
// ── A = WL_Water_Ocean 그대로 (기준) ──────────────────────────
var a = Copy(SrcOcean, Dir + "Farm_Water_WL_A.mat", sb);
// ── B = 데모 톤 (816a 실측 = 데모 Water.mat 의 깊은물/얕은물) ──
var b = Copy(SrcOcean, Dir + "Farm_Water_WL_B.mat", sb);
if (b != null)
{
b.SetColor(P_WaterColor, new Color(0.298f, 0.800f, 1.000f, 1f));
b.SetColor(P_DarkColor, new Color(0.133f, 0.518f, 0.745f, 1f));
b.SetColor(P_FoamShadow, new Color(0.80f, 0.90f, 0.96f, 1f));
b.SetFloat(P_FoamDistance, 3f);
b.SetFloat(P_FoamScale, 36f);
b.SetFloat(P_DeepDistance, 5f);
b.SetFloat(P_Height, 0.12f);
b.SetFloat(P_WaweSpeed, 0.5f);
EditorUtility.SetDirty(b);
}
// ── C = 차분(채도↓ · 파도·거품 작게) ───────────────────────────
var c = Copy(SrcOcean, Dir + "Farm_Water_WL_C.mat", sb);
if (c != null)
{
c.SetColor(P_WaterColor, new Color(0.360f, 0.690f, 0.820f, 1f));
c.SetColor(P_DarkColor, new Color(0.170f, 0.420f, 0.570f, 1f));
c.SetColor(P_FoamShadow, new Color(0.78f, 0.86f, 0.92f, 1f));
c.SetFloat(P_FoamDistance, 2.2f);
c.SetFloat(P_FoamScale, 28f);
c.SetFloat(P_DeepDistance, 7f);
c.SetFloat(P_Height, 0.09f);
c.SetFloat(P_WaweSpeed, 0.4f);
c.SetFloat(P_FoamSpeed, 0.4f);
EditorUtility.SetDirty(c);
}
AssetDatabase.SaveAssets();
// ── FI 원본 물 머티리얼 찾기 (remap 의 from 을 그대로 재사용) ──
Material fiWater = null;
var so = AssetDatabase.LoadAssetAtPath<WL.Look.Farm.WLIslandLookSettings>(SO);
if (so != null && so.materialRemap != null)
foreach (var e in so.materialRemap)
if (e != null && e.from != null && e.from.shader != null
&& e.from.shader.name == "Shader Graphs/Simple Water") fiWater = e.from;
sb.AppendLine("FI 원본 물 = " + (fiWater == null ? "🔴 못 찾음" : AssetDatabase.GetAssetPath(fiWater)));
// ── SO 배선 ───────────────────────────────────────────────────
if (so != null)
{
so.waterFrom = fiWater;
so.waterTo = b; // 1차 기본 = B (3단 비교 뒤 확정)
so.waterMode = 1;
so.skyScopeEnabled = 1;
if (so.skyScenes == null || so.skyScenes.Length < 4)
so.skyScenes = new string[] { "Level01", "WL_FarmLook", "WL_Dungeon01", "WL_Dungeon02" };
EditorUtility.SetDirty(so);
AssetDatabase.SaveAssets();
sb.AppendLine("SO 배선 완료 — waterMode=" + so.waterMode + " waterTo=" + (so.waterTo ? so.waterTo.name : "없음")
+ " skyScopeEnabled=" + so.skyScopeEnabled + " skyScenes=" + string.Join(",", so.skyScenes));
}
else sb.AppendLine("🔴 SO 못 읽음 " + SO);
Dump(sb);
}
/// <summary>3단 중 하나를 SO 에 물린다 (비교 캡처용).</summary>
public static void PickA() { Pick("Farm_Water_WL_A"); }
public static void PickB() { Pick("Farm_Water_WL_B"); }
public static void PickC() { Pick("Farm_Water_WL_C"); }
public static void PickOff() { Pick(null); }
static void Pick(string name)
{
var so = AssetDatabase.LoadAssetAtPath<WL.Look.Farm.WLIslandLookSettings>(SO);
if (so == null) { Debug.Log("[816h] SO 없음"); return; }
if (name == null) { so.waterMode = 0; }
else { so.waterMode = 1; so.waterTo = AssetDatabase.LoadAssetAtPath<Material>(Dir + name + ".mat"); }
EditorUtility.SetDirty(so); AssetDatabase.SaveAssets();
Debug.Log("[816h] 물 = " + (name ?? "지금(FarmingIsland)") + " mode=" + so.waterMode);
}
static Material Copy(string src, string dst, System.Text.StringBuilder sb)
{
if (System.IO.File.Exists(dst)) AssetDatabase.DeleteAsset(dst);
if (!AssetDatabase.CopyAsset(src, dst)) { sb.AppendLine("🔴 복사 실패 " + dst); return null; }
AssetDatabase.ImportAsset(dst);
var m = AssetDatabase.LoadAssetAtPath<Material>(dst);
sb.AppendLine("복사 " + dst + " = " + (m == null ? "null" : m.shader.name));
return m;
}
static void Dump(System.Text.StringBuilder sb)
{
System.IO.File.WriteAllText("AgentScripts/WL816h_BUILD.txt", sb.ToString());
Debug.Log("[816h build]\n" + sb);
}
}

View File

@ -0,0 +1,22 @@
error=6 warning=408 log=1398
--- error 메시지(중복 묶음) ---
×1 PlayFabException: Must be logged in to call this method
PlayFab.PlayFabClientAPI.GetTitleNews (PlayFab.ClientModels.GetTitleNewsRequest request, System.Action`1[T] resultCallba
ServerInfo.Get_News (System.Action`1[T] _act) (at Assets/Script/Server/ServerInfo.cs:428)
DataCheckMgr+<Co_1Min>d__11.MoveNext () (at Assets/Script/Util/DataCheckMgr.cs:38)
×1 NullReferenceException: Object reference not set to an instance of an object
DataCheckMgr+<Co_1Sec>d__13.MoveNext () (at Assets/Script/Util/DataCheckMgr.cs:59)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
×1 NullReferenceException: Object reference not set to an instance of an object
InGameInfo.Set_Init () (at Assets/Script/Info/InGameInfo.cs:46)
InGameInfo+<Start>d__16.MoveNext () (at Assets/Script/Info/InGameInfo.cs:78)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
×1 NullReferenceException: Object reference not set to an instance of an object
ProjectileInfo+<Start>d__7.MoveNext () (at Assets/Script/Info/ProjectileInfo.cs:33)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
×1 NullReferenceException: Object reference not set to an instance of an object
DropItemInfo.Make_DropItem (System.Int32 key, System.Int32 count) (at Assets/Script/Info/DropItemInfo.cs:60)
DropItemInfo.Start () (at Assets/Script/Info/DropItemInfo.cs:24)
×1 NullReferenceException: Object reference not set to an instance of an object
LoadMapMgr.Awake () (at Assets/Script/Ingame/LoadMapMgr.cs:16)

View File

@ -0,0 +1,22 @@
error=6 warning=410 log=4139
--- error 메시지(중복 묶음) ---
×1 NullReferenceException: Object reference not set to an instance of an object
ProjectileInfo+<Start>d__7.MoveNext () (at Assets/Script/Info/ProjectileInfo.cs:33)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
×1 PlayFabException: Must be logged in to call this method
PlayFab.PlayFabClientAPI.GetTitleNews (PlayFab.ClientModels.GetTitleNewsRequest request, System.Action`1[T] resultCallba
ServerInfo.Get_News (System.Action`1[T] _act) (at Assets/Script/Server/ServerInfo.cs:428)
DataCheckMgr+<Co_1Min>d__11.MoveNext () (at Assets/Script/Util/DataCheckMgr.cs:38)
×1 NullReferenceException: Object reference not set to an instance of an object
DataCheckMgr+<Co_1Sec>d__13.MoveNext () (at Assets/Script/Util/DataCheckMgr.cs:59)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
×1 NullReferenceException: Object reference not set to an instance of an object
InGameInfo.Set_Init () (at Assets/Script/Info/InGameInfo.cs:46)
InGameInfo+<Start>d__16.MoveNext () (at Assets/Script/Info/InGameInfo.cs:78)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)
×1 NullReferenceException: Object reference not set to an instance of an object
DropItemInfo.Make_DropItem (System.Int32 key, System.Int32 count) (at Assets/Script/Info/DropItemInfo.cs:60)
DropItemInfo.Start () (at Assets/Script/Info/DropItemInfo.cs:24)
×1 NullReferenceException: Object reference not set to an instance of an object
LoadMapMgr.Awake () (at Assets/Script/Ingame/LoadMapMgr.cs:16)

View File

@ -0,0 +1,58 @@
// WL-816h — 콘솔 error/warning 수와 error 메시지만 뽑아 파일로 (토큰 절약)
using System.Reflection;
using UnityEngine;
public static class WL816h_Console
{
public static void Dump()
{
var t = System.Type.GetType("UnityEditor.LogEntries,UnityEditor");
var sb = new System.Text.StringBuilder();
object[] args = { 0, 0, 0 };
t.GetMethod("GetCountsByType", BindingFlags.Public | BindingFlags.Static).Invoke(null, args);
sb.AppendLine("error=" + args[0] + " warning=" + args[1] + " log=" + args[2]);
int n = (int)t.GetMethod("StartGettingEntries", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
var entryType = System.Type.GetType("UnityEditor.LogEntry,UnityEditor");
var entry = System.Activator.CreateInstance(entryType);
var getEntry = t.GetMethod("GetEntryInternal", BindingFlags.Public | BindingFlags.Static);
var msgF = entryType.GetField("message", BindingFlags.Public | BindingFlags.Instance);
var modeF = entryType.GetField("mode", BindingFlags.Public | BindingFlags.Instance);
var seen = new System.Collections.Generic.Dictionary<string, int>();
for (int i = 0; i < n; i++)
{
object[] a2 = { i, entry };
getEntry.Invoke(null, a2);
int mode = (int)modeF.GetValue(a2[1]);
// Error(1) | Assert(2) | Fatal(0x10) | ScriptingError(0x100) | ScriptingException(0x400) | ScriptCompileError(0x800)
bool isErr = (mode & (1 | 2 | 0x10 | 0x100 | 0x400 | 0x800 | 0x2000)) != 0;
if (!isErr) continue;
string m = (string)msgF.GetValue(a2[1]);
if (m == null) continue;
// 메시지 1줄 + 스택 앞 3줄 (누가 냈는지 보려고)
var lines = m.Split('\n');
var key = new System.Text.StringBuilder(lines[0].Length > 140 ? lines[0].Substring(0, 140) : lines[0]);
for (int k = 1; k < lines.Length && k <= 3; k++)
{
var s = lines[k].Trim();
if (s.Length == 0) continue;
if (s.Length > 120) s = s.Substring(0, 120);
key.Append("\n ").Append(s);
}
string kk = key.ToString();
seen[kk] = seen.ContainsKey(kk) ? seen[kk] + 1 : 1;
}
t.GetMethod("EndGettingEntries", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
sb.AppendLine("--- error 메시지(중복 묶음) ---");
foreach (var kv in seen) sb.AppendLine(" ×" + kv.Value + " " + kv.Key);
if (seen.Count == 0) sb.AppendLine(" (없음)");
System.IO.File.WriteAllText("AgentScripts/WL816h_CONSOLE.txt", sb.ToString());
Debug.Log("[816h console]\n" + sb);
}
public static void Clear()
{
var t = System.Type.GetType("UnityEditor.LogEntries,UnityEditor");
t.GetMethod("Clear", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
}
}

View File

@ -0,0 +1,2 @@
데모 = #647676 → Screenshots_WL/WL816h/x_demo_horizon.png
나란히 = Screenshots_WL/WL816h/d_demo_vs_island.png (좌 데모 / 우 우리 섬 · 같은 화각)

View File

@ -0,0 +1,81 @@
// WL-816h — ⓓ 데모 씬과 나란히 (에디트 모드 렌더 · §9 데모 Play 안 함)
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEditor;
public static class WL816h_Demo
{
const string Dir = "Screenshots_WL/WL816h/";
const int W = 1080, H = 1920;
public static void Run()
{
var sb = new System.Text.StringBuilder();
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/LowPolyFantasyArena/Scenes/LowPolyArena_Demo.unity",
UnityEditor.SceneManagement.OpenSceneMode.Single);
// 수평선이 보이는 화각 — 우리 섬 캡처(b_after_horizon)와 같은 fov·피치
var go = new GameObject("~WL816hDemoCam"); go.hideFlags = HideFlags.DontSave;
var c = go.AddComponent<Camera>();
c.orthographic = false; c.fieldOfView = 55f; c.nearClipPlane = 0.3f; c.farClipPlane = 2000f;
c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f;
go.transform.position = new Vector3(-14f, 8f, -14f);
go.transform.rotation = Quaternion.Euler(4f, 45f, 0f);
go.AddComponent<UniversalAdditionalCameraData>();
sb.AppendLine("데모 = " + Shot(c, Dir + "x_demo_horizon.png"));
Object.DestroyImmediate(go);
Pair(Dir + "x_demo_horizon.png", Dir + "b_after_horizon.png", Dir + "d_demo_vs_island.png");
sb.AppendLine("나란히 = " + Dir + "d_demo_vs_island.png (좌 데모 / 우 우리 섬 · 같은 화각)");
System.IO.File.WriteAllText("AgentScripts/WL816h_DEMO.txt", sb.ToString());
Debug.Log("[816h demo]\n" + sb);
// 다음 작업을 위해 InGame 으로 돌려 둔다(데모 씬 저장 0)
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
}
static string Shot(Camera cam, string path)
{
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var tex = new Texture2D(W, H, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, W, H), 0, 0); tex.Apply();
RenderTexture.active = pA; cam.targetTexture = null;
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
var px = tex.GetPixels32(); long r = 0, g = 0, b = 0;
for (int i = 0; i < px.Length; i += 7) { r += px[i].r; g += px[i].g; b += px[i].b; }
int n = (px.Length + 6) / 7;
Object.DestroyImmediate(tex); rt.Release(); Object.DestroyImmediate(rt);
return "#" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(b / n)).ToString("X2") + " → " + path;
}
static void Pair(string left, string right, string outPath)
{
var a = Load(left); var b = Load(right);
if (a == null || b == null) { Debug.Log("[816h] 나란히 실패 " + left + " / " + right); return; }
int w = a.width + b.width, h = Mathf.Max(a.height, b.height);
var o = new Texture2D(w, h, TextureFormat.RGB24, false);
var fill = new Color32[w * h];
for (int i = 0; i < fill.Length; i++) fill[i] = new Color32(24, 24, 28, 255);
o.SetPixels32(fill);
o.SetPixels32(0, 0, a.width, a.height, a.GetPixels32());
o.SetPixels32(a.width, 0, b.width, b.height, b.GetPixels32());
o.Apply();
System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG());
Object.DestroyImmediate(o); Object.DestroyImmediate(a); Object.DestroyImmediate(b);
}
static Texture2D Load(string p)
{
if (!System.IO.File.Exists(p)) return null;
var t = new Texture2D(2, 2, TextureFormat.RGB24, false);
t.LoadImage(System.IO.File.ReadAllBytes(p));
return t;
}
}

View File

@ -0,0 +1,8 @@
=== ⑥ 기능 무영향 (PD 경로 · 채택 상태) ===
물 : mat=Farm_Water_WL_C · MeshCollider=있음 enabled=True mesh=Plane · MeshFilter=Plane · layer=0 · pos=(0.0, -1.0, 0.0) · scale=(100, 1, 100)
걷기: (0.00, 0.00, 0.00) → (4.24, 0.01, 4.24) · 이동 6.00 m · grounded=True
풀(확장 전): 타일 5 · 인스턴스 680 · 드로우콜 2 · 삼각형 6111 · 제외점 358 · 밀도 1.80(=3.24개/㎡) · 섬 타일 5
풀(1칸 잠금): 타일 4 · 인스턴스 602 · 드로우콜 2 · 삼각형 5409 · 제외점 240 · 밀도 1.80(=3.24개/㎡)
풀(다시 열기): 타일 5 · 인스턴스 699 · 드로우콜 2 · 삼각형 6282 · 제외점 339 · 밀도 1.80(=3.24개/㎡) · 재생성 2회
최종 = Screenshots_WL/WL816h/b_final_pd_path.png
SkyScope held=True · held(Level01) → amb=Skybox light=(0.212,0.227,0.259) skybox=Default-Skybox fog=False refl=Skybox sun=DirectionalLight

115
AgentScripts/WL816h_Func.cs Normal file
View File

@ -0,0 +1,115 @@
// WL-816h — ⑥ 기능 무영향 실측 (걷기 · 섬 확장 · 물 콜라이더) + 최종 PD 경로 캡처
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Rendering.Universal;
using FIIsland = CryingSnow.FarmingIsland.Island;
public static class WL816h_Func
{
public static void Open()
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
}
public static void Start()
{
var go = GameObject.Find("~WL816hFunc");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816hFunc");
go.AddComponent<WL816h_FuncRunner>();
}
}
public class WL816h_FuncRunner : MonoBehaviour
{
static System.Text.StringBuilder sb;
static void L(string s) { sb.AppendLine(s); }
void Start() { StartCoroutine(Co()); }
IEnumerator Co()
{
sb = new System.Text.StringBuilder();
L("=== ⑥ 기능 무영향 (PD 경로 · 채택 상태) ===");
var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive);
while (op != null && !op.isDone) yield return null;
for (int i = 0; i < 7; i++) yield return new WaitForSeconds(1f);
// 물 — 콜라이더·메시가 그대로인가 (머티리얼만 바꿨다)
Renderer water = null;
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
if (water != null)
{
var mc = water.GetComponent<MeshCollider>();
var mf = water.GetComponent<MeshFilter>();
L("물 : mat=" + water.sharedMaterial.name + " · MeshCollider=" + (mc != null ? ("있음 enabled=" + mc.enabled + " mesh=" + (mc.sharedMesh ? mc.sharedMesh.name : "없음")) : "없음")
+ " · MeshFilter=" + (mf != null && mf.sharedMesh ? mf.sharedMesh.name : "없음")
+ " · layer=" + water.gameObject.layer + " · pos=" + water.transform.position.ToString("F1")
+ " · scale=" + water.transform.localScale.ToString("F0"));
}
// 걷기 — FI 플레이어의 CharacterController 로 대각선 6 m
var cc = Object.FindFirstObjectByType<CharacterController>(FindObjectsInactive.Exclude);
if (cc != null)
{
var p0 = cc.transform.position;
var dir = new Vector3(1f, 0f, 1f).normalized;
float moved = 0f;
for (int i = 0; i < 120 && moved < 6f; i++)
{ cc.Move(dir * 0.05f + Vector3.down * 0.05f); moved += 0.05f; yield return null; }
var p1 = cc.transform.position;
L("걷기: " + p0.ToString("F2") + " → " + p1.ToString("F2")
+ " · 이동 " + Vector3.Distance(new Vector3(p0.x, 0, p0.z), new Vector3(p1.x, 0, p1.z)).ToString("F2") + " m"
+ " · grounded=" + cc.isGrounded);
}
else L("걷기: CharacterController 없음(세이브 상태에 따라 없을 수 있다)");
// 섬 확장 — 타일 하나 잠갔다 다시 열기 (풀이 따라오나)
int before = WL.Look.Farm.WLIslandGrass.LastLog != null ? 1 : 0;
var islands = Object.FindObjectsByType<FIIsland>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
L("풀(확장 전): " + WL.Look.Farm.WLIslandGrass.LastLog + " · 섬 타일 " + islands.Length);
FIIsland target = null;
foreach (var isl in islands) if (isl != null && isl.IsUnlocked && isl.gameObject.activeInHierarchy) target = isl;
if (target != null)
{
target.gameObject.SetActive(false);
yield return new WaitForSeconds(2f);
L("풀(1칸 잠금): " + WL.Look.Farm.WLIslandGrass.LastLog);
target.gameObject.SetActive(true);
yield return new WaitForSeconds(3f);
L("풀(다시 열기): " + WL.Look.Farm.WLIslandGrass.LastLog + " · 재생성 " + WL.Look.Farm.WLIslandLook.GrassRebuilds + "회");
}
// 최종 PD 경로 캡처
Camera live = null;
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue;
if (c.name.StartsWith("~WL816h")) continue;
if (live == null || c.depth > live.depth) live = c;
}
L("최종 = " + Shot(live, "Screenshots_WL/WL816h/b_final_pd_path.png"));
L("SkyScope held=" + WL.Look.Farm.WLSkyScope.Held + " · " + WL.Look.Farm.WLSkyScope.LastLog);
System.IO.File.WriteAllText("AgentScripts/WL816h_FUNC.txt", sb.ToString());
Debug.Log("[816h func]\n" + sb);
}
static string Shot(Camera cam, string path)
{
if (cam == null) return "카메라 없음";
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(1080, 1920, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; var pA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var tex = new Texture2D(1080, 1920, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, 1080, 1920), 0, 0); tex.Apply();
RenderTexture.active = pA; cam.targetTexture = pT;
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
Object.DestroyImmediate(tex); rt.Release(); Object.DestroyImmediate(rt);
return path;
}
}

View File

@ -0,0 +1,24 @@
=== WL-816h 지금 상태 (PD 경로 = InGame 활성 + Level01 Additive) ===
t0 활성씬=InGame / RenderSettings: amb=Skybox light=(0.212,0.227,0.259) sky=(0.212,0.227,0.259) I=1 skybox=Default-Skybox/Skybox/Procedural fog=False refl=Skybox/1 sun=없음
Load_Map 예외(=로그인 없이는 못 탄다): NullReferenceException
→ SceneInfo.Load_AddScene 과 같은 호출로 대체: LoadSceneAsync("Level01", Additive)
t+6s 활성씬=InGame sceneCount=2
🔴 RenderSettings: amb=Flat light=(0.217,0.228,0.250) sky=(0.217,0.228,0.250) I=1 skybox=Default-Skybox/Skybox/Procedural fog=False refl=Skybox/1 sun=DirectionalLight
IslandLook: 렌더러 1575 light=1 refLook=True
RefLook : applied=True log=Ⓐ17 Ⓑ6mat/md0.12 Ⓒ0.30 Ⓓoff
CAM Main Camera scene=InGame live=False depth=5 tag=MainCamera clear=Skybox 🔴post=True
CAM MainCamera scene=Level01 live=True depth=-1 tag=MainCamera clear=Skybox 🔴post=True
→ 보이는 카메라 = MainCamera(Level01)
Camera.main = MainCamera(Level01)
Volume Global Volume global=True w=1 prio=0 profile=GlobalVolumeProfile_Blind
WATER obj=Water layer=0 mat=Farm_SimpleWater_Demo shader=Shader Graphs/Simple Water queue=2999 bounds=(1000, 0, 1000) pos=(0.0, -1.0, 0.0)
WATER obj=WateringCan layer=0 mat=Farm_Palette_ToonTex shader=Shader Graphs/Toon queue=2000 bounds=(1, 1, 1) pos=(0.8, 1.1, 0.0)
WATER obj=WaterParticle layer=0 mat=WaterCan shader=Universal Render Pipeline/Particles/Unlit queue=2450 bounds=(0, 0, 0) pos=(0.0, 0.0, 0.0)
URP asset = URP-Performant opaqueTex=True depthTex=True msaa=1
하늘(섬) = #7998B7 → Screenshots_WL/WL816h/a_now_sky.png
섬 화면 = #6FAFD1 → Screenshots_WL/WL816h/a_now_island.png
물 근접 = #80B7C6 → Screenshots_WL/WL816h/a_now_water.png

View File

@ -0,0 +1,14 @@
=== ② 「파란 하늘」의 정체 + 섬 나간 뒤 오염 (고치기 전) ===
보이는 카메라 = MainCamera fov=60 euler=(45, 0, 0) pos=(0.0, 15.6, -15.6)
물 렌더러 = Water mat=Farm_SimpleWater_Demo shader=Shader Graphs/Simple Water
물 ON = 상단10%=#5BB5FE 하단10%=#5BB5FE → Screenshots_WL/WL816h/a1_water_on.png
물 OFF = 상단10%=#5E4D68 하단10%=#5C4C66 → Screenshots_WL/WL816h/a2_water_off.png
섬 내리기 전 : amb=Flat light=(0.217,0.228,0.250) skySrc=(0.217,0.228,0.250) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=DirectionalLight
섬 내린 뒤 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
InGame 원본 : amb=Skybox light=(0.212,0.227,0.259) skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음 (씬 파일 실측)
🔴 오염 = 없음(오염 0)
전투 맵(Map_C01) 올린 뒤 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
🔴 오염 = 없음(오염 0)
전투맵 하늘 = 상단10%=#586773 하단10%=#4D3B1E → Screenshots_WL/WL816h/f0_before_battle_sky.png

View File

@ -0,0 +1,209 @@
// WL-816h — ① 지금 상태 실측 (PD 실행 경로 · 하늘 · 물)
// PD 경로 재현 = InGame 을 활성 씬으로 Play → Level01 을 Additive (816f 와 같은 호출)
// 로그인은 워커 금지(§9)라 못 탄다 → 구조만 같게.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
public static class WL816h_Probe
{
public const string Dir = "Screenshots_WL/WL816h/";
public const int W = 1080, H = 1920;
public static void Open()
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
Debug.Log("[816h] InGame 열림");
}
public static void Start()
{
var go = GameObject.Find("~WL816hProbe");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816hProbe");
go.AddComponent<WL816h_ProbeRunner>();
Debug.Log("[816h] 러너 시작");
}
// ── 에디트 모드: 레퍼런스(아레나·데모) 씬의 하늘을 그대로 읽고 찍는다 ──
public static void RefScenes()
{
var sb = new System.Text.StringBuilder();
Ref(sb, "Assets/WL/Look/Arena/Scenes/WL_ArenaProto.unity", "arena");
Ref(sb, "Assets/LowPolyFantasyArena/Scenes/LowPolyArena_Demo.unity", "demo");
System.IO.File.WriteAllText("AgentScripts/WL816h_REF.txt", sb.ToString());
Debug.Log("[816h ref]\n" + sb);
}
static void Ref(System.Text.StringBuilder sb, string path, string tag)
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(path, UnityEditor.SceneManagement.OpenSceneMode.Single);
sb.AppendLine("### " + tag + " " + path);
sb.AppendLine(WL816h_Util.SkyLine());
var cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Include, FindObjectsSortMode.None);
foreach (var c in cams)
{
var ac = c.GetComponent<UniversalAdditionalCameraData>();
sb.AppendLine(" CAM " + c.name + " active=" + c.gameObject.activeInHierarchy + " en=" + c.enabled
+ " ortho=" + c.orthographic + (c.orthographic ? (" size=" + c.orthographicSize) : (" fov=" + c.fieldOfView))
+ " clear=" + c.clearFlags + " post=" + (ac == null ? "noACD" : ac.renderPostProcessing.ToString()));
}
var vols = Object.FindObjectsByType<Volume>(FindObjectsInactive.Include, FindObjectsSortMode.None);
sb.AppendLine(" Volume 수 = " + vols.Length);
// 하늘만 보이는 카메라로 찍는다(수평선 위)
var cam = WL816h_Util.SkyCam();
sb.AppendLine(" 하늘 화면색 = " + WL816h_Util.Shot(cam, Dir + "ref_sky_" + tag + ".png", true));
Object.DestroyImmediate(cam.gameObject);
}
}
public static class WL816h_Util
{
public static string SkyLine()
{
return "RenderSettings: amb=" + RenderSettings.ambientMode + " light=" + F(RenderSettings.ambientLight)
+ " sky=" + F(RenderSettings.ambientSkyColor) + " I=" + RenderSettings.ambientIntensity
+ " skybox=" + (RenderSettings.skybox ? RenderSettings.skybox.name + "/" + RenderSettings.skybox.shader.name : "없음")
+ " fog=" + RenderSettings.fog + " refl=" + RenderSettings.defaultReflectionMode
+ "/" + RenderSettings.reflectionIntensity
+ " sun=" + (RenderSettings.sun ? RenderSettings.sun.name : "없음");
}
public static string F(Color c) { return "(" + c.r.ToString("F3") + "," + c.g.ToString("F3") + "," + c.b.ToString("F3") + ")"; }
/// <summary>수평선 위만 잡는 카메라 — 화면의 대부분이 하늘이다.</summary>
public static Camera SkyCam()
{
var go = new GameObject("~WL816hSkyCam"); go.hideFlags = HideFlags.DontSave;
var c = go.AddComponent<Camera>();
c.orthographic = false; c.fieldOfView = 50f;
c.nearClipPlane = 0.3f; c.farClipPlane = 2000f;
c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f;
go.transform.position = new Vector3(0f, 40f, 0f);
go.transform.rotation = Quaternion.Euler(-16f, 30f, 0f); // 위를 본다 = 하늘만
if (go.GetComponent<UniversalAdditionalCameraData>() == null) go.AddComponent<UniversalAdditionalCameraData>();
return c;
}
/// <summary>오프스크린 렌더 → PNG. 반환 = 화면 평균색(#RRGGBB).</summary>
public static string Shot(Camera cam, string path, bool wantAvg)
{
if (cam == null) return "카메라 없음";
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(WL816h_Probe.W, WL816h_Probe.H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var prevT = cam.targetTexture; var prevA = RenderTexture.active;
cam.targetTexture = rt; cam.Render();
RenderTexture.active = rt;
var tex = new Texture2D(WL816h_Probe.W, WL816h_Probe.H, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, WL816h_Probe.W, WL816h_Probe.H), 0, 0); tex.Apply();
RenderTexture.active = prevA; cam.targetTexture = prevT;
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
string avg = "";
if (wantAvg)
{
var px = tex.GetPixels32();
long r = 0, g = 0, b = 0;
for (int i = 0; i < px.Length; i++) { r += px[i].r; g += px[i].g; b += px[i].b; }
avg = "#" + ((int)(r / px.Length)).ToString("X2") + ((int)(g / px.Length)).ToString("X2") + ((int)(b / px.Length)).ToString("X2");
}
Object.DestroyImmediate(tex); rt.Release(); Object.DestroyImmediate(rt);
return avg + " → " + path;
}
}
public class WL816h_ProbeRunner : MonoBehaviour
{
static System.Text.StringBuilder sb;
void Start() { StartCoroutine(Co()); }
static void L(string s) { sb.AppendLine(s); }
IEnumerator Co()
{
sb = new System.Text.StringBuilder();
L("=== WL-816h 지금 상태 (PD 경로 = InGame 활성 + Level01 Additive) ===");
L("t0 활성씬=" + SceneManager.GetActiveScene().name + " / " + WL816h_Util.SkyLine());
bool viaGame = false;
try { if (InGameInfo.Ins != null) { InGameInfo.Ins.Load_Map(900); viaGame = true; } }
catch (System.Exception e) { L("Load_Map 예외(=로그인 없이는 못 탄다): " + e.GetType().Name); }
if (!viaGame)
{
L("→ SceneInfo.Load_AddScene 과 같은 호출로 대체: LoadSceneAsync(\"Level01\", Additive)");
var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive);
while (op != null && !op.isDone) yield return null;
}
for (int i = 0; i < 6; i++) yield return new WaitForSeconds(1f);
L("");
L("t+6s 활성씬=" + SceneManager.GetActiveScene().name + " sceneCount=" + SceneManager.sceneCount);
L("🔴 " + WL816h_Util.SkyLine());
L("IslandLook: 렌더러 " + WL.Look.Farm.WLIslandLook.SwappedRenderers + " light=" + WL.Look.Farm.WLIslandLook.LightingApplied
+ " refLook=" + WL.Look.Farm.WLIslandLook.ReferenceLookApplied);
L("RefLook : applied=" + WL.Look.Arena.WLReferenceLook.IsApplied + " log=" + WL.Look.Arena.WLReferenceLook.LastLog);
// ── 🔴 카메라 · 포스트 — 아레나 무드가 「보이는 카메라」에 실제로 걸렸나 ──
L("");
Camera live = null;
var cams = Object.FindObjectsByType<Camera>(FindObjectsInactive.Include, FindObjectsSortMode.None);
foreach (var c in cams)
{
bool isLive = c.gameObject.activeInHierarchy && c.enabled && c.targetTexture == null;
var ac = c.GetComponent<UniversalAdditionalCameraData>();
L("CAM " + c.name + " scene=" + c.gameObject.scene.name + " live=" + isLive + " depth=" + c.depth
+ " tag=" + c.tag + " clear=" + c.clearFlags
+ " 🔴post=" + (ac == null ? "noACD" : ac.renderPostProcessing.ToString()));
if (isLive && (live == null || c.depth > live.depth)) live = c;
}
L("→ 보이는 카메라 = " + (live == null ? "없음" : live.name + "(" + live.gameObject.scene.name + ")"));
L("Camera.main = " + (Camera.main == null ? "없음" : Camera.main.name + "(" + Camera.main.gameObject.scene.name + ")"));
var vols = Object.FindObjectsByType<Volume>(FindObjectsInactive.Include, FindObjectsSortMode.None);
foreach (var v in vols) L("Volume " + v.name + " global=" + v.isGlobal + " w=" + v.weight + " prio=" + v.priority
+ " profile=" + (v.sharedProfile ? v.sharedProfile.name : "없음"));
// ── 물 ──
L("");
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Include, FindObjectsSortMode.None))
{
if (r == null || r.gameObject.scene.name != "Level01") continue;
var m = r.sharedMaterial;
if (m == null || m.shader == null) continue;
if (!m.shader.name.ToLower().Contains("water") && !r.name.ToLower().Contains("water")) continue;
L("WATER obj=" + r.name + " layer=" + r.gameObject.layer + " mat=" + m.name + " shader=" + m.shader.name
+ " queue=" + m.renderQueue + " bounds=" + r.bounds.size.ToString("F0") + " pos=" + r.transform.position.ToString("F1"));
}
// ── URP 렌더러가 Opaque/Depth 텍스처를 주나(ToonWaterU 가 요구) ──
var urp = GraphicsSettings.defaultRenderPipeline as UniversalRenderPipelineAsset;
L("URP asset = " + (urp == null ? "없음" : urp.name + " opaqueTex=" + urp.supportsCameraOpaqueTexture
+ " depthTex=" + urp.supportsCameraDepthTexture + " msaa=" + urp.msaaSampleCount));
// ── 캡처 ──
L("");
L("하늘(섬) = " + WL816h_Util.Shot(WL816h_Util.SkyCam(), WL816h_Probe.Dir + "a_now_sky.png", true));
L("섬 화면 = " + WL816h_Util.Shot(live, WL816h_Probe.Dir + "a_now_island.png", true));
L("물 근접 = " + WL816h_Util.Shot(WaterCam(), WL816h_Probe.Dir + "a_now_water.png", true));
System.IO.File.WriteAllText("AgentScripts/WL816h_PROBE.txt", sb.ToString());
Debug.Log("[816h probe 완료]\n" + sb);
}
/// <summary>물이 화면의 절반을 차지하는 카메라(섬 가장자리 바깥).</summary>
public static Camera WaterCam()
{
var go = GameObject.Find("~WL816hWaterCam");
if (go == null) { go = new GameObject("~WL816hWaterCam"); go.hideFlags = HideFlags.DontSave; }
var c = go.GetComponent<Camera>(); if (c == null) c = go.AddComponent<Camera>();
c.orthographic = false; c.fieldOfView = 45f;
c.nearClipPlane = 0.3f; c.farClipPlane = 2000f;
c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f;
go.transform.position = new Vector3(-18f, 6f, -18f);
go.transform.rotation = Quaternion.Euler(12f, 45f, 0f);
if (go.GetComponent<UniversalAdditionalCameraData>() == null) go.AddComponent<UniversalAdditionalCameraData>();
return c;
}
}

View File

@ -0,0 +1,143 @@
// WL-816h — ② 「쨍한 파란 하늘」의 정체 + 섬에서 나간 뒤 하늘 오염 실측 (지금 상태 = 고치기 전)
using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
public static class WL816h_Probe2
{
public const string Dir = "Screenshots_WL/WL816h/";
public const int W = 1080, H = 1920;
public static void Start()
{
var go = GameObject.Find("~WL816hProbe2");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816hProbe2");
go.AddComponent<WL816h_Probe2Runner>();
Debug.Log("[816h p2] 러너 시작");
}
public static string SkyLine()
{
return "amb=" + RenderSettings.ambientMode + " light=" + F(RenderSettings.ambientLight)
+ " skySrc=" + F(RenderSettings.ambientSkyColor) + " I=" + RenderSettings.ambientIntensity
+ " skybox=" + (RenderSettings.skybox ? RenderSettings.skybox.name : "없음")
+ " fog=" + RenderSettings.fog + " refl=" + RenderSettings.defaultReflectionMode + "/" + RenderSettings.reflectionIntensity
+ " sun=" + (RenderSettings.sun ? RenderSettings.sun.name : "없음");
}
public static string F(Color c) { return "(" + c.r.ToString("F3") + "," + c.g.ToString("F3") + "," + c.b.ToString("F3") + ")"; }
public static Camera SkyCam()
{
var go = GameObject.Find("~WL816hSkyCam2");
if (go == null) { go = new GameObject("~WL816hSkyCam2"); go.hideFlags = HideFlags.DontSave; }
var c = go.GetComponent<Camera>(); if (c == null) c = go.AddComponent<Camera>();
c.orthographic = false; c.fieldOfView = 50f; c.nearClipPlane = 0.3f; c.farClipPlane = 2000f;
c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f;
go.transform.position = new Vector3(0f, 40f, 0f);
go.transform.rotation = Quaternion.Euler(-16f, 30f, 0f);
if (go.GetComponent<UniversalAdditionalCameraData>() == null) go.AddComponent<UniversalAdditionalCameraData>();
return c;
}
public static string Shot(Camera cam, string path)
{
if (cam == null) return "카메라 없음";
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var prevT = cam.targetTexture; var prevA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var tex = new Texture2D(W, H, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, W, H), 0, 0); tex.Apply();
RenderTexture.active = prevA; cam.targetTexture = prevT;
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
// 위 10 % · 아래 10 % 평균
string s = "";
s += "상단10%=" + Band(tex, 0.90f, 1.00f) + " 하단10%=" + Band(tex, 0.00f, 0.10f);
Object.DestroyImmediate(tex); rt.Release(); Object.DestroyImmediate(rt);
return s + " → " + path;
}
static string Band(Texture2D t, float y0, float y1)
{
int a = Mathf.RoundToInt(y0 * (t.height - 1)), b = Mathf.RoundToInt(y1 * (t.height - 1));
long r = 0, g = 0, bl = 0; int n = 0;
var px = t.GetPixels32();
for (int y = a; y < b; y += 4)
for (int x = 0; x < t.width; x += 4) { var c = px[y * t.width + x]; r += c.r; g += c.g; bl += c.b; n++; }
if (n == 0) return "-";
return "#" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(bl / n)).ToString("X2");
}
}
public class WL816h_Probe2Runner : MonoBehaviour
{
static System.Text.StringBuilder sb;
static void L(string s) { sb.AppendLine(s); }
void Start() { StartCoroutine(Co()); }
IEnumerator Co()
{
sb = new System.Text.StringBuilder();
L("=== ② 「파란 하늘」의 정체 + 섬 나간 뒤 오염 (고치기 전) ===");
Camera live = null;
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue;
if (live == null || c.depth > live.depth) live = c;
}
L("보이는 카메라 = " + (live == null ? "없음" : live.name + " fov=" + live.fieldOfView
+ " euler=" + live.transform.eulerAngles.ToString("F0") + " pos=" + live.transform.position.ToString("F1")));
Renderer water = null;
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
L("물 렌더러 = " + (water == null ? "없음" : water.name + " mat=" + water.sharedMaterial.name
+ " shader=" + water.sharedMaterial.shader.name));
L("물 ON = " + WL816h_Probe2.Shot(live, WL816h_Probe2.Dir + "a1_water_on.png"));
if (water != null) water.enabled = false;
yield return null;
L("물 OFF = " + WL816h_Probe2.Shot(live, WL816h_Probe2.Dir + "a2_water_off.png"));
if (water != null) water.enabled = true;
yield return null;
L("");
L("섬 내리기 전 : " + WL816h_Probe2.SkyLine());
var op = SceneManager.UnloadSceneAsync("Level01");
while (op != null && !op.isDone) yield return null;
yield return new WaitForSeconds(1.5f);
L("섬 내린 뒤 : " + WL816h_Probe2.SkyLine());
L("InGame 원본 : amb=Skybox light=(0.212,0.227,0.259) skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음 (씬 파일 실측)");
L("🔴 오염 = " + Diff());
var op2 = SceneManager.LoadSceneAsync("Map_C01", LoadSceneMode.Additive);
while (op2 != null && !op2.isDone) yield return null;
yield return new WaitForSeconds(1.5f);
L("");
L("전투 맵(Map_C01) 올린 뒤 : " + WL816h_Probe2.SkyLine());
L("🔴 오염 = " + Diff());
L("전투맵 하늘 = " + WL816h_Probe2.Shot(WL816h_Probe2.SkyCam(), WL816h_Probe2.Dir + "f0_before_battle_sky.png"));
System.IO.File.WriteAllText("AgentScripts/WL816h_PROBE2.txt", sb.ToString());
Debug.Log("[816h p2 완료]\n" + sb);
}
static string Diff()
{
string d = "";
if (RenderSettings.ambientMode != AmbientMode.Skybox) d += "ambientMode=" + RenderSettings.ambientMode + "(원본 Skybox) · ";
var a = RenderSettings.ambientLight;
if (Mathf.Abs(a.r - 0.212f) > 0.004f || Mathf.Abs(a.g - 0.227f) > 0.004f || Mathf.Abs(a.b - 0.259f) > 0.004f)
d += "ambientLight=" + WL816h_Probe2.F(a) + "(원본 (0.212,0.227,0.259)) · ";
if (RenderSettings.fog) d += "fog on · ";
if (RenderSettings.sun != null) d += "sun=" + RenderSettings.sun.name + "(원본 없음) · ";
if (RenderSettings.skybox == null || RenderSettings.skybox.name != "Default-Skybox")
d += "skybox=" + (RenderSettings.skybox ? RenderSettings.skybox.name : "없음") + " · ";
return d.Length == 0 ? "없음(오염 0)" : d;
}
}

View File

@ -0,0 +1,14 @@
### arena Assets/WL/Look/Arena/Scenes/WL_ArenaProto.unity
RenderSettings: amb=Skybox light=(0.212,0.227,0.259) sky=(0.212,0.227,0.259) I=1 skybox=Default-Skybox/Skybox/Procedural fog=False refl=Skybox/1 sun=Directional Light
CAM PlanarReflectionProbe active=True en=True ortho=True size=5 clear=SolidColor post=False
CAM Main Camera active=True en=True ortho=True size=10 clear=Skybox post=False
Volume 수 = 0
하늘 화면색 = #798EA9 → Screenshots_WL/WL816h/ref_sky_arena.png
### demo Assets/LowPolyFantasyArena/Scenes/LowPolyArena_Demo.unity
RenderSettings: amb=Skybox light=(0.212,0.227,0.259) sky=(0.212,0.227,0.259) I=1 skybox=Default-Skybox/Skybox/Procedural fog=False refl=Skybox/1 sun=Directional Light
CAM Camera1 active=True en=True ortho=False fov=60 clear=Skybox post=noACD
CAM Camera2 active=True en=True ortho=False fov=60 clear=Skybox post=noACD
CAM Camera4 active=True en=True ortho=False fov=60 clear=Skybox post=noACD
CAM Camera3 active=True en=True ortho=False fov=60 clear=Skybox post=noACD
Volume 수 = 0
하늘 화면색 = #88A4C4 → Screenshots_WL/WL816h/ref_sky_demo.png

View File

@ -0,0 +1,11 @@
=== 되돌리기 실측 [enabled_=1 skyScope=1 waterMode=1] ===
InGame 원래 하늘 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
물 : Farm_Water_WL_C / Shader Graphs/ToonWaterU
머티리얼 교체 : 렌더러 1575 · 물 1
풀 : 타일 5 · 인스턴스 680 · 드로우콜 2 · 삼각형 6111 · 제외점 358 · 밀도 1.80(=3.24개/㎡)
RefLook : True
SkyScope : held=True acquires=1 restores=0
섬 하늘 : amb=Flat light=(0.217,0.228,0.250) skySrc=(0.217,0.228,0.250) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=DirectionalLight
화면 : #729AA9 → Screenshots_WL/WL816h/z_rollback_water_now.png
전투 맵 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
🔴 원래대로 = 예

View File

@ -0,0 +1,11 @@
=== 되돌리기 실측 [enabled_=0 skyScope=0 waterMode=0] ===
InGame 원래 하늘 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
물 : SimpleWater / Shader Graphs/Simple Water
머티리얼 교체 : 렌더러 0 · 물 0
풀 :
RefLook : False
SkyScope : held=False acquires=0 restores=0
섬 하늘 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=DirectionalLight
화면 : #2891BA → Screenshots_WL/WL816h/z_rollback_off.png
전투 맵 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
🔴 원래대로 = 예

View File

@ -0,0 +1,131 @@
// WL-816h — ⑤ 되돌리기 실측 (SO 스위치 하나로 100 % 복귀)
// R1 = waterMode 0 + skyScopeEnabled 0 → 816f 상태(FarmingIsland 물 · 스코프 없음)
// R2 = enabled_ 0 → 섬 룩 전체 off (816e/816f 가 쓰던 스위치)
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor;
public static class WL816h_Rollback
{
const string SO = "Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset";
const string Dir = "Screenshots_WL/WL816h/";
public static void SetR1() { Set(1, 0, 0); } // 섬 룩은 그대로 · 물/스코프만 끈다
public static void SetR2() { Set(0, 0, 0); } // 전부 off
public static void SetOn() { Set(1, 1, 1); } // 채택 상태로 복귀
static void Set(int enabled_, int sky, int water)
{
var so = AssetDatabase.LoadAssetAtPath<WL.Look.Farm.WLIslandLookSettings>(SO);
if (so == null) { Debug.Log("[816h] SO 없음"); return; }
so.enabled_ = enabled_; so.skyScopeEnabled = sky; so.waterMode = water;
EditorUtility.SetDirty(so); AssetDatabase.SaveAssets();
WL.Look.Farm.WLIslandLookSettings.Invalidate();
Debug.Log("[816h] SO enabled_=" + enabled_ + " skyScope=" + sky + " waterMode=" + water);
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
}
public static void Start()
{
var go = GameObject.Find("~WL816hRollback");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816hRollback");
go.AddComponent<WL816h_RollbackRunner>();
}
}
/// <summary>run_script 는 파일 하나만 컴파일한다 → 도우미를 여기에 그대로 둔다.</summary>
public static class RB
{
public const int W = 1080, H = 1920;
public static string Sky()
{
return "amb=" + RenderSettings.ambientMode + " light=" + F(RenderSettings.ambientLight)
+ " skySrc=" + F(RenderSettings.ambientSkyColor) + " I=" + RenderSettings.ambientIntensity
+ " skybox=" + (RenderSettings.skybox ? RenderSettings.skybox.name : "없음")
+ " fog=" + RenderSettings.fog + " refl=" + RenderSettings.defaultReflectionMode + "/" + RenderSettings.reflectionIntensity
+ " sun=" + (RenderSettings.sun ? RenderSettings.sun.name : "없음");
}
static string F(Color c) { return "(" + c.r.ToString("F3") + "," + c.g.ToString("F3") + "," + c.b.ToString("F3") + ")"; }
public static string Shot(Camera cam, string path)
{
if (cam == null) return "카메라 없음";
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; var pA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var tex = new Texture2D(W, H, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, W, H), 0, 0); tex.Apply();
RenderTexture.active = pA; cam.targetTexture = pT;
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
var px = tex.GetPixels32(); long r = 0, g = 0, b = 0;
for (int i = 0; i < px.Length; i += 7) { r += px[i].r; g += px[i].g; b += px[i].b; }
int n = (px.Length + 6) / 7;
string s = "#" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(b / n)).ToString("X2");
Object.DestroyImmediate(tex); rt.Release(); Object.DestroyImmediate(rt);
return s + " → " + path;
}
}
public class WL816h_RollbackRunner : MonoBehaviour
{
void Start() { StartCoroutine(Co()); }
IEnumerator Co()
{
var sb = new System.Text.StringBuilder();
var cfg = WL.Look.Farm.WLIslandLookSettings.Instance;
string tag = "enabled_=" + (cfg == null ? -1 : cfg.enabled_)
+ " skyScope=" + (cfg == null ? -1 : cfg.skyScopeEnabled)
+ " waterMode=" + (cfg == null ? -1 : cfg.waterMode);
sb.AppendLine("=== 되돌리기 실측 [" + tag + "] ===");
string pristine = RB.Sky();
sb.AppendLine("InGame 원래 하늘 : " + pristine);
var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive);
while (op != null && !op.isDone) yield return null;
for (int i = 0; i < 7; i++) yield return new WaitForSeconds(1f);
Renderer water = null;
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
sb.AppendLine("물 : " + (water == null ? "없음" : water.sharedMaterial.name + " / " + water.sharedMaterial.shader.name));
sb.AppendLine("머티리얼 교체 : 렌더러 " + WL.Look.Farm.WLIslandLook.SwappedRenderers
+ " · 물 " + WL.Look.Farm.WLIslandLook.WaterSwapped);
sb.AppendLine("풀 : " + WL.Look.Farm.WLIslandGrass.LastLog);
sb.AppendLine("RefLook : " + WL.Look.Arena.WLReferenceLook.IsApplied);
sb.AppendLine("SkyScope : held=" + WL.Look.Farm.WLSkyScope.Held
+ " acquires=" + WL.Look.Farm.WLSkyScope.Acquires + " restores=" + WL.Look.Farm.WLSkyScope.Restores);
sb.AppendLine("섬 하늘 : " + RB.Sky());
Camera live = null;
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue;
if (c.name.StartsWith("~WL816h")) continue;
if (live == null || c.depth > live.depth) live = c;
}
string shot = "Screenshots_WL/WL816h/z_rollback_" + (cfg != null && cfg.enabled_ == 0 ? "off" : "water_now") + ".png";
sb.AppendLine("화면 : " + RB.Shot(live, shot));
// 섬을 내리고 전투 맵 → 하늘이 원래대로인가
var u = SceneManager.UnloadSceneAsync("Level01");
while (u != null && !u.isDone) yield return null;
yield return new WaitForSeconds(2.5f);
var b = SceneManager.LoadSceneAsync("Map_C01", LoadSceneMode.Additive);
while (b != null && !b.isDone) yield return null;
yield return new WaitForSeconds(1.5f);
string after = RB.Sky();
sb.AppendLine("전투 맵 : " + after);
sb.AppendLine("🔴 원래대로 = " + (after == pristine ? "예" : "🔴 아니오 (전 " + pristine + ")"));
string path = "AgentScripts/WL816h_ROLLBACK_" + (cfg != null && cfg.enabled_ == 0 ? "R2" : "R1") + ".txt";
System.IO.File.WriteAllText(path, sb.ToString());
Debug.Log("[816h rollback]\n" + sb);
}
}

View File

@ -0,0 +1,51 @@
=== WL-816h 적용 확인 (PD 경로 = InGame 활성 + Level01 Additive) ===
0) InGame 원래 하늘 : amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
Load_Map(900) = 🔴 로그인 없이는 못 탄다 → LoadSceneAsync(Level01, Additive) 로 대체(816f 와 같음)
1) 섬 진입 — 활성씬=InGame sceneCount=2
IslandLook 렌더러 1575 · 물 교체 1 · refLook=True
🔴 SkyScope held=True by=Level01 acquires=1 restores=0
섬 하늘 = amb=Flat light=(0.217,0.228,0.250) skySrc=(0.217,0.228,0.250) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=DirectionalLight
물 렌더러 = Water mat=Farm_Water_WL_C shader=Shader Graphs/ToonWaterU queue=3000
보이는 카메라 = MainCamera(Level01)
2) 물 값 3단 비교 + 성능 (같은 카메라 1080×1920 · 60프레임 오프스크린)
[지금(FI SimpleWater)] 0.828 ms/frame
게임화면 상10%=#5BB5FE 중=#8BC1AA 하10%=#5BB5FE → Screenshots_WL/WL816h/w_0_now_live.png
수평선 상10%=#6174C2 중=#5CB7FE 하10%=#8AB1CC → Screenshots_WL/WL816h/w_0_now_horizon.png
[A=WL_Water_Ocean 원본] 0.864 ms/frame
게임화면 상10%=#0FBFEB 중=#77C2A6 하10%=#1DC0E9 → Screenshots_WL/WL816h/w_1_a_live.png
수평선 상10%=#6174C2 중=#2BC2EF 하10%=#4497B6 → Screenshots_WL/WL816h/w_1_a_horizon.png
[B=데모 톤] 0.814 ms/frame
게임화면 상10%=#50B0EB 중=#83BEA6 하10%=#53B0E9 → Screenshots_WL/WL816h/w_2_b_live.png
수평선 상10%=#6174C2 중=#55B1EF 하10%=#76A0B9 → Screenshots_WL/WL816h/w_2_b_horizon.png
[C=차분] 0.853 ms/frame
게임화면 상10%=#6097C2 중=#88B89B 하10%=#6397C1 → Screenshots_WL/WL816h/w_3_c_live.png
수평선 상10%=#6174C2 중=#659AC5 하10%=#8093A3 → Screenshots_WL/WL816h/w_3_c_horizon.png
→ 채택 = Farm_Water_WL_C
2-b) 성능 전/후 (같은 카메라 · 60프레임 × 2회 · 순서 교대)
0회차 전(FI SimpleWater) = 0.855 ms/frame
0회차 후(Farm_Water_WL_C) = 0.901 ms/frame
1회차 전(FI SimpleWater) = 0.889 ms/frame
1회차 후(Farm_Water_WL_C) = 0.886 ms/frame
3단 비교 한 장 = Screenshots_WL/WL816h/e_water_steps.png · e_water_steps_horizon.png
3) 적용 후
섬 게임화면 = 상10%=#6097C2 중=#87B79B 하10%=#6397C1 → Screenshots_WL/WL816h/b_after_island.png
수평선 = 상10%=#6174C2 중=#659AC5 하10%=#8093A4 → Screenshots_WL/WL816h/b_after_horizon.png
물 근접 = 상10%=#8399E6 중=#78807A 하10%=#4C7EA7 → Screenshots_WL/WL816h/b_after_water.png
하늘만 = 상10%=#4958A3 중=#7186D3 하10%=#6598C2 → Screenshots_WL/WL816h/b_after_sky.png
좌우 비교 = Screenshots_WL/WL816h/c_side_by_side.png (좌 지금 / 우 적용 후)
4) 🔴 맵별 하늘 격리 — 섬 → 던전 → 전투 맵
[섬] amb=Flat light=(0.217,0.228,0.250) skySrc=(0.217,0.228,0.250) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=DirectionalLight
[섬] 하늘 = 상10%=#4958A3 중=#7186D3 하10%=#6598C2 → Screenshots_WL/WL816h/f1_island_sky.png
[던전] SkyScope held=True by=Level01 acquires=1 restores=0
[던전] amb=Flat light=(0.217,0.228,0.250) skySrc=(0.217,0.228,0.250) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=Directional Light
[던전] 하늘 = 상10%=#4958A3 중=#7186D3 하10%=#60506F → Screenshots_WL/WL816h/f2_dungeon_sky.png
[전투] SkyScope held=False acquires=1 restores=1
[전투] amb=Skybox light=(0.212,0.227,0.259) skySrc=(0.212,0.227,0.259) I=1 skybox=Default-Skybox fog=False refl=Skybox/1 sun=없음
[전투] 하늘 = 상10%=#586773 중=#839397 하10%=#4D3A1D → Screenshots_WL/WL816h/f3_battle_sky.png
🔴 원래대로인가 = 예 — 글자 하나까지 같다(오염 0)
한 장 = Screenshots_WL/WL816h/f_sky_isolation.png (좌 섬 / 중 던전 / 우 전투 맵)

View File

@ -0,0 +1,323 @@
// WL-816h — ④ PD 경로에서 적용 확인 · 물 3단 비교 · 성능 전/후 · 🔴 맵별 하늘 격리
// 전부 Play 중 실측. 🔴 Play 중에 에셋(SO·머티리얼)을 고치지 않는다(§9) — 렌더러만 바꾼다.
using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
public static class WL816h_Verify
{
public const string Dir = "Screenshots_WL/WL816h/";
public const int W = 1080, H = 1920;
public static void Open()
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
Debug.Log("[816h] InGame 열림");
}
public static void Start()
{
var go = GameObject.Find("~WL816hVerify");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816hVerify");
go.AddComponent<WL816h_VerifyRunner>();
Debug.Log("[816h] verify 러너 시작");
}
// ── 공용 ────────────────────────────────────────────────────────────
public static string Sky()
{
return "amb=" + RenderSettings.ambientMode + " light=" + F(RenderSettings.ambientLight)
+ " skySrc=" + F(RenderSettings.ambientSkyColor) + " I=" + RenderSettings.ambientIntensity
+ " skybox=" + (RenderSettings.skybox ? RenderSettings.skybox.name : "없음")
+ " fog=" + RenderSettings.fog + " refl=" + RenderSettings.defaultReflectionMode + "/" + RenderSettings.reflectionIntensity
+ " sun=" + (RenderSettings.sun ? RenderSettings.sun.name : "없음");
}
public static string F(Color c) { return "(" + c.r.ToString("F3") + "," + c.g.ToString("F3") + "," + c.b.ToString("F3") + ")"; }
public static Camera Cam(string name, Vector3 pos, Vector3 euler, float fov, CameraClearFlags clear)
{
var go = GameObject.Find(name);
if (go == null) { go = new GameObject(name); go.hideFlags = HideFlags.DontSave; }
var c = go.GetComponent<Camera>(); if (c == null) c = go.AddComponent<Camera>();
c.orthographic = false; c.fieldOfView = fov; c.nearClipPlane = 0.3f; c.farClipPlane = 2000f;
c.clearFlags = clear; c.cullingMask = ~0; c.depth = -100f;
go.transform.position = pos; go.transform.rotation = Quaternion.Euler(euler);
var ac = go.GetComponent<UniversalAdditionalCameraData>();
if (ac == null) ac = go.AddComponent<UniversalAdditionalCameraData>();
ac.renderPostProcessing = true; // 아레나 무드가 걸린 화면 그대로
return c;
}
/// <summary>섬 가장자리 바깥 — 바다가 화면의 절반을 차지한다.</summary>
public static Camera WaterCam()
{ return Cam("~WL816hWaterCam", new Vector3(-16f, 5.5f, -16f), new Vector3(10f, 45f, 0f), 45f, CameraClearFlags.Skybox); }
/// <summary>수평선이 화면에 들어오는 각도 — 하늘과 바다가 함께 보인다.</summary>
public static Camera HorizonCam()
{ return Cam("~WL816hHorizonCam", new Vector3(-14f, 8f, -14f), new Vector3(4f, 45f, 0f), 55f, CameraClearFlags.Skybox); }
public static Camera SkyCam()
{ return Cam("~WL816hSkyCam3", new Vector3(0f, 40f, 0f), new Vector3(-16f, 30f, 0f), 50f, CameraClearFlags.Skybox); }
public static Texture2D Grab(Camera cam)
{
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; var pA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var tex = new Texture2D(W, H, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, W, H), 0, 0); tex.Apply();
RenderTexture.active = pA; cam.targetTexture = pT;
rt.Release(); Object.DestroyImmediate(rt);
return tex;
}
public static string Shot(Camera cam, string path)
{
if (cam == null) return "카메라 없음";
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var tex = Grab(cam);
System.IO.File.WriteAllBytes(path, tex.EncodeToPNG());
string s = "상10%=" + Band(tex, 0.90f, 1.00f) + " 중=" + Band(tex, 0.45f, 0.55f) + " 하10%=" + Band(tex, 0f, 0.10f);
Object.DestroyImmediate(tex);
return s + " → " + path;
}
public static string Band(Texture2D t, float y0, float y1)
{
int a = Mathf.RoundToInt(y0 * (t.height - 1)), b = Mathf.RoundToInt(y1 * (t.height - 1));
var px = t.GetPixels32();
long r = 0, g = 0, bl = 0; int n = 0;
for (int y = a; y < b; y += 3) for (int x = 0; x < t.width; x += 3)
{ var c = px[y * t.width + x]; r += c.r; g += c.g; bl += c.b; n++; }
if (n == 0) return "-";
return "#" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(bl / n)).ToString("X2");
}
/// <summary>같은 카메라로 60프레임 오프스크린 렌더 — ms/frame.</summary>
public static float Ms(Camera cam, int frames)
{
var rt = new RenderTexture(W, H, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; cam.targetTexture = rt;
for (int i = 0; i < 10; i++) cam.Render(); // 워밍업
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < frames; i++) cam.Render();
sw.Stop();
cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt);
return (float)sw.Elapsed.TotalMilliseconds / frames;
}
/// <summary>좌/우 두 장을 한 장으로 (PD 판단용).</summary>
public static void Pair(string left, string right, string outPath)
{
var a = Load(left); var b = Load(right);
if (a == null || b == null) return;
int w = a.width + b.width, h = Mathf.Max(a.height, b.height);
var o = new Texture2D(w, h, TextureFormat.RGB24, false);
var fill = new Color32[w * h];
for (int i = 0; i < fill.Length; i++) fill[i] = new Color32(24, 24, 28, 255);
o.SetPixels32(fill);
o.SetPixels32(0, 0, a.width, a.height, a.GetPixels32());
o.SetPixels32(a.width, 0, b.width, b.height, b.GetPixels32());
o.Apply();
System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG());
Object.DestroyImmediate(o); Object.DestroyImmediate(a); Object.DestroyImmediate(b);
}
/// <summary>여러 장을 가로로 이어 붙인다(값 3단 비교용).</summary>
public static void Strip(string[] paths, string outPath)
{
var ts = new Texture2D[paths.Length];
int w = 0, h = 0;
for (int i = 0; i < paths.Length; i++)
{ ts[i] = Load(paths[i]); if (ts[i] == null) return; w += ts[i].width; h = Mathf.Max(h, ts[i].height); }
var o = new Texture2D(w, h, TextureFormat.RGB24, false);
var fill = new Color32[w * h];
for (int i = 0; i < fill.Length; i++) fill[i] = new Color32(24, 24, 28, 255);
o.SetPixels32(fill);
int x = 0;
for (int i = 0; i < ts.Length; i++) { o.SetPixels32(x, 0, ts[i].width, ts[i].height, ts[i].GetPixels32()); x += ts[i].width; }
o.Apply();
System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG());
Object.DestroyImmediate(o);
for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]);
}
static Texture2D Load(string p)
{
if (!System.IO.File.Exists(p)) return null;
var t = new Texture2D(2, 2, TextureFormat.RGB24, false);
t.LoadImage(System.IO.File.ReadAllBytes(p));
return t;
}
}
public class WL816h_VerifyRunner : MonoBehaviour
{
static System.Text.StringBuilder sb;
static void L(string s) { sb.AppendLine(s); }
const string MatDir = "Assets/WL/Look/Farm/Materials/";
void Start() { StartCoroutine(Co()); }
IEnumerator Co()
{
sb = new System.Text.StringBuilder();
L("=== WL-816h 적용 확인 (PD 경로 = InGame 활성 + Level01 Additive) ===");
// 활성 씬(InGame)의 **손 안 댄** 하늘 = 나중에 「원래대로」 판정 기준
string pristine = WL816h_Verify.Sky();
L("0) InGame 원래 하늘 : " + pristine);
bool viaGame = false;
try { if (InGameInfo.Ins != null) { InGameInfo.Ins.Load_Map(900); viaGame = true; } }
catch (System.Exception) { }
L(" Load_Map(900) = " + (viaGame ? "성공" : "🔴 로그인 없이는 못 탄다 → LoadSceneAsync(Level01, Additive) 로 대체(816f 와 같음)"));
if (!viaGame)
{
var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive);
while (op != null && !op.isDone) yield return null;
}
for (int i = 0; i < 7; i++) yield return new WaitForSeconds(1f);
// ── 1) 훅이 돌았나 ────────────────────────────────────────────
L("");
L("1) 섬 진입 — 활성씬=" + SceneManager.GetActiveScene().name + " sceneCount=" + SceneManager.sceneCount);
L(" IslandLook 렌더러 " + WL.Look.Farm.WLIslandLook.SwappedRenderers
+ " · 물 교체 " + WL.Look.Farm.WLIslandLook.WaterSwapped
+ " · refLook=" + WL.Look.Farm.WLIslandLook.ReferenceLookApplied);
L(" 🔴 SkyScope held=" + WL.Look.Farm.WLSkyScope.Held + " by=" + WL.Look.Farm.WLSkyScope.HeldBy
+ " acquires=" + WL.Look.Farm.WLSkyScope.Acquires + " restores=" + WL.Look.Farm.WLSkyScope.Restores);
L(" 섬 하늘 = " + WL816h_Verify.Sky());
Renderer water = null;
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
L(" 물 렌더러 = " + (water == null ? "🔴 없음" : water.name + " mat=" + water.sharedMaterial.name
+ " shader=" + water.sharedMaterial.shader.name + " queue=" + water.sharedMaterial.renderQueue));
Camera live = null;
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue;
if (c.name.StartsWith("~WL816h")) continue;
if (live == null || c.depth > live.depth) live = c;
}
L(" 보이는 카메라 = " + (live == null ? "없음" : live.name + "(" + live.gameObject.scene.name + ")"));
// ── 2) 물 3단 비교 + 성능 (같은 카메라 · 같은 프레임 구간) ────
L("");
L("2) 물 값 3단 비교 + 성능 (같은 카메라 1080×1920 · 60프레임 오프스크린)");
string[] names = { null, "Farm_Water_WL_A", "Farm_Water_WL_B", "Farm_Water_WL_C" };
string[] labels = { "지금(FI SimpleWater)", "A=WL_Water_Ocean 원본", "B=데모 톤", "C=차분" };
string[] liveShots = new string[4];
string[] horizonShots = new string[4];
var fiMat = water != null ? water.sharedMaterial : null; // 지금 걸려 있는 것(= WL 워터 B)
// 「지금」 = FarmingIsland 물(우리 복사본 Farm_SimpleWater_Demo)
Material now = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(MatDir + "Farm_SimpleWater_Demo.mat");
for (int i = 0; i < names.Length; i++)
{
Material m = names[i] == null ? now : UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(MatDir + names[i] + ".mat");
if (m == null) { L(" 🔴 머티리얼 없음 " + (names[i] ?? "Farm_SimpleWater_Demo")); continue; }
if (water != null) water.sharedMaterial = m;
yield return null; yield return null;
yield return new WaitForSeconds(0.4f);
string tag = names[i] == null ? "now" : names[i].Substring(names[i].Length - 1).ToLower();
liveShots[i] = WL816h_Verify.Dir + "w_" + i + "_" + tag + "_live.png";
horizonShots[i] = WL816h_Verify.Dir + "w_" + i + "_" + tag + "_horizon.png";
string s1 = WL816h_Verify.Shot(live, liveShots[i]);
string s2 = WL816h_Verify.Shot(WL816h_Verify.HorizonCam(), horizonShots[i]);
float ms = WL816h_Verify.Ms(live, 60);
L(" [" + labels[i] + "] " + ms.ToString("F3") + " ms/frame");
L(" 게임화면 " + s1);
L(" 수평선 " + s2);
}
// 채택값으로 되돌린다(SO 가 가리키는 것)
var cfg = WL.Look.Farm.WLIslandLookSettings.Instance;
if (water != null && cfg != null && cfg.waterTo != null) water.sharedMaterial = cfg.waterTo;
yield return null;
L(" → 채택 = " + (cfg != null && cfg.waterTo != null ? cfg.waterTo.name : "?"));
// ── 2-b) 성능 전/후 — 순서 바꿔 두 번씩 (측정 순서 편향 제거) ──
L("");
L("2-b) 성능 전/후 (같은 카메라 · 60프레임 × 2회 · 순서 교대)");
var adopted = cfg != null ? cfg.waterTo : null;
for (int round = 0; round < 2; round++)
{
foreach (var pair in new[] { new object[] { "전(FI SimpleWater)", now }, new object[] { "후(" + (adopted ? adopted.name : "?") + ")", adopted } })
{
var m = pair[1] as Material; if (m == null) continue;
if (water != null) water.sharedMaterial = m;
yield return null; yield return null;
L(" " + round + "회차 " + (string)pair[0] + " = " + WL816h_Verify.Ms(live, 60).ToString("F3") + " ms/frame");
}
}
if (water != null && adopted != null) water.sharedMaterial = adopted;
yield return null;
WL816h_Verify.Strip(liveShots, WL816h_Verify.Dir + "e_water_steps.png");
WL816h_Verify.Strip(horizonShots, WL816h_Verify.Dir + "e_water_steps_horizon.png");
L(" 3단 비교 한 장 = " + WL816h_Verify.Dir + "e_water_steps.png · e_water_steps_horizon.png");
// ── 3) 적용 후 대표 캡처 ──────────────────────────────────────
L("");
L("3) 적용 후");
L(" 섬 게임화면 = " + WL816h_Verify.Shot(live, WL816h_Verify.Dir + "b_after_island.png"));
L(" 수평선 = " + WL816h_Verify.Shot(WL816h_Verify.HorizonCam(), WL816h_Verify.Dir + "b_after_horizon.png"));
L(" 물 근접 = " + WL816h_Verify.Shot(WL816h_Verify.WaterCam(), WL816h_Verify.Dir + "b_after_water.png"));
L(" 하늘만 = " + WL816h_Verify.Shot(WL816h_Verify.SkyCam(), WL816h_Verify.Dir + "b_after_sky.png"));
WL816h_Verify.Pair(WL816h_Verify.Dir + "a_now_island.png", WL816h_Verify.Dir + "b_after_island.png",
WL816h_Verify.Dir + "c_side_by_side.png");
L(" 좌우 비교 = " + WL816h_Verify.Dir + "c_side_by_side.png (좌 지금 / 우 적용 후)");
// ── 4) 🔴 맵별 하늘 격리 ──────────────────────────────────────
L("");
L("4) 🔴 맵별 하늘 격리 — 섬 → 던전 → 전투 맵");
L(" [섬] " + WL816h_Verify.Sky());
string islandSky = WL816h_Verify.Shot(WL816h_Verify.SkyCam(), WL816h_Verify.Dir + "f1_island_sky.png");
L(" [섬] 하늘 = " + islandSky);
// 섬 → 던전 (같은 하늘이어야 한다)
var u1 = SceneManager.UnloadSceneAsync("Level01");
while (u1 != null && !u1.isDone) yield return null;
var d1 = SceneManager.LoadSceneAsync("WL_Dungeon01", LoadSceneMode.Additive);
while (d1 != null && !d1.isDone) yield return null;
yield return new WaitForSeconds(2f);
L(" [던전] SkyScope held=" + WL.Look.Farm.WLSkyScope.Held + " by=" + WL.Look.Farm.WLSkyScope.HeldBy
+ " acquires=" + WL.Look.Farm.WLSkyScope.Acquires + " restores=" + WL.Look.Farm.WLSkyScope.Restores);
L(" [던전] " + WL816h_Verify.Sky());
L(" [던전] 하늘 = " + WL816h_Verify.Shot(WL816h_Verify.SkyCam(), WL816h_Verify.Dir + "f2_dungeon_sky.png"));
// 던전 → 전투 맵 (원래대로여야 한다)
var u2 = SceneManager.UnloadSceneAsync("WL_Dungeon01");
while (u2 != null && !u2.isDone) yield return null;
var b1 = SceneManager.LoadSceneAsync("Map_C01", LoadSceneMode.Additive);
while (b1 != null && !b1.isDone) yield return null;
yield return new WaitForSeconds(2f);
L(" [전투] SkyScope held=" + WL.Look.Farm.WLSkyScope.Held
+ " acquires=" + WL.Look.Farm.WLSkyScope.Acquires + " restores=" + WL.Look.Farm.WLSkyScope.Restores);
string after = WL816h_Verify.Sky();
L(" [전투] " + after);
L(" [전투] 하늘 = " + WL816h_Verify.Shot(WL816h_Verify.SkyCam(), WL816h_Verify.Dir + "f3_battle_sky.png"));
L(" 🔴 원래대로인가 = " + (after == pristine ? "예 — 글자 하나까지 같다(오염 0)" : "🔴 아니오\n 전 : " + pristine + "\n 후 : " + after));
WL816h_Verify.Strip(new string[] {
WL816h_Verify.Dir + "f1_island_sky.png",
WL816h_Verify.Dir + "f2_dungeon_sky.png",
WL816h_Verify.Dir + "f3_battle_sky.png" },
WL816h_Verify.Dir + "f_sky_isolation.png");
L(" 한 장 = " + WL816h_Verify.Dir + "f_sky_isolation.png (좌 섬 / 중 던전 / 우 전투 맵)");
System.IO.File.WriteAllText("AgentScripts/WL816h_VERIFY.txt", sb.ToString());
Debug.Log("[816h verify 완료]\n" + sb);
}
}

View File

@ -0,0 +1,101 @@
%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: Farm_Water_WL_A
m_Shader: {fileID: -6465566751694194690, guid: 85b142f88e4bec1488c6b275a0e5dc57,
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:
- Texture2D_086cedcb1d864765840f9996e4b0002d:
m_Texture: {fileID: 2800000, guid: 945a5174b1a6da34ea1028ed2feeb1e9, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_1d2b8f4484d74423a27218f18b962ade:
m_Texture: {fileID: 2800000, guid: d48aae5302069a94f9410b8d6b76fed1, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_4094dc7f19e94579ac3bbc9c811f51a4:
m_Texture: {fileID: 2800000, guid: 62100fbe73f198245b71c0a6eeeb94f6, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_685ca00e8e7c4cb2b45a9e11981bb64a:
m_Texture: {fileID: 2800000, guid: 5088aa2234cf5b24cad13def77f7da5f, type: 3}
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:
- Vector1_07238257334b4a149e675e2451801030: 7.83
- Vector1_101dc4546b684d40bc2ff2fc59ab43d5: 5
- Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f: 50
- Vector1_21ae4fce4585460386edec89c9895501: 0
- Vector1_2b4963cef1de4859983ffcbae94c6f60: 0
- Vector1_3089b6a325a44c1686907af4ee3b0776: 0.6
- Vector1_34f757bec6b8422b9aef3b9d97117a6e: 4
- Vector1_566e288f42864b8e9432d81fbdb83f38: 3.36
- Vector1_68f0c21b684f4b7c9ebef8789113b107: 2
- Vector1_7090c8ca8ea84e2d85858ae4beb5be38: 1
- Vector1_85ea9246e72a44ed9e0482861767c826: 0.03
- Vector1_8e22a98f75c94b218c49e6c4805e799d: 0.01
- Vector1_99cc56b5c6fd474082f07f00a6df94f9: 0.0394
- Vector1_ad7e0fcd37f44d68b68de6f06bb43b96: 0.01
- Vector1_c6f2603b30534ec8b0039379573789e3: 1
- Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9: 0.2
- Vector1_dd1e17693dc14b10b91828bdfd5adaa8: 0
- Vector1_ff7a2780aaa94ddd86e156c4707e39a2: 0.64
- _QueueControl: 0
- _QueueOffset: 0
- _XRMotionVectorsPass: 1
m_Colors:
- Color_1ec6cccf8ead489ebb917674f7e8b3b1: {r: 1, g: 1, b: 1, a: 1}
- Color_2323d69962e04c499c5d5f0925432b55: {r: 1, g: 0.93773586, b: 0.93773586,
a: 1}
- Color_9af4ad59934f40d1ae6565e6ab22c45e: {r: 0, g: 0.8823529, b: 1, a: 1}
- Color_ca031ae309ff42bdb95f777248fb961d: {r: 0, g: 0.11372443, b: 0.41509432,
a: 1}
- Color_e1f155248d144786a62fc1585ca21e9a: {r: 1, g: 1, b: 1, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &7840779067325084833
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: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 675e37d255df5a44386db0f4cf281a32
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,99 @@
%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: Farm_Water_WL_B
m_Shader: {fileID: -6465566751694194690, guid: 85b142f88e4bec1488c6b275a0e5dc57,
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:
- Texture2D_086cedcb1d864765840f9996e4b0002d:
m_Texture: {fileID: 2800000, guid: 945a5174b1a6da34ea1028ed2feeb1e9, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_1d2b8f4484d74423a27218f18b962ade:
m_Texture: {fileID: 2800000, guid: d48aae5302069a94f9410b8d6b76fed1, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_4094dc7f19e94579ac3bbc9c811f51a4:
m_Texture: {fileID: 2800000, guid: 62100fbe73f198245b71c0a6eeeb94f6, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_685ca00e8e7c4cb2b45a9e11981bb64a:
m_Texture: {fileID: 2800000, guid: 5088aa2234cf5b24cad13def77f7da5f, type: 3}
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:
- Vector1_07238257334b4a149e675e2451801030: 7.83
- Vector1_101dc4546b684d40bc2ff2fc59ab43d5: 3
- Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f: 36
- Vector1_21ae4fce4585460386edec89c9895501: 0
- Vector1_2b4963cef1de4859983ffcbae94c6f60: 0
- Vector1_3089b6a325a44c1686907af4ee3b0776: 0.6
- Vector1_34f757bec6b8422b9aef3b9d97117a6e: 4
- Vector1_566e288f42864b8e9432d81fbdb83f38: 5
- Vector1_68f0c21b684f4b7c9ebef8789113b107: 2
- Vector1_7090c8ca8ea84e2d85858ae4beb5be38: 1
- Vector1_85ea9246e72a44ed9e0482861767c826: 0.03
- Vector1_8e22a98f75c94b218c49e6c4805e799d: 0.01
- Vector1_99cc56b5c6fd474082f07f00a6df94f9: 0.0394
- Vector1_ad7e0fcd37f44d68b68de6f06bb43b96: 0.01
- Vector1_c6f2603b30534ec8b0039379573789e3: 1
- Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9: 0.12
- Vector1_dd1e17693dc14b10b91828bdfd5adaa8: 0
- Vector1_ff7a2780aaa94ddd86e156c4707e39a2: 0.5
- _QueueControl: 0
- _QueueOffset: 0
- _XRMotionVectorsPass: 1
m_Colors:
- Color_1ec6cccf8ead489ebb917674f7e8b3b1: {r: 1, g: 1, b: 1, a: 1}
- Color_2323d69962e04c499c5d5f0925432b55: {r: 0.8, g: 0.9, b: 0.96, a: 1}
- Color_9af4ad59934f40d1ae6565e6ab22c45e: {r: 0.298, g: 0.8, b: 1, a: 1}
- Color_ca031ae309ff42bdb95f777248fb961d: {r: 0.133, g: 0.518, b: 0.745, a: 1}
- Color_e1f155248d144786a62fc1585ca21e9a: {r: 1, g: 1, b: 1, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &7840779067325084833
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: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4ccbf1a15347b64459d3a1fa63cc303d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,99 @@
%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: Farm_Water_WL_C
m_Shader: {fileID: -6465566751694194690, guid: 85b142f88e4bec1488c6b275a0e5dc57,
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:
- Texture2D_086cedcb1d864765840f9996e4b0002d:
m_Texture: {fileID: 2800000, guid: 945a5174b1a6da34ea1028ed2feeb1e9, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_1d2b8f4484d74423a27218f18b962ade:
m_Texture: {fileID: 2800000, guid: d48aae5302069a94f9410b8d6b76fed1, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_4094dc7f19e94579ac3bbc9c811f51a4:
m_Texture: {fileID: 2800000, guid: 62100fbe73f198245b71c0a6eeeb94f6, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- Texture2D_685ca00e8e7c4cb2b45a9e11981bb64a:
m_Texture: {fileID: 2800000, guid: 5088aa2234cf5b24cad13def77f7da5f, type: 3}
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:
- Vector1_07238257334b4a149e675e2451801030: 7.83
- Vector1_101dc4546b684d40bc2ff2fc59ab43d5: 2.2
- Vector1_11671d7a4cdb4d059a6c69e39f3f7b3f: 28
- Vector1_21ae4fce4585460386edec89c9895501: 0
- Vector1_2b4963cef1de4859983ffcbae94c6f60: 0
- Vector1_3089b6a325a44c1686907af4ee3b0776: 0.4
- Vector1_34f757bec6b8422b9aef3b9d97117a6e: 4
- Vector1_566e288f42864b8e9432d81fbdb83f38: 7
- Vector1_68f0c21b684f4b7c9ebef8789113b107: 2
- Vector1_7090c8ca8ea84e2d85858ae4beb5be38: 1
- Vector1_85ea9246e72a44ed9e0482861767c826: 0.03
- Vector1_8e22a98f75c94b218c49e6c4805e799d: 0.01
- Vector1_99cc56b5c6fd474082f07f00a6df94f9: 0.0394
- Vector1_ad7e0fcd37f44d68b68de6f06bb43b96: 0.01
- Vector1_c6f2603b30534ec8b0039379573789e3: 1
- Vector1_d813b569a4d541d1b2ac4ea9bc66a3b9: 0.09
- Vector1_dd1e17693dc14b10b91828bdfd5adaa8: 0
- Vector1_ff7a2780aaa94ddd86e156c4707e39a2: 0.4
- _QueueControl: 0
- _QueueOffset: 0
- _XRMotionVectorsPass: 1
m_Colors:
- Color_1ec6cccf8ead489ebb917674f7e8b3b1: {r: 1, g: 1, b: 1, a: 1}
- Color_2323d69962e04c499c5d5f0925432b55: {r: 0.78, g: 0.86, b: 0.92, a: 1}
- Color_9af4ad59934f40d1ae6565e6ab22c45e: {r: 0.36, g: 0.69, b: 0.82, a: 1}
- Color_ca031ae309ff42bdb95f777248fb961d: {r: 0.17, g: 0.42, b: 0.57, a: 1}
- Color_e1f155248d144786a62fc1585ca21e9a: {r: 1, g: 1, b: 1, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &7840779067325084833
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: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c4a590309ecaa044da75b96fa1e150a3
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -55,6 +55,16 @@ MonoBehaviour:
- 0.5
- 2
- 5
skyScopeEnabled: 1
skyScenes:
- Level01
- WL_FarmLook
- WL_Dungeon01
- WL_Dungeon02
skyReleaseDelaySeconds: 1.5
waterMode: 1
waterFrom: {fileID: 2100000, guid: ce0f8fd131f36964dbc918b8c63f838b, type: 2}
waterTo: {fileID: 2100000, guid: c4a590309ecaa044da75b96fa1e150a3, type: 2}
grassEnabled: 1
scatter:
- enabled_: 1

View File

@ -268,8 +268,30 @@ namespace WL.Look.Farm
}
}
/// <summary>
/// 🔴 816h — 섬 둘레의 바다(`Water` · 1000×1000 평면)를 **WL 워터 셰이더**로.
/// `Assets/FarmingIsland/**` 는 0줄 — 렌더러의 `sharedMaterials` 만 런타임에 바꾼다.
/// `waterMode = 0` 이면 이 판정 자체를 건너뛰어 지금(FarmingIsland 물)으로 100 % 돌아간다.
/// </summary>
static bool IsWater(WLIslandLookSettings cfg, Material src)
{
if (src == null) return false;
if (cfg.waterFrom != null && src == cfg.waterFrom) return true;
if (src.shader != null && src.shader.name == "Shader Graphs/Simple Water") return true;
// 이미 우리 복사본(Farm_SimpleWater_Demo)으로 바뀐 뒤 다시 훑는 경우
return src.name.StartsWith("Farm_SimpleWater");
}
public static int WaterSwapped;
static Material Lookup(WLIslandLookSettings cfg, Material src)
{
if (cfg.waterMode != 0 && cfg.waterTo != null && IsWater(cfg, src))
{
if (src != cfg.waterTo) WaterSwapped++;
return cfg.waterTo;
}
for (int i = 0; i < cfg.materialRemap.Length; i++)
{
var e = cfg.materialRemap[i];
@ -286,15 +308,23 @@ namespace WL.Look.Farm
// ─────────────────────────────────────────────────────────────────
public static void ApplyLighting(WLIslandLookSettings cfg, Scene scene)
{
RenderSettings.ambientMode = AmbientMode.Skybox;
RenderSettings.ambientSkyColor = cfg.ambientSky;
RenderSettings.ambientEquatorColor = cfg.ambientEquator;
RenderSettings.ambientGroundColor = cfg.ambientGround;
RenderSettings.ambientLight = cfg.ambientSky;
RenderSettings.ambientIntensity = cfg.ambientIntensity;
if (cfg.fogOff != 0) RenderSettings.fog = false;
if (cfg.skybox != null) RenderSettings.skybox = cfg.skybox;
RenderSettings.defaultReflectionMode = DefaultReflectionMode.Skybox;
// 🔴 816h — 하늘(앰비언트·스카이박스·안개·반사)은 **활성 씬(InGame)** 소유라
// 여기서 그냥 쓰면 섬에서 나간 뒤 전투 맵·로비까지 그대로 남는다.
// 그래서 `WLSkyScope` 가 **스냅샷 → 적용 → 나갈 때 원복** 을 맡는다.
// (값은 그대로 이 SO 것 = 아레나/데모 값. 새 값 0)
if (cfg.skyScopeEnabled != 0) WLSkyScope.Acquire(cfg, scene.name);
else
{
RenderSettings.ambientMode = AmbientMode.Skybox;
RenderSettings.ambientSkyColor = cfg.ambientSky;
RenderSettings.ambientEquatorColor = cfg.ambientEquator;
RenderSettings.ambientGroundColor = cfg.ambientGround;
RenderSettings.ambientLight = cfg.ambientSky;
RenderSettings.ambientIntensity = cfg.ambientIntensity;
if (cfg.fogOff != 0) RenderSettings.fog = false;
if (cfg.skybox != null) RenderSettings.skybox = cfg.skybox;
RenderSettings.defaultReflectionMode = DefaultReflectionMode.Skybox;
}
var lights = Object.FindObjectsByType<Light>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
for (int i = 0; i < lights.Length; i++)

View File

@ -171,6 +171,32 @@ namespace WL.Look.Farm
[Tooltip("런타임에 뒤늦게 생기는 오브젝트(상인·작물·아이템)까지 잡기 위해 다시 훑는 시각(초).")]
public float[] rescanAtSeconds = new float[] { 0.5f, 2f, 5f };
// ───────────────────────────────── §816h-1 하늘 범위
[Header("§816h — 하늘(RenderSettings)은 「활성 씬」 소유다")]
[Tooltip("🔴 816f/816h 실측 — 섬·던전·전투 맵은 전부 `InGame` 위에 **Additive** 로 붙는다. " +
"그래서 앰비언트·스카이박스·안개는 붙는 씬이 아니라 **활성 씬(InGame)** 것이 쓰인다. " +
"1 이면 아래 `skyScenes` 에 들어간 맵에 들어갈 때만 활성 씬의 하늘을 **스냅샷 뜨고** 우리 값으로 바꾸고, " +
"그 맵에서 나가면 **스냅샷 그대로 되돌린다**(= 다른 맵 오염 0).")]
public int skyScopeEnabled = 1;
[Tooltip("하늘을 통일할 맵. 섬과 던전이 같은 하늘을 쓰게 한다. 전투 맵은 여기 넣지 않는다(원래대로).")]
public string[] skyScenes = new string[] { "Level01", "WL_FarmLook", "WL_Dungeon01", "WL_Dungeon02" };
[Tooltip("맵을 바꿀 때 `SceneInfo` 는 내리기와 올리기를 같은 프레임에 시작한다(실측). " +
"이만큼 기다린 뒤에도 범위 맵이 하나도 없을 때만 하늘을 반납한다 — 섬↔던전 이동에서 한 번 튀는 것을 막는다.")]
public float skyReleaseDelaySeconds = 1.5f;
// ───────────────────────────────── §816h-2 물
[Header("§816h — 섬의 물을 WL 워터 셰이더로 (PD 지시)")]
[Tooltip("0 = 지금(FarmingIsland 물 · 100 % 복귀) · 1 = WL 워터(`ToonWaterU`).")]
public int waterMode = 1;
[Tooltip("교체 대상 판별 — FarmingIsland 원본 물 머티리얼(참조만 · 0줄 수정).")]
public Material waterFrom;
[Tooltip("WL 워터 복사본(`Assets/WL/Materials/WL_Water_Ocean.mat` 기준). 비우면 교체하지 않는다.")]
public Material waterTo;
// ───────────────────────────────── §1 풀밭
[Header("§1 — 섬 타일 위 풀밭 (데모와 같은 인스턴싱)")]
[Tooltip("0 이면 풀을 깔지 않는다.")]

View File

@ -0,0 +1,271 @@
// ─────────────────────────────────────────────────────────────────────────────
// WLSkyScope.cs — 하늘(RenderSettings)을 「들어간 맵 동안만」 빌려 쓰고 나갈 때 돌려준다
// (WL-816h · #816)
//
// ■ 왜 필요한가 — 🔴 실측(816f · 816h)
// `RenderSettings`(앰비언트·스카이박스·안개·반사·sun)는 **씬마다 하나가 아니라
// 「활성 씬」 하나가 소유**한다. 이 게임은 `InGame` 을 활성으로 두고 섬·던전·전투 맵을
// 전부 **Additive** 로 붙인다(`SceneInfo.Load_AddScene` 실측). 그래서
// · 섬 씬(`Level01`)이 제 씬에 적어 둔 하늘(FarmingIsland Skybox)은 **절대 안 쓰이고**
// · 누가 `RenderSettings` 에 쓰면 그것은 **모든 맵에 남는다**(전투 맵·로비까지 오염).
// 816e/816f 의 `WLIslandLook.ApplyLighting` 은 값을 **쓰기만** 하고 되돌리지 않았다.
// 지금은 쓰는 값이 마침 `InGame` 원본과 같아서 오염이 안 보였을 뿐이다(816h 실측 = 차이 0).
//
// ■ 그래서 이렇게 고친다
// `skyScenes`(섬·던전)에 **처음 들어갈 때 활성 씬의 하늘을 통째로 스냅샷**해 두고
// 우리 값(= 아레나/데모와 같은 값 · SO 재사용)으로 바꾼다.
// 그 맵들이 **하나도 안 남았을 때** 스냅샷을 **글자 그대로** 되돌린다.
// → 섬·던전은 같은 하늘 · 전투 맵·로비는 원래대로.
//
// ■ C8 되돌리기 — `WLIslandLookSettings.skyScopeEnabled = 0` 이면 아무것도 하지 않는다.
// 씬·에셋 파일을 한 글자도 쓰지 않는다(전부 런타임 메모리).
//
// 🔴 Debug.LogError / Debug.LogException 을 쓰지 않는다(ErrorLogHookManager 팝업).
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
namespace WL.Look.Farm
{
public static class WLSkyScope
{
public const string RunnerName = "~WLSkyScopeRunner";
// ── 진단(프로브가 읽는다) ────────────────────────────────────────
public static bool Held;
public static int Acquires, Applies, Restores;
public static string LastLog = "";
public static string HeldBy = "";
struct Snap
{
public bool valid;
public string ownerScene;
public AmbientMode mode;
public Color light, sky, equator, ground;
public float intensity;
public Material skybox;
public bool fog; public Color fogColor; public FogMode fogMode;
public float fogDensity, fogStart, fogEnd;
public DefaultReflectionMode reflMode; public float reflIntensity;
public Light sun;
}
static Snap s_snap;
static int s_snapHandle; // 스냅샷을 뜬 활성 씬
static bool s_installed;
static WLSkyScopeRunner s_runner;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
public static void Install()
{
if (s_installed) return;
var cfg = WLIslandLookSettings.Instance;
if (cfg == null || cfg.enabled_ == 0 || cfg.skyScopeEnabled == 0) return;
s_installed = true;
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.sceneUnloaded += OnSceneUnloaded;
SceneManager.activeSceneChanged += OnActiveSceneChanged;
// 🔴 아직 아무 맵도 안 붙은 지금이 「활성 씬의 원래 하늘」이다 — 여기서 한 번만 뜬다.
CaptureIfNeeded();
for (int i = 0; i < SceneManager.sceneCount; i++)
{
var sc = SceneManager.GetSceneAt(i);
if (sc.isLoaded && IsScoped(cfg, sc.name)) Acquire(cfg, sc.name);
}
}
static void OnActiveSceneChanged(Scene from, Scene to)
{
// 활성 씬이 바뀌면 하늘의 주인이 바뀐 것 — 새 주인의 원래 값을 다시 뜬다.
s_snap.valid = false;
Held = false; HeldBy = "";
CaptureIfNeeded();
}
public static bool IsScoped(WLIslandLookSettings cfg, string sceneName)
{
if (cfg == null || cfg.skyScenes == null) return false;
for (int i = 0; i < cfg.skyScenes.Length; i++)
if (cfg.skyScenes[i] == sceneName) return true;
return false;
}
static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
var cfg = WLIslandLookSettings.Instance;
if (cfg == null || cfg.enabled_ == 0 || cfg.skyScopeEnabled == 0) return;
if (!IsScoped(cfg, scene.name)) return;
Acquire(cfg, scene.name);
}
static void OnSceneUnloaded(Scene scene)
{
var cfg = WLIslandLookSettings.Instance;
if (cfg == null || cfg.skyScopeEnabled == 0) return;
if (!Held) return;
// 🔴 맵을 바꿀 때 `SceneInfo` 는 **같은 프레임에** 내리기와 올리기를 함께 시작한다.
// 그래서 바로 되돌리면 「섬 → 던전」 에서 잘못 되돌아간다. 두 프레임 기다렸다
// **그때도 범위 맵이 하나도 없을 때만** 되돌린다.
EnsureRunner();
if (s_runner != null) s_runner.StartCoroutine(Co_MaybeRelease(cfg));
else ReleaseIfEmpty(cfg);
}
static IEnumerator Co_MaybeRelease(WLIslandLookSettings cfg)
{
yield return null;
yield return null;
// 🔴 섬 → 던전처럼 범위 안에서 맵만 바뀔 때는 새 맵이 다 올라올 때까지 기다린다.
// (안 기다리면 반납했다가 다시 빌리면서 화면이 한 번 튄다 — 816h 실측)
float wait = cfg != null ? cfg.skyReleaseDelaySeconds : 1.5f;
if (wait > 0f) yield return new WaitForSeconds(wait);
ReleaseIfEmpty(cfg);
}
static void ReleaseIfEmpty(WLIslandLookSettings cfg)
{
for (int i = 0; i < SceneManager.sceneCount; i++)
{
var sc = SceneManager.GetSceneAt(i);
if (sc.isLoaded && IsScoped(cfg, sc.name)) return; // 아직 섬/던전에 있다
}
Release(cfg);
}
// ─────────────────────────────────────────────────────────────────
/// <summary>섬·던전에 들어갈 때 — 활성 씬의 하늘을 스냅샷하고 우리 값으로 바꾼다.</summary>
public static void Acquire(WLIslandLookSettings cfg, string sceneName)
{
if (cfg == null || cfg.skyScopeEnabled == 0) return;
// 🔴 스냅샷은 **활성 씬마다 딱 한 번**만 뜬다.
// 여기서 다시 뜨면, 이미 다른 시스템(던전 씬에 들어 있는 `WL_ReferenceLook`)이
// 앰비언트를 바꿔 놓은 뒤의 값을 「원래 값」으로 잘못 기억한다(816h 1차 실측에서 실제로 났다).
CaptureIfNeeded();
if (!Held)
{
Held = true;
HeldBy = sceneName;
Acquires++;
}
ApplySky(cfg);
}
/// <summary>섬·던전에서 나갈 때 — 스냅샷을 글자 그대로 되돌린다.</summary>
public static void Release(WLIslandLookSettings cfg)
{
if (!Held) return;
Restore();
Held = false; HeldBy = "";
Restores++;
if (cfg != null) cfg.Log("하늘 반납 — 활성 씬(" + s_snap.ownerScene + ") 원래대로");
LastLog = "released → " + Describe();
}
static void CaptureIfNeeded()
{
var act = SceneManager.GetActiveScene();
if (s_snap.valid && s_snapHandle == act.handle) return;
s_snapHandle = act.handle;
Capture();
}
static void Capture()
{
s_snap.valid = true;
s_snap.ownerScene = SceneManager.GetActiveScene().name;
s_snap.mode = RenderSettings.ambientMode;
s_snap.light = RenderSettings.ambientLight;
s_snap.sky = RenderSettings.ambientSkyColor;
s_snap.equator = RenderSettings.ambientEquatorColor;
s_snap.ground = RenderSettings.ambientGroundColor;
s_snap.intensity = RenderSettings.ambientIntensity;
s_snap.skybox = RenderSettings.skybox;
s_snap.fog = RenderSettings.fog;
s_snap.fogColor = RenderSettings.fogColor;
s_snap.fogMode = RenderSettings.fogMode;
s_snap.fogDensity = RenderSettings.fogDensity;
s_snap.fogStart = RenderSettings.fogStartDistance;
s_snap.fogEnd = RenderSettings.fogEndDistance;
s_snap.reflMode = RenderSettings.defaultReflectionMode;
s_snap.reflIntensity = RenderSettings.reflectionIntensity;
s_snap.sun = RenderSettings.sun;
}
static void Restore()
{
if (!s_snap.valid) return;
RenderSettings.ambientMode = s_snap.mode;
RenderSettings.ambientLight = s_snap.light;
RenderSettings.ambientSkyColor = s_snap.sky;
RenderSettings.ambientEquatorColor = s_snap.equator;
RenderSettings.ambientGroundColor = s_snap.ground;
RenderSettings.ambientIntensity = s_snap.intensity;
RenderSettings.skybox = s_snap.skybox;
RenderSettings.fog = s_snap.fog;
RenderSettings.fogColor = s_snap.fogColor;
RenderSettings.fogMode = s_snap.fogMode;
RenderSettings.fogDensity = s_snap.fogDensity;
RenderSettings.fogStartDistance = s_snap.fogStart;
RenderSettings.fogEndDistance = s_snap.fogEnd;
RenderSettings.defaultReflectionMode = s_snap.reflMode;
RenderSettings.reflectionIntensity = s_snap.reflIntensity;
RenderSettings.sun = s_snap.sun; // 내려간 씬의 라이트면 자동으로 null 이 된다
}
/// <summary>아레나/데모와 같은 하늘 — 값은 전부 SO 에서 온다(새 값 0).</summary>
static void ApplySky(WLIslandLookSettings cfg)
{
// 하늘 그 자체(스카이박스·안개·반사)는 언제나 우리 값으로.
if (cfg.fogOff != 0) RenderSettings.fog = false;
if (cfg.skybox != null) RenderSettings.skybox = cfg.skybox;
RenderSettings.defaultReflectionMode = DefaultReflectionMode.Skybox;
// 🔴 앰비언트(무드)는 `WLReferenceLook`(814t 아레나 룩)의 것이다.
// 던전 씬에는 `WL_ReferenceLook` 이 **씬에 들어 있어** 우리보다 먼저 켜진다.
// 그때 여기서 앰비언트를 덮어쓰면 던전의 아레나 무드가 죽는다 → 이미 걸렸으면 손대지 않는다.
// (섬에서는 우리가 먼저 → 이 값을 깔고, 그 위에 아레나 무드가 얹힌다 = 던전과 같은 결과)
if (!WL.Look.Arena.WLReferenceLook.IsApplied)
{
RenderSettings.ambientMode = AmbientMode.Skybox;
RenderSettings.ambientSkyColor = cfg.ambientSky;
RenderSettings.ambientEquatorColor = cfg.ambientEquator;
RenderSettings.ambientGroundColor = cfg.ambientGround;
RenderSettings.ambientLight = cfg.ambientSky;
RenderSettings.ambientIntensity = cfg.ambientIntensity;
}
Applies++;
LastLog = "held(" + HeldBy + ") → " + Describe();
}
public static string Describe()
{
return "amb=" + RenderSettings.ambientMode
+ " light=(" + RenderSettings.ambientLight.r.ToString("F3") + ","
+ RenderSettings.ambientLight.g.ToString("F3") + ","
+ RenderSettings.ambientLight.b.ToString("F3") + ")"
+ " skybox=" + (RenderSettings.skybox ? RenderSettings.skybox.name : "없음")
+ " fog=" + RenderSettings.fog
+ " refl=" + RenderSettings.defaultReflectionMode
+ " sun=" + (RenderSettings.sun ? RenderSettings.sun.name : "없음");
}
static void EnsureRunner()
{
if (s_runner != null) return;
var go = new GameObject(RunnerName);
go.hideFlags = HideFlags.DontSave;
Object.DontDestroyOnLoad(go);
s_runner = go.AddComponent<WLSkyScopeRunner>();
}
}
/// <summary>코루틴 한 개를 태우기 위한 빈 그릇.</summary>
public sealed class WLSkyScopeRunner : MonoBehaviour { }
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 574d1f0a1b453ca4fbf7b1b25cf059a6