using System.Collections.Generic; using System.IO; using PhxhSDK; using UnityEngine; using UnityEditor; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using UnityEngine.Rendering; using UnityEditorGameObjectUtility = UnityEditor.GameObjectUtility; /// /// 灯光烘焙工具类 /// 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 = rootTransform.FindChildRecursive(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 UnityEditorGameObjectUtility.SetStaticEditorFlags(light.gameObject, 0); // 设置烘焙灯光的static UnityEditorGameObjectUtility.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[] files = Directory.GetFiles(lightmapSourceDirAssetPath); foreach (string file in files) { if (!file.EndsWith(".meta")) { string fileName = Path.GetFileName(file); AssetDatabase.MoveAsset(file, lightmapDirAssetPath + "/" + fileName); } } Directory.Delete(lightmapSourceDirAssetPath); AssetDatabase.Refresh(); /*string destLightmapDir = $"{lightmapDirAssetPath}"; // 如果目标已存在,先删除 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("光照烘焙文件移动完成"); } }