整理后处理脚本
parent
dd1e696010
commit
4ede122621
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,215 @@
|
|||
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>());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 065916795ee704f07b75513739284fc4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// 灯光烘焙工具类
|
||||
/// </summary>
|
||||
public static class LightmapUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理参与烘焙的节点
|
||||
/// </summary>
|
||||
public static void PreProcessBake(List<string> rootNames, Transform rootTransform, bool castShadow, bool needReplaceShader,
|
||||
List<Renderer> allBakeRenderers, List<Renderer> needReplaceRenderers)
|
||||
{
|
||||
foreach (var rootName in rootNames)
|
||||
{
|
||||
var rootObj = SceneUtils.FindChildRecursive(rootTransform, rootName);
|
||||
if (rootObj != null)
|
||||
{
|
||||
SceneUtils.SetStaticFlagsRecursive(rootObj.gameObject, StaticEditorFlags.ContributeGI);
|
||||
var renderers = rootObj.GetComponentsInChildren<Renderer>(true);
|
||||
if (renderers != null && renderers.Length > 0)
|
||||
{
|
||||
Debug.Log($"从{rootName}收集到 {renderers.Length} 个渲染器用于烘焙");
|
||||
foreach (var renderer in renderers)
|
||||
{
|
||||
Debug.Log($"处理从{rootName}收集到物体{renderer.gameObject.name}的渲染器");
|
||||
if (renderer.receiveShadows)
|
||||
{
|
||||
renderer.shadowCastingMode = castShadow ? ShadowCastingMode.On : ShadowCastingMode.Off;
|
||||
allBakeRenderers.Add(renderer);
|
||||
if (needReplaceShader)
|
||||
needReplaceRenderers.Add(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"从{rootName}收集不到渲染器");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 准备灯光:将实时灯光改为烘焙灯光
|
||||
/// </summary>
|
||||
public static void PrepareLight(Transform root, List<Light> realTimeLights, List<Light> bakedLights)
|
||||
{
|
||||
var lights = root.GetComponentsInChildren<Light>();
|
||||
foreach (var light in lights)
|
||||
{
|
||||
light.transform.position = new Vector3(0, 0, 0);
|
||||
// 复制灯光对象
|
||||
var bakeLightObj = Object.Instantiate(light.gameObject, light.transform.parent);
|
||||
var bakeLight = bakeLightObj.GetComponent<Light>();
|
||||
|
||||
// 设置为烘焙模式
|
||||
bakeLightObj.name = light.name + "_Bake";
|
||||
bakeLight.lightmapBakeType = LightmapBakeType.Baked;
|
||||
|
||||
// 取消实时灯光的static
|
||||
GameObjectUtility.SetStaticEditorFlags(light.gameObject, 0);
|
||||
// 设置烘焙灯光的static
|
||||
GameObjectUtility.SetStaticEditorFlags(bakeLightObj, StaticEditorFlags.ContributeGI);
|
||||
|
||||
// 添加到列表
|
||||
bakedLights.Add(bakeLight);
|
||||
realTimeLights.Add(light);
|
||||
}
|
||||
|
||||
// 关闭实时灯光
|
||||
foreach (var realTimeLight in realTimeLights)
|
||||
{
|
||||
if (realTimeLight != null)
|
||||
realTimeLight.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// 开启烘焙灯光
|
||||
foreach (var bakeLight in bakedLights)
|
||||
{
|
||||
if (bakeLight != null)
|
||||
bakeLight.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复实时灯光
|
||||
/// </summary>
|
||||
public static void RevertLight(List<Light> realTimeLights, List<Light> bakedLights)
|
||||
{
|
||||
// 开启实时灯光
|
||||
foreach (var realTimeLight in realTimeLights)
|
||||
{
|
||||
if (realTimeLight != null)
|
||||
realTimeLight.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
Debug.Log($"销毁{bakedLights.Count}个烘焙灯光");
|
||||
// 销毁烘焙灯光
|
||||
foreach (var bakeLight in bakedLights)
|
||||
{
|
||||
if (bakeLight != null)
|
||||
Object.DestroyImmediate(bakeLight.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行烘焙
|
||||
/// </summary>
|
||||
public static void Bake(Scene activeScene)
|
||||
{
|
||||
// 设置烘焙参数并开始烘焙
|
||||
var lightingSettings = new LightingSettings();
|
||||
|
||||
Debug.Log($"烘焙时 场景是{activeScene.name}");
|
||||
if (Lightmapping.TryGetLightingSettings(out var existingSettings))
|
||||
{
|
||||
lightingSettings = existingSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingSettings.name = $"{activeScene.name}_LightingSettings";
|
||||
AssetDatabase.CreateAsset(lightingSettings, $"Assets/{lightingSettings.name}.asset");
|
||||
Lightmapping.lightingSettings = lightingSettings;
|
||||
}
|
||||
|
||||
// 设置烘焙参数
|
||||
lightingSettings.mixedBakeMode = MixedLightingMode.Subtractive;
|
||||
lightingSettings.lightmapper = LightingSettings.Lightmapper.ProgressiveGPU;
|
||||
lightingSettings.directSampleCount = 1;
|
||||
lightingSettings.indirectSampleCount = 1;
|
||||
lightingSettings.environmentSampleCount = 1;
|
||||
lightingSettings.lightProbeSampleCountMultiplier = 8;
|
||||
lightingSettings.maxBounces = 1;
|
||||
lightingSettings.filteringMode = LightingSettings.FilterMode.Auto;
|
||||
lightingSettings.lightmapResolution = 40;
|
||||
lightingSettings.lightmapPadding = 2;
|
||||
lightingSettings.lightmapMaxSize = 1024;
|
||||
lightingSettings.lightmapCompression = LightmapCompression.HighQuality;
|
||||
lightingSettings.indirectScale = 0;
|
||||
|
||||
Lightmapping.lightingSettings = lightingSettings;
|
||||
|
||||
// 强制场景保存以确保设置生效
|
||||
EditorSceneManager.MarkSceneDirty(activeScene);
|
||||
EditorSceneManager.SaveOpenScenes();
|
||||
|
||||
Debug.Log("开始烘焙灯光...");
|
||||
Lightmapping.Bake();
|
||||
Debug.Log("灯光烘焙完成");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动光照烘焙相关文件到指定目录
|
||||
/// </summary>
|
||||
public static void CopyLightmapFiles(Scene scene, string lightmapDirPath)
|
||||
{
|
||||
string sceneName = scene.name;
|
||||
|
||||
Debug.Log("开始移动光照烘焙文件...");
|
||||
|
||||
try
|
||||
{
|
||||
// 确保目标目录存在
|
||||
string lightmapDirAssetPath = SceneUtils.GetAssetPath(lightmapDirPath);
|
||||
if (!AssetDatabase.IsValidFolder(lightmapDirAssetPath))
|
||||
{
|
||||
// 创建父目录结构
|
||||
string[] folders = lightmapDirAssetPath.Split('/');
|
||||
string currentPath = folders[0]; // Assets
|
||||
|
||||
for (int i = 1; i < folders.Length; i++)
|
||||
{
|
||||
string folderName = folders[i];
|
||||
string parentPath = currentPath;
|
||||
currentPath = $"{currentPath}/{folderName}";
|
||||
|
||||
if (!AssetDatabase.IsValidFolder(currentPath))
|
||||
{
|
||||
AssetDatabase.CreateFolder(parentPath, folderName);
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
// 1. 移动LightingSettings.asset文件
|
||||
string lightingSettingsPath = $"Assets/{sceneName}_LightingSettings.asset";
|
||||
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(lightingSettingsPath) != null)
|
||||
{
|
||||
string destPath = $"{lightmapDirAssetPath}/{sceneName}_LightingSettings.asset";
|
||||
|
||||
// 如果目标已存在,先删除
|
||||
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(destPath) != null)
|
||||
{
|
||||
AssetDatabase.DeleteAsset(destPath);
|
||||
}
|
||||
|
||||
AssetDatabase.MoveAsset(lightingSettingsPath, destPath);
|
||||
Debug.Log($"已移动: {lightingSettingsPath} -> {destPath}");
|
||||
}
|
||||
|
||||
// 2. 移动整个光照目录
|
||||
string lightmapDirName = sceneName;
|
||||
string lightmapSourceDir = $"{Path.GetDirectoryName(scene.path)}/{lightmapDirName}";
|
||||
string lightmapSourceDirAssetPath = SceneUtils.GetAssetPath(lightmapSourceDir);
|
||||
|
||||
if (AssetDatabase.IsValidFolder(lightmapSourceDirAssetPath))
|
||||
{
|
||||
string destLightmapDir = $"{lightmapDirAssetPath}/{lightmapDirName}";
|
||||
|
||||
// 如果目标已存在,先删除
|
||||
if (AssetDatabase.IsValidFolder(destLightmapDir))
|
||||
{
|
||||
AssetDatabase.DeleteAsset(destLightmapDir);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
// 直接移动整个目录
|
||||
string result = AssetDatabase.MoveAsset(lightmapSourceDirAssetPath, destLightmapDir);
|
||||
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
Debug.Log($"已成功移动光照数据目录: {lightmapSourceDirAssetPath} -> {destLightmapDir}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"移动光照数据目录失败: {result}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"找不到光照数据目录: {lightmapSourceDirAssetPath}");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"移动光照文件时出错: {e.Message}");
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log("光照烘焙文件移动完成");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 82ef00a42a40b4cffacc73f85be50b34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,506 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
/// <summary>
|
||||
/// 材质工具类,处理材质和贴图的复制、替换等操作
|
||||
/// </summary>
|
||||
public static class MaterialUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理单个材质及其关联的贴图
|
||||
/// </summary>
|
||||
public static void ProcessMaterialAndTexture(Material sourceMat, string targetDir, string prefix,
|
||||
Dictionary<Material, Material> matMapping,
|
||||
Dictionary<Texture, Texture> texMapping)
|
||||
{
|
||||
if (sourceMat == null || matMapping.ContainsKey(sourceMat))
|
||||
return;
|
||||
|
||||
// 收集原始材质中的所有贴图引用
|
||||
Dictionary<string, Texture> textureProperties = new Dictionary<string, Texture>();
|
||||
Dictionary<string, Vector2> textureScales = new Dictionary<string, Vector2>();
|
||||
Dictionary<string, Vector2> textureOffsets = new Dictionary<string, Vector2>();
|
||||
|
||||
// 常见贴图属性名称
|
||||
string[] texturePropertyNames = new string[]
|
||||
{
|
||||
"_MainTex", "_BaseMap", "_AlbedoMap", "_DiffuseMap",
|
||||
"_BumpMap", "_NormalMap", "_EmissionMap", "_MetallicGlossMap",
|
||||
"_OcclusionMap", "_DetailAlbedoMap", "_DetailNormalMap", "_SpecGlossMap",
|
||||
"_ParallaxMap", "_DetailMask", "_MaskMap", "_SmoothnessMap"
|
||||
};
|
||||
|
||||
// 收集原始材质中的所有贴图
|
||||
foreach (var propName in texturePropertyNames)
|
||||
{
|
||||
if (sourceMat.HasProperty(propName))
|
||||
{
|
||||
Texture tex = sourceMat.GetTexture(propName);
|
||||
if (tex != null)
|
||||
{
|
||||
textureProperties[propName] = tex;
|
||||
textureScales[propName] = sourceMat.GetTextureScale(propName);
|
||||
textureOffsets[propName] = sourceMat.GetTextureOffset(propName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到任何贴图属性,至少确保我们查看_MainTex
|
||||
if (textureProperties.Count == 0 && sourceMat.mainTexture != null)
|
||||
{
|
||||
textureProperties["_MainTex"] = sourceMat.mainTexture;
|
||||
textureScales["_MainTex"] = sourceMat.mainTextureScale;
|
||||
textureOffsets["_MainTex"] = sourceMat.mainTextureOffset;
|
||||
}
|
||||
|
||||
// 为每个唯一贴图创建副本
|
||||
Dictionary<Texture, Texture> localTexMapping = new Dictionary<Texture, Texture>();
|
||||
foreach (var texEntry in textureProperties)
|
||||
{
|
||||
Texture originalTexture = texEntry.Value;
|
||||
if (originalTexture == null) continue;
|
||||
|
||||
// 检查这个贴图是否已经有映射
|
||||
if (texMapping.ContainsKey(originalTexture))
|
||||
{
|
||||
localTexMapping[originalTexture] = texMapping[originalTexture];
|
||||
continue;
|
||||
}
|
||||
|
||||
// 否则创建新的贴图副本
|
||||
string originalTexPath = AssetDatabase.GetAssetPath(originalTexture);
|
||||
if (string.IsNullOrEmpty(originalTexPath)) continue; // 跳过内置贴图
|
||||
|
||||
string texName = $"{prefix}{Path.GetFileNameWithoutExtension(originalTexPath)}";
|
||||
string texExtension = Path.GetExtension(originalTexPath);
|
||||
string newTexPath = $"{targetDir}/{texName}{texExtension}";
|
||||
|
||||
// 避免重复创建相同的贴图
|
||||
if (!AssetDatabase.LoadAssetAtPath<Texture>(newTexPath))
|
||||
{
|
||||
AssetDatabase.CopyAsset(originalTexPath, newTexPath);
|
||||
Debug.Log($"已复制贴图: {originalTexPath} -> {newTexPath}");
|
||||
}
|
||||
|
||||
Texture copiedTexture = AssetDatabase.LoadAssetAtPath<Texture>(newTexPath);
|
||||
if (copiedTexture != null)
|
||||
{
|
||||
localTexMapping[originalTexture] = copiedTexture;
|
||||
texMapping[originalTexture] = copiedTexture;
|
||||
}
|
||||
}
|
||||
|
||||
// 准备材质路径
|
||||
string matName = $"{prefix}{sourceMat.name}";
|
||||
string newMatPath = $"{targetDir}/{matName}.mat";
|
||||
|
||||
// 重要: 无论如何都创建新材质,而不是复制,以确保所有引用都被正确更新
|
||||
Material copiedMat = new Material(sourceMat.shader);
|
||||
|
||||
// 设置所有非贴图属性
|
||||
CopyAllMaterialProperties(sourceMat, copiedMat);
|
||||
|
||||
// 删除可能存在的旧材质
|
||||
if (AssetDatabase.LoadAssetAtPath<Material>(newMatPath) != null)
|
||||
{
|
||||
AssetDatabase.DeleteAsset(newMatPath);
|
||||
}
|
||||
|
||||
// 创建新材质资产
|
||||
AssetDatabase.CreateAsset(copiedMat, newMatPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
// 重新加载刚保存的材质,确保获取正确的引用
|
||||
copiedMat = AssetDatabase.LoadAssetAtPath<Material>(newMatPath);
|
||||
if (copiedMat == null)
|
||||
{
|
||||
Debug.LogError($"无法加载新创建的材质: {newMatPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新所有贴图引用 - 必须在创建资产后进行,确保引用正确保存
|
||||
bool anyTexChanged = false;
|
||||
foreach (var texProp in textureProperties)
|
||||
{
|
||||
string propName = texProp.Key;
|
||||
Texture originalTexture = texProp.Value;
|
||||
|
||||
if (originalTexture != null && localTexMapping.ContainsKey(originalTexture) &&
|
||||
copiedMat.HasProperty(propName))
|
||||
{
|
||||
Texture newTexture = localTexMapping[originalTexture];
|
||||
|
||||
// 特殊处理_MainTex,确保它被正确更新
|
||||
if (propName == "_MainTex")
|
||||
{
|
||||
copiedMat.mainTexture = newTexture;
|
||||
Debug.Log($"显式设置 {copiedMat.name} 的 mainTexture");
|
||||
}
|
||||
|
||||
copiedMat.SetTexture(propName, newTexture);
|
||||
|
||||
// 设置缩放和偏移
|
||||
if (textureScales.ContainsKey(propName) && textureOffsets.ContainsKey(propName))
|
||||
{
|
||||
copiedMat.SetTextureScale(propName, textureScales[propName]);
|
||||
copiedMat.SetTextureOffset(propName, textureOffsets[propName]);
|
||||
}
|
||||
|
||||
Debug.Log($"已更新材质 {copiedMat.name} 的贴图属性 {propName}");
|
||||
anyTexChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有任何贴图被更改,确保再次保存材质
|
||||
if (anyTexChanged)
|
||||
{
|
||||
EditorUtility.SetDirty(copiedMat);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
// 再次检查是否所有贴图属性都已正确设置
|
||||
bool allTexturePropsSet = true;
|
||||
foreach (var texProp in textureProperties)
|
||||
{
|
||||
if (localTexMapping.ContainsKey(texProp.Value) &&
|
||||
copiedMat.HasProperty(texProp.Key))
|
||||
{
|
||||
Texture expectedTexture = localTexMapping[texProp.Value];
|
||||
Texture actualTexture = copiedMat.GetTexture(texProp.Key);
|
||||
|
||||
if (actualTexture != expectedTexture)
|
||||
{
|
||||
allTexturePropsSet = false;
|
||||
Debug.LogError($"材质 {copiedMat.name} 的贴图属性 {texProp.Key} 未能正确设置");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allTexturePropsSet)
|
||||
{
|
||||
Debug.Log($"材质 {copiedMat.name} 的所有贴图属性已正确设置");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 强制通过序列化方式修复引用
|
||||
FixMaterialTextureReferences(copiedMat, localTexMapping);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到映射中
|
||||
matMapping[sourceMat] = copiedMat;
|
||||
Debug.Log($"已处理材质: {sourceMat.name} -> {newMatPath}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用序列化方式强制修复材质中的贴图引用
|
||||
/// </summary>
|
||||
public static void FixMaterialTextureReferences(Material material, Dictionary<Texture, Texture> texMapping)
|
||||
{
|
||||
string assetPath = AssetDatabase.GetAssetPath(material);
|
||||
if (string.IsNullOrEmpty(assetPath)) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 读取材质文件
|
||||
string materialText = File.ReadAllText(assetPath);
|
||||
bool changed = false;
|
||||
|
||||
// 对于每一个贴图映射,查找并替换GUID
|
||||
foreach (var mapping in texMapping)
|
||||
{
|
||||
Texture originalTexture = mapping.Key;
|
||||
Texture newTexture = mapping.Value;
|
||||
|
||||
string originalGuid = string.Empty;
|
||||
string newGuid = string.Empty;
|
||||
|
||||
// 获取原始贴图和新贴图的GUID
|
||||
string originalPath = AssetDatabase.GetAssetPath(originalTexture);
|
||||
string newPath = AssetDatabase.GetAssetPath(newTexture);
|
||||
|
||||
if (!string.IsNullOrEmpty(originalPath))
|
||||
{
|
||||
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(originalTexture, out originalGuid, out long _);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(newPath))
|
||||
{
|
||||
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(newTexture, out newGuid, out long _);
|
||||
}
|
||||
|
||||
// 如果找到了GUID,进行替换
|
||||
if (!string.IsNullOrEmpty(originalGuid) && !string.IsNullOrEmpty(newGuid))
|
||||
{
|
||||
Debug.Log($"在材质 {material.name} 中替换GUID: {originalGuid} -> {newGuid}");
|
||||
|
||||
string pattern = $"guid: {originalGuid}";
|
||||
string replacement = $"guid: {newGuid}";
|
||||
|
||||
if (materialText.Contains(pattern))
|
||||
{
|
||||
materialText = materialText.Replace(pattern, replacement);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有修改,写回文件
|
||||
if (changed)
|
||||
{
|
||||
Debug.Log($"使用文本编辑方式修复材质 {material.name} 的贴图引用");
|
||||
File.WriteAllText(assetPath, materialText);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError($"修复材质贴图引用时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制材质的所有属性
|
||||
/// </summary>
|
||||
public static void CopyAllMaterialProperties(Material source, Material destination)
|
||||
{
|
||||
// 复制浮点数、颜色和矢量属性
|
||||
Shader shader = source.shader;
|
||||
int propertyCount = ShaderUtil.GetPropertyCount(shader);
|
||||
|
||||
for (int i = 0; i < propertyCount; i++)
|
||||
{
|
||||
string propertyName = ShaderUtil.GetPropertyName(shader, i);
|
||||
ShaderUtil.ShaderPropertyType propertyType = ShaderUtil.GetPropertyType(shader, i);
|
||||
|
||||
switch (propertyType)
|
||||
{
|
||||
case ShaderUtil.ShaderPropertyType.Color:
|
||||
destination.SetColor(propertyName, source.GetColor(propertyName));
|
||||
break;
|
||||
case ShaderUtil.ShaderPropertyType.Vector:
|
||||
destination.SetVector(propertyName, source.GetVector(propertyName));
|
||||
break;
|
||||
case ShaderUtil.ShaderPropertyType.Float:
|
||||
case ShaderUtil.ShaderPropertyType.Range:
|
||||
destination.SetFloat(propertyName, source.GetFloat(propertyName));
|
||||
break;
|
||||
case ShaderUtil.ShaderPropertyType.TexEnv:
|
||||
// 贴图属性在外部处理
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 复制关键字
|
||||
foreach (string keyword in source.shaderKeywords)
|
||||
{
|
||||
destination.EnableKeyword(keyword);
|
||||
}
|
||||
|
||||
// 复制渲染队列
|
||||
destination.renderQueue = source.renderQueue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新地面对象的材质引用
|
||||
/// </summary>
|
||||
public static void UpdateGroundMaterialReferences(GameObject ground, Dictionary<Material, Material> matMapping)
|
||||
{
|
||||
Renderer renderer = ground.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
UpdateRendererMaterialReferences(renderer, matMapping);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新渲染器的材质引用
|
||||
/// </summary>
|
||||
public static void UpdateRendererMaterialReferences(Renderer renderer, Dictionary<Material, Material> matMapping)
|
||||
{
|
||||
Material[] sharedMaterials = renderer.sharedMaterials;
|
||||
bool changed = false;
|
||||
|
||||
for (int i = 0; i < sharedMaterials.Length; i++)
|
||||
{
|
||||
Material originalMat = sharedMaterials[i];
|
||||
if (originalMat != null && matMapping.ContainsKey(originalMat))
|
||||
{
|
||||
sharedMaterials[i] = matMapping[originalMat];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
renderer.sharedMaterials = sharedMaterials;
|
||||
EditorUtility.SetDirty(renderer);
|
||||
Debug.Log($"已更新 {renderer.gameObject.name} 的材质引用");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保没有原始引用残留
|
||||
/// </summary>
|
||||
public static void EnsureNoOriginalReferences(GameObject obj)
|
||||
{
|
||||
// 递归处理所有子对象
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
EnsureNoOriginalReferences(child.gameObject);
|
||||
}
|
||||
|
||||
// 设置对象为脏,确保Unity序列化变更
|
||||
EditorUtility.SetDirty(obj);
|
||||
|
||||
// 如果是预制体实例,解包它
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(obj))
|
||||
{
|
||||
PrefabUtility.UnpackPrefabInstance(obj, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在整个场景中查找并替换所有材质引用
|
||||
/// </summary>
|
||||
public static void FindAndReplaceAllMaterialReferences(Dictionary<Material, Material> matMapping)
|
||||
{
|
||||
// 获取场景中的所有渲染器
|
||||
Renderer[] allRenderers = Object.FindObjectsOfType<Renderer>();
|
||||
|
||||
foreach (var renderer in allRenderers)
|
||||
{
|
||||
UpdateRendererMaterialReferences(renderer, matMapping);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 替换材质的Shader为光照贴图支持的Shader
|
||||
/// </summary>
|
||||
public static void ReplaceShaderWithLightmapShader(List<Renderer> renderers)
|
||||
{
|
||||
// 追踪已处理的材质
|
||||
var processedMaterials = new HashSet<Material>(); // 避免处理重复材质
|
||||
|
||||
// 尝试查找光照贴图Shader
|
||||
var lightmapShader = Shader.Find("NLD_URP/NLD_Scene_Lightmap");
|
||||
if (lightmapShader == null)
|
||||
{
|
||||
Debug.LogError("找不到NLD_Scene_Lightmap着色器,请确保它存在于项目中");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"开始处理 {renderers.Count} 个渲染器用于Shader替换");
|
||||
|
||||
foreach (var renderer in renderers)
|
||||
{
|
||||
if (renderer == null)
|
||||
continue;
|
||||
|
||||
// 获取渲染器的所有材质
|
||||
Material[] sharedMaterials = renderer.sharedMaterials;
|
||||
if (sharedMaterials == null || sharedMaterials.Length == 0)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < sharedMaterials.Length; i++)
|
||||
{
|
||||
Material material = sharedMaterials[i];
|
||||
if (material == null)
|
||||
continue;
|
||||
|
||||
// 如果已经处理过这个材质,跳过
|
||||
if (processedMaterials.Contains(material))
|
||||
continue;
|
||||
|
||||
processedMaterials.Add(material);
|
||||
|
||||
if (material.shader != lightmapShader)
|
||||
{
|
||||
// 记录原始shader名称,仅用于日志
|
||||
string originalShaderName = material.shader != null ? material.shader.name : "未知";
|
||||
|
||||
// 保存原始主贴图及其Scale/Offset
|
||||
Texture mainTexture = null;
|
||||
Vector2 texScale = Vector2.one;
|
||||
Vector2 texOffset = Vector2.zero;
|
||||
Color baseColor = Color.white;
|
||||
|
||||
// 检查和保存原始贴图信息
|
||||
if (material.HasProperty("_MainTex"))
|
||||
{
|
||||
mainTexture = material.GetTexture("_MainTex");
|
||||
texScale = material.GetTextureScale("_MainTex");
|
||||
texOffset = material.GetTextureOffset("_MainTex");
|
||||
}
|
||||
else if (material.HasProperty("_BaseMap"))
|
||||
{
|
||||
mainTexture = material.GetTexture("_BaseMap");
|
||||
texScale = material.GetTextureScale("_BaseMap");
|
||||
texOffset = material.GetTextureOffset("_BaseMap");
|
||||
}
|
||||
else if (material.HasProperty("_AlbedoMap"))
|
||||
{
|
||||
mainTexture = material.GetTexture("_AlbedoMap");
|
||||
texScale = material.GetTextureScale("_AlbedoMap");
|
||||
texOffset = material.GetTextureOffset("_AlbedoMap");
|
||||
}
|
||||
else if (material.HasProperty("_DiffuseMap"))
|
||||
{
|
||||
mainTexture = material.GetTexture("_DiffuseMap");
|
||||
texScale = material.GetTextureScale("_DiffuseMap");
|
||||
texOffset = material.GetTextureOffset("_DiffuseMap");
|
||||
}
|
||||
|
||||
// 保存原始颜色
|
||||
if (material.HasProperty("_Color"))
|
||||
{
|
||||
baseColor = material.GetColor("_Color");
|
||||
}
|
||||
else if (material.HasProperty("_BaseColor"))
|
||||
{
|
||||
baseColor = material.GetColor("_BaseColor");
|
||||
}
|
||||
|
||||
// 修改shader
|
||||
material.shader = lightmapShader;
|
||||
|
||||
// 设置贴图
|
||||
if (mainTexture != null)
|
||||
{
|
||||
if (material.HasProperty("_BaseMap"))
|
||||
{
|
||||
material.SetTexture("_BaseMap", mainTexture);
|
||||
material.SetTextureScale("_BaseMap", texScale);
|
||||
material.SetTextureOffset("_BaseMap", texOffset);
|
||||
}
|
||||
|
||||
if (material.HasProperty("_MainTex"))
|
||||
{
|
||||
material.SetTexture("_MainTex", mainTexture);
|
||||
material.SetTextureScale("_MainTex", texScale);
|
||||
material.SetTextureOffset("_MainTex", texOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置颜色
|
||||
if (material.HasProperty("_BaseColor"))
|
||||
{
|
||||
material.SetColor("_BaseColor", baseColor);
|
||||
}
|
||||
|
||||
if (material.HasProperty("_Color"))
|
||||
{
|
||||
material.SetColor("_Color", baseColor);
|
||||
}
|
||||
|
||||
material.SetFloat("_Outline", 0.001f); //
|
||||
|
||||
Debug.Log($"已替换材质 {material.name} 的Shader: {originalShaderName} -> NLD_Scene_Lightmap");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9c4dd253ebf784d1e9cfa4d3d68d1181
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 网格合并工具类
|
||||
/// </summary>
|
||||
public static class MeshCombineUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 收集渲染器
|
||||
/// </summary>
|
||||
public static List<Renderer> CollectRenderers(List<Transform> roots)
|
||||
{
|
||||
List<Renderer> allRenderers = new();
|
||||
foreach (var root in roots)
|
||||
{
|
||||
if (!root)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var render = root.GetComponentsInChildren<Renderer>();
|
||||
if (render is not { Length: > 0 })
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
allRenderers.AddRange(render);
|
||||
}
|
||||
|
||||
return allRenderers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据距离对渲染器进行分组
|
||||
/// </summary>
|
||||
public static Dictionary<string, List<Renderer>> GroupRenderersByCircularDistance(List<Renderer> renderers,
|
||||
float maxDistance)
|
||||
{
|
||||
var groups = new Dictionary<string, List<Renderer>>();
|
||||
var groupIndex = 0;
|
||||
|
||||
// 已分组的渲染器
|
||||
var processedRenderers = new HashSet<Renderer>();
|
||||
|
||||
// 对所有渲染器进行处理
|
||||
while (processedRenderers.Count < renderers.Count)
|
||||
{
|
||||
// 找到第一个未处理的渲染器作为新组的起点
|
||||
Renderer startRenderer = null;
|
||||
foreach (var renderer in renderers)
|
||||
{
|
||||
if (!processedRenderers.Contains(renderer))
|
||||
{
|
||||
startRenderer = renderer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startRenderer == null)
|
||||
break;
|
||||
|
||||
// 创建新组
|
||||
var currentGroup = new List<Renderer>();
|
||||
currentGroup.Add(startRenderer);
|
||||
processedRenderers.Add(startRenderer);
|
||||
|
||||
bool addedNew = true;
|
||||
while (addedNew)
|
||||
{
|
||||
addedNew = false;
|
||||
|
||||
// 计算当前组的中心点
|
||||
var groupCenter = CalculateGroupCenter(currentGroup);
|
||||
|
||||
// 查找距离中心点在阈值内的未处理渲染器
|
||||
foreach (var renderer in renderers)
|
||||
{
|
||||
if (processedRenderers.Contains(renderer))
|
||||
continue;
|
||||
|
||||
var distance = Vector3.Distance(groupCenter, renderer.transform.position);
|
||||
if (!(distance <= maxDistance)) continue;
|
||||
currentGroup.Add(renderer);
|
||||
processedRenderers.Add(renderer);
|
||||
addedNew = true;
|
||||
}
|
||||
}
|
||||
|
||||
groups.Add($"Group_{groupIndex}", currentGroup);
|
||||
groupIndex++;
|
||||
}
|
||||
|
||||
Debug.Log($"基于圆形区域分组:将{renderers.Count}个渲染器分成{groups.Count}个组,半径为{maxDistance}");
|
||||
return groups;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算渲染组的中心点
|
||||
/// </summary>
|
||||
private static Vector3 CalculateGroupCenter(List<Renderer> group)
|
||||
{
|
||||
if (group.Count == 0)
|
||||
return Vector3.zero;
|
||||
|
||||
var sum = Vector3.zero;
|
||||
foreach (var renderer in group)
|
||||
{
|
||||
sum += renderer.transform.position;
|
||||
}
|
||||
|
||||
return sum / group.Count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3be33ff74463a4d3c8296b795a31f868
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// 场景操作工具类
|
||||
/// </summary>
|
||||
public static class SceneUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 递归查找子节点
|
||||
/// </summary>
|
||||
public static Transform FindChildRecursive(Transform parent, string childName)
|
||||
{
|
||||
// 首先检查直接子节点
|
||||
Transform child = parent.Find(childName);
|
||||
if (child != null)
|
||||
return child;
|
||||
|
||||
// 如果直接子节点中没找到,递归查找每个子节点
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
child = FindChildRecursive(parent.GetChild(i), childName);
|
||||
if (child != null)
|
||||
return child;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归设置GameObject的静态标志
|
||||
/// </summary>
|
||||
public static void SetStaticFlagsRecursive(GameObject obj, StaticEditorFlags flags)
|
||||
{
|
||||
// 设置当前物体的静态标志
|
||||
GameObjectUtility.SetStaticEditorFlags(obj, flags);
|
||||
|
||||
// 递归设置所有子物体
|
||||
for (int i = 0; i < obj.transform.childCount; i++)
|
||||
{
|
||||
Transform child = obj.transform.GetChild(i);
|
||||
SetStaticFlagsRecursive(child.gameObject, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给地面添加BoxCollider
|
||||
/// </summary>
|
||||
public static void AddBoxColliderToGround(GameObject ground)
|
||||
{
|
||||
if (ground != null)
|
||||
{
|
||||
Object.DestroyImmediate(ground.GetComponent<Collider>());
|
||||
var boxCollider = ground.gameObject.AddComponent<BoxCollider>();
|
||||
boxCollider.size = new Vector3(1, 1, 1);
|
||||
boxCollider.center = new Vector3(0, 0, 0.5f);
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(ground.gameObject.scene);
|
||||
EditorSceneManager.SaveOpenScenes();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("地面节点不存在,无法添加BoxCollider");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置地面渲染队列
|
||||
/// </summary>
|
||||
public static void SetGroundRenderQueue(GameObject ground, int renderQueue)
|
||||
{
|
||||
if (ground != null)
|
||||
{
|
||||
GameObjectUtility.SetStaticEditorFlags(ground, StaticEditorFlags.ContributeGI);
|
||||
var renderer = ground.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
renderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||
var materials = renderer.sharedMaterials;
|
||||
foreach (var material in materials)
|
||||
{
|
||||
if (material != null)
|
||||
{
|
||||
renderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||
material.renderQueue = renderQueue;
|
||||
Debug.Log($"将地面的材质 {material.name} 的RenderQueue改为{renderQueue}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新资源以确保RenderQueue修改已保存
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解包预制体
|
||||
/// </summary>
|
||||
public static void UnpackPrefab(GameObject obj)
|
||||
{
|
||||
if (obj != null && PrefabUtility.IsPartOfPrefabInstance(obj))
|
||||
{
|
||||
Debug.Log($"解包场景{obj.scene.name} 的预制体: {obj.name}");
|
||||
|
||||
PrefabUtility.UnpackPrefabInstance(obj,
|
||||
PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(obj.scene);
|
||||
EditorSceneManager.SaveOpenScenes();
|
||||
|
||||
// 强制刷新
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除Scene中的重复EventSystem
|
||||
/// </summary>
|
||||
public static void RemoveRedundantEventSystems(Scene scene)
|
||||
{
|
||||
foreach (var rootObj in scene.GetRootGameObjects())
|
||||
{
|
||||
UnityEngine.EventSystems.EventSystem[] eventSystems = rootObj.GetComponentsInChildren<UnityEngine.EventSystems.EventSystem>();
|
||||
if (null == eventSystems)
|
||||
continue;
|
||||
|
||||
for (var i = 0; i < eventSystems.Length; ++i)
|
||||
{
|
||||
Object.DestroyImmediate(eventSystems[i].gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置雾的位置
|
||||
/// </summary>
|
||||
public static void SetFogPosition(GameObject fog)
|
||||
{
|
||||
if (fog == null)
|
||||
return;
|
||||
var transform = fog.transform;
|
||||
var position = transform.position;
|
||||
transform.position = new Vector3(position.x, position.y + 0.01f, position.z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标准化的资源路径
|
||||
/// </summary>
|
||||
public static string GetAssetPath(string path)
|
||||
{
|
||||
// 已经是Assets路径格式
|
||||
if (path.StartsWith("Assets"))
|
||||
return path;
|
||||
|
||||
// 绝对路径转相对Assets路径
|
||||
string fullPath = Path.GetFullPath(path);
|
||||
string assetsFullPath = Path.GetFullPath(Application.dataPath);
|
||||
|
||||
if (fullPath.StartsWith(assetsFullPath))
|
||||
return "Assets" + fullPath.Substring(assetsFullPath.Length).Replace('\\', '/');
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cf8205ca3560b49cea7493bb6d55f615
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue