声明:这篇绝不是网上那些转来转去千篇一律的 合并方法 搜老半天看的都是同一篇博客
一点帮助都没有 还是自己写个吧
1.工程里面 合并场景主要是为了降低draw call
2、不同shader的尽量不要合并 不同shader 参数的也尽量不要合并
3、本篇博客主要是合并场景里的 不会动的 不考虑人物 只考虑MeshRenderer
步骤:
一、首先要找出场景里用到最多的shader 不一定是一个 可能是两个三个个 至少这些shader在90%的物体上用到了
二、打开这个场景 EditorSceneManger.OpenScene(path) 在Editor下打开这个场景 拿到一个Scene对象
三、用Scene.GetRootGameObjects() 获取到根目录下的游戏物体
四、遍历这个根目录 拿到所有符合条件的MeshRenderer组件(材质球只有一个、shader是满足条件的shader、贴图大小满足条件、组件是激活的 等等)
五、遍历这些MeshRenderer 将这些按照 合并策略分类(我这个项目合并策略是 场景里一个15x15的格子里 shader一样、shader参数一样的才进行合并) (坐标|shader|参数 为字典的Key List为字典的Value)
六、遍历这个字典的每一项 开始进行合并
1、先合并这些对应的贴图 我用的是texturePacker进行合并贴图 这样省去很多功夫
①写好一个.bat文件 用于直接进行命令行处理TexturePacker合并文件
需要设置环境变量
具体参数可以去TexturePacker官网上查
set "Max_Size=%1"
set "Poweroftow=%2"
set "BorderPadding=%3"
set "ShapePadding=%4"
set "TargetPath=%5"
set "SourcePaths=%~6"
TexturePacker --sheet %TargetPath%_tp{n}.tga ^
--data %TargetPath%_tp{n}_cfg.txt ^
--texture-format tga ^
--disable-rotation ^
--format unity ^
--multipack ^
--max-size %Max_Size% ^
--trim-mode None ^
--extrude 0 ^
--opt RGBA8888 ^
--png-opt-level 2 ^
--border-padding %BorderPadding% ^
--shape-padding %ShapePadding% ^
--disable-auto-alias ^
--size-constraints %Poweroftow% %SourcePaths%
②先将要合并的资源拷呗到一个文件夹下
③然后执行这个.bat文件 具体怎么执行 用Process 类 再具体就百度吧
④执行完之后 合并出来的可能不只一张图片 如果超过一张图片 就要重新合并 此时要讲原来的MeshRenderer二分,用递归再次合并两个一半的MeshRenderer数组 直到合并出来只有一个图集 同时会生成一个cfg配置文件 用来显示原来的图片在生成的图片在那一部分
2、贴图合并成功之后就该进行网格合并了
①拿到上一步贴图合并成功的MeshRenderer数组 再拿到MeshRenderer对象上的MeshFilter身上的sharedMesh
②用Unity Api Mesh.Combine(CombineInstance[]) 进行合并网格
3、 网格合并成功之后 要修改这个网格的UV坐标
一个网格有多少个顶点 就有多少个Uv坐标 这个坐标用来控制这个顶点显示图片上哪一部分的内容
所以这一步很重要 要重新刷一遍网格的所有UV坐标
根据之前合并贴图成功时生成的配置文件,这个文件是个Json文件,
将原来的MeshUV 根据映射转换成 大的图集上的UV坐标
4、创建个空物体 带有MeshRenderer MeshFilter 的组件 用于接收生成的网格 和 材质球
创建材质球 设置shader 和参数 和贴图
给MeshRenderer设置这个材质球 MeshFilter设置这个Mesh
5、最后将生成的Material 和Mesh 分别生成一个资源 AssetDatabase.CreateAssert(Obejc,path)
因为之前生成的Material和Mesh只是在内存里 一切换场景就没有了 所有要生成.asset文件
代码:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System;
using UnityEditor.SceneManagement;
using System.Linq;
using System.Collections.Generic;
using System.IO;
public class CombineTool : Editor
{
private const int GRIDSIDE = 15;
private const string PATH = "Assets/Resources/scene/";
private static string ASSET_PATH = EditorConfig.assetPath;
[MenuItem("Test/Test")]
public static void Test()
{
}
[MenuItem("Debug/合并场景不烘焙")]
public static void CombineSceneNotBake()
{
CombineScene(false);
}
/// <summary>
/// 合并所有场景
/// </summary>
/// <param name="bake"></param>
private static void CombineScene(bool bake)
{
var files=AssetDatebase.GetAllAssetPath().where(s=>s.EndWith(".unity"));
foreach(var item in files){
CombineOneScene(item, bake);
}
EditorUtility.ClearProgressBar();
}
/// <summary>
/// 合并一个场景
/// </summary>
/// <param name="path"></param>
private static void CombineOneScene(string path, bool bake)
{
var scene = EditorSceneManager.OpenScene(path);
PBTitle = "正在合并场景:" + scene.name;
SceneData sd = GetSceneData(scene);
if (sd == null) return;
var combineGO = CreatCombineObj(scene);
var dic = ClassifyByPositionAndShaderAndProprity(scene);
int count = 0;
foreach (var item in dic)
{
PBContent = count + "/" + dic.Count;
PBProcess = (float)count / dic.Count;
string[] ss = item.Key.Split('|'); //0是坐标 1是shader 2是颜色 3是cutoff值
Combine(item.Value.Where(s => s != null).ToArray(), scene.name, ref count, ss, combineGO.transform);
}
sd.Export(bake);
Debug.Log("合并场景:" + scene.name);
}
/// <summary>
/// 指定位置创建一个Combine物体 用于存放合并后的物体
/// </summary>
/// <param name="scene"></param>
/// <returns></returns>
private static GameObject CreatCombineObj(UnityEngine.SceneManagement.Scene scene)
{
var roots = scene.GetRootGameObjects();
GameObject combineGO = new GameObject("Combine");
foreach (var item in roots)
{
if (item.name == scene.name)
{
combineGO.transform.SetParent(item.transform);
break;
}
}
return combineGO;
}
/// <summary>
/// 获取场景里的所有只有一个材质球的MeshRenderer shader为Scene/Diffuse 或者 是 Scene/Cutout/Diffuse 且 贴图长和宽不能大于1024
/// </summary>
/// <param name="s"></param>
private static MeshRenderer[] GetAllMeshsInScene(UnityEngine.SceneManagement.Scene scene)
{
PBState = "查找符合标准的MeshRenderer";
const int texture_MaxSize = 1024;
var roots = scene.GetRootGameObjects();
var meshrenders = new List<MeshRenderer>();
foreach (var item in roots)
{
meshrenders.AddRange(item.GetComponentsInChildren<MeshRenderer>());
}
return meshrenders.Where(s => s
&& s.enabled == true
&& s.sharedMaterials.Length == 1
&& s.sharedMaterial
&& (s.sharedMaterial.shader.name == "scenes/Diffuse"
|| s.sharedMaterial.shader.name == "scenes/Cutout/Diffuse")
&& s.sharedMaterial.GetTexture("_MainTex")
&& s.sharedMaterial.GetTexture("_MainTex").texelSize.x <= texture_MaxSize
&& s.sharedMaterial.GetTexture("_MainTex").texelSize.y <= texture_MaxSize)
.ToArray();
}
/// <summary>
/// 保存资源
/// </summary>
/// <param name="go">对象</param>
/// <param name="path">相对于Resource/scene/的路经</param>
/// <param name="name">名字</param>
private static void CreateAsset(UnityEngine.Object go, string path, string name)
{
PBState = "保存资源";
if (!Directory.Exists(PATH + path)) Directory.CreateDirectory(PATH + path);
AssetDatabase.CreateAsset(go, PATH + path + "/" + name);
}
/// <summary>
/// 根据坐标,shader,参数分类
/// </summary>
/// <param name="meshrenderers"></param>
private static Dictionary<string, List<MeshRenderer>> ClassifyByPositionAndShaderAndProprity(UnityEngine.SceneManagement.Scene scene)
{
PBState = "分类MeshRenderer";
Dictionary<string, List<MeshRenderer>> dic = new Dictionary<string, List<MeshRenderer>>();
foreach (var item in GetAllMeshsInScene(scene))
{
Material mt = item.sharedMaterial;
string tag;
if (mt.shader.name == "scenes/Cutout/Diffuse")
tag = GetGridIndex(item.transform) + "|" + mt.shader.name + "|" + mt.GetColor("_Color") + "|" + mt.GetFloat("_Cutoff");
else
tag = GetGridIndex(item.transform) + "|" + mt.shader.name + "|" + mt.GetColor("_Colors");
if (!dic.ContainsKey(tag))
{
dic.Add(tag, new List<MeshRenderer>() { item });
}
else
{
dic[tag].Add(item);
}
}
//清除只有1个的List
List<string> checkOneRenderList = new List<string>();
foreach (var item in dic)
{
if (item.Value.Count == 1) checkOneRenderList.Add(item.Key);
}
foreach (var item in checkOneRenderList)
{
dic.Remove(item);
}
return dic;
}
/// <summary>
/// 合并网格
/// </summary>
/// <param name="renderers"></param>
/// <param name="filePath">_tp0_cfg.txt的路径</param>
/// <returns></returns>
private static Mesh CombineMesh(MeshRenderer[] renderers, string filePath)
{
PBState = "合并网格";
var dicOfPackFrame = GetPackedFram(filePath);//根据图片名称 拿到在合并后的图片里的信息
List<Vector2> uvs = new List<Vector2>(); //存放原来的Mesh的UV
CombineInstance[] cis = new CombineInstance[renderers.Length];
int uvCount = 0;
for (int i = 0; i < cis.Length; i++)
{
cis[i].mesh = renderers[i].GetComponent<MeshFilter>().sharedMesh;
cis[i].transform = renderers[i].transform.localToWorldMatrix;
Texture t = renderers[i].sharedMaterial.GetTexture("_MainTex");
string textureName = Path.GetFileName(AssetDatabase.GetAssetPath(t));
uvs.AddRange(cis[i].mesh.uv.Select(s => TransfromUV(s, dicOfPackFrame[textureName], t.wrapMode)).ToArray());
uvCount += cis[i].mesh.uv.Length;
}
Mesh m = new Mesh();
m.CombineMeshes(cis, true, true);
m.uv = uvs.ToArray();
return m;
}
/// <summary>
/// 合并 合并一个List MeshRnder 的 整个逻辑
/// </summary>
/// <param name="renderers"></param>
/// <param name="sceneName">场景名称 用于标记</param>
/// <param name="index">计数器</param>
/// <param name="parameter">material的各个参数 //0是坐标 1是shader 2是颜色 3是cutoff值</param>
/// <param name="combineRoot">合并的根物体 所有合并产生的物体都要放到这个物体下面</param>
/// <returns></returns>
private static void Combine(MeshRenderer[] renderers, string sceneName, ref int index, string[] parameter, Transform combineRoot)
{
if (renderers.Length < 2) return;
PBState = "合并";
var textures = renderers.Select(s => {
if (s == null)
{
Debug.Log(s);
Debug.Log("有贴图为空");
}
return s.sharedMaterial ? s.sharedMaterial.GetTexture("_MainTex") : null;
});
var texturePaths = textures.Select(s => ASSET_PATH + AssetDatabase.GetAssetPath(s)).ToArray();//获取贴图的绝对路径
string path = CopyFileToDirectiory(texturePaths, PATH + sceneName + "/" + index);//将其拷呗到指定文件夹下
if (CombineTexture(path))//若果合并成功
{
Mesh m = CombineMesh(renderers, path + "/_tp0_cfg.txt");
Texture t = AssetDatabase.LoadAssetAtPath<Texture>(path + "/_tp0.tga");
Material mat = new Material(Shader.Find(parameter[1]));
if (parameter[1].Contains("Cutoff"))
{
mat.SetColor("_Color", ColorParse(parameter[2]));
mat.SetFloat("_Cutoff", float.Parse(parameter[3]));
}
else
{
mat.SetColor("_Colors", ColorParse(parameter[2]));
}
mat.SetTexture("_MainTex", t);
GameObject go = new GameObject(index + "", typeof(MeshRenderer), typeof(MeshFilter));
go.transform.SetParent(combineRoot.transform);
go.GetComponent<MeshFilter>().sharedMesh = m;
go.GetComponent<MeshRenderer>().sharedMaterial = mat;
CreateAsset(m, sceneName + "/" + index, index + "_mesh.asset");
CreateAsset(mat, sceneName + "/" + index, index + "_mat.asset");
index++;
foreach (var item in renderers)
{
if (item) DestroyImmediate(item.gameObject, false);
}
}
else//合并贴图失败
{
if (renderers.Length > 2)
{
MeshRenderer[] r1 = new MeshRenderer[renderers.Length / 2];
MeshRenderer[] r2 = new MeshRenderer[renderers.Length - r1.Length];
for (int i = 0; i < r1.Length; i++)
{
r1[i] = renderers[i];
}
for (int i = 0; i < r2.Length; i++)
{
r2[i] = renderers[r1.Length + i];
}
if (r1.Length > 1) Combine(r1, sceneName, ref index, parameter, combineRoot);
Combine(r2, sceneName, ref index, parameter, combineRoot);
}
}
}
/// <summary>
/// 找到一个场景里的SceneData
/// </summary>
/// <param name="scene"></param>
/// <returns></returns>
private static SceneData GetSceneData(UnityEngine.SceneManagement.Scene scene)
{
var roots = scene.GetRootGameObjects();
foreach (var item in roots)
{
SceneData m = item.GetComponentInChildren<SceneData>();
if (m) return m;
}
return null;
}
/// <summary>
/// 输入一个原本的uv 转换成合并后贴图的uv
/// </summary>
/// <param name="uv"></param>
/// <param name="packedFrame"></param>
/// <param name="twm">5.3.7版本 只有两种 以后可能会有多种</param>
/// <returns></returns>
///
static int tempppp = 0;
private static Vector2 TransfromUV(Vector2 uv, TexturePacker.PackedFrame packedFrame, TextureWrapMode twm)
{
Vector2 temp = uv;
Vector2 temp2 = uv;
Vector2 temp3 = uv;
Vector2 temp4 = uv;
if (twm == TextureWrapMode.Clamp)
{
uv.x = Mathf.Clamp(uv.x, 0, 1);
uv.y = Mathf.Clamp(uv.y, 0, 1);
}
else if (twm == TextureWrapMode.Repeat)//*****************以后可能会有多种
{
uv.x = Mathf.Repeat(uv.x, 1);
uv.y = Mathf.Repeat(uv.y, 1);
}
Vector2 altaSize = packedFrame.atlasSize;
Rect frame = packedFrame.frame;
Vector2 smallZuoxiaJiao = new Vector2(frame.x, altaSize.y - frame.y - frame.height);//原来图片的左下角相对于合并后的图片的位置
Vector2 point = new Vector2(smallZuoxiaJiao.x + Mathf.CeilToInt(uv.x * frame.width), smallZuoxiaJiao.y + Mathf.CeilToInt(uv.y * frame.height));
Vector2 result = new Vector2(point.x / altaSize.x, point.y / altaSize.y);
return result;
}
/// <summary>
/// 合并一个路径下的图片 还是放在这个路径下
/// </summary>
/// <param name="path"> 绝对路径 最后不要加/</param>
private static bool CombineTexture(string path)
{
PBState = "合并贴图";
string[] files = Directory.GetFiles(path);
var maxSize = 2048;
var poweroftow = "POT";
var borderPadding = 0;
var shapePadding = 0;
var command = GlobalEditorHelper.GetAssetsPath(ASSET_PATH + PATH + "combinetexture.bat");
Util.ExecuteCmd(EditorConfig.processPath, command, string.Format(" {0} {1} {2} {3} {4} {5}", maxSize, poweroftow, borderPadding, shapePadding, path + "/", path));
foreach (var item in files)
{
File.Delete(item);
}
if (Directory.GetFiles(path).Length > 2) //如果大于2 说明合并了1个以上的贴图
{
foreach (var item in Directory.GetFiles(path))
{
File.Delete(item);
}
return false;
}
else
{
AssetDatabase.Refresh();
return true;
}
}
/// <summary>
/// 将一个txt文件解析成List PacekdFram
/// </summary>
/// <param name="path"></param>
private static Dictionary<string, TexturePacker.PackedFrame> GetPackedFram(string path)
{
TextAsset txt = AssetDatabase.LoadAssetAtPath<TextAsset>(path.Substring(path.IndexOf("Assets")));
if (txt == null) Debug.Log(path);
TexturePacker.MetaData meta = TexturePacker.GetMetaData(txt.text);
Hashtable table = txt.text.hashtableFromJson();
List<TexturePacker.PackedFrame> frames = new List<TexturePacker.PackedFrame>();
Hashtable frameTable = (Hashtable)table["frames"];
foreach (DictionaryEntry entry in frameTable)
{
frames.Add(new TexturePacker.PackedFrame((string)entry.Key, meta.size, (Hashtable)entry.Value));
}
return frames.ToDictionary(s => s.name, s => s);
}
/// <summary>
/// 拷呗一些文件 到另一个文件夹下面
/// </summary>
/// <param name="files"></param>
/// <param name="path">绝对路径 最后不要加斜线</param>
private static string CopyFileToDirectiory(string[] files, string path)
{
PBState = "拷呗贴图";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
foreach (var item in files)
{
if (File.Exists(item)) File.Copy(item, path + "/" + item.Substring(item.LastIndexOf('/')), true);
}
return path;
}
/// <summary>
/// 将一个特定字符串解析成Color
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private static Color ColorParse(string s)
{
s = s.Substring(5, s.Length - 6);
string[] ss = s.Split(',');
return new Color(float.Parse(ss[0]), float.Parse(ss[1]), float.Parse(ss[2]), float.Parse(ss[3]));
}
/// <summary>
/// 判读两个物体是不是在同一个格子里
/// </summary>
/// <param name="t1"></param>
/// <param name="t2"></param>
/// <returns></returns>
private static bool InSameGrid(Transform t1, Transform t2)
{
return (GetGridIndex(t1) == GetGridIndex(t2));
}
/// <summary>
/// 计算一个物体的格子坐标
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private static Vector2 GetGridIndex(Transform t)
{
return new Vector2((int)(t.position.x / GRIDSIDE), (int)(t.position.z / GRIDSIDE));
}
}
BUT!!!
There is a big Problem.
如果原来贴图的格式是Clamp格式的 那么以上代码完全可行
如果是Repeat格式的 就非常有可能不可行
因为转换UV坐标时 要将原来的UV坐标给Math.Clamp 或者 Math.Repeat 处理到0~1
假如两个相邻的顶点uv坐标是(0.9,0.5)(1.1,0.5) 那么这两个点之间本应该draw 0.2个单位
经过Math.Repeat处理一下之后就变成了(0.9,0.5)(0.1,0.5) 那么这两个点之间就会draw 0.8个单位 而且还是反着draw的
所以 这个问题基本上无法避免
而且 很无奈的是 要自己处理这个问题会非常费时费力 遇到这种情况就要用插件了
推荐一款MeshBaker插件 AssetStore 有免费版的
但是这个插件是一步一步操作的 所以要写工具一键全部合并还是得靠自己写代码
下载完插件之后 以下代码就能运行了
代码:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System;
using UnityEditor.SceneManagement;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using DigitalOpus.MB.Core;
public class CombineTool : Editor
{
private const int GRIDSIDE = 15;
private const string PATH = "Assets/Resources/scene/";
private static string ASSET_PATH = EditorConfig.assetPath;
private const string LAYER_NAME = "block";
#region ProgressBar
private static string title = "";
private static string PBTitle
{
set
{
title = value;
EditorUtility.DisplayProgressBar(title, content + " " + state, process);
}
get { return title; }
}
private static string content = "";
private static string PBContent
{
get { return content; }
set
{
content = value;
EditorUtility.DisplayProgressBar(title, content + " " + state, process);
}
}
private static string state = "";
private static string PBState
{
get { return state; }
set
{
state = value;
EditorUtility.DisplayProgressBar(title, content + " " + state, process);
}
}
private static float process = 0;
private static float PBProcess
{
get { return process; }
set
{
process = value;
EditorUtility.DisplayProgressBar(title, content + " " + state, process);
}
}
#endregion
[MenuItem("Debug/合并场景不烘焙")]
public static void CombineSceneNotBake()
{
CombineScene(false);
}
/// <summary>
/// 合并所有场景
/// </summary>
/// <param name="bake"></param>
private static void CombineScene(bool bake)
{
var scenes = AssetDatabase.GetAllAssetPaths().Where(s => s.EndsWith(".unity"));
foreach (var item in scenes)
{
CombineOneScene(item, bake);
}
// CombineOneScene("Assets/Scenes/Scenes01_PLZZ.unity",bake);
EditorUtility.ClearProgressBar();
}
/// <summary>
/// 合并一个场景
/// </summary>
/// <param name="path"></param>
private static void CombineOneScene(string path, bool bake)
{
var scene = EditorSceneManager.OpenScene(path);
PBTitle = "正在合并场景:" + scene.name;
SceneData sd = GetSceneData(scene);
if (sd == null) return;
var combineGO = CreatCombineObj(scene);
var dic = ClassifyByPositionAndShaderAndProprity(scene);
if (dic.Count == 0)
{
sd.Export(bake);
return;
}
string directory = PATH + scene.name + "/";
if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
int count = 0;
foreach (var item in dic)
{
PBContent = count + "/" + dic.Count;
PBProcess = (float)count / dic.Count;
Combine(item.Value.Where(s => s != null).Select(s => s.gameObject).ToArray(), scene, ref count, combineGO.transform, directory);
}
sd.Export(bake);
Debug.Log("合并场景:" + scene.name);
}
/// <summary>
/// 指定位置创建一个Combine物体 用于存放合并后的物体
/// </summary>
/// <param name="scene"></param>
/// <returns></returns>
private static GameObject CreatCombineObj(UnityEngine.SceneManagement.Scene scene)
{
var roots = scene.GetRootGameObjects();
GameObject combineGO = new GameObject("Combine");
foreach (var item in roots)
{
if (item.name == scene.name)
{
combineGO.transform.SetParent(item.transform);
break;
}
}
return combineGO;
}
/// <summary>
/// 获取场景里的所有只有一个材质球的MeshRenderer shader为Scene/Diffuse 或者 是 Scene/Cutout/Diffuse 且 贴图长和宽不能大于1024
/// </summary>
/// <param name="s"></param>
private static MeshRenderer[] GetAllMeshsInScene(UnityEngine.SceneManagement.Scene scene)
{
const int texture_MaxSize = 1024;
var roots = scene.GetRootGameObjects();
var meshrenders = new List<MeshRenderer>();
GameObject combineGO = new GameObject("Combine");
foreach (var item in roots)
{
if (item.name == scene.name)
{
combineGO.transform.SetParent(item.transform);
meshrenders.AddRange(item.GetComponentsInChildren<MeshRenderer>());
break;
}
}
foreach (var item in meshrenders.Where(s => s.gameObject.layer == LayerMask.NameToLayer(LAYER_NAME)))
{
item.transform.SetParent(combineGO.transform);
}
return meshrenders.Where(s => s
&& s.gameObject.layer!=LayerMask.NameToLayer(LAYER_NAME)
&& s.enabled == true
&& s.sharedMaterials.Length == 1
&& s.sharedMaterial
&& (s.sharedMaterial.shader.name == "scenes/Diffuse"
|| s.sharedMaterial.shader.name == "scenes/Cutout/Diffuse")
&& s.sharedMaterial.GetTexture("_MainTex")
&& s.sharedMaterial.GetTexture("_MainTex").texelSize.x <= texture_MaxSize
&& s.sharedMaterial.GetTexture("_MainTex").texelSize.y <= texture_MaxSize)
.ToArray();
}
/// <summary>
/// 根据坐标,shader,参数分类
/// </summary>
/// <param name="meshrenderers"></param>
private static Dictionary<string, List<MeshRenderer>> ClassifyByPositionAndShaderAndProprity(UnityEngine.SceneManagement.Scene
scene)
{
Dictionary<string, List<MeshRenderer>> dic = new Dictionary<string, List<MeshRenderer>>();
foreach (var item in GetAllMeshsInScene(scene))
{
Material mt = item.sharedMaterial;
string tag;
if (mt.shader.name == "scenes/Cutout/Diffuse")
tag = GetGridIndex(item.transform) + "|" + mt.shader.name + "|" + mt.GetColor("_Color") + "|" + mt.GetFloat
("_Cutoff");
else
tag = GetGridIndex(item.transform) + "|" + mt.shader.name + "|" + mt.GetColor("_Colors");
if (!dic.ContainsKey(tag))
{
dic.Add(tag, new List<MeshRenderer>() { item });
}
else
{
dic[tag].Add(item);
}
}
//清除只有1个的List
List<string> checkOneRenderList = new List<string>();
foreach (var item in dic)
{
if (item.Value.Count == 1) checkOneRenderList.Add(item.Key);
}
foreach (var item in checkOneRenderList)
{
dic.Remove(item);
}
return dic;
}
/// <summary>
/// 合并 合并一个List MeshRnder 的 整个逻辑
/// </summary>
/// <param name="renderers"></param>
/// <param name="sceneName">场景名称 用于标记</param>
/// <param name="index">计数器</param>
/// <param name="parameter">material的各个参数 //0是坐标 1是shader 2是颜色 3是cutoff值</param>
/// <param name="combineRoot">合并的根物体 所有合并产生的物体都要放到这个物体下面</param>
/// <returns></returns>
private static void Combine(GameObject[] gos, UnityEngine.SceneManagement.Scene scene, ref int index, Transform
combineRoot, string directory)
{
if (gos.Length < 2) return;
GameObject tempgo = new GameObject(scene.name + "_combine_" + index);
tempgo.transform.SetParent(combineRoot);
GameObject meshbaker = MB3_MeshBakerEditor.CreateNewMeshBaker();
meshbaker.transform.SetParent(tempgo.transform);
MB3_TextureBaker mbtb = meshbaker.GetComponent<MB3_TextureBaker>();
MB3_MeshBaker mbmb = meshbaker.GetComponentInChildren<MB3_MeshBaker>();
mbtb.fixOutOfBoundsUVs = true;
mbtb.maxAtlasSize = 2048;
mbtb.maxTilingBakeSize = 1024;
mbtb.atlasPadding = 0;
mbtb.considerNonTextureProperties = true;
mbtb.meshBakerTexturePackerForcePowerOfTwo = true;
mbtb.objsToMesh = gos.ToList();
//mbtb.textureBakeResults 这个赋值会包含在下面这个方法里
MB3_TextureBakerEditorInternal.CreateCombinedMaterialAssets(mbtb, directory + index + ".asset");
mbtb.CreateAtlases(null, true, new MB3_EditorMethods());
if (mbtb.textureBakeResults != null) EditorUtility.SetDirty(mbtb.textureBakeResults);
mbmb.textureBakeResults = mbtb.textureBakeResults;
mbmb.CombinedMeshContains(tempgo);
mbmb.useObjsToMeshFromTexBaker = true;
mbmb.meshCombiner.doNorm = true;
mbmb.meshCombiner.doTan = true;
mbmb.meshCombiner.doUV = true;
mbmb.resultPrefab = tempgo;
mbmb.meshCombiner.outputOption = MB2_OutputOptions.bakeIntoSceneObject;
mbmb.meshCombiner.resultSceneObject = tempgo;
// mbmb.meshCombiner.targetRenderer = tempgo.AddComponent<MeshRenderer>();
mbmb.meshCombiner.Apply();
MB3_MeshBakerEditorInternal.bake(mbmb);
Mesh tempMesh = tempgo.GetComponentInChildren<MeshFilter>().sharedMesh;
AssetDatabase.CreateAsset(tempMesh, directory + "/" + index + "-mesh.asset");
index++;
foreach (var item in gos)
{
DestroyImmediate(item, false);
}
DestroyImmediate(meshbaker);
}
/// <summary>
/// 找到一个场景里的SceneData
/// </summary>
/// <param name="scene"></param>
/// <returns></returns>
private static SceneData GetSceneData(UnityEngine.SceneManagement.Scene scene)
{
var roots = scene.GetRootGameObjects();
foreach (var item in roots)
{
SceneData m = item.GetComponentInChildren<SceneData>();
if (m) return m;
}
return null;
}
/// <summary>
/// 判读两个物体是不是在同一个格子里
/// </summary>
/// <param name="t1"></param>
/// <param name="t2"></param>
/// <returns></returns>
private static bool InSameGrid(Transform t1, Transform t2)
{
return (GetGridIndex(t1) == GetGridIndex(t2));
}
/// <summary>
/// 计算一个物体的格子坐标
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private static Vector2 GetGridIndex(Transform t)
{
return new Vector2((int)(t.position.x / GRIDSIDE), (int)(t.position.z / GRIDSIDE));
}
}
代码简单了很多。。。
而且不会有上述那种棘手的问题。
这个插件处理上述问题是通过合并贴图的时候压缩一下,分析UV坐标,可能合并很多张一样的,可能会进行拉伸或者缩放
这些反正都不用自己考虑了