Unity Edior下合併場景 合併網格 合併貼圖
宣告:這篇絕不是網上那些轉來轉去千篇一律的 合併方法 搜老半天看的都是同一篇部落格
一點幫助都沒有 還是自己寫個吧
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 +