Files
AIGame/AIClient/AgentScripts/DiagnoseHomeCampLightmaps.cs

121 lines
5.3 KiB
C#

#if UNITY_EDITOR
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
/// <summary>Dump HomeCamp lightmap stats and force a lightmap-only capture for shadow diagnosis.</summary>
public static class DiagnoseHomeCampLightmaps
{
const string ScenePath = "Assets/Bundles/Scenes/Town/HomeCamp/HomeCamp.unity";
const string Review = "D:/UD/AI/AIGame/Tools/output/homecamp_review";
public static string Run()
{
Directory.CreateDirectory(Review);
var scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single);
var root = scene.GetRootGameObjects().Single(g => g.name == "HomeCamp");
var ground = root.transform.Find("Ground")?.GetComponentInChildren<MeshRenderer>();
var maps = LightmapSettings.lightmaps;
if (maps == null || maps.Length == 0) return "FAIL: no lightmaps loaded";
if (!ground) return "FAIL: no ground";
var lm = maps[0].lightmapColor;
var path = Review + "/lightmap0.png";
ExportReadable(lm, path);
// Sample a few texels for contrast (sunlit vs likely shade).
var readable = MakeReadable(lm);
float minL = 99, maxL = 0, sum = 0;
int n = 0;
for (int y = 0; y < readable.height; y += 8)
for (int x = 0; x < readable.width; x += 8)
{
var c = readable.GetPixel(x, y);
float l = c.r * .3f + c.g * .59f + c.b * .11f;
if (l < minL) minL = l; if (l > maxL) maxL = l; sum += l; n++;
}
Object.DestroyImmediate(readable);
var lights = Object.FindObjectsByType<Light>(FindObjectsSortMode.None)
.Select(l => l.name + " type=" + l.type + " bake=" + l.lightmapBakeType + " inten=" + l.intensity + " en=" + l.enabled)
.ToArray();
var mat = ground.sharedMaterial;
var kw = string.Join(",", mat.shaderKeywords ?? System.Array.Empty<string>());
var sun = Object.FindObjectsByType<Light>(FindObjectsSortMode.None).FirstOrDefault(l => l.type == LightType.Directional && l.name.Contains("Sun"));
// Capture A: as-is
var cam = root.GetComponentInChildren<Camera>();
Capture(cam, Review + "/diag_with_lights.png");
// Capture B: disable all realtime-contributing lights so only lightmaps/probes remain
var prev = Object.FindObjectsByType<Light>(FindObjectsSortMode.None).Select(l => (l, l.enabled)).ToArray();
foreach (var (l, _) in prev) l.enabled = false;
Capture(cam, Review + "/diag_lightmap_only.png");
foreach (var (l, en) in prev) l.enabled = en;
return "maps=" + maps.Length + " groundLM=" + ground.lightmapIndex
+ " scale=" + ground.lightmapScaleOffset
+ " lmSize=" + lm.width + "x" + lm.height
+ " lumaMin=" + minL.ToString("F3") + " max=" + maxL.ToString("F3") + " avg=" + (sum / n).ToString("F3")
+ " exported=" + path
+ " keywords=[" + kw + "]"
+ " lights=[" + string.Join("; ", lights) + "]"
+ " sunBake=" + (sun ? sun.lightmapBakeType.ToString() : "null");
}
static void Capture(Camera camera, string file)
{
var rt = RenderTexture.GetTemporary(720, 1280, 24, RenderTextureFormat.ARGB32);
var old = RenderTexture.active; var oldTarget = camera.targetTexture; var oldAspect = camera.aspect;
var tex = new Texture2D(720, 1280, TextureFormat.RGB24, false);
try
{
camera.aspect = 720f / 1280; camera.targetTexture = rt; RenderTexture.active = rt;
camera.Render();
tex.ReadPixels(new Rect(0, 0, 720, 1280), 0, 0); tex.Apply();
File.WriteAllBytes(file, tex.EncodeToPNG());
}
finally
{
camera.targetTexture = oldTarget; camera.aspect = oldAspect; RenderTexture.active = old;
RenderTexture.ReleaseTemporary(rt); Object.DestroyImmediate(tex);
}
}
static Texture2D MakeReadable(Texture2D src)
{
var rt = RenderTexture.GetTemporary(src.width, src.height, 0, RenderTextureFormat.ARGBFloat);
Graphics.Blit(src, rt);
var prev = RenderTexture.active; RenderTexture.active = rt;
var tex = new Texture2D(src.width, src.height, TextureFormat.RGBAFloat, false);
tex.ReadPixels(new Rect(0, 0, src.width, src.height), 0, 0); tex.Apply();
RenderTexture.active = prev; RenderTexture.ReleaseTemporary(rt);
return tex;
}
static void ExportReadable(Texture2D src, string path)
{
var tex = MakeReadable(src);
// Tone-map HDR lightmap into LDR preview
var outTex = new Texture2D(tex.width, tex.height, TextureFormat.RGB24, false);
for (int y = 0; y < tex.height; y++)
for (int x = 0; x < tex.width; x++)
{
var c = tex.GetPixel(x, y);
// Unity lightmaps are often dLDR / RGBM-ish; simple expose
float e = 1.5f;
outTex.SetPixel(x, y, new Color(Mathf.Clamp01(c.r * e), Mathf.Clamp01(c.g * e), Mathf.Clamp01(c.b * e), 1));
}
outTex.Apply();
File.WriteAllBytes(path, outTex.EncodeToPNG());
Object.DestroyImmediate(tex); Object.DestroyImmediate(outTex);
}
}
#endif