NLDClient-yudde/ProjectNLD/Assets/Editor/Scene/PostProcesser/PostProcessor.cs

1313 lines
48 KiB
C#
Raw Normal View History

2025-04-14 15:51:02 +08:00
using System;
2024-01-15 20:25:49 +08:00
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.EventSystems;
2024-04-28 18:19:18 +08:00
using UnityEngine.Rendering;
2024-01-15 20:25:49 +08:00
using UnityEngine.SceneManagement;
using System.IO;
2025-04-14 15:51:02 +08:00
using Object = UnityEngine.Object;
2024-01-15 20:25:49 +08:00
public abstract class PostProcessor
{
public const string SCENE_POST_PROCESS_NAME = "PostProcess";
private const string SCENE_SURFACE_FOLDER_NAME = "SurfaceData";
private const string SCENE_COMBINED_NAME = "Combined";
private const string GROUND_SPLIT_NAME = "GroundSplit";
2025-04-07 18:55:27 +08:00
private const string LIGHT_BAKE_NAME = "LightMaps";
2024-10-22 16:10:43 +08:00
protected const string SCENE_POSTPROCESS_DIR = "Assets/Art_Out/AutoGen/PostProcessScenes";
protected const string PREFAB_POSTPROCESS_DIR = "Assets/Art_Out/AutoGen/PostProcessPrefabs";
2024-01-15 20:25:49 +08:00
protected const string SURFACE_SHADER_PATH = "Assets/Code/Shaders/Scene/NLD_Scene_Surface.shader";
protected const string SCENE_ADDRESSABLE_GROUP = "PostProcessScenes";
protected const string PREFAB_ADDRESSABLE_GROUP = "PostProcessPrefabs";
// 区分剧情场景前缀
protected const string STORY_SCENE_PREFIX = "story_";
2024-01-15 20:25:49 +08:00
private const int GROUND_SPLIT_WIDTH = 1024;
private const int GROUND_SPLIT_HEIGHT = 1024;
private const int UPP = 100;
2025-04-14 15:51:02 +08:00
// 存储渲染器和它们的原始材质映射
private Dictionary<Renderer, Material[]> originalMaterials = new Dictionary<Renderer, Material[]>();
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 存储需要进行材质恢复的渲染器列表
private List<Renderer> renderersToRestore = new List<Renderer>();
2024-10-22 16:10:43 +08:00
private readonly List<string> sceneRoots = new()
2025-04-07 18:55:27 +08:00
{
"Main Camera", "TerrainGridSystem", "Art", "SceneManager", "MapEditor", "LevelEditor", "TGSPreview",
"InputManager (Singleton)"
};
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
/// <summary>
/// 需要烘焙的节点
/// </summary>
private readonly List<string> bakeRoot = new()
{
2025-04-16 15:28:21 +08:00
"Trees", "Buildings", "CombinedRoot"
2025-04-14 15:51:02 +08:00
};
/// <summary>
/// 需要烘焙和关闭阴影的地面节点
/// </summary>
private readonly List<string> groundRoot = new()
{
"Ground_2"
};
2024-10-22 16:10:43 +08:00
2024-01-15 20:25:49 +08:00
protected string ProcessedResourceDir => $"{ResourcesBaseDir}/{PostProcessFolderName}";
protected abstract string ResourcesBaseDir { get; }
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
private string LightBakeDir => $"{ProcessedResourceDir}/{LIGHT_BAKE_NAME}";
2024-01-15 20:25:49 +08:00
private string SurfaceDir => $"{ProcessedResourceDir}/{SCENE_SURFACE_FOLDER_NAME}";
private string CombinedDir => $"{ProcessedResourceDir}/{SCENE_COMBINED_NAME}";
private string GroundSplitDir => $"{ProcessedResourceDir}/{GROUND_SPLIT_NAME}";
protected abstract string PostProcessFolderName { get; }
protected PostProcessInstructor _processInstructor;
private PostProcessInstructor _clonedProcessInstructor;
//private NLDSceneManager NLDSceneManager { get; set; }
//private NLDSceneManager _postProcessSceneManager;
private bool HasClone { get; set; }
2024-01-16 18:37:02 +08:00
protected abstract Object AssetToPostProcess { get; }
protected string OriginAssetPath => AssetDatabase.GetAssetPath(AssetToPostProcess);
2024-10-22 16:10:43 +08:00
2024-01-16 18:37:02 +08:00
protected abstract string OutputAssetPath { get; }
2024-01-15 20:25:49 +08:00
private PostProcessInstructor PostProcessInstructor => HasClone ? _clonedProcessInstructor : _processInstructor;
2024-01-17 13:44:26 +08:00
private Transform CombinedObjectsRoot
2024-01-15 20:25:49 +08:00
{
get
{
2024-01-17 13:44:26 +08:00
if (PostProcessInstructor == null || PostProcessInstructor.combinedObjectsRoot == null)
2024-01-15 20:25:49 +08:00
{
2025-04-07 14:18:07 +08:00
Debug.LogError("找不到Art节点!");
2024-01-15 20:25:49 +08:00
return PostProcessInstructor.transform.parent;
}
2024-01-17 13:44:26 +08:00
return PostProcessInstructor.combinedObjectsRoot;
2024-01-15 20:25:49 +08:00
}
}
private bool CheckPostProcessInstructor(PostProcessInstructor postProcessInstructor)
{
if (postProcessInstructor == null)
{
Debug.LogError("postProcessInstructor is null");
return false;
}
2024-10-22 16:10:43 +08:00
if (postProcessInstructor.processPrefab &&
2025-04-07 18:55:27 +08:00
(!PrefabUtility.IsPartOfAnyPrefab(postProcessInstructor) ||
EditorUtility.IsPersistent(postProcessInstructor)))
2024-01-15 20:25:49 +08:00
{
2024-01-16 14:23:05 +08:00
Debug.LogError("postProcessInstructor不在任何预制体内或者其不是预制体实例");
2024-01-15 20:25:49 +08:00
return false;
}
2024-09-24 16:57:21 +08:00
var currentScene = postProcessInstructor.gameObject.scene;
var objs = currentScene.GetRootGameObjects();
foreach (var obj in objs)
{
if (!sceneRoots.Contains(obj.name))
{
DebugUtil.LogWarning("{1} 场景有其他节点:{0},请检查节点规范", obj.name, currentScene.name);
}
}
2024-01-15 20:25:49 +08:00
return true;
}
protected virtual void Init(PostProcessInstructor postProcessInstructor)
{
_processInstructor = postProcessInstructor;
}
2025-04-07 18:55:27 +08:00
public void PostProcess(PostProcessInstructor postProcessInstructor, bool destroyAfterPostProcess = false,
bool defaultCameraParam = true)
2024-01-15 20:25:49 +08:00
{
if (!CheckPostProcessInstructor(postProcessInstructor))
return;
Init(postProcessInstructor);
HasClone = false;
EditorSceneManager.SaveOpenScenes();
PrepareFolders();
//NLDSceneManager = CommonUtils.GetSceneRootComponent<NLDSceneManager>(Scene);
//暂时先不渲染成面片(地面阴影还没法解决,以及一些与笔刷工具的耦合)
//BakeSurfaceData();
2025-04-15 16:33:01 +08:00
2024-01-15 20:25:49 +08:00
_clonedProcessInstructor = Clone();
2024-01-16 14:23:05 +08:00
HasClone = true;
2024-01-15 20:25:49 +08:00
if (_clonedProcessInstructor == null)
{
Debug.LogError("_clonedProcessInstructor is null!");
return;
}
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
2024-01-15 20:25:49 +08:00
BakeCombinedGameObject();
2025-04-16 15:28:21 +08:00
BakeLightmaps();
2025-04-03 12:55:11 +08:00
// SplitGroundTexture();
2024-01-15 20:25:49 +08:00
SetFogPosition();
2024-10-22 16:10:43 +08:00
if (!defaultCameraParam)
{
SetCameraParam();
}
2025-04-07 18:55:27 +08:00
RemoveRedundant();
2024-10-22 16:10:43 +08:00
2024-01-16 14:23:05 +08:00
DestroyUselessObject();
2024-01-15 20:25:49 +08:00
AfterAll(destroyAfterPostProcess);
PostProcessData.EditorInstance.AddPostProcessData(AssetToPostProcess, OutputAssetPath);
2024-01-16 18:37:02 +08:00
Debug.Log($"执行后处理成功,后处理资源源路径:{OriginAssetPath} 后处理后路径:{OutputAssetPath}");
2024-01-26 16:02:49 +08:00
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
2024-01-15 20:25:49 +08:00
}
protected abstract void AfterAll(bool destroyAfterPostProcess);
public static PostProcessInstructor FindInstructorInScene(Scene scene)
{
var instructors = Object.FindObjectsOfType<PostProcessInstructor>();
return instructors.FirstOrDefault(pi => pi.gameObject.scene == scene);
}
// private void DeleteSurfaceData(SceneSurfaceData surfaceData)
// {
// var mat = AssetDatabase.LoadAssetAtPath<Material>(surfaceData.materialPath);
// if (mat == null)
// {
// return;
// }
//
// AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(mat.mainTexture));
// AssetDatabase.DeleteAsset(surfaceData.materialPath);
// }
private void PrepareFolders()
{
AssetDatabase.DeleteAsset(ProcessedResourceDir);
2024-01-16 14:23:05 +08:00
AssetDatabase.CreateFolder(ResourcesBaseDir, PostProcessFolderName);
2024-01-15 20:25:49 +08:00
AssetDatabase.CreateFolder(ProcessedResourceDir, SCENE_SURFACE_FOLDER_NAME);
AssetDatabase.CreateFolder(ProcessedResourceDir, SCENE_COMBINED_NAME);
AssetDatabase.CreateFolder(ProcessedResourceDir, GROUND_SPLIT_NAME);
}
protected abstract PostProcessInstructor Clone();
2024-01-16 14:23:05 +08:00
2024-01-15 20:25:49 +08:00
//烘焙面片数据
// private void BakeSurfaceData()
// {
// if (NLDSceneManager == null)
// return;
// NLDSceneManager.allSceneSurfaceData.Clear();
// List<SceneObjectRenderInfo> renderInfos = new();
// var camera = Camera.main;
// if (camera == null)
// {
// Debug.LogError("找不到主相机!请设置主相机的tag");
// return;
// }
//
// foreach (var sObj in NLDSceneManager.sceneObjects)
// {
// if (sObj && sObj.renderInfo && !renderInfos.Contains(sObj.renderInfo))
// {
// var brush = SceneBrushHelper.GetSceneBrushByRenderInfo(sObj.renderInfo);
// if (!brush.SupportSurface)
// continue;
// renderInfos.Add(sObj.renderInfo);
// var gameObject = brush.prefab;
// var texPath =
// EditorUtil.GetAssetUniquePath($"{SurfaceDir}/{gameObject.name}_surface.jpg", out var name);
// Vector3 offset = Vector3.zero;
// Vector3 scale = Vector3.one;
// Quaternion rotation = Quaternion.identity;
// var texture = gameObject.RenderToTexture(camera, texPath, ref offset, ref scale, ref rotation);
// if (texture != null)
// {
// var material = new Material(AssetDatabase.LoadAssetAtPath<Shader>(SURFACE_SHADER_PATH))
// {
// mainTexture = texture
// };
// material.enableInstancing = true;
// var matPath = $"{SurfaceDir}/{gameObject.name}_surface.mat".Replace("\\", "/");
// EditorUtil.CreateAnUniqueAsset(material, matPath);
// SceneSurfaceData surfaceData = new()
// {
// renderInfo = sObj.renderInfo,
// materialPath = matPath,
// cachedOffset = offset,
// eulerAngleID = gameObject.transform.eulerAngles,
// cachedRotation = rotation.eulerAngles,
// cachedScale = scale,
// valid = true,
// };
// NLDSceneManager.allSceneSurfaceData.Add(surfaceData);
// }
// }
// }
//
// //MarkSceneDirty();
// }
//合并网格,贴图
private void BakeCombinedGameObject()
{
2024-01-17 13:44:26 +08:00
var art = CombinedObjectsRoot;
2025-04-15 16:33:01 +08:00
2025-04-07 14:18:07 +08:00
// 不再自动执行模型切割,由外部单独调用
2025-04-15 16:33:01 +08:00
2025-04-07 14:18:07 +08:00
// 收集渲染器
2024-01-15 20:25:49 +08:00
var renderers = CollectRenderers();
2025-04-15 16:33:01 +08:00
2025-04-07 14:18:07 +08:00
Debug.Log($"合批前收集到 {renderers.Count} 个渲染器");
2025-04-15 16:33:01 +08:00
2025-04-07 14:18:07 +08:00
var prefix = GetScenePrefix();
2024-01-15 20:25:49 +08:00
var combinedRoot = new GameObject("CombinedRoot");
combinedRoot.transform.parent = art.transform;
2025-04-01 16:59:45 +08:00
2025-04-07 14:18:07 +08:00
try
2025-04-01 16:59:45 +08:00
{
2025-04-07 14:18:07 +08:00
if (PostProcessInstructor.enableBatchGrouping)
{
// 按照距离对渲染器进行分组
2025-04-07 18:55:27 +08:00
Dictionary<string, List<Renderer>> rendererGroups =
GroupRenderersByCircularDistance(renderers, PostProcessInstructor.batchGroupDistance);
2025-04-07 14:18:07 +08:00
SceneCombineUtil.Instance.CombineGameObjectsByGroups(rendererGroups, combinedRoot.transform,
CombinedDir,
(int)PostProcessInstructor.postProcessTextureUnitSize,
PostProcessInstructor.sampleMaterials, prefix);
}
else
{
// 使用原有的合批方式
SceneCombineUtil.Instance.CombineGameObjects(renderers, combinedRoot.transform, CombinedDir,
(int)PostProcessInstructor.postProcessTextureUnitSize,
PostProcessInstructor.sampleMaterials, prefix);
}
2025-04-15 16:33:01 +08:00
2025-04-07 14:18:07 +08:00
// 如果是剧情场景,重命名生成的所有物体添加前缀
if (!string.IsNullOrEmpty(prefix))
{
var combined = combinedRoot.GetComponentsInChildren<Transform>();
foreach (var trans in combined)
{
if (trans != combinedRoot.transform && !trans.name.StartsWith(prefix))
{
trans.name = prefix + trans.name;
}
}
}
foreach (var renderer in renderers)
{
if (renderer != null && renderer.gameObject != null)
{
Object.DestroyImmediate(renderer.gameObject);
}
}
2025-04-01 16:59:45 +08:00
}
2025-04-07 14:18:07 +08:00
catch (System.Exception ex)
2025-04-01 16:59:45 +08:00
{
2025-04-07 14:18:07 +08:00
Debug.LogError($"合批过程中发生错误: {ex.Message}\n{ex.StackTrace}");
// 如果合批失败,保留原始物体
if (combinedRoot != null)
{
Object.DestroyImmediate(combinedRoot);
}
}
2025-04-07 14:18:07 +08:00
}
2025-04-01 16:59:45 +08:00
// 根据距离对渲染器进行分组
2025-04-07 18:55:27 +08:00
private Dictionary<string, List<Renderer>> GroupRenderersByCircularDistance(List<Renderer> renderers,
float maxDistance)
2025-04-01 16:59:45 +08:00
{
Dictionary<string, List<Renderer>> groups = new Dictionary<string, List<Renderer>>();
int groupIndex = 0;
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 已分组的渲染器
HashSet<Renderer> processedRenderers = new HashSet<Renderer>();
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 对所有渲染器进行处理
while (processedRenderers.Count < renderers.Count)
{
// 找到第一个未处理的渲染器作为新组的起点
Renderer startRenderer = null;
foreach (var renderer in renderers)
{
if (!processedRenderers.Contains(renderer))
{
startRenderer = renderer;
break;
}
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
if (startRenderer == null)
break;
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 创建新组
List<Renderer> currentGroup = new List<Renderer>();
currentGroup.Add(startRenderer);
processedRenderers.Add(startRenderer);
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
bool addedNew = true;
while (addedNew)
{
addedNew = false;
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 计算当前组的中心点
Vector3 groupCenter = CalculateGroupCenter(currentGroup);
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 查找距离中心点在阈值内的未处理渲染器
foreach (var renderer in renderers)
{
if (processedRenderers.Contains(renderer))
continue;
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
float distance = Vector3.Distance(groupCenter, renderer.transform.position);
if (distance <= maxDistance)
{
currentGroup.Add(renderer);
processedRenderers.Add(renderer);
addedNew = true;
}
}
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 保存当前组
groups.Add($"Group_{groupIndex}", currentGroup);
groupIndex++;
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
Debug.Log($"基于圆形区域分组:将{renderers.Count}个渲染器分成{groups.Count}个组,半径为{maxDistance}");
return groups;
}
private Vector3 CalculateGroupCenter(List<Renderer> group)
{
if (group.Count == 0)
return Vector3.zero;
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
Vector3 sum = Vector3.zero;
foreach (var renderer in group)
{
sum += renderer.transform.position;
}
2025-04-07 18:55:27 +08:00
2025-04-01 16:59:45 +08:00
return sum / group.Count;
}
// 原先基于顶点数的分组方法(保留作为备用)
private Dictionary<string, List<Renderer>> GroupRenderers(List<Renderer> renderers, int groupSize)
{
Dictionary<string, List<Renderer>> groups = new Dictionary<string, List<Renderer>>();
int totalVertexCount = 0;
int groupIndex = 0;
List<Renderer> currentGroup = new List<Renderer>();
foreach (var renderer in renderers)
{
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter == null || meshFilter.sharedMesh == null)
continue;
// 获取当前渲染器的顶点数
int vertexCount = meshFilter.sharedMesh.vertexCount;
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 如果当前组顶点数已经超过限制或这个模型本身太大,创建新组
if ((totalVertexCount + vertexCount > groupSize && currentGroup.Count > 0) || vertexCount > groupSize)
{
// 保存当前组
if (currentGroup.Count > 0)
{
groups.Add($"Group_{groupIndex}", new List<Renderer>(currentGroup));
currentGroup.Clear();
totalVertexCount = 0;
groupIndex++;
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 如果单个模型超过大小限制,单独放一组
if (vertexCount > groupSize)
{
groups.Add($"Group_{groupIndex}_LargeModel_{renderer.name}", new List<Renderer> { renderer });
groupIndex++;
continue;
}
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 添加到当前组
currentGroup.Add(renderer);
totalVertexCount += vertexCount;
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
// 确保最后一组也被添加
if (currentGroup.Count > 0)
{
groups.Add($"Group_{groupIndex}", new List<Renderer>(currentGroup));
}
2025-04-15 16:33:01 +08:00
2025-04-01 16:59:45 +08:00
Debug.Log($"分组合批:将{renderers.Count}个渲染器分成{groups.Count}个组,按每组约{groupSize}个顶点");
return groups;
}
2024-01-15 20:25:49 +08:00
private List<Renderer> CollectRenderers()
{
List<Renderer> allRenderers = new();
2024-01-17 13:44:26 +08:00
foreach (var root in PostProcessInstructor.rootsToCombine)
2024-01-15 20:25:49 +08:00
{
if (!root)
{
continue;
}
2024-10-22 16:10:43 +08:00
var render = root.GetComponentsInChildren<Renderer>();
if (render is not { Length: > 0 })
{
continue;
}
2025-04-15 16:33:01 +08:00
allRenderers.AddRange(render);
2024-01-15 20:25:49 +08:00
}
return allRenderers;
}
2025-04-08 14:17:55 +08:00
#region 地面切图
2024-01-15 20:25:49 +08:00
private void SplitGroundTexture()
{
var ground = PostProcessInstructor.ground;
if (ground == null)
return;
var renderer = ground.GetComponent<MeshRenderer>();
if (renderer == null)
return;
var mat = renderer.sharedMaterial;
if (mat == null)
return;
var texture = mat.mainTexture as Texture2D;
if (texture == null)
return;
2025-04-15 16:33:01 +08:00
var prefix = GetScenePrefix();
2024-01-16 14:23:05 +08:00
var groundParent = Object.Instantiate(ground, ground.transform.parent, true);
2024-01-15 20:25:49 +08:00
groundParent.name = "Ground";
2025-04-15 16:33:01 +08:00
// 计算原始地面的大小
var originalScale = ground.transform.localScale;
var originalWidth = originalScale.x;
var originalHeight = originalScale.y;
2024-01-15 20:25:49 +08:00
var originPos = -new Vector3(originalWidth / 2f, originalHeight / 2f, 0);
2024-01-15 20:25:49 +08:00
groundParent.transform.localScale = Vector3.one;
// 确保目录存在
if (!AssetDatabase.IsValidFolder(GroundSplitDir))
{
var parentDir = Path.GetDirectoryName(GroundSplitDir);
if (!AssetDatabase.IsValidFolder(parentDir))
{
AssetDatabase.CreateFolder(Path.GetDirectoryName(parentDir), Path.GetFileName(parentDir));
}
2025-04-07 18:55:27 +08:00
AssetDatabase.CreateFolder(parentDir, Path.GetFileName(GroundSplitDir));
}
2025-04-07 18:55:27 +08:00
var textures =
SplitTextureUtil.SplitTexture(texture, GROUND_SPLIT_WIDTH, GROUND_SPLIT_HEIGHT, GroundSplitDir, prefix);
2024-01-15 20:25:49 +08:00
// 计算每个分割块的大小(基于原始地面大小)
var rowCount = textures.GetLength(0);
var columnCount = textures.GetLength(1);
var blockWidth = originalWidth / columnCount;
var blockHeight = originalHeight / rowCount;
for (int row = 0; row < rowCount; row++)
2024-01-15 20:25:49 +08:00
{
for (int column = 0; column < columnCount; column++)
2024-01-15 20:25:49 +08:00
{
var splitTexture = textures[row, column];
if (splitTexture == null)
{
Debug.LogError($"Failed to load split texture at row {row}, column {column}");
continue;
}
2024-01-15 20:25:49 +08:00
var splitGround = Object.Instantiate(ground, groundParent.transform, true);
Object.DestroyImmediate(splitGround.GetComponent<Collider>());
var splitName = $"{prefix}Ground_{row}_{column}";
2024-01-15 20:25:49 +08:00
splitGround.name = splitName;
2025-04-15 16:33:01 +08:00
// 设置固定的quad大小,不随贴图尺寸变化
splitGround.transform.localScale = new Vector3(blockWidth, blockHeight, 1);
// 创建并保存材质
2024-01-15 20:25:49 +08:00
var splitMat = Object.Instantiate(mat);
splitMat.mainTexture = splitTexture;
var matPath = $"{GroundSplitDir}/{splitName}.mat";
AssetDatabase.CreateAsset(splitMat, matPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
// 重新加载保存后的材质
var savedMat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
if (savedMat == null)
{
Debug.LogError($"Failed to load saved material at {matPath}");
continue;
}
var meshRenderer = splitGround.GetComponent<MeshRenderer>();
if (meshRenderer != null)
{
meshRenderer.sharedMaterial = savedMat;
meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
}
// 计算位置,使用固定的block大小
2024-02-02 16:45:56 +08:00
splitGround.transform.localPosition =
2025-04-07 18:55:27 +08:00
originPos + new Vector3(column * blockWidth + blockWidth / 2f, row * blockHeight + blockHeight / 2f,
0);
2024-01-15 20:25:49 +08:00
}
}
Object.DestroyImmediate(ground);
Object.DestroyImmediate(groundParent.GetComponent<Renderer>());
Object.DestroyImmediate(groundParent.GetComponent<Collider>());
var boxCollider = groundParent.gameObject.AddComponent<BoxCollider>();
boxCollider.size = new Vector3(200, 200, 1);
2024-01-15 20:25:49 +08:00
boxCollider.center = new Vector3(0, 0, 0.5f);
Object.DestroyImmediate(groundParent.GetComponent<MeshFilter>());
}
2025-04-08 14:17:55 +08:00
#endregion
2025-04-15 16:33:01 +08:00
2025-04-08 14:17:55 +08:00
2024-01-15 20:25:49 +08:00
private void SetFogPosition()
{
var fog = PostProcessInstructor.fog;
if (fog == null)
return;
var transform = fog.transform;
var position = transform.position;
transform.position = new Vector3(position.x, position.y + 0.01f, position.z);
2024-01-15 20:25:49 +08:00
}
2024-01-16 14:23:05 +08:00
private void RemoveRedundant()
{
Scene postScene = PostProcessInstructor.gameObject.scene;
2025-04-07 18:55:27 +08:00
foreach (GameObject rootObj in postScene.GetRootGameObjects())
{
EventSystem[] eventSystems = rootObj.GetComponentsInChildren<EventSystem>();
if (null == eventSystems)
continue;
for (int i = 0; i < eventSystems.Length; ++i)
{
Object.DestroyImmediate(eventSystems[i].gameObject);
}
}
}
2024-10-22 16:10:43 +08:00
2024-01-16 14:23:05 +08:00
private void DestroyUselessObject()
{
2024-01-17 13:44:26 +08:00
foreach (var root in PostProcessInstructor.rootsToCombine)
2024-01-16 14:23:05 +08:00
{
if (!root)
{
continue;
}
2024-10-22 16:10:43 +08:00
2024-01-16 14:23:05 +08:00
Object.DestroyImmediate(root.gameObject, true);
}
Object.DestroyImmediate(PostProcessInstructor.gameObject, true);
}
private bool IsStoryScene()
{
string sceneName = PostProcessInstructor.gameObject.scene.name;
return sceneName.Contains(STORY_SCENE_PREFIX);
}
private string GetScenePrefix()
{
return IsStoryScene() ? STORY_SCENE_PREFIX : "";
}
2025-04-07 18:55:27 +08:00
2025-04-08 14:17:55 +08:00
#region 保存相机参数
private void SetCameraParam()
{
var postScene = PostProcessInstructor.gameObject.scene;
var scene = _processInstructor.gameObject.scene;
foreach (var rootObj in scene.GetRootGameObjects())
{
if (rootObj.CompareTag("MainCamera"))
{
CloneCameraToScene(rootObj, postScene);
break;
}
}
}
private void CloneCameraToScene(GameObject obj, Scene scene)
{
// 只更改transform
var oldPosition = obj.transform.position;
var oldRotation = obj.transform.rotation;
GameObject oldCamera = null;
foreach (var rootObj in scene.GetRootGameObjects())
{
if (rootObj.CompareTag("MainCamera"))
{
oldCamera = rootObj;
break;
}
}
if (oldCamera == null) return;
oldCamera.transform.position = oldPosition;
oldCamera.transform.rotation = oldRotation;
}
#endregion
#region 烘焙
/// <summary>
/// 烘焙灯光贴图的方法
/// </summary>
2025-04-07 18:55:27 +08:00
private void BakeLightmaps()
{
// 检查是否开启了烘焙选项
2025-04-16 15:28:21 +08:00
if (PostProcessInstructor == null || !PostProcessInstructor.enableLightmapBaking)
2025-04-07 18:55:27 +08:00
return;
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
Debug.Log("开始灯光烘焙过程...");
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 清空旧的材质映射
originalMaterials.Clear();
renderersToRestore.Clear();
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
// 1. 从CombinedObjectsRoot下查找灯光,分为烘焙灯光和实时灯光
2025-04-07 18:55:27 +08:00
var bakeLights = new List<Light>();
var realtimeLights = new List<Light>();
2025-04-08 14:17:55 +08:00
2025-04-16 15:28:21 +08:00
var lights = CombinedObjectsRoot.GetComponentsInChildren<Light>();
2025-04-07 18:55:27 +08:00
foreach (var light in lights)
{
// 跳过相机上的灯光,避免重复
if (light.GetComponentInParent<Camera>() != null)
continue;
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 复制灯光对象
var realtimeLightObj = Object.Instantiate(light.gameObject, light.transform.parent);
var realtimeLight = realtimeLightObj.GetComponent<Light>();
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 设置为烘焙和实时模式
light.gameObject.name += "_Bake";
light.lightmapBakeType = LightmapBakeType.Baked;
realtimeLight.lightmapBakeType = LightmapBakeType.Realtime;
2025-04-07 19:50:53 +08:00
// 取消烘焙灯光的static
GameObjectUtility.SetStaticEditorFlags(light.gameObject, 0);
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 添加到列表
bakeLights.Add(light);
2025-04-08 14:17:55 +08:00
break;
2025-04-07 18:55:27 +08:00
}
2025-04-16 15:28:21 +08:00
// 查找并关闭所有实时灯光
var allSceneLights = Object.FindObjectsOfType<Light>();
2025-04-08 14:17:55 +08:00
2025-04-16 15:28:21 +08:00
foreach (var light in allSceneLights)
2025-04-07 18:55:27 +08:00
{
2025-04-16 15:28:21 +08:00
// 只处理实时灯光
if (light.lightmapBakeType == LightmapBakeType.Realtime)
{
if (light.gameObject.activeSelf)
{
light.gameObject.SetActive(false);
realtimeLights.Add(light);
}
}
2025-04-07 18:55:27 +08:00
}
2025-04-08 14:17:55 +08:00
2025-04-14 15:51:02 +08:00
// 3. 收集指定节点下需要烘焙的渲染器
2025-04-07 18:55:27 +08:00
var bakedRenderers = new List<Renderer>();
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
// 处理bakeRoot中的渲染器,从CombinedObjectsRoot下查找
2025-04-14 15:51:02 +08:00
foreach (var rootName in bakeRoot)
2025-04-07 18:55:27 +08:00
{
2025-04-16 15:28:21 +08:00
var rootObj = FindChildRecursive(CombinedObjectsRoot, rootName);
2025-04-14 15:51:02 +08:00
if (rootObj != null)
{
var renderers = rootObj.GetComponentsInChildren<Renderer>(true);
if (renderers != null && renderers.Length > 0)
{
Debug.Log($"从{rootName}收集到 {renderers.Length} 个渲染器用于烘焙");
foreach (var renderer in renderers)
{
if (renderer.receiveShadows)
{
2025-04-15 16:33:01 +08:00
// 保证物体阴影打开
renderer.shadowCastingMode = ShadowCastingMode.On;
2025-04-14 15:51:02 +08:00
bakedRenderers.Add(renderer);
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 设置静态标志
GameObjectUtility.SetStaticEditorFlags(renderer.gameObject,
StaticEditorFlags.ContributeGI | StaticEditorFlags.ReflectionProbeStatic);
}
}
}
}
}
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
// 处理groundRoot中的渲染器,从CombinedObjectsRoot下查找
2025-04-14 15:51:02 +08:00
foreach (var rootName in groundRoot)
{
2025-04-16 15:28:21 +08:00
var rootObj = FindChildRecursive(CombinedObjectsRoot, rootName);
2025-04-14 15:51:02 +08:00
if (rootObj != null)
{
var renderers = rootObj.GetComponentsInChildren<Renderer>(true);
if (renderers != null && renderers.Length > 0)
{
Debug.Log($"从{rootName}收集到 {renderers.Length} 个地面渲染器用于烘焙");
foreach (var renderer in renderers)
{
2025-04-16 15:28:21 +08:00
renderer.shadowCastingMode = ShadowCastingMode.Off;
2025-04-15 16:33:01 +08:00
GameObjectUtility.SetStaticEditorFlags(renderer.gameObject,
StaticEditorFlags.ContributeGI | StaticEditorFlags.ReflectionProbeStatic);
DebugUtil.Log("groundRoot渲染器已设置静态标志");
2025-04-14 15:51:02 +08:00
}
}
}
}
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
// 处理 PostProcessInstructor.ground 指定的渲染器
if (PostProcessInstructor.ground != null)
2025-04-14 15:51:02 +08:00
{
2025-04-16 15:28:21 +08:00
var renderer = PostProcessInstructor.ground.GetComponent<Renderer>();
2025-04-15 16:33:01 +08:00
if (renderer != null)
2025-04-07 18:55:27 +08:00
{
2025-04-16 15:28:21 +08:00
renderer.shadowCastingMode = ShadowCastingMode.Off;
2025-04-14 15:51:02 +08:00
// 设置静态标志
2025-04-08 14:17:55 +08:00
GameObjectUtility.SetStaticEditorFlags(renderer.gameObject,
2025-04-14 15:51:02 +08:00
StaticEditorFlags.ContributeGI | StaticEditorFlags.ReflectionProbeStatic);
2025-04-16 15:28:21 +08:00
DebugUtil.Log("PostProcessInstructor.ground渲染器已设置静态标志");
// 将PostProcessInstructor.ground的RenderQueue改为3000
2025-04-15 16:33:01 +08:00
var materials = renderer.sharedMaterials;
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] != null)
{
2025-04-16 15:28:21 +08:00
renderer.shadowCastingMode = ShadowCastingMode.Off;
2025-04-15 16:33:01 +08:00
materials[i].renderQueue = 3000;
2025-04-16 15:28:21 +08:00
Debug.Log($"将PostProcessInstructor.ground的材质 {materials[i].name} 的RenderQueue从3000改回2000");
2025-04-15 16:33:01 +08:00
}
}
}
}
2025-04-08 14:17:55 +08:00
2025-04-16 15:28:21 +08:00
Debug.Log($"总共收集到 {bakedRenderers.Count} 个渲染器用于烘焙");
// 替换Shader为支持光照贴图的Shader
ReplaceShaderWithLightmapShader(bakedRenderers);
2025-04-07 18:55:27 +08:00
// 4. 设置烘焙参数并开始烘焙
var lightingSettings = new LightingSettings();
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 获取当前场景的烘焙设置
var activeScene = SceneManager.GetActiveScene();
if (Lightmapping.TryGetLightingSettings(out var existingSettings))
{
lightingSettings = existingSettings;
}
else
{
// 如果没有现有设置,创建新的并分配给场景
lightingSettings.name = $"{activeScene.name}_LightingSettings";
AssetDatabase.CreateAsset(lightingSettings, $"Assets/{lightingSettings.name}.asset");
Lightmapping.lightingSettings = lightingSettings;
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 设置烘焙参数
2025-04-08 14:17:55 +08:00
lightingSettings.lightmapper = LightingSettings.Lightmapper.ProgressiveGPU;
2025-04-07 18:55:27 +08:00
lightingSettings.directSampleCount = 1;
lightingSettings.indirectSampleCount = 1;
lightingSettings.environmentSampleCount = 1;
lightingSettings.lightProbeSampleCountMultiplier = 8;
lightingSettings.maxBounces = 1;
lightingSettings.lightmapResolution = 40;
lightingSettings.lightmapPadding = 2;
lightingSettings.lightmapMaxSize = 1024;
lightingSettings.lightmapCompression = LightmapCompression.HighQuality;
lightingSettings.filteringMode = LightingSettings.FilterMode.Auto;
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
Lightmapping.lightingSettings = lightingSettings;
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 强制场景保存以确保设置生效
EditorSceneManager.MarkSceneDirty(activeScene);
EditorSceneManager.SaveOpenScenes();
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
Debug.Log("开始烘焙灯光...");
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 5. 开始烘焙
Lightmapping.Bake();
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
Debug.Log("灯光烘焙完成");
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 6. 关闭所有烘焙物体的阴影投射
foreach (var renderer in bakedRenderers)
{
if (renderer != null)
renderer.shadowCastingMode = ShadowCastingMode.Off;
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 7. 删除烘焙灯光,打开实时灯光
foreach (var light in bakeLights)
{
if (light != null)
Object.DestroyImmediate(light.gameObject);
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
foreach (var light in realtimeLights)
{
if (light != null)
light.gameObject.SetActive(true);
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 8. 恢复非地面物体的原始材质
2025-04-16 15:28:21 +08:00
RestoreOriginalMaterials();
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
// 9. 只将PostProcessInstructor.ground的RenderQueue从3000改回2000
if (PostProcessInstructor.ground != null)
2025-04-14 15:51:02 +08:00
{
2025-04-16 15:28:21 +08:00
var renderer = PostProcessInstructor.ground.GetComponent<Renderer>();
2025-04-14 15:51:02 +08:00
if (renderer != null)
{
var materials = renderer.sharedMaterials;
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] != null)
{
materials[i].renderQueue = 2000;
2025-04-16 15:28:21 +08:00
Debug.Log($"将PostProcessInstructor.ground的材质 {materials[i].name} 的RenderQueue从3000改回2000");
2025-04-14 15:51:02 +08:00
}
}
}
}
2025-04-15 16:33:01 +08:00
2025-04-14 17:21:38 +08:00
// 刷新资源以确保RenderQueue修改已保存
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
2025-04-14 15:51:02 +08:00
// 10. 复制光照烘焙文件到目标路径
2025-04-07 19:50:53 +08:00
CopyLightmapFiles(activeScene);
2025-04-08 14:17:55 +08:00
2025-04-14 15:51:02 +08:00
// 11. 保存场景
2025-04-07 18:55:27 +08:00
EditorSceneManager.MarkSceneDirty(activeScene);
EditorSceneManager.SaveOpenScenes();
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
Debug.Log("灯光烘焙处理完成");
}
2025-04-08 14:17:55 +08:00
/// <summary>
/// 移动光照烘焙相关文件到指定目录
/// </summary>
2025-04-07 18:55:27 +08:00
private void CopyLightmapFiles(Scene scene)
{
string sceneName = scene.name;
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
Debug.Log("开始移动光照烘焙文件...");
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
try
{
// 确保目标目录存在
string lightmapDirAssetPath = GetAssetPath(LightBakeDir);
if (!AssetDatabase.IsValidFolder(lightmapDirAssetPath))
{
// 创建父目录结构
string[] folders = lightmapDirAssetPath.Split('/');
string currentPath = folders[0]; // Assets
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
for (int i = 1; i < folders.Length; i++)
{
string folderName = folders[i];
string parentPath = currentPath;
currentPath = $"{currentPath}/{folderName}";
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
if (!AssetDatabase.IsValidFolder(currentPath))
{
AssetDatabase.CreateFolder(parentPath, folderName);
}
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
AssetDatabase.Refresh();
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 1. 移动LightingSettings.asset文件
string lightingSettingsPath = $"Assets/{sceneName}_LightingSettings.asset";
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(lightingSettingsPath) != null)
{
string destPath = $"{lightmapDirAssetPath}/{sceneName}_LightingSettings.asset";
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 如果目标已存在,先删除
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(destPath) != null)
{
AssetDatabase.DeleteAsset(destPath);
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
AssetDatabase.MoveAsset(lightingSettingsPath, destPath);
Debug.Log($"已移动: {lightingSettingsPath} -> {destPath}");
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 2. 移动整个光照目录
string lightmapDirName = sceneName;
string lightmapSourceDir = $"{Path.GetDirectoryName(scene.path)}/{lightmapDirName}";
string lightmapSourceDirAssetPath = GetAssetPath(lightmapSourceDir);
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
if (AssetDatabase.IsValidFolder(lightmapSourceDirAssetPath))
{
string destLightmapDir = $"{lightmapDirAssetPath}/{lightmapDirName}";
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 如果目标已存在,先删除
if (AssetDatabase.IsValidFolder(destLightmapDir))
{
AssetDatabase.DeleteAsset(destLightmapDir);
AssetDatabase.Refresh();
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 直接移动整个目录
string result = AssetDatabase.MoveAsset(lightmapSourceDirAssetPath, destLightmapDir);
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
if (string.IsNullOrEmpty(result))
{
Debug.Log($"已成功移动光照数据目录: {lightmapSourceDirAssetPath} -> {destLightmapDir}");
}
else
{
Debug.LogError($"移动光照数据目录失败: {result}");
}
}
else
{
Debug.LogWarning($"找不到光照数据目录: {lightmapSourceDirAssetPath}");
}
}
catch (System.Exception e)
{
Debug.LogError($"移动光照文件时出错: {e.Message}");
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
AssetDatabase.Refresh();
Debug.Log("光照烘焙文件移动完成");
}
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 获取Unity资源路径的简化方法
private string GetAssetPath(string path)
{
// 已经是Assets路径格式
if (path.StartsWith("Assets"))
return path;
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
// 绝对路径转相对Assets路径
string fullPath = Path.GetFullPath(path);
string assetsFullPath = Path.GetFullPath(Application.dataPath);
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
if (fullPath.StartsWith(assetsFullPath))
return "Assets" + fullPath.Substring(assetsFullPath.Length).Replace('\\', '/');
2025-04-08 14:17:55 +08:00
2025-04-07 18:55:27 +08:00
return path;
}
2025-04-07 19:50:53 +08:00
// 替换材质的Shader为光照贴图支持的Shader
2025-04-14 15:51:02 +08:00
private void ReplaceShaderWithLightmapShader(List<Renderer> renderers)
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
// 清空旧的材质映射
originalMaterials.Clear();
renderersToRestore.Clear();
2025-04-15 16:33:01 +08:00
// 追踪已处理的材质和它们的新版本
Dictionary<Material, Material> processedMaterialMap = new Dictionary<Material, Material>();
2025-04-07 19:50:53 +08:00
// 尝试查找光照贴图Shader
2025-04-08 14:17:55 +08:00
var lightmapShader = Shader.Find("NLD_URP/NLD_Scene_Lightmap");
2025-04-07 19:50:53 +08:00
if (lightmapShader == null)
{
Debug.LogError("找不到NLD_Scene_Lightmap着色器,请确保它存在于项目中");
return;
}
int replacedCount = 0;
2025-04-14 15:51:02 +08:00
HashSet<Material> processedMaterials = new HashSet<Material>(); // 避免处理重复材质
2025-04-08 14:17:55 +08:00
2025-04-14 15:51:02 +08:00
Debug.Log($"处理 {renderers.Count} 个渲染器用于Shader替换");
2025-04-07 19:50:53 +08:00
foreach (var renderer in renderers)
{
if (renderer == null)
continue;
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 跳过地面渲染器(它们将使用地面专用的shader)
bool isGroundRenderer = false;
Transform parent = renderer.transform.parent;
while (parent != null)
{
2025-04-15 16:33:01 +08:00
if (groundRoot.Contains(parent.name) ||
2025-04-16 15:28:21 +08:00
(PostProcessInstructor.ground != null && parent == PostProcessInstructor.ground.transform))
2025-04-14 15:51:02 +08:00
{
isGroundRenderer = true;
break;
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
parent = parent.parent;
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
if (isGroundRenderer)
{
Debug.Log($"跳过地面渲染器: {renderer.name}");
continue;
}
2025-04-07 19:50:53 +08:00
// 获取渲染器的所有材质
2025-04-14 15:51:02 +08:00
Material[] sharedMaterials = renderer.sharedMaterials;
if (sharedMaterials == null || sharedMaterials.Length == 0)
2025-04-07 19:50:53 +08:00
continue;
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 保存原始材质数组
Material[] originalMaterialsArray = new Material[sharedMaterials.Length];
Array.Copy(sharedMaterials, originalMaterialsArray, sharedMaterials.Length);
originalMaterials[renderer] = originalMaterialsArray;
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 添加到需要恢复的渲染器列表
renderersToRestore.Add(renderer);
2025-04-07 19:50:53 +08:00
// 创建新的材质数组,用于替换
2025-04-14 15:51:02 +08:00
Material[] newMaterials = new Material[sharedMaterials.Length];
2025-04-07 19:50:53 +08:00
2025-04-14 15:51:02 +08:00
for (int i = 0; i < sharedMaterials.Length; i++)
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
Material originalMaterial = sharedMaterials[i];
2025-04-07 19:50:53 +08:00
if (originalMaterial == null)
{
newMaterials[i] = null;
continue;
}
2025-04-15 16:33:01 +08:00
// 如果已经处理过这个材质,使用已经替换好的版本
if (processedMaterialMap.TryGetValue(originalMaterial, out Material replacedMaterial))
2025-04-07 19:50:53 +08:00
{
2025-04-15 16:33:01 +08:00
newMaterials[i] = replacedMaterial;
2025-04-07 19:50:53 +08:00
continue;
}
processedMaterials.Add(originalMaterial);
2025-04-14 15:51:02 +08:00
// 创建材质实例,避免修改原始共享材质
Material instanceMaterial = new Material(originalMaterial);
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
if (instanceMaterial.shader != lightmapShader)
2025-04-07 19:50:53 +08:00
{
// 记录原始shader
2025-04-14 15:51:02 +08:00
string originalShaderName = instanceMaterial.shader != null ? instanceMaterial.shader.name : "未知";
2025-04-07 19:50:53 +08:00
2025-04-15 16:33:01 +08:00
// 保存原始主贴图及其Scale/Offset
2025-04-07 19:50:53 +08:00
Texture mainTexture = null;
2025-04-15 16:33:01 +08:00
Vector2 texScale = Vector2.one;
Vector2 texOffset = Vector2.zero;
2025-04-08 14:17:55 +08:00
2025-04-07 19:50:53 +08:00
// 检查不同的可能贴图属性名
2025-04-14 15:51:02 +08:00
if (instanceMaterial.HasProperty("_MainTex"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
mainTexture = instanceMaterial.GetTexture("_MainTex");
2025-04-15 16:33:01 +08:00
texScale = instanceMaterial.GetTextureScale("_MainTex");
texOffset = instanceMaterial.GetTextureOffset("_MainTex");
2025-04-16 15:28:21 +08:00
Debug.Log(
$"从材质 {instanceMaterial.name} 的 _MainTex 找到主贴图, Scale:{texScale}, Offset:{texOffset}");
2025-04-07 19:50:53 +08:00
}
2025-04-14 15:51:02 +08:00
else if (instanceMaterial.HasProperty("_BaseMap"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
mainTexture = instanceMaterial.GetTexture("_BaseMap");
2025-04-15 16:33:01 +08:00
texScale = instanceMaterial.GetTextureScale("_BaseMap");
texOffset = instanceMaterial.GetTextureOffset("_BaseMap");
2025-04-16 15:28:21 +08:00
Debug.Log(
$"从材质 {instanceMaterial.name} 的 _BaseMap 找到主贴图, Scale:{texScale}, Offset:{texOffset}");
2025-04-07 19:50:53 +08:00
}
2025-04-14 15:51:02 +08:00
else if (instanceMaterial.HasProperty("_AlbedoMap"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
mainTexture = instanceMaterial.GetTexture("_AlbedoMap");
2025-04-15 16:33:01 +08:00
texScale = instanceMaterial.GetTextureScale("_AlbedoMap");
texOffset = instanceMaterial.GetTextureOffset("_AlbedoMap");
2025-04-16 15:28:21 +08:00
Debug.Log(
$"从材质 {instanceMaterial.name} 的 _AlbedoMap 找到主贴图, Scale:{texScale}, Offset:{texOffset}");
2025-04-07 19:50:53 +08:00
}
2025-04-14 15:51:02 +08:00
else if (instanceMaterial.HasProperty("_DiffuseMap"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
mainTexture = instanceMaterial.GetTexture("_DiffuseMap");
2025-04-15 16:33:01 +08:00
texScale = instanceMaterial.GetTextureScale("_DiffuseMap");
texOffset = instanceMaterial.GetTextureOffset("_DiffuseMap");
2025-04-16 15:28:21 +08:00
Debug.Log(
$"从材质 {instanceMaterial.name} 的 _DiffuseMap 找到主贴图, Scale:{texScale}, Offset:{texOffset}");
2025-04-07 19:50:53 +08:00
}
2025-04-08 14:17:55 +08:00
2025-04-07 19:50:53 +08:00
// 记录原始颜色
Color baseColor = Color.white;
2025-04-14 15:51:02 +08:00
if (instanceMaterial.HasProperty("_Color"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
baseColor = instanceMaterial.GetColor("_Color");
2025-04-07 19:50:53 +08:00
}
2025-04-14 15:51:02 +08:00
else if (instanceMaterial.HasProperty("_BaseColor"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
baseColor = instanceMaterial.GetColor("_BaseColor");
2025-04-07 19:50:53 +08:00
}
// 应用新Shader
2025-04-14 15:51:02 +08:00
instanceMaterial.shader = lightmapShader;
2025-04-07 19:50:53 +08:00
// 恢复主贴图到_BaseMap (这是Lightmap shader使用的属性名)
if (mainTexture != null)
{
2025-04-14 15:51:02 +08:00
if (instanceMaterial.HasProperty("_BaseMap"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
instanceMaterial.SetTexture("_BaseMap", mainTexture);
2025-04-15 16:33:01 +08:00
instanceMaterial.SetTextureScale("_BaseMap", texScale);
instanceMaterial.SetTextureOffset("_BaseMap", texOffset);
2025-04-16 15:28:21 +08:00
Debug.Log(
$"将主贴图设置到 {instanceMaterial.name} 的 _BaseMap, 并设置Scale:{texScale}, Offset:{texOffset}");
2025-04-07 19:50:53 +08:00
}
2025-04-08 14:17:55 +08:00
2025-04-07 19:50:53 +08:00
// 同时尝试设置旧属性以兼容
2025-04-14 15:51:02 +08:00
if (instanceMaterial.HasProperty("_MainTex"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
instanceMaterial.SetTexture("_MainTex", mainTexture);
2025-04-15 16:33:01 +08:00
instanceMaterial.SetTextureScale("_MainTex", texScale);
instanceMaterial.SetTextureOffset("_MainTex", texOffset);
2025-04-07 19:50:53 +08:00
}
}
else
{
2025-04-14 15:51:02 +08:00
Debug.LogWarning($"材质 {instanceMaterial.name} 没有找到可用的主贴图");
2025-04-07 19:50:53 +08:00
}
2025-04-08 14:17:55 +08:00
2025-04-07 19:50:53 +08:00
// 设置颜色
2025-04-14 15:51:02 +08:00
if (instanceMaterial.HasProperty("_BaseColor"))
2025-04-07 19:50:53 +08:00
{
2025-04-14 15:51:02 +08:00
instanceMaterial.SetColor("_BaseColor", baseColor);
2025-04-07 19:50:53 +08:00
}
2025-04-16 15:28:21 +08:00
2025-04-15 16:33:01 +08:00
if (instanceMaterial.HasProperty("_Color"))
{
instanceMaterial.SetColor("_Color", baseColor);
}
2025-04-07 19:50:53 +08:00
replacedCount++;
2025-04-14 15:51:02 +08:00
Debug.Log($"已替换材质 {instanceMaterial.name} 的Shader: {originalShaderName} -> NLD_Scene_Lightmap");
2025-04-07 19:50:53 +08:00
}
2025-04-15 16:33:01 +08:00
// 将新材质添加到映射表中
processedMaterialMap[originalMaterial] = instanceMaterial;
2025-04-14 15:51:02 +08:00
newMaterials[i] = instanceMaterial;
2025-04-07 19:50:53 +08:00
}
// 应用新材质数组
renderer.sharedMaterials = newMaterials;
}
Debug.Log($"完成Shader替换,共处理了 {replacedCount} 个材质");
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 恢复原始材质(地面材质除外)
private void RestoreOriginalMaterials()
{
Debug.Log("开始恢复非地面原始材质...");
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
int restoredCount = 0;
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 遍历所有需要恢复的渲染器
foreach (var renderer in renderersToRestore)
{
if (renderer == null || !originalMaterials.ContainsKey(renderer))
continue;
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 检查是否是地面渲染器,地面渲染器的材质不需要恢复
bool isGroundRenderer = false;
Transform parent = renderer.transform.parent;
while (parent != null)
{
2025-04-15 16:33:01 +08:00
if (groundRoot.Contains(parent.name) ||
2025-04-16 15:28:21 +08:00
(PostProcessInstructor.ground != null &&
(parent == PostProcessInstructor.ground.transform ||
renderer.gameObject == PostProcessInstructor.ground)))
2025-04-14 15:51:02 +08:00
{
isGroundRenderer = true;
Debug.Log($"跳过地面渲染器材质恢复: {renderer.name}");
break;
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
parent = parent.parent;
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
if (isGroundRenderer)
continue;
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 获取原始材质数组
Material[] originalMaterialsArray = originalMaterials[renderer];
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 恢复原始材质
renderer.sharedMaterials = originalMaterialsArray;
restoredCount++;
}
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
Debug.Log($"已恢复 {restoredCount} 个非地面渲染器的原始材质");
2025-04-15 16:33:01 +08:00
2025-04-14 15:51:02 +08:00
// 清空材质映射和渲染器列表,释放内存
originalMaterials.Clear();
renderersToRestore.Clear();
}
2025-04-15 16:33:01 +08:00
2025-04-16 15:28:21 +08:00
// 递归查找子节点的辅助方法
private Transform FindChildRecursive(Transform parent, string childName)
{
// 首先检查直接子节点
Transform child = parent.Find(childName);
if (child != null)
return child;
// 如果直接子节点中没找到,递归查找每个子节点
for (int i = 0; i < parent.childCount; i++)
{
child = FindChildRecursive(parent.GetChild(i), childName);
if (child != null)
return child;
}
return null;
}
2025-04-08 14:17:55 +08:00
#endregion
2024-01-15 20:25:49 +08:00
}