264 lines
10 KiB
C#
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);
|
|
}
|
|
} |