//--------------------------------------------------------------------------------------- // OnGUI //--------------------------------------------------------------------------------------- void OnGUI() { // 场景名字 var scenePath = EditorApplication.currentScene; string sceneName = UtilityTools.GetFileName(scenePath); if (_sceneName != sceneName) { _sceneName = sceneName; LoadSettings(); } EditorGUI.BeginChangeCheck(); // 树列表 EditorGUILayout.LabelField("场景树"); for (int i = 0; i < _settings.trees.Count; ++i) { DrawSeparator(1, 1); var tree = _settings.trees[i]; tree.name = EditorGUILayout.TextField("名称", tree.name); tree.splitType = (SceneTreeSplitType)EditorGUILayout.EnumPopup("划分类型", tree.splitType); tree.objType = (SceneTreeObjType)EditorGUILayout.EnumPopup("对象类型", tree.objType); tree.maxDepth = EditorGUILayout.IntField("最大层数", tree.maxDepth); tree.viewDistance = EditorGUILayout.FloatField("可视距离", tree.viewDistance); tree.maxItemBoundsSize = EditorGUILayout.FloatField("最大物体大小", tree.maxItemBoundsSize); } // 导出 GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); _recovertScene = GUILayout.Toggle(_recovertScene, "导出完是否恢复"); _backScene = GUILayout.Toggle(_backScene, "备份场景"); _compressScene = GUILayout.Toggle(_compressScene, "压缩场景"); _compressRes = GUILayout.Toggle(_compressRes, "压缩资源"); GUILayout.EndHorizontal(); GUILayout.Space(20); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("检查设置", GUILayout.Width(100))) { int settingsObjTypeFlag = 0; SceneTree.CheckSettings(_settings.trees, out settingsObjTypeFlag); } else if (GUILayout.Button("导出资源", GUILayout.Width(100))) { BuildScene(_backScene, true, _compressScene, _compressRes); } else { GUILayout.EndHorizontal(); GUILayout.Space(10); if (EditorGUI.EndChangeCheck()) { SaveSettings(); } } }
/// <summary> /// 生成 /// </summary> public static SceneTree[] Build(List <SceneTreeSettings> settings, List <MeshCollider> meshColliders) { // 检查设置 int settingsObjTypeFlag = 0; if (!CheckSettings(settings, out settingsObjTypeFlag)) { return(null); } // 收集GameObject并计算包围盒 var gos = (GameObject[])GameObject.FindObjectsOfType <GameObject>(); var items = new List <SceneItem>(); Bounds sceneBounds = new Bounds(); // 检测自动计算场景包围盒 bool bCalculateSceneBound = false; var ters = GameObject.FindGameObjectsWithTag("Terrain"); if (ters == null || ters.Length <= 0) { bCalculateSceneBound = true; } var otherColliders = new List <Collider>(); var sb = new StringBuilder(); sb.AppendFormat("Start build {0} items...\n", gos.Length); for (int i = 0; i < gos.Length; ++i) { var go = gos[i]; EditorUtility.DisplayProgressBar(string.Format("Build items({0}/{1})", i + 1, gos.Length), go.name, (float)(i + 1) / gos.Length); if (UtilityTools.IsEditorOnly(go)) { continue; } // 包围盒 int objTypeFlag = 0; otherColliders.Clear(); var bounds = GetBounds(go, otherColliders, meshColliders, out objTypeFlag); if (objTypeFlag == 0) { continue; } var size = Vector3.Distance(bounds.min, bounds.max); if (size < MathUtil.fEpsilon) { Debug.LogErrorFormat("Invalid bounds of {0}!", go.name); continue; } /// 场景中没有表示地形,自动累计 if (bCalculateSceneBound) { sceneBounds.Encapsulate(bounds); } else { // 使用地形包围盒生成场景包围盒 if (go.CompareTag("Terrain")) { go.layer = LayerDefine.Terrain; if (sceneBounds.size.x < MathUtil.fEpsilon) { sceneBounds = bounds; } else { sceneBounds.Encapsulate(bounds); } } } // 没有交集 if ((settingsObjTypeFlag & objTypeFlag) == 0) { continue; } // 加入列表 var item = new SceneItem(); item.go = go; item.colliders = otherColliders.ToArray(); item.bounds = bounds; item.radius = size * 0.5f; item.size = size; item.objTypeFlag = objTypeFlag; item.cfg = go.GetComponent <EditorSceneObject>(); items.Add(item); } EditorUtility.ClearProgressBar(); sb.Append("Build items complete."); Debug.Log(sb.ToString()); sb.Length = 0; var meshColliderCount = meshColliders.Count; sb.AppendFormat("MeshCollider count is {0}", meshColliderCount); Debug.Log(sb.ToString()); // 场景包围盒大小为0 if (sceneBounds.size.x < MathUtil.fEpsilon) { Debug.LogError("Build scene bounds failed!"); return(null); } // 列表 var itemCount = items.Count; var treeItems = new List <SceneItem> [settings.Count]; for (int i = 0; i < treeItems.Length; ++i) { treeItems[i] = new List <SceneItem>(); } // 把对象分别填充到每棵树的列表中 for (int i = 0, ni = 0, ci = items.Count, cn = ci; i < ci; ++i, ++ni) { var item = items[i]; EditorUtility.DisplayProgressBar(string.Format("Insert items to tree({0}/{1})", ni + 1, cn), item.go.name, (float)(ni + 1) / cn); for (int j = 0, cj = settings.Count; j < cj; ++j) { var setting = settings[j]; var list = treeItems[j]; if ((item.objTypeFlag & (1 << (int)setting.objType)) == 0) { continue; } if (SceneTreeObjType.Renderer == setting.objType) { if (null != item.cfg && !string.IsNullOrEmpty(item.cfg.specSceneTree)) { if (item.cfg.specSceneTree == setting.name) { list.Add(item); items.RemoveAt(i--); --ci; break; } continue; } // 只包含指定名字对象 if (setting.name == "grass") { continue; } // 大小 if (item.size < setting.maxItemBoundsSize) { list.Add(item); items.RemoveAt(i--); --ci; break; } continue; } // 碰撞体 if (SceneTreeObjType.Collider == setting.objType) { list.Add(item); if (item.objTypeFlag == (1 << (int)setting.objType)) { items.RemoveAt(i--); --ci; } continue; } } } EditorUtility.ClearProgressBar(); // 剩下的,放到最后一个节点 if (items.Count > 0) { Debug.LogWarningFormat("{0} items can not add to trees!", items.Count); treeItems[settings.Count - 1].AddRange(items); items.Clear(); } // 生成 var trees = new List <SceneTree>(); for (int i = 0; i < treeItems.Length; ++i) { var setting = settings[i]; EditorUtility.DisplayProgressBar(string.Format("SplitScene({0}/{1})", i + 1, treeItems.Length), setting.name, (float)(i + 1) / treeItems.Length); var list = treeItems[i]; if (list.Count < 1) { continue; } var tree = new SceneTree(setting); tree.SplitScene(list, sceneBounds); trees.Add(tree); } EditorUtility.ClearProgressBar(); // 打印日志 sb.Length = 0; var scenePath = EditorApplication.currentScene; if (string.IsNullOrEmpty(scenePath)) { scenePath = "Untitled"; } sb.AppendFormat("Scene build complete. [{0}]\n", scenePath); sb.Append("---------------------------------------------------------------\n"); sb.AppendFormat("TreeCount[{0}]\n", trees.Count); sb.AppendFormat("ItemCount[{0}]\n", itemCount); Debug.Log(sb.ToString()); for (int i = 0; i < trees.Count; ++i) { var tree = trees[i]; if (null != tree) { tree.LogTreeInfo(); } } return(trees.ToArray()); }
/// <summary> /// 生成场景 /// </summary> void BuildScene(bool exportScene, bool exportRes, bool compressScene, bool compressRes) { // 先保存场景 EditorApplication.SaveScene(); // 场景名字 var scenePath = EditorApplication.currentScene; string sceneName = UtilityTools.GetFileName(scenePath); // 导出目录 var exportPath = UtilityTools.GenResExportPath(string.Format("scene/{0}", sceneName), sceneName); var exportDir = Path.GetDirectoryName(exportPath); // 删除目录 if (exportRes && exportScene) { Directory.Delete(exportDir, true); } // 创建目录 if (!Directory.Exists(exportDir)) { Directory.CreateDirectory(exportDir); } /// 开始处理数据 try { do { AssetsBackuper.inst.Clear(); if (exportScene) { var outputDir = EditorUtil.GetSceneOutputPath(null); AssetDatabase.DeleteAsset(outputDir); var outputPath = EditorUtil.GetSceneOutputPath(string.Format("{0}.unity", sceneName)); EditorApplication.SaveScene(outputPath); } // 树结构 var meshColliders = new List <MeshCollider>(); var trees = SceneTree.Build(_settings.trees, meshColliders); if (null == trees) { break; } SaveSettings(); SceneTree.Export(trees, meshColliders, exportRes, compressRes); // 准备导出 EditorApplication.SaveScene(); AssetDatabase.SaveAssets(); if (exportScene) { ResExportUtil.ExportCurrentScene(true, compressScene); } }while(false); } catch (Exception e) { Debug.LogException(e); AssetsBackuper.inst.Recover(); AssetDatabase.SaveAssets(); } finally { // 还原修改过的资源和场景 if (_recovertScene) { AssetsBackuper.inst.Recover(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); EditorApplication.OpenScene(scenePath); Resources.UnloadUnusedAssets(); } } }
/// <summary> /// 构造 /// </summary> /// <param name="tree"></param> /// <param name="depth"></param> public SceneTreeNode(SceneTree tree, int depth) { _tree = tree; _depth = depth; }