using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEditor;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEngine.Rendering;
///
/// 灯光烘焙工具类
///
public static class LightmapUtils
{
///
/// 处理参与烘焙的节点
///
public static void PreProcessBake(List rootNames, Transform rootTransform, bool castShadow, bool needReplaceShader,
List allBakeRenderers, List needReplaceRenderers)
{
foreach (var rootName in rootNames)
{
var rootObj = SceneUtils.FindChildRecursive(rootTransform, rootName);
if (rootObj != null)
{
SceneUtils.SetStaticFlagsRecursive(rootObj.gameObject, StaticEditorFlags.ContributeGI);
var renderers = rootObj.GetComponentsInChildren(true);
if (renderers != null && renderers.Length > 0)
{
Debug.Log($"从{rootName}收集到 {renderers.Length} 个渲染器用于烘焙");
foreach (var renderer in renderers)
{
Debug.Log($"处理从{rootName}收集到物体{renderer.gameObject.name}的渲染器");
if (renderer.receiveShadows)
{
renderer.shadowCastingMode = castShadow ? ShadowCastingMode.On : ShadowCastingMode.Off;
allBakeRenderers.Add(renderer);
if (needReplaceShader)
needReplaceRenderers.Add(renderer);
}
}
}
else
{
Debug.Log($"从{rootName}收集不到渲染器");
}
}
}
}
///
/// 准备灯光:将实时灯光改为烘焙灯光
///
public static void PrepareLight(Transform root, List realTimeLights, List bakedLights)
{
var lights = root.GetComponentsInChildren();
foreach (var light in lights)
{
light.transform.position = new Vector3(0, 0, 0);
// 复制灯光对象
var bakeLightObj = Object.Instantiate(light.gameObject, light.transform.parent);
var bakeLight = bakeLightObj.GetComponent();
// 设置为烘焙模式
bakeLightObj.name = light.name + "_Bake";
bakeLight.lightmapBakeType = LightmapBakeType.Baked;
// 取消实时灯光的static
GameObjectUtility.SetStaticEditorFlags(light.gameObject, 0);
// 设置烘焙灯光的static
GameObjectUtility.SetStaticEditorFlags(bakeLightObj, StaticEditorFlags.ContributeGI);
// 添加到列表
bakedLights.Add(bakeLight);
realTimeLights.Add(light);
}
// 关闭实时灯光
foreach (var realTimeLight in realTimeLights)
{
if (realTimeLight != null)
realTimeLight.gameObject.SetActive(false);
}
// 开启烘焙灯光
foreach (var bakeLight in bakedLights)
{
if (bakeLight != null)
bakeLight.gameObject.SetActive(true);
}
}
///
/// 恢复实时灯光
///
public static void RevertLight(List realTimeLights, List bakedLights)
{
// 开启实时灯光
foreach (var realTimeLight in realTimeLights)
{
if (realTimeLight != null)
realTimeLight.gameObject.SetActive(true);
}
Debug.Log($"销毁{bakedLights.Count}个烘焙灯光");
// 销毁烘焙灯光
foreach (var bakeLight in bakedLights)
{
if (bakeLight != null)
Object.DestroyImmediate(bakeLight.gameObject);
}
}
///
/// 执行烘焙
///
public static void Bake(Scene activeScene)
{
// 设置烘焙参数并开始烘焙
var lightingSettings = new LightingSettings();
Debug.Log($"烘焙时 场景是{activeScene.name}");
if (Lightmapping.TryGetLightingSettings(out var existingSettings))
{
lightingSettings = existingSettings;
}
else
{
lightingSettings.name = $"{activeScene.name}_LightingSettings";
AssetDatabase.CreateAsset(lightingSettings, $"Assets/{lightingSettings.name}.asset");
Lightmapping.lightingSettings = lightingSettings;
}
// 设置烘焙参数
lightingSettings.mixedBakeMode = MixedLightingMode.Subtractive;
lightingSettings.lightmapper = LightingSettings.Lightmapper.ProgressiveGPU;
lightingSettings.directSampleCount = 1;
lightingSettings.indirectSampleCount = 1;
lightingSettings.environmentSampleCount = 1;
lightingSettings.lightProbeSampleCountMultiplier = 8;
lightingSettings.maxBounces = 1;
lightingSettings.filteringMode = LightingSettings.FilterMode.Auto;
lightingSettings.lightmapResolution = 40;
lightingSettings.lightmapPadding = 2;
lightingSettings.lightmapMaxSize = 1024;
lightingSettings.lightmapCompression = LightmapCompression.HighQuality;
lightingSettings.indirectScale = 1;
lightingSettings.directionalityMode = LightmapsMode.NonDirectional;
Lightmapping.lightingSettings = lightingSettings;
// 强制场景保存以确保设置生效
EditorSceneManager.MarkSceneDirty(activeScene);
EditorSceneManager.SaveOpenScenes();
Debug.Log("开始烘焙灯光...");
Lightmapping.Bake();
Debug.Log("灯光烘焙完成");
}
///
/// 移动光照烘焙相关文件到指定目录
///
public static void CopyLightmapFiles(Scene scene, string lightmapDirPath)
{
string sceneName = scene.name;
Debug.Log("开始移动光照烘焙文件...");
try
{
// 确保目标目录存在
string lightmapDirAssetPath = SceneUtils.GetAssetPath(lightmapDirPath);
if (!AssetDatabase.IsValidFolder(lightmapDirAssetPath))
{
// 创建父目录结构
string[] folders = lightmapDirAssetPath.Split('/');
string currentPath = folders[0]; // Assets
for (int i = 1; i < folders.Length; i++)
{
string folderName = folders[i];
string parentPath = currentPath;
currentPath = $"{currentPath}/{folderName}";
if (!AssetDatabase.IsValidFolder(currentPath))
{
AssetDatabase.CreateFolder(parentPath, folderName);
}
}
AssetDatabase.Refresh();
}
// 1. 移动LightingSettings.asset文件
string lightingSettingsPath = $"Assets/{sceneName}_LightingSettings.asset";
if (AssetDatabase.LoadAssetAtPath(lightingSettingsPath) != null)
{
string destPath = $"{lightmapDirAssetPath}/{sceneName}_LightingSettings.asset";
// 如果目标已存在,先删除
if (AssetDatabase.LoadAssetAtPath(destPath) != null)
{
AssetDatabase.DeleteAsset(destPath);
}
AssetDatabase.MoveAsset(lightingSettingsPath, destPath);
Debug.Log($"已移动: {lightingSettingsPath} -> {destPath}");
}
// 2. 移动整个光照目录
string lightmapDirName = sceneName;
string lightmapSourceDir = $"{Path.GetDirectoryName(scene.path)}/{lightmapDirName}";
string lightmapSourceDirAssetPath = SceneUtils.GetAssetPath(lightmapSourceDir);
if (AssetDatabase.IsValidFolder(lightmapSourceDirAssetPath))
{
string destLightmapDir = $"{lightmapDirAssetPath}/{lightmapDirName}";
// 如果目标已存在,先删除
if (AssetDatabase.IsValidFolder(destLightmapDir))
{
AssetDatabase.DeleteAsset(destLightmapDir);
AssetDatabase.Refresh();
}
// 直接移动整个目录
string result = AssetDatabase.MoveAsset(lightmapSourceDirAssetPath, destLightmapDir);
if (string.IsNullOrEmpty(result))
{
Debug.Log($"已成功移动光照数据目录: {lightmapSourceDirAssetPath} -> {destLightmapDir}");
}
else
{
Debug.LogError($"移动光照数据目录失败: {result}");
}
}
else
{
Debug.LogWarning($"找不到光照数据目录: {lightmapSourceDirAssetPath}");
}
}
catch (System.Exception e)
{
Debug.LogError($"移动光照文件时出错: {e.Message}");
}
AssetDatabase.Refresh();
Debug.Log("光照烘焙文件移动完成");
}
}