121 lines
5.3 KiB
C#
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
|