NLDClient-yudde/ProjectNLD/Assets/Editor/Scene/PostProcesser/Utils/GroundUtils.cs

215 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
/// <summary>
/// 地面处理工具类
/// </summary>
public static class GroundUtils
{
/// <summary>
/// 修改地面贴图及材质的路径 用于打包
/// </summary>
public static void ChangeMapTextureAndMatPath(GameObject ground, string targetDir, string prefix,
List<string> groundRootNames, Transform rootTransform, Transform unpackedRoot)
{
if (ground == null)
{
Debug.LogError("找不到地面对象,无法修改地面贴图和材质路径");
return;
}
// 获取地面的渲染器
var renderer = ground.GetComponent<MeshRenderer>();
if (renderer == null || renderer.sharedMaterial == null)
{
Debug.LogError("地面对象缺少渲染器或材质");
return;
}
// 确保目标目录存在
EnsureDirectoryExists(targetDir);
// 处理材质和贴图
Dictionary<Material, Material> matMapping = new Dictionary<Material, Material>();
Dictionary<Texture, Texture> texMapping = new Dictionary<Texture, Texture>();
// 处理主地面材质
MaterialUtils.ProcessMaterialAndTexture(renderer.sharedMaterial, targetDir, prefix, matMapping, texMapping);
// 处理groundRoot下的所有材质
foreach (var rootName in groundRootNames)
{
var rootObj = SceneUtils.FindChildRecursive(rootTransform, rootName);
if (rootObj != null)
{
var renderers = rootObj.GetComponentsInChildren<Renderer>(true);
foreach (var r in renderers)
{
foreach (var mat in r.sharedMaterials)
{
if (mat != null)
{
MaterialUtils.ProcessMaterialAndTexture(mat, targetDir, prefix, matMapping, texMapping);
}
}
}
}
}
// 更新场景中地面对象的材质引用
MaterialUtils.UpdateGroundMaterialReferences(ground, matMapping);
// 检查其他地面节点
foreach (var rootName in groundRootNames)
{
var rootObj = SceneUtils.FindChildRecursive(rootTransform, rootName);
if (rootObj != null)
{
var renderers = rootObj.GetComponentsInChildren<Renderer>(true);
foreach (var r in renderers)
{
MaterialUtils.UpdateRendererMaterialReferences(r, matMapping);
}
}
}
// 解除预制体对原始贴图的引用
if (unpackedRoot != null)
{
// 如果Art节点是从预制体解包的确保彻底断开所有引用
MaterialUtils.EnsureNoOriginalReferences(unpackedRoot.gameObject);
}
// 在整个场景中查找任何可能仍然引用原始材质或贴图的渲染器
MaterialUtils.FindAndReplaceAllMaterialReferences(matMapping);
// 脏标记整个场景,确保所有改动都被保存
EditorSceneManager.MarkSceneDirty(ground.scene);
// 保存所有更改
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("地面贴图和材质路径修改完成");
}
/// <summary>
/// 确保目录存在
/// </summary>
private static void EnsureDirectoryExists(string dirPath)
{
if (!AssetDatabase.IsValidFolder(dirPath))
{
string parentDir = Path.GetDirectoryName(dirPath);
if (!AssetDatabase.IsValidFolder(parentDir))
{
AssetDatabase.CreateFolder(Path.GetDirectoryName(parentDir), Path.GetFileName(parentDir));
}
AssetDatabase.CreateFolder(parentDir, Path.GetFileName(dirPath));
AssetDatabase.Refresh();
}
}
/// <summary>
/// 切割地面贴图
/// </summary>
public static void SplitGroundTexture(GameObject ground, string groundSplitDir, string prefix, int splitWidth, int splitHeight)
{
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, ground.transform.parent, true);
groundParent.name = "Ground";
// 计算原始地面的大小
var originalScale = ground.transform.localScale;
var originalWidth = originalScale.x;
var originalHeight = originalScale.y;
var originPos = -new Vector3(originalWidth / 2f, originalHeight / 2f, 0);
groundParent.transform.localScale = Vector3.one;
// 确保目录存在
EnsureDirectoryExists(groundSplitDir);
var textures = SplitTextureUtil.SplitTexture(texture, splitWidth, splitHeight, groundSplitDir, prefix);
// 计算每个分割块的大小(基于原始地面大小)
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++)
{
for (int column = 0; column < columnCount; column++)
{
var splitTexture = textures[row, column];
if (splitTexture == null)
{
Debug.LogError($"Failed to load split texture at row {row}, column {column}");
continue;
}
var splitGround = Object.Instantiate(ground, groundParent.transform, true);
Object.DestroyImmediate(splitGround.GetComponent<Collider>());
var splitName = $"{prefix}Ground_{row}_{column}";
splitGround.name = splitName;
// 设置固定的quad大小不随贴图尺寸变化
splitGround.transform.localScale = new Vector3(blockWidth, blockHeight, 1);
// 创建并保存材质
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大小
splitGround.transform.localPosition =
originPos + new Vector3(column * blockWidth + blockWidth / 2f, row * blockHeight + blockHeight / 2f,
0);
}
}
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);
boxCollider.center = new Vector3(0, 0, 0.5f);
Object.DestroyImmediate(groundParent.GetComponent<MeshFilter>());
}
}