215 lines
8.0 KiB
C#
215 lines
8.0 KiB
C#
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>());
|
||
}
|
||
} |