[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>
This commit is contained in:
parent
f04ac8cfb6
commit
0b649230d8
|
|
@ -0,0 +1,58 @@
|
|||
// WL-816f — 채택값을 에셋에 굽는다(에디트 모드).
|
||||
// ① 풀 머티리얼 복사본 `Farm_Grass_Demo.mat`(데모 `Instanced_Grass` 0줄 · 복사본만)
|
||||
// ② SO: 풀 머티리얼 교체 · 밀도 2.5 → 1.8
|
||||
public static class WL816f_Build
|
||||
{
|
||||
const string SoPath = "Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset";
|
||||
const string MatPath = "Assets/WL/Look/Farm/Materials/Farm_Grass_Demo.mat";
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
var cfg = UnityEditor.AssetDatabase.LoadAssetAtPath<WL.Look.Farm.WLIslandLookSettings>(SoPath);
|
||||
if (cfg == null) { UnityEngine.Debug.Log("SO 없음"); return; }
|
||||
|
||||
// ① 풀 머티리얼 복사본
|
||||
UnityEngine.Material grassSrc = null;
|
||||
for (int i = 0; i < cfg.scatter.Length; i++)
|
||||
if (cfg.scatter[i] != null && cfg.scatter[i].label.Contains("풀")) grassSrc = cfg.scatter[i].material;
|
||||
if (grassSrc == null) { UnityEngine.Debug.Log("풀 머티리얼 없음"); return; }
|
||||
|
||||
var mat = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(MatPath);
|
||||
if (mat == null)
|
||||
{
|
||||
mat = new UnityEngine.Material(grassSrc);
|
||||
mat.name = "Farm_Grass_Demo";
|
||||
UnityEditor.AssetDatabase.CreateAsset(mat, MatPath);
|
||||
sb.AppendLine("새 머티리얼 " + MatPath + " (원본 " + grassSrc.name + " 복사)");
|
||||
}
|
||||
else sb.AppendLine("기존 머티리얼 갱신 " + MatPath);
|
||||
|
||||
// 816f 실측 채택값 — 풀 화면색 ≈ 바닥 화면색(데모와 같은 「안 튀는 풀」)
|
||||
mat.SetColor("_DiffuseColor", Hex("#A6E39F"));
|
||||
mat.SetColor("_ShadowDiffuseColor", Hex("#95CC8F"));
|
||||
UnityEditor.EditorUtility.SetDirty(mat);
|
||||
|
||||
// ② SO
|
||||
for (int i = 0; i < cfg.scatter.Length; i++)
|
||||
{
|
||||
var s = cfg.scatter[i];
|
||||
if (s == null) continue;
|
||||
if (s.label.Contains("풀")) { s.material = mat; s.density = 1.8f; sb.AppendLine("풀: mat→Farm_Grass_Demo · density 2.5→1.8"); }
|
||||
else if (s.label.Contains("꽃")) { s.density = 1.8f; sb.AppendLine("꽃: density 2.5→1.8 (풀과 같은 층)"); }
|
||||
}
|
||||
UnityEditor.EditorUtility.SetDirty(cfg);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
|
||||
sb.AppendLine("soilToneEnabled=" + cfg.soilToneEnabled + " soilTint=" + cfg.soilTint + " soilCheckerContrast=" + cfg.soilCheckerContrast);
|
||||
sb.AppendLine("islandTopMaterial=" + (cfg.islandTopMaterial ? cfg.islandTopMaterial.name : "없음")
|
||||
+ " _BaseMap=" + (cfg.islandTopMaterial && cfg.islandTopMaterial.GetTexture("_BaseMap")
|
||||
? cfg.islandTopMaterial.GetTexture("_BaseMap").name : "없음"));
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_BUILD.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
static UnityEngine.Color Hex(string h)
|
||||
{ UnityEngine.Color c; UnityEngine.ColorUtility.TryParseHtmlString(h, out c); return c; }
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// WL-816f — SO 토글(되돌리기 검증용)
|
||||
public static class WL816f_Ctl
|
||||
{
|
||||
const string kSo = "Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset";
|
||||
public static void Off() { Set(0); }
|
||||
public static void On() { Set(1); }
|
||||
static void Set(int en)
|
||||
{
|
||||
var so = UnityEditor.AssetDatabase.LoadAssetAtPath<WL.Look.Farm.WLIslandLookSettings>(kSo);
|
||||
so.enabled_ = en;
|
||||
UnityEditor.EditorUtility.SetDirty(so);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
WL.Look.Farm.WLIslandLookSettings.Invalidate();
|
||||
UnityEngine.Debug.Log("[816f Ctl] enabled_=" + en);
|
||||
}
|
||||
|
||||
/// <summary>Play 중: 되돌리기 상태 실측 + 캡처</summary>
|
||||
public static void Rollback()
|
||||
{
|
||||
var go = UnityEngine.GameObject.Find("~WL816fRb");
|
||||
if (go != null) UnityEngine.Object.DestroyImmediate(go);
|
||||
go = new UnityEngine.GameObject("~WL816fRb");
|
||||
go.AddComponent<WL816f_RbRunner>();
|
||||
}
|
||||
}
|
||||
|
||||
public class WL816f_RbRunner : UnityEngine.MonoBehaviour
|
||||
{
|
||||
void Start() { StartCoroutine(Co()); }
|
||||
System.Collections.IEnumerator Co()
|
||||
{
|
||||
if (UnityEngine.SceneManagement.SceneManager.sceneCount < 2)
|
||||
{
|
||||
var op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Level01", UnityEngine.SceneManagement.LoadSceneMode.Additive);
|
||||
while (op != null && !op.isDone) yield return null;
|
||||
}
|
||||
for (int i = 0; i < 6; i++) yield return new UnityEngine.WaitForSeconds(1f);
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
var cfg = WL.Look.Farm.WLIslandLookSettings.Instance;
|
||||
sb.AppendLine("enabled_=" + (cfg == null ? -1 : cfg.enabled_));
|
||||
sb.AppendLine("머티리얼 교체 " + WL.Look.Farm.WLIslandLook.SwappedRenderers + " · 풀 " + WL.Look.Farm.WLIslandGrass.Instances
|
||||
+ " · refLook " + WL.Look.Arena.WLReferenceLook.IsApplied
|
||||
+ " · Soil톤 farm " + WL.Look.Farm.WLIslandLook.SoilFarmsToned);
|
||||
sb.AppendLine("ambient " + UnityEngine.RenderSettings.ambientMode + " " + UnityEngine.RenderSettings.ambientLight
|
||||
+ " skybox=" + (UnityEngine.RenderSettings.skybox ? UnityEngine.RenderSettings.skybox.name : "없음"));
|
||||
var soils = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Soil>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
string c0 = "-", c1 = "-";
|
||||
for (int i = 0; i < soils.Length && i < 2; i++)
|
||||
{
|
||||
var r = soils[i].GetComponentInChildren<UnityEngine.Renderer>(true);
|
||||
if (r == null) continue;
|
||||
if (i == 0) c0 = UnityEngine.ColorUtility.ToHtmlStringRGB(r.material.color);
|
||||
else c1 = UnityEngine.ColorUtility.ToHtmlStringRGB(r.material.color);
|
||||
}
|
||||
sb.AppendLine("Soil 색 [0]=" + c0 + " [1]=" + c1);
|
||||
var rends = UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
var shaders = new System.Collections.Generic.Dictionary<string, int>();
|
||||
for (int i = 0; i < rends.Length; i++)
|
||||
{
|
||||
if (rends[i].gameObject.scene.name != "Level01") continue;
|
||||
var m = rends[i].sharedMaterial; if (m == null) continue;
|
||||
var k = m.shader.name;
|
||||
shaders[k] = shaders.ContainsKey(k) ? shaders[k] + 1 : 1;
|
||||
}
|
||||
foreach (var kv in shaders) sb.AppendLine("shader " + kv.Key + " ×" + kv.Value);
|
||||
|
||||
var cams = UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
UnityEngine.Camera top = null;
|
||||
for (int i = 0; i < cams.Length; i++) { var c = cams[i]; if (!c.enabled || c.targetTexture != null) continue; if (top == null || c.depth > top.depth) top = c; }
|
||||
if (top != null)
|
||||
{
|
||||
System.IO.Directory.CreateDirectory("Screenshots_WL/WL816f");
|
||||
var rt = new UnityEngine.RenderTexture(1080, 1920, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
||||
rt.Create(); var pt = top.targetTexture; top.targetTexture = rt; top.Render();
|
||||
UnityEngine.RenderTexture.active = rt;
|
||||
var tex = new UnityEngine.Texture2D(1080, 1920, UnityEngine.TextureFormat.RGB24, false);
|
||||
tex.ReadPixels(new UnityEngine.Rect(0, 0, 1080, 1920), 0, 0); tex.Apply();
|
||||
System.IO.File.WriteAllBytes("Screenshots_WL/WL816f/z_rollback.png", UnityEngine.ImageConversion.EncodeToPNG(tex));
|
||||
UnityEngine.RenderTexture.active = null; top.targetTexture = pt;
|
||||
UnityEngine.Object.DestroyImmediate(tex); rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
|
||||
sb.AppendLine("캡처 Screenshots_WL/WL816f/z_rollback.png");
|
||||
}
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_ROLLBACK.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log("[816f rollback]\n" + sb.ToString());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// WL-816f §2 — 데모 바닥 vs 우리 바닥 실측(에디트 모드 · 데모 씬 Play 안 함)
|
||||
// ① 풀 메시의 월드 크기 ② 격자 간격 ③ 풀 머티리얼 색 ④ 바닥 머티리얼 색
|
||||
public static class WL816f_Ground
|
||||
{
|
||||
public static void Run()
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
|
||||
// ── 데모 ────────────────────────────────────────────────────
|
||||
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
|
||||
"Assets/3DPixelArtEnvironment/Demo/Demo.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||||
sb.AppendLine("=== 데모 (Demo.unity) ===");
|
||||
var tibs = UnityEngine.Object.FindObjectsByType<Environment.Instancing.TerrainInstancesBehaviour>(
|
||||
UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
|
||||
foreach (var t in tibs)
|
||||
{
|
||||
sb.AppendLine("TIB " + t.name + " lossyScale=" + t.transform.lossyScale.ToString("F3")
|
||||
+ " posVar=" + t.PositionVariance + " scaleVar=" + t.ScaleVariance);
|
||||
var terr = t.GetComponent<UnityEngine.Terrain>();
|
||||
if (terr != null) sb.AppendLine(" terrain size=" + terr.terrainData.size.ToString("F1")
|
||||
+ " alphamapTex=" + terr.terrainData.alphamapTextureCount
|
||||
+ " mat=" + (terr.materialTemplate ? terr.materialTemplate.name + " (" + terr.materialTemplate.shader.name + ")" : "없음"));
|
||||
Layer(sb, "1층", t.FirstLayer, t.transform.lossyScale);
|
||||
Layer(sb, "2층", t.SecondLayer, t.transform.lossyScale);
|
||||
Layer(sb, "3층", t.ThirdLayer, t.transform.lossyScale);
|
||||
Layer(sb, "4층", t.FourthLayer, t.transform.lossyScale);
|
||||
if (terr != null && terr.materialTemplate != null) MatDump(sb, " 지형mat ", terr.materialTemplate);
|
||||
}
|
||||
|
||||
// 데모 지형 스플랫 — 1층(풀)이 차지하는 면적 비율
|
||||
foreach (var t in tibs)
|
||||
{
|
||||
var terr = t.GetComponent<UnityEngine.Terrain>();
|
||||
if (terr == null || terr.terrainData.alphamapTextureCount == 0) continue;
|
||||
var tex = terr.terrainData.alphamapTextures[0];
|
||||
var px = tex.GetPixels();
|
||||
int[] cnt = new int[4];
|
||||
for (int i = 0; i < px.Length; i++)
|
||||
{
|
||||
float[] v = { px[i].r, px[i].g, px[i].b, px[i].a };
|
||||
int bi = 0; for (int k = 1; k < 4; k++) if (v[k] > v[bi]) bi = k;
|
||||
cnt[bi]++;
|
||||
}
|
||||
sb.AppendLine(" 스플랫 지배비율(" + tex.width + "x" + tex.height + "): 1층 " + (100f * cnt[0] / px.Length).ToString("F1")
|
||||
+ "% · 2층 " + (100f * cnt[1] / px.Length).ToString("F1") + "% · 3층 " + (100f * cnt[2] / px.Length).ToString("F1")
|
||||
+ "% · 4층 " + (100f * cnt[3] / px.Length).ToString("F1") + "%");
|
||||
}
|
||||
|
||||
// ── 우리 ────────────────────────────────────────────────────
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=== 우리 (WLIslandLookSettings) ===");
|
||||
var cfg = UnityEditor.AssetDatabase.LoadAssetAtPath<WL.Look.Farm.WLIslandLookSettings>(
|
||||
"Assets/WL/Look/Farm/Resources/WL/WLIslandLookSettings.asset");
|
||||
sb.AppendLine("posVar=" + cfg.positionVariance + " scaleVar=" + cfg.scaleVariance + " edgeInset=" + cfg.edgeInset);
|
||||
for (int i = 0; i < cfg.scatter.Length; i++)
|
||||
{
|
||||
var s = cfg.scatter[i];
|
||||
var b = s.mesh != null ? s.mesh.bounds.size : UnityEngine.Vector3.zero;
|
||||
sb.AppendLine(" [" + s.label + "] en=" + s.enabled_ + " mesh=" + (s.mesh ? s.mesh.name : "없음")
|
||||
+ " bounds=" + b.ToString("F3") + " scale=" + s.scale
|
||||
+ " → 월드 " + (b * s.scale).ToString("F3")
|
||||
+ " · prob=" + s.probability + " density=" + s.density + "(=" + (s.density * s.density).ToString("F2") + "개/㎡ · 격자 "
|
||||
+ (1f / s.density).ToString("F3") + "m)"
|
||||
+ " mat=" + (s.material ? s.material.name : "없음"));
|
||||
if (s.material != null) MatDump(sb, " ", s.material);
|
||||
}
|
||||
sb.AppendLine("islandTopMaterial = " + (cfg.islandTopMaterial ? cfg.islandTopMaterial.name : "없음"));
|
||||
if (cfg.islandTopMaterial != null) MatDump(sb, " ", cfg.islandTopMaterial);
|
||||
for (int i = 0; i < cfg.materialRemap.Length; i++)
|
||||
{
|
||||
var e = cfg.materialRemap[i];
|
||||
sb.AppendLine(" remap en=" + e.enabled_ + " " + (e.from ? e.from.name : "-") + " → " + (e.to ? e.to.name : "-")
|
||||
+ (e.to != null && e.to.HasProperty("_BaseMap") && e.to.GetTexture("_BaseMap") != null
|
||||
? " 🔴텍스처 " + e.to.GetTexture("_BaseMap").name : " (텍스처 없음)"));
|
||||
}
|
||||
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_GROUND.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
static void Layer(System.Text.StringBuilder sb, string name,
|
||||
Environment.Instancing.TerrainInstancesBehaviour.TerrainInstancingInput inp, UnityEngine.Vector3 lossy)
|
||||
{
|
||||
if (inp == null || inp.Settings == null || inp.Settings.Length == 0) { sb.AppendLine(" " + name + " (없음)"); return; }
|
||||
sb.AppendLine(" " + name + " Density=" + inp.Density + " (=" + (inp.Density * inp.Density).ToString("F2")
|
||||
+ "개/㎡ · 격자 " + (1f / inp.Density).ToString("F3") + "m)");
|
||||
foreach (var s in inp.Settings)
|
||||
{
|
||||
var b = s.Mesh != null ? s.Mesh.bounds.size : UnityEngine.Vector3.zero;
|
||||
var w = new UnityEngine.Vector3(b.x * s.Scale * lossy.x, b.y * s.Scale * lossy.y, b.z * s.Scale * lossy.z);
|
||||
sb.AppendLine(" mesh=" + (s.Mesh ? s.Mesh.name + "(tri " + (s.Mesh.triangles.Length / 3) + ")" : "없음")
|
||||
+ " bounds=" + b.ToString("F3") + " Scale=" + s.Scale + " → 월드 " + w.ToString("F3")
|
||||
+ " prob=" + s.Probability + " nOff=" + s.NormalOffset
|
||||
+ " mat=" + (s.Material ? s.Material.name : "없음"));
|
||||
if (s.Material != null) MatDump(sb, " ", s.Material);
|
||||
}
|
||||
}
|
||||
|
||||
static void MatDump(System.Text.StringBuilder sb, string pad, UnityEngine.Material m)
|
||||
{
|
||||
string[] cols = { "_DiffuseColor", "_ShadowDiffuseColor", "_BaseColor", "_Color", "_TopColor", "_BottomColor", "_TipColor" };
|
||||
string[] flts = { "_Shades", "_Brightness", "_MinimumDarkness", "_AmbientStrength", "_Cull", "_WindStrength", "_WindDensity" };
|
||||
var s = pad + "shader=" + m.shader.name;
|
||||
foreach (var c in cols) if (m.HasProperty(c)) s += " " + c + "=" + Hex(m.GetColor(c));
|
||||
foreach (var f in flts) if (m.HasProperty(f)) s += " " + f + "=" + m.GetFloat(f).ToString("F3");
|
||||
if (m.HasProperty("_BaseMap")) s += " _BaseMap=" + (m.GetTexture("_BaseMap") ? m.GetTexture("_BaseMap").name : "없음");
|
||||
if (m.HasProperty("_ShadowBaseMap")) s += " _ShadowBaseMap=" + (m.GetTexture("_ShadowBaseMap") ? m.GetTexture("_ShadowBaseMap").name : "없음");
|
||||
sb.AppendLine(s);
|
||||
}
|
||||
|
||||
static string Hex(UnityEngine.Color c)
|
||||
{
|
||||
return "(" + c.r.ToString("F3") + "," + c.g.ToString("F3") + "," + c.b.ToString("F3") + ")#"
|
||||
+ UnityEngine.ColorUtility.ToHtmlStringRGB(c);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# WL-816f 바닥 단계 비교 — 이름 | 바닥초록HEX | 풀Diffuse | 풀Shadow | 밀도 | 꽃확률 | 풀Scale ('-' = 그대로)
|
||||
# 바닥색 채택 = A0E4A2 (데모 평균 #94BE81 에 화면색을 맞춘 역산값)
|
||||
# ── 2단계: 풀 색 대비 3단 ──
|
||||
c1 | A0E4A2 | C6F398 | 40533C | 2.5 | - | -
|
||||
c2 | A0E4A2 | ABDE93 | 9AC884 | 2.5 | - | -
|
||||
c3 | A0E4A2 | A6E39F | 95CC8F | 2.5 | - | -
|
||||
# ── 3단계: 밀도 3단 (대비 = c2) ──
|
||||
e1 | A0E4A2 | ABDE93 | 9AC884 | 2.50 | - | -
|
||||
e2 | A0E4A2 | ABDE93 | 9AC884 | 1.80 | - | -
|
||||
e3 | A0E4A2 | ABDE93 | 9AC884 | 1.25 | - | -
|
||||
# ── 후보 조합 ──
|
||||
f1 | A0E4A2 | A6E39F | 95CC8F | 1.80 | - | -
|
||||
f2 | A0E4A2 | ABDE93 | 9AC884 | 2.20 | - | -
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
// WL-816f — ① PD 실행 경로 재현 (로그인 없이): InGame 씬 Play → Level01 을 Additive 로 붙인다.
|
||||
// = InGameInfo.Load_Map(900) → SceneInfo.Load_AddScene 이 하는 것과 같은 구조(활성 씬 = InGame).
|
||||
// 배치모드 헤드리스에서 동작. 캡처는 오프스크린 렌더.
|
||||
public static class WL816f_Pd
|
||||
{
|
||||
public const string Dir = "Screenshots_WL/WL816f/";
|
||||
public const int W = 1080, H = 1920;
|
||||
public static string Report = "";
|
||||
|
||||
// ── 에디트 모드: 씬 준비 ───────────────────────────────────────────
|
||||
public static void Open()
|
||||
{
|
||||
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
|
||||
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||||
UnityEngine.Debug.Log("[816f] InGame 열림 dirty=" + UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().isDirty);
|
||||
}
|
||||
|
||||
// ── Play 중: 러너를 띄운다 ─────────────────────────────────────────
|
||||
public static void Start()
|
||||
{
|
||||
var go = UnityEngine.GameObject.Find("~WL816fPd");
|
||||
if (go != null) UnityEngine.Object.DestroyImmediate(go);
|
||||
go = new UnityEngine.GameObject("~WL816fPd");
|
||||
go.AddComponent<WL816f_PdRunner>();
|
||||
UnityEngine.Debug.Log("[816f] 러너 시작");
|
||||
}
|
||||
|
||||
public static void Fetch()
|
||||
{
|
||||
var txt = WL816f_PdRunner.Log;
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_PD.txt", txt);
|
||||
UnityEngine.Debug.Log("[816f]\n" + txt);
|
||||
}
|
||||
}
|
||||
|
||||
public class WL816f_PdRunner : UnityEngine.MonoBehaviour
|
||||
{
|
||||
public static string Log = "(아직)";
|
||||
static System.Text.StringBuilder sb;
|
||||
|
||||
void Start() { StartCoroutine(Co()); }
|
||||
|
||||
System.Collections.IEnumerator Co()
|
||||
{
|
||||
sb = new System.Text.StringBuilder();
|
||||
L("=== PD 경로 재현 (InGame 활성 + Level01 Additive) ===");
|
||||
L("t0 활성씬=" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name
|
||||
+ " sceneCount=" + UnityEngine.SceneManagement.SceneManager.sceneCount);
|
||||
|
||||
// 훅 설치 상태
|
||||
var cfg = WL.Look.Farm.WLIslandLookSettings.Instance;
|
||||
L("SO enabled_=" + (cfg == null ? -1 : cfg.enabled_) + " applyLook=" + (cfg == null ? -1 : cfg.applyLook)
|
||||
+ " grass=" + (cfg == null ? -1 : cfg.grassEnabled));
|
||||
|
||||
// InGameInfo 로 진짜 경로를 태워 본다
|
||||
bool viaGame = false;
|
||||
try
|
||||
{
|
||||
if (InGameInfo.Ins != null)
|
||||
{
|
||||
L("InGameInfo.Ins 있음 → Load_Map(900) 시도");
|
||||
InGameInfo.Ins.Load_Map(900);
|
||||
viaGame = true;
|
||||
}
|
||||
}
|
||||
catch (System.Exception e) { L("Load_Map 예외: " + e.GetType().Name + " " + e.Message); }
|
||||
|
||||
if (!viaGame)
|
||||
{
|
||||
L("→ 로그인 없이는 Load_Map 이 못 돈다. SceneInfo.Load_AddScene 과 **같은 호출**로 대체:");
|
||||
L(" SceneManager.LoadSceneAsync(\"Level01\", Additive)");
|
||||
var op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Level01", UnityEngine.SceneManagement.LoadSceneMode.Additive);
|
||||
while (op != null && !op.isDone) yield return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++) yield return new UnityEngine.WaitForSeconds(1f);
|
||||
|
||||
L("");
|
||||
L("t+6s 활성씬=" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name
|
||||
+ " sceneCount=" + UnityEngine.SceneManagement.SceneManager.sceneCount);
|
||||
for (int i = 0; i < UnityEngine.SceneManagement.SceneManager.sceneCount; i++)
|
||||
{
|
||||
var s = UnityEngine.SceneManagement.SceneManager.GetSceneAt(i);
|
||||
L(" scene[" + i + "] " + s.name + " loaded=" + s.isLoaded + " roots=" + (s.isLoaded ? s.rootCount : -1));
|
||||
}
|
||||
|
||||
// ── 훅이 돌았나 ───────────────────────────────────────────────
|
||||
L("");
|
||||
L("IslandLook : 렌더러 " + WL.Look.Farm.WLIslandLook.SwappedRenderers + " 슬롯 " + WL.Look.Farm.WLIslandLook.SwappedSlots
|
||||
+ " look=" + WL.Look.Farm.WLIslandLook.LookApplied + " light=" + WL.Look.Farm.WLIslandLook.LightingApplied
|
||||
+ " refLook=" + WL.Look.Farm.WLIslandLook.ReferenceLookApplied + " grassSpawned=" + WL.Look.Farm.WLIslandLook.GrassSpawned);
|
||||
L("Grass : " + WL.Look.Farm.WLIslandGrass.LastLog);
|
||||
var g = UnityEngine.Object.FindFirstObjectByType<WL.Look.Farm.WLIslandGrass>(UnityEngine.FindObjectsInactive.Include);
|
||||
L("GrassObj : " + (g == null ? "없음" : (g.name + " active=" + g.gameObject.activeInHierarchy + "/" + g.enabled
|
||||
+ " scene=" + g.gameObject.scene.name + " layer=" + g.gameObject.layer)));
|
||||
L("RefLook : applied=" + WL.Look.Arena.WLReferenceLook.IsApplied + " outlined=" + WL.Look.Arena.WLReferenceLook.OutlinedRenderers);
|
||||
L("ambient : " + UnityEngine.RenderSettings.ambientMode + " " + UnityEngine.RenderSettings.ambientLight
|
||||
+ " skybox=" + (UnityEngine.RenderSettings.skybox ? UnityEngine.RenderSettings.skybox.name : "없음")
|
||||
+ " fog=" + UnityEngine.RenderSettings.fog);
|
||||
|
||||
// ── 카메라 — 누가 실제로 화면을 그리나 ────────────────────────
|
||||
L("");
|
||||
var cams = UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
|
||||
UnityEngine.Camera top = null;
|
||||
for (int i = 0; i < cams.Length; i++)
|
||||
{
|
||||
var c = cams[i];
|
||||
bool live = c.gameObject.activeInHierarchy && c.enabled && c.targetTexture == null;
|
||||
L("CAM " + c.name + " scene=" + c.gameObject.scene.name + " live=" + live
|
||||
+ " depth=" + c.depth + " mask=0x" + c.cullingMask.ToString("X") + " clear=" + c.clearFlags
|
||||
+ " pos=" + c.transform.position.ToString("F1"));
|
||||
if (live && (top == null || c.depth > top.depth)) top = c;
|
||||
}
|
||||
L("→ 화면에 보이는 카메라 = " + (top == null ? "없음" : top.name + " (scene " + top.gameObject.scene.name + ")"));
|
||||
if (top != null)
|
||||
{
|
||||
L(" 그 카메라의 컬링마스크에 들어가는 레이어:");
|
||||
string inc = "", exc = "";
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
string n = UnityEngine.LayerMask.LayerToName(i);
|
||||
if (string.IsNullOrEmpty(n)) continue;
|
||||
if ((top.cullingMask & (1 << i)) != 0) inc += i + ":" + n + " "; else exc += i + ":" + n + " ";
|
||||
}
|
||||
L(" 포함 = " + inc);
|
||||
L(" 🔴제외 = " + exc);
|
||||
}
|
||||
|
||||
// ── 섬 렌더러가 어느 레이어에 있나 ────────────────────────────
|
||||
L("");
|
||||
var counts = new System.Collections.Generic.Dictionary<int, int>();
|
||||
var rends = UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
int nIsland = 0;
|
||||
for (int i = 0; i < rends.Length; i++)
|
||||
{
|
||||
if (rends[i].gameObject.scene.name != "Level01") continue;
|
||||
nIsland++;
|
||||
int l = rends[i].gameObject.layer;
|
||||
counts[l] = counts.ContainsKey(l) ? counts[l] + 1 : 1;
|
||||
}
|
||||
L("Level01 렌더러 " + nIsland + " 개의 레이어 분포:");
|
||||
foreach (var kv in counts)
|
||||
L(" layer " + kv.Key + " (" + UnityEngine.LayerMask.LayerToName(kv.Key) + ") = " + kv.Value
|
||||
+ (top != null ? ((top.cullingMask & (1 << kv.Key)) != 0 ? " [보임]" : " 🔴[안 보임]") : ""));
|
||||
L("풀이 그려지는 레이어 = " + UnityEngine.LayerMask.NameToLayer("Default") + " (InstancesBehaviour.Update 고정)");
|
||||
|
||||
L("Soil 톤 : farm " + WL.Look.Farm.WLIslandLook.SoilFarmsToned + " · 타일 " + WL.Look.Farm.WLIslandLook.SoilTilesRepainted);
|
||||
|
||||
// ── 캡처 (보이는 카메라 그대로 + 위에서 + 표준 바닥 카메라) ──
|
||||
Shot(top, WL816f_Pd.Dir + "a_pd_path.png");
|
||||
Shot(TopCam(), WL816f_Pd.Dir + "a_pd_path_top.png");
|
||||
Shot(GroundCam(CleanSpot(), 6f), WL816f_Pd.Dir + "x_ours_ground.png");
|
||||
Shot(GroundCam(CleanSpot(), 10f), WL816f_Pd.Dir + "x_ours_wide.png");
|
||||
|
||||
Log = sb.ToString();
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_PD.txt", Log);
|
||||
UnityEngine.Debug.Log("[816f 완료]\n" + Log);
|
||||
}
|
||||
|
||||
static void L(string s) { sb.AppendLine(s); }
|
||||
|
||||
/// <summary>소품이 가장 적은(=풀이 가장 넓은) 섬 타일의 중심.</summary>
|
||||
UnityEngine.Vector3 CleanSpot()
|
||||
{
|
||||
var islands = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Island>(
|
||||
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
UnityEngine.Vector3 best = UnityEngine.Vector3.zero; int bs = int.MaxValue;
|
||||
for (int i = 0; i < islands.Length; i++)
|
||||
{
|
||||
var isl = islands[i];
|
||||
if (isl == null || !isl.IsUnlocked || !isl.gameObject.activeInHierarchy) continue;
|
||||
int sc = isl.GetComponentsInChildren<UnityEngine.Collider>(false).Length;
|
||||
if (sc < bs) { bs = sc; best = isl.transform.position; }
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/// <summary>표준 바닥 카메라 — 데모와 같은 화각(직교 · euler 30,60,0).</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;
|
||||
}
|
||||
|
||||
UnityEngine.Camera TopCam()
|
||||
{
|
||||
var go = new UnityEngine.GameObject("~WL816fTop");
|
||||
var c = go.AddComponent<UnityEngine.Camera>();
|
||||
c.orthographic = true; c.orthographicSize = 14f;
|
||||
c.nearClipPlane = 0.3f; c.farClipPlane = 500f;
|
||||
c.clearFlags = UnityEngine.CameraClearFlags.Skybox;
|
||||
c.cullingMask = ~0;
|
||||
c.depth = -100f;
|
||||
var rot = UnityEngine.Quaternion.Euler(30f, 60f, 0f);
|
||||
go.transform.rotation = rot;
|
||||
go.transform.position = new UnityEngine.Vector3(0f, 1f, 0f) - rot * UnityEngine.Vector3.forward * 60f;
|
||||
if (go.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() == null)
|
||||
go.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
|
||||
return c;
|
||||
}
|
||||
|
||||
public static void Shot(UnityEngine.Camera cam, string path)
|
||||
{
|
||||
if (cam == null) { L("캡처 실패(카메라 없음) " + path); return; }
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
|
||||
var rt = new UnityEngine.RenderTexture(WL816f_Pd.W, WL816f_Pd.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(WL816f_Pd.W, WL816f_Pd.H, UnityEngine.TextureFormat.RGB24, false);
|
||||
tex.ReadPixels(new UnityEngine.Rect(0, 0, WL816f_Pd.W, WL816f_Pd.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);
|
||||
if (sb != null) L("캡처 " + path);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
// WL-816f — ① PD 실행 경로(로그인 → Load_Map(900) → Level01 Additive) 구조 실측
|
||||
// 에디트 모드 전용. InGame 씬이 섬 위에 무엇을 얹는지(조명·Volume·카메라)를 본다.
|
||||
public static class WL816f_Probe
|
||||
{
|
||||
public static void Run()
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
|
||||
// 1) InGame 씬(= PD 경로의 활성 씬)을 연다
|
||||
var sc = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
|
||||
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
|
||||
sb.AppendLine("=== InGame.unity (PD 경로의 ACTIVE 씬) ===");
|
||||
Dump(sb, sc);
|
||||
|
||||
// 2) Level01 을 Additive 로 얹는다 (= Load_Map(900) 과 같은 구조)
|
||||
var sc2 = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
|
||||
"Assets/FarmingIsland/Scenes/Level01.unity", UnityEditor.SceneManagement.OpenSceneMode.Additive);
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=== Level01.unity (Additive) ===");
|
||||
Dump(sb, sc2);
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("active scene = " + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
|
||||
sb.AppendLine("RenderSettings(활성 씬 기준) ambient=" + UnityEngine.RenderSettings.ambientMode
|
||||
+ " light=" + UnityEngine.RenderSettings.ambientLight
|
||||
+ " sky=" + UnityEngine.RenderSettings.ambientSkyColor
|
||||
+ " skyboxMat=" + (UnityEngine.RenderSettings.skybox ? UnityEngine.RenderSettings.skybox.name : "없음")
|
||||
+ " fog=" + UnityEngine.RenderSettings.fog);
|
||||
|
||||
// 3) 레이어 이름 확인 (풀은 Default 레이어에 그려진다)
|
||||
sb.AppendLine("layer Default=" + UnityEngine.LayerMask.NameToLayer("Default"));
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
string n = UnityEngine.LayerMask.LayerToName(i);
|
||||
if (!string.IsNullOrEmpty(n)) sb.Append(i + ":" + n + " ");
|
||||
}
|
||||
sb.AppendLine();
|
||||
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_PROBE.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
static void Dump(System.Text.StringBuilder sb, UnityEngine.SceneManagement.Scene sc)
|
||||
{
|
||||
var roots = sc.GetRootGameObjects();
|
||||
sb.AppendLine("roots=" + roots.Length);
|
||||
for (int i = 0; i < roots.Length; i++) sb.Append(roots[i].name + (roots[i].activeSelf ? "" : "(off)") + " · ");
|
||||
sb.AppendLine();
|
||||
|
||||
// 카메라
|
||||
foreach (var r in roots)
|
||||
foreach (var c in r.GetComponentsInChildren<UnityEngine.Camera>(true))
|
||||
sb.AppendLine(" CAM " + Path(c.transform) + " active=" + c.gameObject.activeInHierarchy + "/" + c.enabled
|
||||
+ " depth=" + c.depth + " mask=0x" + c.cullingMask.ToString("X")
|
||||
+ " clear=" + c.clearFlags + " ortho=" + c.orthographic + " fov=" + c.fieldOfView
|
||||
+ " far=" + c.farClipPlane
|
||||
+ " urp=" + (c.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>() != null
|
||||
? ("post=" + c.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>().renderPostProcessing
|
||||
+ " volMask=0x" + c.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>().volumeLayerMask.value.ToString("X")
|
||||
+ " type=" + c.GetComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>().renderType)
|
||||
: "없음"));
|
||||
|
||||
// 라이트
|
||||
foreach (var r in roots)
|
||||
foreach (var l in r.GetComponentsInChildren<UnityEngine.Light>(true))
|
||||
sb.AppendLine(" LIGHT " + Path(l.transform) + " active=" + l.gameObject.activeInHierarchy + "/" + l.enabled
|
||||
+ " " + l.type + " col=" + l.color + " I=" + l.intensity + " sh=" + l.shadows
|
||||
+ " rot=" + l.transform.eulerAngles);
|
||||
|
||||
// Volume (포스트)
|
||||
foreach (var r in roots)
|
||||
foreach (var v in r.GetComponentsInChildren<UnityEngine.Rendering.Volume>(true))
|
||||
sb.AppendLine(" VOL " + Path(v.transform) + " active=" + v.gameObject.activeInHierarchy + "/" + v.enabled
|
||||
+ " global=" + v.isGlobal + " prio=" + v.priority + " weight=" + v.weight
|
||||
+ " profile=" + (v.sharedProfile ? v.sharedProfile.name + " [" + Comps(v.sharedProfile) + "]" : "없음")
|
||||
+ " layer=" + v.gameObject.layer);
|
||||
|
||||
// RenderSettings 는 씬별이다 — 씬을 활성으로 만들고 읽는다
|
||||
var prev = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
||||
UnityEngine.SceneManagement.SceneManager.SetActiveScene(sc);
|
||||
sb.AppendLine(" RS ambient=" + UnityEngine.RenderSettings.ambientMode
|
||||
+ " light=" + UnityEngine.RenderSettings.ambientLight + " sky=" + UnityEngine.RenderSettings.ambientSkyColor
|
||||
+ " I=" + UnityEngine.RenderSettings.ambientIntensity
|
||||
+ " skyboxMat=" + (UnityEngine.RenderSettings.skybox ? UnityEngine.RenderSettings.skybox.name : "없음")
|
||||
+ " fog=" + UnityEngine.RenderSettings.fog + " sun=" + (UnityEngine.RenderSettings.sun ? UnityEngine.RenderSettings.sun.name : "없음"));
|
||||
if (prev.IsValid() && prev != sc) UnityEngine.SceneManagement.SceneManager.SetActiveScene(prev);
|
||||
|
||||
// MapData / GlobalVolumeMgr / CheckShadow 같은 룩 관여 컴포넌트
|
||||
foreach (var r in roots)
|
||||
foreach (var m in r.GetComponentsInChildren<UnityEngine.MonoBehaviour>(true))
|
||||
{
|
||||
if (m == null) continue;
|
||||
string t = m.GetType().Name;
|
||||
if (t == "MapData" || t == "GlobalVolumeMgr" || t == "CheckShadow" || t == "SetSkybox"
|
||||
|| t == "GraphicsManager" || t == "UniversalRenderPipelineAsset")
|
||||
sb.AppendLine(" COMP " + t + " @ " + Path(m.transform) + " active=" + m.gameObject.activeInHierarchy + "/" + m.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static string Comps(UnityEngine.Rendering.VolumeProfile p)
|
||||
{
|
||||
var s = "";
|
||||
for (int i = 0; i < p.components.Count; i++) s += p.components[i].GetType().Name + (p.components[i].active ? "" : "(off)") + ",";
|
||||
return s;
|
||||
}
|
||||
|
||||
static string Path(UnityEngine.Transform t)
|
||||
{
|
||||
string s = t.name;
|
||||
while (t.parent != null) { t = t.parent; s = t.name + "/" + s; }
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
// WL-816f §2 — PD 경로(InGame 활성 + Level01 Additive) Play 에서 바닥 3요소를 단계별로 바꿔 캡처한다.
|
||||
// 변형 목록은 AgentScripts/WL816f_PLAN.txt (한 줄 = 한 단계)
|
||||
// 이름 | 바닥초록HEX | 풀Diffuse | 풀Shadow | 밀도 | 꽃확률 | 풀Scale
|
||||
// '-' = 그대로.
|
||||
// 🔴 에셋을 고치지 않는다 — 전부 런타임 인스턴스(Material/Texture2D/SO 복사본).
|
||||
public static class WL816f_Sweep
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
var go = UnityEngine.GameObject.Find("~WL816fSweep");
|
||||
if (go != null) UnityEngine.Object.DestroyImmediate(go);
|
||||
go = new UnityEngine.GameObject("~WL816fSweep");
|
||||
go.AddComponent<WL816f_SweepRunner>();
|
||||
UnityEngine.Debug.Log("[816f sweep] 시작");
|
||||
}
|
||||
}
|
||||
|
||||
public class WL816f_SweepRunner : UnityEngine.MonoBehaviour
|
||||
{
|
||||
const string Dir = "Screenshots_WL/WL816f/";
|
||||
const int W = 1080, H = 1920;
|
||||
static System.Text.StringBuilder sb;
|
||||
|
||||
UnityEngine.Material groundMat, grassMat, flowerMat;
|
||||
UnityEngine.Texture2D groundTex;
|
||||
UnityEngine.Color32 sand = new UnityEngine.Color32(0xCC, 0xCB, 0xB5, 255);
|
||||
UnityEngine.Color32 dirt = new UnityEngine.Color32(0x80, 0x70, 0x57, 255);
|
||||
WL.Look.Farm.WLIslandLookSettings rt;
|
||||
UnityEngine.Vector3 aim;
|
||||
|
||||
void Start() { StartCoroutine(Co()); }
|
||||
|
||||
System.Collections.IEnumerator Co()
|
||||
{
|
||||
sb = new System.Text.StringBuilder();
|
||||
|
||||
// ── PD 경로 부팅 ────────────────────────────────────────────
|
||||
if (UnityEngine.SceneManagement.SceneManager.sceneCount < 2)
|
||||
{
|
||||
var op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Level01", UnityEngine.SceneManagement.LoadSceneMode.Additive);
|
||||
while (op != null && !op.isDone) yield return null;
|
||||
}
|
||||
for (int i = 0; i < 5; i++) yield return new UnityEngine.WaitForSeconds(1f);
|
||||
|
||||
var g = UnityEngine.Object.FindFirstObjectByType<WL.Look.Farm.WLIslandGrass>(UnityEngine.FindObjectsInactive.Include);
|
||||
if (g == null) { L("🔴 WLIslandGrass 없음 — 중단"); Done(); yield break; }
|
||||
|
||||
var src = WL.Look.Farm.WLIslandLookSettings.Instance;
|
||||
rt = UnityEngine.Object.Instantiate(src); // 에셋을 고치지 않기 위한 런타임 복사본
|
||||
g.cfg = rt;
|
||||
|
||||
// 런타임 머티리얼·텍스처
|
||||
groundTex = new UnityEngine.Texture2D(8, 8, UnityEngine.TextureFormat.RGBA32, false);
|
||||
groundTex.filterMode = UnityEngine.FilterMode.Point;
|
||||
groundTex.wrapMode = UnityEngine.TextureWrapMode.Clamp;
|
||||
SetGround(new UnityEngine.Color32(0xAF, 0xED, 0xAE, 255));
|
||||
|
||||
groundMat = new UnityEngine.Material(rt.islandTopMaterial);
|
||||
groundMat.SetTexture("_BaseMap", groundTex);
|
||||
if (groundMat.HasProperty("_ShadowBaseMap")) groundMat.SetTexture("_ShadowBaseMap", groundTex);
|
||||
rt.islandTopMaterial = groundMat;
|
||||
|
||||
for (int i = 0; i < rt.scatter.Length; i++)
|
||||
{
|
||||
var s = rt.scatter[i];
|
||||
if (s == null || s.material == null) continue;
|
||||
if (s.label.Contains("풀")) { grassMat = new UnityEngine.Material(s.material); s.material = grassMat; }
|
||||
else if (s.label.Contains("꽃")) { flowerMat = new UnityEngine.Material(s.material); s.material = flowerMat; }
|
||||
}
|
||||
|
||||
// 섬 본체 렌더러에 런타임 바닥 머티리얼을 얹는다
|
||||
int nb = 0;
|
||||
var rends = UnityEngine.Object.FindObjectsByType<UnityEngine.Renderer>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
|
||||
for (int i = 0; i < rends.Length; i++)
|
||||
{
|
||||
var r = rends[i];
|
||||
if (r == null || r.gameObject.scene.name != "Level01") continue;
|
||||
if (r.GetComponent<CryingSnow.FarmingIsland.Island>() == null) continue;
|
||||
var ms = r.sharedMaterials;
|
||||
bool ch = false;
|
||||
for (int m = 0; m < ms.Length; m++) if (ms[m] != null && ms[m].name.StartsWith("Farm_IslandTop_Demo")) { ms[m] = groundMat; ch = true; }
|
||||
if (ch) { r.sharedMaterials = ms; nb++; }
|
||||
}
|
||||
L("바닥 머티리얼 런타임 교체 렌더러 " + nb);
|
||||
|
||||
// 조준점 = 깨끗한 잔디 타일 중심(막힌 것이 가장 적은 타일)
|
||||
aim = PickCleanSpot();
|
||||
L("조준점 " + aim.ToString("F2"));
|
||||
|
||||
// ── 변형 실행 ───────────────────────────────────────────────
|
||||
string planPath = "AgentScripts/WL816f_PLAN.txt";
|
||||
if (!System.IO.File.Exists(planPath)) { L("PLAN 없음"); Done(); yield break; }
|
||||
var lines = System.IO.File.ReadAllLines(planPath);
|
||||
foreach (var raw in lines)
|
||||
{
|
||||
var line = raw.Trim();
|
||||
if (line.Length == 0 || line.StartsWith("#")) continue;
|
||||
var p = line.Split('|');
|
||||
for (int i = 0; i < p.Length; i++) p[i] = p[i].Trim();
|
||||
string name = p[0];
|
||||
|
||||
if (p.Length > 1 && p[1] != "-") SetGround(Hex(p[1]));
|
||||
if (p.Length > 2 && p[2] != "-" && grassMat != null) grassMat.SetColor("_DiffuseColor", HexC(p[2]));
|
||||
if (p.Length > 3 && p[3] != "-" && grassMat != null) grassMat.SetColor("_ShadowDiffuseColor", HexC(p[3]));
|
||||
if (p.Length > 4 && p[4] != "-") SetDensity(float.Parse(p[4]));
|
||||
if (p.Length > 5 && p[5] != "-") SetFlowerProb(float.Parse(p[5]));
|
||||
if (p.Length > 6 && p[6] != "-") SetGrassScale(float.Parse(p[6]));
|
||||
|
||||
g.Rebuild();
|
||||
yield return null; yield return null;
|
||||
|
||||
var cam = GroundCam(aim, 6f);
|
||||
Shoot(cam, Dir + name + ".png");
|
||||
L(name + " : 타일 " + WL.Look.Farm.WLIslandGrass.Tiles + " · 인스턴스 " + WL.Look.Farm.WLIslandGrass.Instances
|
||||
+ " · 밀도 " + WL.Look.Farm.WLIslandGrass.UsedDensity.ToString("F2")
|
||||
+ " · 삼각형 " + WL.Look.Farm.WLIslandGrass.Triangles
|
||||
+ " · 그라운드 " + UnityEngine.ColorUtility.ToHtmlStringRGB(groundTex.GetPixel(0, 7))
|
||||
+ " · 풀D " + (grassMat ? UnityEngine.ColorUtility.ToHtmlStringRGB(grassMat.GetColor("_DiffuseColor")) : "-")
|
||||
+ " · 풀S " + (grassMat ? UnityEngine.ColorUtility.ToHtmlStringRGB(grassMat.GetColor("_ShadowDiffuseColor")) : "-"));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Done();
|
||||
}
|
||||
|
||||
void Done()
|
||||
{
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_SWEEP.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log("[816f sweep 완료]\n" + sb.ToString());
|
||||
}
|
||||
|
||||
static void L(string s) { sb.AppendLine(s); }
|
||||
|
||||
void SetGround(UnityEngine.Color32 green)
|
||||
{
|
||||
// Island01 UV 배치: 위 절반 = 모래/흙, 아래 절반(v<0.5) = 잔디
|
||||
var px = new UnityEngine.Color32[64];
|
||||
for (int y = 0; y < 8; y++)
|
||||
for (int x = 0; x < 8; x++)
|
||||
px[y * 8 + x] = y < 4 ? green : (x < 4 ? sand : dirt);
|
||||
groundTex.SetPixels32(px); groundTex.Apply();
|
||||
}
|
||||
|
||||
void SetDensity(float d)
|
||||
{
|
||||
for (int i = 0; i < rt.scatter.Length; i++)
|
||||
{
|
||||
var s = rt.scatter[i];
|
||||
if (s == null) continue;
|
||||
if (s.label.Contains("풀") || s.label.Contains("꽃")) s.density = d;
|
||||
}
|
||||
}
|
||||
void SetFlowerProb(float p)
|
||||
{
|
||||
for (int i = 0; i < rt.scatter.Length; i++)
|
||||
if (rt.scatter[i] != null && rt.scatter[i].label.Contains("꽃")) rt.scatter[i].probability = p;
|
||||
}
|
||||
void SetGrassScale(float v)
|
||||
{
|
||||
for (int i = 0; i < rt.scatter.Length; i++)
|
||||
if (rt.scatter[i] != null && (rt.scatter[i].label.Contains("풀") || rt.scatter[i].label.Contains("꽃"))) rt.scatter[i].scale = v;
|
||||
}
|
||||
|
||||
/// <summary>표준 바닥 카메라 — 데모와 같은 화각(직교 · euler 30,60,0).</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)
|
||||
{
|
||||
if (cam == null) return;
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
|
||||
var rt2 = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
||||
rt2.antiAliasing = 1; rt2.Create();
|
||||
var prevT = cam.targetTexture; var prevA = UnityEngine.RenderTexture.active;
|
||||
cam.targetTexture = rt2; cam.Render();
|
||||
UnityEngine.RenderTexture.active = rt2;
|
||||
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);
|
||||
rt2.Release(); UnityEngine.Object.DestroyImmediate(rt2);
|
||||
}
|
||||
|
||||
static UnityEngine.Color32 Hex(string h)
|
||||
{
|
||||
UnityEngine.Color c; UnityEngine.ColorUtility.TryParseHtmlString(h.StartsWith("#") ? h : "#" + h, out c);
|
||||
return (UnityEngine.Color32)c;
|
||||
}
|
||||
static UnityEngine.Color HexC(string h)
|
||||
{
|
||||
UnityEngine.Color c; UnityEngine.ColorUtility.TryParseHtmlString(h.StartsWith("#") ? h : "#" + h, out c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>풀이 가장 넓게 깔린 타일의 중심을 고른다(소품·밭이 적은 곳).</summary>
|
||||
UnityEngine.Vector3 PickCleanSpot()
|
||||
{
|
||||
var islands = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Island>(
|
||||
UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
UnityEngine.Vector3 best = UnityEngine.Vector3.zero; int bestScore = int.MaxValue;
|
||||
for (int i = 0; i < islands.Length; i++)
|
||||
{
|
||||
var isl = islands[i];
|
||||
if (isl == null || !isl.IsUnlocked || !isl.gameObject.activeInHierarchy) continue;
|
||||
int score = isl.GetComponentsInChildren<UnityEngine.Collider>(false).Length;
|
||||
if (score < bestScore) { bestScore = score; best = isl.transform.position; }
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// WL-816f — PD 경로 Play 에서 ⓓ성능 ⓔ기능(걷기·농사·건설/확장) ⓕ되돌리기를 실측한다.
|
||||
public static class WL816f_Verify
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
var go = UnityEngine.GameObject.Find("~WL816fVerify");
|
||||
if (go != null) UnityEngine.Object.DestroyImmediate(go);
|
||||
go = new UnityEngine.GameObject("~WL816fVerify");
|
||||
go.AddComponent<WL816f_VerifyRunner>();
|
||||
}
|
||||
}
|
||||
|
||||
public class WL816f_VerifyRunner : UnityEngine.MonoBehaviour
|
||||
{
|
||||
const string Dir = "Screenshots_WL/WL816f/";
|
||||
static System.Text.StringBuilder sb;
|
||||
void Start() { StartCoroutine(Co()); }
|
||||
|
||||
System.Collections.IEnumerator Co()
|
||||
{
|
||||
sb = new System.Text.StringBuilder();
|
||||
if (UnityEngine.SceneManagement.SceneManager.sceneCount < 2)
|
||||
{
|
||||
var op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Level01", UnityEngine.SceneManagement.LoadSceneMode.Additive);
|
||||
while (op != null && !op.isDone) yield return null;
|
||||
}
|
||||
for (int i = 0; i < 6; i++) yield return new UnityEngine.WaitForSeconds(1f);
|
||||
|
||||
L("=== WL-816f 검증 (PD 경로 · InGame 활성 + Level01 Additive) ===");
|
||||
L("풀 : " + WL.Look.Farm.WLIslandGrass.LastLog);
|
||||
L("Soil 톤 : farm " + WL.Look.Farm.WLIslandLook.SoilFarmsToned + " · 타일 " + WL.Look.Farm.WLIslandLook.SoilTilesRepainted);
|
||||
|
||||
// ── ⓓ 성능 : 같은 카메라로 60프레임 오프스크린 렌더 ─────────
|
||||
var cam = FindLiveCam();
|
||||
L("");
|
||||
L("[성능] 카메라 " + (cam ? cam.name : "없음"));
|
||||
float onMs = RenderBench(cam, 60);
|
||||
var g = UnityEngine.Object.FindFirstObjectByType<WL.Look.Farm.WLIslandGrass>(UnityEngine.FindObjectsInactive.Include);
|
||||
int instOn = WL.Look.Farm.WLIslandGrass.Instances;
|
||||
long triOn = WL.Look.Farm.WLIslandGrass.Triangles;
|
||||
if (g != null) g.enabled = false; // 풀만 끈 상태
|
||||
yield return null; yield return null;
|
||||
float offMs = RenderBench(cam, 60);
|
||||
if (g != null) g.enabled = true;
|
||||
yield return null; yield return null;
|
||||
L("풀 켬 " + onMs.ToString("F3") + " ms/frame · 풀 끔 " + offMs.ToString("F3") + " ms/frame · 델타 " + (onMs - offMs).ToString("F3") + " ms");
|
||||
L("인스턴스 " + instOn + " · 삼각형(풀) " + triOn + " · 드로우콜 +" + WL.Look.Farm.WLIslandGrass.DrawnConfigs);
|
||||
|
||||
// ── ⓔ 기능 ─────────────────────────────────────────────────
|
||||
L("");
|
||||
L("[기능]");
|
||||
// 풀 콜라이더 0 · 레이캐스트 · NavMesh
|
||||
int colliders = 0;
|
||||
var gobj = g != null ? g.gameObject : null;
|
||||
if (gobj != null) colliders = gobj.GetComponentsInChildren<UnityEngine.Collider>(true).Length;
|
||||
L("풀 오브젝트 콜라이더 = " + colliders + " (0 이어야 한다)");
|
||||
|
||||
int hit = 0, nav = 0;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
var p = new UnityEngine.Vector3(UnityEngine.Random.Range(-7f, 7f), 3f, UnityEngine.Random.Range(-7f, 7f));
|
||||
UnityEngine.RaycastHit h;
|
||||
if (UnityEngine.Physics.Raycast(p, UnityEngine.Vector3.down, out h, 10f)) hit++;
|
||||
UnityEngine.AI.NavMeshHit nh;
|
||||
if (UnityEngine.AI.NavMesh.SamplePosition(new UnityEngine.Vector3(p.x, 0f, p.z), out nh, 1.5f, ~0)) nav++;
|
||||
}
|
||||
L("풀밭 100점 아래 레이캐스트 적중 " + hit + "/100 · NavMesh 샘플 " + nav + "/100");
|
||||
|
||||
// 걷기 — FI PlayerController 의 CharacterController
|
||||
var cc = UnityEngine.Object.FindFirstObjectByType<UnityEngine.CharacterController>(UnityEngine.FindObjectsInactive.Exclude);
|
||||
if (cc != null)
|
||||
{
|
||||
var p0 = cc.transform.position;
|
||||
var dir = new UnityEngine.Vector3(1f, 0f, 1f).normalized;
|
||||
float moved = 0f;
|
||||
for (int i = 0; i < 120; i++) { cc.Move(dir * 0.05f + UnityEngine.Vector3.down * 0.02f); yield return null; }
|
||||
moved = UnityEngine.Vector3.Distance(new UnityEngine.Vector3(p0.x, 0f, p0.z), new UnityEngine.Vector3(cc.transform.position.x, 0f, cc.transform.position.z));
|
||||
L("걷기 : " + p0.ToString("F2") + " → " + cc.transform.position.ToString("F2") + " = " + moved.ToString("F2") + " m · grounded=" + cc.isGrounded);
|
||||
}
|
||||
else L("걷기 : CharacterController 없음(미확인)");
|
||||
|
||||
// 농사 — Farm/Soil 개수 + 씨뿌리기 상태 전환
|
||||
var farms = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Farm>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
var soils = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Soil>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
L("농사 : Farm " + farms.Length + " · Soil " + soils.Length);
|
||||
int painted = 0;
|
||||
for (int i = 0; i < soils.Length; i++)
|
||||
{
|
||||
var r = soils[i].GetComponentInChildren<UnityEngine.Renderer>(true);
|
||||
if (r != null && r.sharedMaterial != null) painted++;
|
||||
}
|
||||
L("Soil 렌더러 살아있음 " + painted + "/" + soils.Length + " · 첫 Soil 색 " +
|
||||
(soils.Length > 0 && soils[0].GetComponentInChildren<UnityEngine.Renderer>(true) != null
|
||||
? UnityEngine.ColorUtility.ToHtmlStringRGB(soils[0].GetComponentInChildren<UnityEngine.Renderer>(true).material.color) : "-"));
|
||||
|
||||
// 확장 — 섬 타일 수
|
||||
var islands = UnityEngine.Object.FindObjectsByType<CryingSnow.FarmingIsland.Island>(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None);
|
||||
int unlocked = 0; for (int i = 0; i < islands.Length; i++) if (islands[i].IsUnlocked && islands[i].gameObject.activeInHierarchy) unlocked++;
|
||||
L("확장 : 섬 타일 전체 " + islands.Length + " · 열린 타일 " + unlocked + " · 풀 깔린 타일 " + WL.Look.Farm.WLIslandGrass.Tiles);
|
||||
|
||||
// ── 최종 캡처 ───────────────────────────────────────────────
|
||||
Shot(FindLiveCam(), Dir + "d_final_wide.png");
|
||||
|
||||
System.IO.File.WriteAllText("AgentScripts/WL816f_VERIFY.txt", sb.ToString());
|
||||
UnityEngine.Debug.Log("[816f verify]\n" + sb.ToString());
|
||||
}
|
||||
|
||||
static void L(string s) { sb.AppendLine(s); }
|
||||
|
||||
static UnityEngine.Camera FindLiveCam()
|
||||
{
|
||||
var cams = UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None);
|
||||
UnityEngine.Camera top = null;
|
||||
for (int i = 0; i < cams.Length; i++)
|
||||
{
|
||||
var c = cams[i];
|
||||
if (!c.enabled || c.targetTexture != null) continue;
|
||||
if (top == null || c.depth > top.depth) top = c;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
static float RenderBench(UnityEngine.Camera cam, int frames)
|
||||
{
|
||||
if (cam == null) return -1f;
|
||||
var rt = new UnityEngine.RenderTexture(1080, 1920, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB);
|
||||
rt.antiAliasing = 1; rt.Create();
|
||||
var prev = cam.targetTexture; cam.targetTexture = rt;
|
||||
cam.Render(); // 워밍업
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
for (int i = 0; i < frames; i++) cam.Render();
|
||||
sw.Stop();
|
||||
cam.targetTexture = prev;
|
||||
rt.Release(); UnityEngine.Object.DestroyImmediate(rt);
|
||||
return (float)sw.Elapsed.TotalMilliseconds / frames;
|
||||
}
|
||||
|
||||
static void Shot(UnityEngine.Camera cam, string path)
|
||||
{
|
||||
if (cam == null) return;
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
|
||||
var rt = new UnityEngine.RenderTexture(1080, 1920, 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(1080, 1920, UnityEngine.TextureFormat.RGB24, false);
|
||||
tex.ReadPixels(new UnityEngine.Rect(0, 0, 1080, 1920), 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);
|
||||
L("캡처 " + path);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-3938375536428912352
|
||||
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
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Farm_Grass_Demo
|
||||
m_Shader: {fileID: -6465566751694194690, guid: 116bae4840169554085c5aa591d459f5,
|
||||
type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _MAIN_LIGHT_SHADOWS
|
||||
- _SHADOWS_SOFT
|
||||
m_InvalidKeywords:
|
||||
- _CLOUDSENABLED
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _AmbientStrength: 0.1
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _Brightness: 0.25
|
||||
- _BumpScale: 1
|
||||
- _CLOUDSENABLED: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cloud_Change: 0.005
|
||||
- _Cloud_Cover: 0.5
|
||||
- _Cloud_Density: 0.01
|
||||
- _Cloud_Strength: 1
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _MAIN_LIGHT: 0
|
||||
- _Metallic: 0
|
||||
- _MinimumDarkness: 0.2
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueControl: 0
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _SHADOWS_SOFT: 1
|
||||
- _Shades: 7
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _VerticalDifference: 1
|
||||
- _WindDensity: 0.2
|
||||
- _WindStrength: 0.3
|
||||
- _WorkflowMode: 1
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Cloud_Movement: {r: 1, g: 1, b: 0, a: 0}
|
||||
- _Cloud_Step: {r: 13, g: 17, b: 0, a: 0}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _DiffuseColor: {r: 0.6509804, g: 0.8901961, b: 0.62352943, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _ShadowDiffuseColor: {r: 0.58431375, g: 0.8, b: 0.56078434, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
- _WindMovement: {r: 6, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bfa67f7091cb7ff418051fec03e5c28c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -38,6 +38,9 @@ MonoBehaviour:
|
|||
to: {fileID: 2100000, guid: 1c9ce9b7865f6d643ad9601f6fa81ba3, type: 2}
|
||||
islandTopMaterial: {fileID: 2100000, guid: 500f1cf3127afb748b316fe28b128edc, type: 2}
|
||||
skipSoilRenderers: 1
|
||||
soilToneEnabled: 1
|
||||
soilTint: {r: 0.84, g: 0.86, b: 0.9, a: 1}
|
||||
soilCheckerContrast: 0.6
|
||||
ambientSky: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
ambientEquator: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
ambientGround: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
|
|
@ -57,11 +60,11 @@ MonoBehaviour:
|
|||
- enabled_: 1
|
||||
label: "\uD480"
|
||||
mesh: {fileID: -4413095505993930501, guid: 1f298817fdd2a184480e8af5b21278bc, type: 3}
|
||||
material: {fileID: 2100000, guid: a194cb4ce6027c246af528b83b728a15, type: 2}
|
||||
material: {fileID: 2100000, guid: bfa67f7091cb7ff418051fec03e5c28c, type: 2}
|
||||
probability: 100
|
||||
scale: 0.35
|
||||
normalOffset: 0.04
|
||||
density: 2.5
|
||||
density: 1.8
|
||||
- enabled_: 1
|
||||
label: "\uAF43"
|
||||
mesh: {fileID: -6327915695457451627, guid: dab2c84bf0b5ced4aaf0cffc4c491d55, type: 3}
|
||||
|
|
@ -69,7 +72,7 @@ MonoBehaviour:
|
|||
probability: 1
|
||||
scale: 0.35
|
||||
normalOffset: 0.04
|
||||
density: 2.5
|
||||
density: 1.8
|
||||
- enabled_: 1
|
||||
label: "\uC790\uAC08"
|
||||
mesh: {fileID: 2928966540353291585, guid: 7f1f11ac2c783374b876f8dc2bb7c7db, type: 3}
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 93 B |
|
|
@ -25,6 +25,7 @@ using UnityEngine.SceneManagement;
|
|||
using CryingSnow.FarmingIsland;
|
||||
using FIIsland = CryingSnow.FarmingIsland.Island;
|
||||
using FISoil = CryingSnow.FarmingIsland.Soil;
|
||||
using FIFarm = CryingSnow.FarmingIsland.Farm;
|
||||
|
||||
namespace WL.Look.Farm
|
||||
{
|
||||
|
|
@ -85,6 +86,7 @@ namespace WL.Look.Farm
|
|||
{
|
||||
s_done.Clear();
|
||||
s_hooked.Clear();
|
||||
s_tonedFarms.Clear();
|
||||
LookApplied = false; GrassSpawned = false; ReferenceLookApplied = false;
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +129,7 @@ namespace WL.Look.Farm
|
|||
}
|
||||
if (cfg.applyLighting != 0) ApplyLighting(cfg, scene);
|
||||
if (cfg.applyLook != 0 && cfg.applyReferenceLook != 0) ApplyReferenceLook(cfg, scene);
|
||||
if (cfg.soilToneEnabled != 0) ToneSoil(cfg, scene);
|
||||
|
||||
if (cfg.grassEnabled != 0) SpawnGrass(cfg, scene);
|
||||
|
||||
|
|
@ -148,6 +151,11 @@ namespace WL.Look.Farm
|
|||
if (w > 0f) yield return new WaitForSeconds(w);
|
||||
if (!scene.isLoaded) yield break;
|
||||
if (cfg.applyLook != 0) { SwapMaterials(cfg, scene); Rescans++; }
|
||||
// 🔴 816f 실측 — PD 실행 경로(Additive)에서 `RenderSettings` 는 **활성 씬(InGame)**
|
||||
// 소유이고, 그 씬에는 조명을 덮어쓰는 코드(`MapData`)가 없다(실측).
|
||||
// 그래서 조명은 재훑기에서 **다시 걸지 않는다** — 다시 걸면 `WLReferenceLook` 의
|
||||
// 무드(Flat)를 Skybox 로 되돌려 오히려 룩이 바뀐다(실측으로 확인).
|
||||
if (cfg.soilToneEnabled != 0) ToneSoil(cfg, scene);
|
||||
HookIslands(cfg, scene);
|
||||
}
|
||||
}
|
||||
|
|
@ -302,6 +310,67 @@ namespace WL.Look.Farm
|
|||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// ②-b 밭(Soil) 칸 표시 — **기능은 그대로 두고 색만** 데모 톤으로 (816f · PD 지시)
|
||||
// FI `Farm` 의 4색(마름1·마름2·젖음1·젖음2)을 런타임에 낮추고
|
||||
// `Soil.Initialize(farm)`(public) 를 다시 불러 칠만 갱신한다.
|
||||
// → 물주기 피드백(마름↔젖음)·칸 구분은 전부 살아 있다. `Assets/FarmingIsland/**` 0줄.
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
static readonly string[] s_soilFields = { "soilDryColor1", "soilDryColor2", "soilWetColor1", "soilWetColor2" };
|
||||
static readonly HashSet<FIFarm> s_tonedFarms = new HashSet<FIFarm>();
|
||||
|
||||
public static int SoilFarmsToned, SoilTilesRepainted;
|
||||
|
||||
public static void ToneSoil(WLIslandLookSettings cfg, Scene scene)
|
||||
{
|
||||
var farms = Object.FindObjectsByType<FIFarm>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
var t = typeof(FIFarm);
|
||||
for (int i = 0; i < farms.Length; i++)
|
||||
{
|
||||
var farm = farms[i];
|
||||
if (farm == null || farm.gameObject.scene != scene) continue;
|
||||
if (s_tonedFarms.Contains(farm)) continue;
|
||||
|
||||
// 1) 마름1/마름2 · 젖음1/젖음2 각각의 평균으로 모으고(대비 축소) 틴트를 곱한다
|
||||
var vals = new Color[4];
|
||||
var fis = new System.Reflection.FieldInfo[4];
|
||||
bool ok = true;
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
fis[k] = t.GetField(s_soilFields[k],
|
||||
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
if (fis[k] == null) { ok = false; break; }
|
||||
vals[k] = (Color)fis[k].GetValue(farm);
|
||||
}
|
||||
if (!ok) continue;
|
||||
|
||||
Apply(cfg, fis, farm, vals, 0, 1); // 마름 한 쌍
|
||||
Apply(cfg, fis, farm, vals, 2, 3); // 젖음 한 쌍
|
||||
s_tonedFarms.Add(farm);
|
||||
SoilFarmsToned++;
|
||||
|
||||
// 2) 이미 칠해진 타일을 다시 칠한다 — FI 의 public 진입점 그대로
|
||||
var soils = farm.GetComponentsInChildren<FISoil>(true);
|
||||
for (int s = 0; s < soils.Length; s++)
|
||||
{
|
||||
if (soils[s] == null) continue;
|
||||
try { soils[s].Initialize(farm); SoilTilesRepainted++; } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Apply(WLIslandLookSettings cfg, System.Reflection.FieldInfo[] fis, FIFarm farm, Color[] v, int a, int b)
|
||||
{
|
||||
var mid = (v[a] + v[b]) * 0.5f;
|
||||
float c = cfg.soilCheckerContrast;
|
||||
var ca = Color.Lerp(mid, v[a], c);
|
||||
var cb = Color.Lerp(mid, v[b], c);
|
||||
fis[a].SetValue(farm, Mul(ca, cfg.soilTint));
|
||||
fis[b].SetValue(farm, Mul(cb, cfg.soilTint));
|
||||
}
|
||||
|
||||
static Color Mul(Color a, Color b) { return new Color(a.r * b.r, a.g * b.g, a.b * b.b, a.a); }
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// ③ 아레나와 같은 외곽선·대비·무드 (씬 비의존 — 816a 실측)
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -136,6 +136,19 @@ namespace WL.Look.Farm
|
|||
[Tooltip("1 이면 농사 타일(Soil)은 원본 머티리얼 그대로 둔다(색을 코드가 직접 칠하는 곳이라 건드리면 안 된다).")]
|
||||
public int skipSoilRenderers = 1;
|
||||
|
||||
// ── 816f: 밭(Soil) 체크무늬 **기능은 유지**하고 색만 데모 톤으로 (PD 2026-09-13)
|
||||
[Header("§0-816f — 밭(Soil) 칸 표시 톤 (기능 유지 · 색만)")]
|
||||
[Tooltip("1 이면 FI `Farm` 의 마른/젖은 흙 색 4개를 런타임에 데모 톤으로 낮춘다. " +
|
||||
"칸 구분(마름/젖음 표시)은 그대로 남는다 — 색만 바뀐다. 0 이면 FI 원본 색.")]
|
||||
public int soilToneEnabled = 1;
|
||||
|
||||
[Tooltip("흙 색에 곱하는 값(0~1). 낮출수록 주황이 죽는다.")]
|
||||
public Color soilTint = new Color(0.84f, 0.86f, 0.90f, 1f);
|
||||
|
||||
[Tooltip("체크무늬 두 색의 차이를 이 비율로 줄인다(1 = FI 원본 차이 · 0 = 차이 없음=칸 안 보임). " +
|
||||
"🔴 0 으로 두지 말 것 — 어디를 갈았는지 안 보인다.")]
|
||||
[Range(0f, 1f)] public float soilCheckerContrast = 0.6f;
|
||||
|
||||
[Header("§0 — 조명 값 (816a 실측 = 데모/아레나와 동일)")]
|
||||
public Color ambientSky = new Color(0.212f, 0.227f, 0.259f, 1f);
|
||||
public Color ambientEquator = new Color(0.114f, 0.125f, 0.133f, 1f);
|
||||
|
|
|
|||
Loading…
Reference in New Issue