using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using BehaviorDesigner.Runtime.Tasks.Unity.UnityGameObject; using Gameplay; using PhxhSDK; using SRF; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; public class ScenePostProcessor : Singlenton { 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"; private const string SCENE_ORIGIN_PATH = "Assets/Scenes/Maps"; private const string SCENE_POSTPROCESS_PATH = "Assets/Art/AutoGen/Maps"; private const string SURFACE_SHADER_PATH = "Assets/Code/Shaders/Scene/NLD_Scene_Surface.shader"; private const string LEVEL_MAP_ADDRESSABLE_GROUP = "LevelMaps"; private const int GROUND_SPLIT_WIDTH = 1024; private const int GROUND_SPLIT_HEIGHT = 1024; private const int UPP = 100; private Scene Scene { get; set; } private NLDSceneManager NLDSceneManager { get; set; } private string PostProcessFolderName { get { var oldSceneDir = Scene.path; var tempSceneDir = oldSceneDir.Replace(SCENE_ORIGIN_PATH, SCENE_POSTPROCESS_PATH); var subStr = tempSceneDir.Substring(SCENE_POSTPROCESS_PATH.Length + 1); var folderName = Path.GetFileNameWithoutExtension(subStr.Replace("/", "_")); return folderName; } } private string SceneDir => $"{SCENE_POSTPROCESS_PATH}/{PostProcessFolderName}"; private string SurfaceDir => $"{SceneDir}/{SCENE_SURFACE_FOLDER_NAME}"; private string CombinedDir => $"{SceneDir}/{SCENE_COMBINED_NAME}"; private string GroundSplitDir => $"{SceneDir}/{GROUND_SPLIT_NAME}"; private Scene _postProcessScene; private NLDSceneManager _postProcessSceneManager; public void PostProcess(Scene scene, bool closePostProcessScene = false) { EditorSceneManager.SaveOpenScenes(); Scene = scene; NLDSceneManager = CommonUtils.GetSceneRootComponent(Scene); PrepareFolders(); BakeSurfaceData(); PrepareScene(); BakeCombinedGameObject(); SplitGroundTexture(); SetFogPosition(); EditorSceneManager.SaveOpenScenes(); EditorUtil.AddPathToAddressable(SceneDir, LEVEL_MAP_ADDRESSABLE_GROUP); if (closePostProcessScene) EditorSceneManager.CloseScene(_postProcessScene, true); EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(_postProcessScene.path)); } private void DeleteSurfaceData(SceneSurfaceData surfaceData) { var mat = AssetDatabase.LoadAssetAtPath(surfaceData.materialPath); if (mat == null) { return; } AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(mat.mainTexture)); AssetDatabase.DeleteAsset(surfaceData.materialPath); } private void PrepareFolders() { AssetDatabase.DeleteAsset(SceneDir); AssetDatabase.CreateFolder(SCENE_POSTPROCESS_PATH, PostProcessFolderName); AssetDatabase.CreateFolder(SceneDir, SCENE_SURFACE_FOLDER_NAME); AssetDatabase.CreateFolder(SceneDir, SCENE_COMBINED_NAME); AssetDatabase.CreateFolder(SceneDir, GROUND_SPLIT_NAME); } private void PrepareScene() { var sceneCount = SceneManager.sceneCount; for (int i = 0; i < sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); if (scene.name.Contains(SCENE_POST_PROCESS_NAME)) EditorSceneManager.CloseScene(scene, true); } var newScenePath = $"{SceneDir}/{Scene.name}_{SCENE_POST_PROCESS_NAME}.unity"; AssetDatabase.CopyAsset(Scene.path, newScenePath); AssetDatabase.Refresh(); _postProcessScene = EditorSceneManager.OpenScene(newScenePath, OpenSceneMode.Additive); _postProcessSceneManager = CommonUtils.GetSceneRootComponent(_postProcessScene); EditorSceneManager.MarkAllScenesDirty(); } //烘焙面片数据 private void BakeSurfaceData() { NLDSceneManager.allSceneSurfaceData.Clear(); List 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(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() { var art = _postProcessSceneManager.Art; var renderers = CollectRenderers(); var combinedRoot = new GameObject("CombinedRoot"); combinedRoot.transform.parent = art.transform; SceneCombineUtil.Instance.CombineGameObjects(renderers, combinedRoot.transform, CombinedDir); foreach (var renderer in renderers) { Object.DestroyImmediate(renderer.gameObject); } } private List CollectRenderers() { var art = _postProcessSceneManager.Art; List allRenderers = new(); foreach (Transform child in art.transform) { var name = child.gameObject.name; if (name == "Trees" || name == "Ground" || name == "Fog" || name == "Stuffs") continue; allRenderers.AddRange(child.GetComponentsInChildren()); } return allRenderers; } private void SplitGroundTexture() { var ground = _postProcessSceneManager.Art.Find("Ground").gameObject; if (ground == null) return; var renderer = ground.GetComponent(); if (renderer == null) return; var mat = renderer.sharedMaterial; if (mat == null) return; var texture = mat.mainTexture as Texture2D; if (texture == null) return; var groundParent = Object.Instantiate(ground, _postProcessSceneManager.Art, true); groundParent.name = "Ground"; var scaleRatioX = ground.transform.localScale.x * UPP / texture.width; var scaleRatioY = ground.transform.localScale.y * UPP / texture.height; var originPos = -new Vector3(ground.transform.localScale.x / 2f, 0, ground.transform.localScale.y / 2f); groundParent.transform.localScale = Vector3.one; //groundParent.transform.localScale = new Vector3(scaleRatio, scaleRatio, 1); var textures = SplitTextureUtil.SplitTexture(texture, GROUND_SPLIT_WIDTH, GROUND_SPLIT_HEIGHT, GroundSplitDir); var fixedWidth = (float)GROUND_SPLIT_WIDTH / UPP * scaleRatioX; var fixedHeight = (float)GROUND_SPLIT_HEIGHT / UPP * scaleRatioY; for (int row = 0; row < textures.GetLength(0); row++) { for (int column = 0; column < textures.GetLength(1); column++) { var splitTexture = textures[row, column]; var xScale = (float)splitTexture.width / UPP * scaleRatioX; var yScale = (float)splitTexture.height / UPP * scaleRatioY; var splitGround = Object.Instantiate(ground, groundParent.transform, true); Object.DestroyImmediate(splitGround.GetComponent()); var splitName = $"Ground_{row}_{column}"; splitGround.name = splitName; splitGround.transform.localScale = new Vector3(xScale, yScale, 1); var splitMat = Object.Instantiate(mat); splitMat.mainTexture = splitTexture; AssetDatabase.CreateAsset(splitMat, $"{GroundSplitDir}/{splitName}.mat"); splitGround.GetComponent().sharedMaterial = splitMat; splitGround.transform.position = originPos + new Vector3(column * fixedWidth + xScale / 2f, 0, row * fixedHeight + yScale / 2f); } } Object.DestroyImmediate(ground); Object.DestroyImmediate(groundParent.GetComponent()); Object.DestroyImmediate(groundParent.GetComponent()); var boxCollider = groundParent.AddComponent(); boxCollider.size = new Vector3(100, 100, 1); boxCollider.center = new Vector3(0, 0, 0.5f); Object.DestroyImmediate(groundParent.GetComponent()); } private void SetFogPosition() { var fog = _postProcessSceneManager.Art.Find("Fog"); if (fog == null) return; var transform = fog.transform; var position = transform.position; transform.position = new Vector3(position.x, position.y + 0.001f, position.z); } }