#if UNITY_EDITOR && !FUNCELL_LAUNCHER using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine.SceneManagement; using UnityEngine; using System; using System.Text; namespace Thousandto.Launcher.ExternalLibs { public class GrassCombine { //private const string ScenePath = "GameAssets/ExportResources/Scene"; //private const string AssetPath = "Assets/GameAssets/ExportResources/scene/{0}/"; //private const string FilePath = "GameAssets/ExportResources/scene/{0}"; #region//const //子节点数量的警告值 public const int CN_MAX_CHILD_COUNT_WANNING = 100; //-----------------------------// //总的顶点数量警告阀值 public const int CN_MAX_VERTEX_COUNT_WANNING = 4096; #endregion public static void CombineScene(string sceneName, string sPath, string aPath, string fPath) { DirectoryInfo directory = new DirectoryInfo(Application.dataPath + "/" + sPath); if (directory == null) return; string sceneFullPath = string.Format(directory.FullName + "\\{0}.unity", sceneName); string assetPath = string.Format(aPath, sceneName); string filePath = string.Format(fPath, sceneName); filePath = Application.dataPath + "/" + filePath; Scene scene = EditorSceneManager.OpenScene(sceneFullPath, OpenSceneMode.Single); GameObject root = GameObject.Find("SceneRoot"); if (root == null) return; Transform rootTrans = root.transform; Transform grass = null; for(int i = 0;i < rootTrans.childCount;i++) { var ch = rootTrans.GetChild(i); if(ch.name.ToLower().Trim() == "grass") { grass = ch; break; } } if (grass == null) return; if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath); for (int m = 0; m < grass.childCount; m++) { Transform child = grass.GetChild(m); if (child == null) continue; Mesh ms = Combine(child, assetPath, filePath); } //string savePath = Path.Combine(assetPath, "Mesh_ScriptTable_Object_" + name + ".asset"); EditorSceneManager.SaveScene(scene); } private static Mesh Combine(Transform region, string assetpath, string filePath) { var info = MeshCombine.CreateMeshCombineInfo(region); if (info != null) { List vList = new List(); List scriptList = new List(); GrassRelationScript relationScript = Thousandto.Core.Base.UnityUtils.RequireComponent(region.gameObject); for (int i = 0; i < region.childCount; i++) { var tran = region.GetChild(i); if (tran == null) continue; MeshFilter childMf = tran.GetComponent(); MeshRenderer rd = tran.GetComponent(); if (childMf == null || rd == null) { UnityEngine.Debug.LogError("Grass已经合并过了"); return null; } int starIndex = vList.Count; ChildMeshDataScript script = Thousandto.Core.Base.UnityUtils.RequireComponent(tran.gameObject); if (script == null) continue; script.ChildMeshInfo = new RuntimeChildMesh(tran, rd.lightmapIndex, rd.lightmapScaleOffset, childMf.sharedMesh.colors); script.ChildMeshInfo.NewVertices = new Vector3[childMf.sharedMesh.vertices.Length]; //计算顶点 for (int m = 0; m < childMf.sharedMesh.vertices.Length; m++) { //先把顶点转换为世界坐标 var wp = tran.localToWorldMatrix.MultiplyPoint3x4(childMf.sharedMesh.vertices[m]); //再把顶点转换为本地坐标 var p = region.worldToLocalMatrix.MultiplyPoint3x4(wp); vList.Add(p); script.ChildMeshInfo.NewVertices[m] = p; script.ChildMeshInfo.StartIndex = starIndex; } scriptList.Add(script); AddColliderBox(tran.gameObject); SetMeshRenderer(rd); info.AddChild(tran); } if (scriptList.Count == CN_MAX_CHILD_COUNT_WANNING + 1) { Debug.LogError("RuntimeMesh Has Too Much Child Count! More then " + CN_MAX_CHILD_COUNT_WANNING); } relationScript.AddRelationScript(scriptList); info.Build(); var mf = Thousandto.Core.Base.UnityUtils.RequireComponent(region.gameObject); var render = Thousandto.Core.Base.UnityUtils.RequireComponent(region.gameObject); render.sharedMaterial = info.Material; render.lightmapIndex = info.LightmapIndex; render.lightmapScaleOffset = new Vector4(1, 1, 0, 0); string result = SaveMeshForAsset(info.NewMesh, region.name, assetpath, filePath); mf.sharedMesh = LoadCombineAsset(result); relationScript.InitCombineInfo(); return info.NewMesh; } else { Debug.LogError("MeshCombineScript: not found renderer child. "); } return null; } private static string SaveMeshForObj(string name, Vector3[] tVertices, Vector2[] tUV, int[] tPolys, string path) { if (!Directory.Exists(path)) Directory.CreateDirectory(path); string savePath = Path.Combine(path, name + ".obj"); StreamWriter sw = new StreamWriter(savePath); try { sw.WriteLine("# T4M File"); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); for (int i = 0; i < tVertices.Length; i++) { //UpdateProgress(); StringBuilder sb = new StringBuilder("v ", tVertices.Length); sb.Append(tVertices[i].x.ToString()).Append(" "). Append(tVertices[i].y.ToString()).Append(" "). Append(tVertices[i].z.ToString()); sw.WriteLine(sb); } for (int i = 0; i < tUV.Length; i++) { //UpdateProgress(); StringBuilder sb = new StringBuilder("vt ", tUV.Length); sb.Append(tUV[i].x.ToString()).Append(" "). Append(tUV[i].y.ToString()); sw.WriteLine(sb); } for (int i = 0; i < tPolys.Length; i += 3) { //UpdateProgress(); StringBuilder sb = new StringBuilder("f ", tPolys.Length); sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" "). Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" "). Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1); sw.WriteLine(sb); } } catch (Exception err) { Debug.Log("Error saving file: " + err.Message); } sw.Close(); AssetDatabase.SaveAssets(); return savePath; } private static string SaveMeshForAsset(Mesh ms, string name, string assetpath, string filepath) { if (ms == null) return string.Empty; string savePath = Path.Combine(assetpath, name + ".asset"); string path = assetpath + name; if (File.Exists(path)) File.Delete(path); AssetDatabase.CreateAsset(ms, savePath); return savePath; } private static Mesh LoadCombineAsset(string path) { Mesh ms = AssetDatabase.LoadAssetAtPath(path, typeof(Mesh)) as Mesh; return ms; } private static void AddColliderBox(GameObject go) { if (go == null) return; var collider = Thousandto.Core.Base.UnityUtils.RequireComponent(go); collider.size = new Vector3(collider.size.x, collider.size.y, 0.2f); collider.isTrigger = true; } private static void SetMeshRenderer(MeshRenderer render) { if (render != null) render.enabled = false; } } } #endif