NLDClient-yudde/ProjectNLD/Assets/Editor/Scene/ScenePostProcessor.cs

264 lines
10 KiB
C#

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<ScenePostProcessor>
{
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<NLDSceneManager>(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<SceneAsset>(_postProcessScene.path));
}
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(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<NLDSceneManager>(_postProcessScene);
EditorSceneManager.MarkAllScenesDirty();
}
//烘焙面片数据
private void BakeSurfaceData()
{
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()
{
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<Renderer> CollectRenderers()
{
var art = _postProcessSceneManager.Art;
List<Renderer> 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<Renderer>());
}
return allRenderers;
}
private void SplitGroundTexture()
{
var ground = _postProcessSceneManager.Art.Find("Ground").gameObject;
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;
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<Collider>());
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<MeshRenderer>().sharedMaterial = splitMat;
splitGround.transform.position =
originPos + new Vector3(column * fixedWidth + xScale / 2f, 0, row * fixedHeight + yScale / 2f);
}
}
Object.DestroyImmediate(ground);
Object.DestroyImmediate(groundParent.GetComponent<Renderer>());
Object.DestroyImmediate(groundParent.GetComponent<Collider>());
var boxCollider = groundParent.AddComponent<BoxCollider>();
boxCollider.size = new Vector3(100, 100, 1);
boxCollider.center = new Vector3(0, 0, 0.5f);
Object.DestroyImmediate(groundParent.GetComponent<MeshFilter>());
}
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);
}
}