private DisposableList <HLODBuildInfo> CreateBuildInfo(TerrainData data, SpaceNode root) { DisposableList <HLODBuildInfo> results = new DisposableList <HLODBuildInfo>(); Queue <SpaceNode> trevelQueue = new Queue <SpaceNode>(); Queue <int> parentQueue = new Queue <int>(); Queue <string> nameQueue = new Queue <string>(); Queue <int> depthQueue = new Queue <int>(); int maxDepth = 0; trevelQueue.Enqueue(root); parentQueue.Enqueue(-1); nameQueue.Enqueue("HLOD"); depthQueue.Enqueue(0); while (trevelQueue.Count > 0) { int currentNodeIndex = results.Count; string name = nameQueue.Dequeue(); SpaceNode node = trevelQueue.Dequeue(); int depth = depthQueue.Dequeue(); HLODBuildInfo info = new HLODBuildInfo { Name = name, ParentIndex = parentQueue.Dequeue(), Target = node, }; for (int i = 0; i < node.GetChildCount(); ++i) { trevelQueue.Enqueue(node.GetChild(i)); parentQueue.Enqueue(currentNodeIndex); nameQueue.Enqueue(name + "_" + (i + 1)); depthQueue.Enqueue(depth + 1); } info.Heightmap = CreateSubHightmap(node.Bounds); info.WorkingObjects.Add(CreateBakedTerrain(name, node.Bounds, info.Heightmap, depth, node.GetChildCount() == 0)); info.Distances.Add(depth); results.Add(info); if (depth > maxDepth) { maxDepth = depth; } } //convert depth to distance for (int i = 0; i < results.Count; ++i) { HLODBuildInfo info = results[i]; for (int di = 0; di < info.Distances.Count; ++di) { info.Distances[di] = maxDepth - info.Distances[di]; } } return(results); }
private DisposableList <HLODBuildInfo> CreateBuildInfo() { List <GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject); ISpaceSplitter spliter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 10.0f, m_hlodComponent.transform.position, hlodTargets, null); return((DisposableList <HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { rootNode, 0.0f })); }
public void SpaceSplitTestSize10() { List <GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject); ISpaceSplitter spliter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 10.0f, m_hlodComponent.transform.position, hlodTargets, null); Assert.AreEqual(CalcLevel(rootNode), 3); Assert.AreEqual(GetTargetCount(rootNode), 9); }
private static List <HLODBuildInfo> CreateBuildInfo(SpaceNode root, float thresholdSize) { List <HLODBuildInfo> results = new List <HLODBuildInfo>(); Queue <SpaceNode> trevelQueue = new Queue <SpaceNode>(); Queue <int> parentQueue = new Queue <int>(); Queue <string> nameQueue = new Queue <string>(); trevelQueue.Enqueue(root); parentQueue.Enqueue(-1); nameQueue.Enqueue(""); while (trevelQueue.Count > 0) { int currentNodeIndex = results.Count; string name = nameQueue.Dequeue(); SpaceNode node = trevelQueue.Dequeue(); HLODBuildInfo info = new HLODBuildInfo { name = name, parentIndex = parentQueue.Dequeue(), target = node }; if (node.ChildTreeNodes != null) { for (int i = 0; i < node.ChildTreeNodes.Count; ++i) { trevelQueue.Enqueue(node.ChildTreeNodes[i]); parentQueue.Enqueue(currentNodeIndex); nameQueue.Enqueue(name + "_" + (i + 1)); } } results.Add(info); //it should add to every parent. List <MeshRenderer> meshRenderers = GetMeshRenderers(node.Objects, thresholdSize); int distance = 0; while (currentNodeIndex >= 0) { var curInfo = results[currentNodeIndex]; curInfo.renderers.AddRange(meshRenderers); curInfo.distances.AddRange(Enumerable.Repeat(distance, meshRenderers.Count)); currentNodeIndex = curInfo.parentIndex; distance += 1; } } return(results); }
private DisposableList <HLODBuildInfo> CreateBuildInfo(HLOD hlod) { MethodInfo buildInfoFunc = typeof(HLODCreator).GetMethod("CreateBuildInfo", BindingFlags.Static | BindingFlags.NonPublic); List <GameObject> hlodTargets = ObjectUtils.HLODTargets(hlod.gameObject); ISpaceSplitter spliter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = spliter.CreateSpaceTree(hlod.GetBounds(), 5.0f, hlod.transform.position, hlodTargets, null); return((DisposableList <HLODBuildInfo>)buildInfoFunc.Invoke(null, new object[] { rootNode, 0.0f })); }
public void Build(SpaceNode rootNode, List <HLODBuildInfo> infos, Action <float> onProgress) { string path = ""; PrefabStage stage = PrefabStageUtility.GetPrefabStage(m_hlod.gameObject); path = stage.prefabAssetPath; path = Path.GetDirectoryName(path) + "/"; var defaultController = m_hlod.gameObject.AddComponent <DefaultController>(); HLODTreeNode convertedRootNode = ConvertNode(rootNode); if (onProgress != null) { onProgress(0.0f); } //I think it is better to do when convert nodes. //But that is not easy because of the structure. for (int i = 0; i < infos.Count; ++i) { var spaceNode = infos[i].target; var hlodTreeNode = convertedTable[infos[i].target]; for (int oi = 0; oi < spaceNode.Objects.Count; ++oi) { int highId = defaultController.AddHighObject(spaceNode.Objects[oi]); hlodTreeNode.HighObjectIds.Add(highId); } for (int oi = 0; oi < infos[i].combinedGameObjects.Count; ++oi) { List <HLODMesh> createdMeshes = ObjectUtils.SaveHLODMesh(path, m_hlod.name, infos[i].combinedGameObjects[oi]); m_hlod.GeneratedObjects.AddRange(createdMeshes); foreach (var mesh in createdMeshes) { int lowId = defaultController.AddLowObject(mesh); hlodTreeNode.LowObjectIds.Add(lowId); } } if (onProgress != null) { onProgress((float)i / (float)infos.Count); } } m_hlod.Root = convertedRootNode; }
private HLODTreeNode ConvertNode(HLODTreeNodeContainer container, SpaceNode rootNode) { HLODTreeNode root = new HLODTreeNode(); root.SetContainer(container); Queue <HLODTreeNode> hlodTreeNodes = new Queue <HLODTreeNode>(); Queue <SpaceNode> spaceNodes = new Queue <SpaceNode>(); Queue <int> levels = new Queue <int>(); hlodTreeNodes.Enqueue(root); spaceNodes.Enqueue(rootNode); levels.Enqueue(0); while (hlodTreeNodes.Count > 0) { var hlodTreeNode = hlodTreeNodes.Dequeue(); var spaceNode = spaceNodes.Dequeue(); int level = levels.Dequeue(); convertedTable[spaceNode] = hlodTreeNode; hlodTreeNode.Level = level; hlodTreeNode.Bounds = spaceNode.Bounds; if (spaceNode.HasChild() == true) { List <HLODTreeNode> childTreeNodes = new List <HLODTreeNode>(spaceNode.GetChildCount()); for (int i = 0; i < spaceNode.GetChildCount(); ++i) { var treeNode = new HLODTreeNode(); treeNode.SetContainer(container); childTreeNodes.Add(treeNode); hlodTreeNodes.Enqueue(treeNode); spaceNodes.Enqueue(spaceNode.GetChild(i)); levels.Enqueue(level + 1); } hlodTreeNode.SetChildTreeNode(childTreeNodes); } } return(root); }
public SimpleBuilder AddSpacedRange(float space, IEnumerable <ISimpleNode> nodes) { AssertState(); SpaceNode?n = null; foreach (ISimpleNode node in nodes) { if (n == null) { n = new SpaceNode(Layout, false, space); } else { Nodes.Add(n); } Nodes.Add(node); } return(this); }
private static int GetTargetCount(SpaceNode node) { int count = 0; Stack <SpaceNode> searchNodes = new Stack <SpaceNode>(); searchNodes.Push(node); while (searchNodes.Count > 0) { SpaceNode curNode = searchNodes.Pop(); count += curNode.Objects.Count; for (int i = 0; i < curNode.GetChildCount(); ++i) { searchNodes.Push(curNode.GetChild(i)); } } return(count); }
private static int CalcLevel(SpaceNode node) { SpaceNode curNode = node; int level = 0; while (curNode != null) { level += 1; if (curNode.HasChild() == true) { curNode = curNode.GetChild(0); } else { curNode = null; } } return(level); }
private HLODTreeNode ConvertNode(SpaceNode rootNode) { HLODTreeNode root = new HLODTreeNode(); Queue <HLODTreeNode> hlodTreeNodes = new Queue <HLODTreeNode>(); Queue <SpaceNode> spaceNodes = new Queue <SpaceNode>(); hlodTreeNodes.Enqueue(root); spaceNodes.Enqueue(rootNode); while (hlodTreeNodes.Count > 0) { var hlodTreeNode = hlodTreeNodes.Dequeue(); var spaceNode = spaceNodes.Dequeue(); convertedTable[spaceNode] = hlodTreeNode; hlodTreeNode.Bounds = spaceNode.Bounds; if (spaceNode.ChildTreeNodes != null) { List <HLODTreeNode> childTreeNodes = new List <HLODTreeNode>(spaceNode.ChildTreeNodes.Count); for (int i = 0; i < spaceNode.ChildTreeNodes.Count; ++i) { var treeNode = new HLODTreeNode(); childTreeNodes.Add(treeNode); hlodTreeNodes.Enqueue(treeNode); spaceNodes.Enqueue(spaceNode.ChildTreeNodes[i]); } hlodTreeNode.ChildNodes = childTreeNodes; } } return(root); }
public void Build(SpaceNode rootNode, DisposableList <HLODBuildInfo> infos, GameObject root, float cullDistance, float lodDistance, bool writeNoPrefab, bool extractMaterial, Action <float> onProgress) { dynamic options = m_streamingOptions; string path = options.OutputDirectory; HLODTreeNodeContainer container = new HLODTreeNodeContainer(); HLODTreeNode convertedRootNode = ConvertNode(container, rootNode); if (onProgress != null) { onProgress(0.0f); } HLODData.TextureCompressionData compressionData; compressionData.PCTextureFormat = options.PCCompression; compressionData.WebGLTextureFormat = options.WebGLCompression; compressionData.AndroidTextureFormat = options.AndroidCompression; compressionData.iOSTextureFormat = options.iOSCompression; compressionData.tvOSTextureFormat = options.tvOSCompression; string filename = $"{path}{root.name}.hlod"; if (Directory.Exists(path) == false) { Directory.CreateDirectory(path); } using (Stream stream = new FileStream(filename, FileMode.Create)) { HLODData data = new HLODData(); data.CompressionData = compressionData; for (int i = 0; i < infos.Count; ++i) { data.AddFromWokringObjects(infos[i].Name, infos[i].WorkingObjects); data.AddFromWorkingColliders(infos[i].Name, infos[i].Colliders); if (onProgress != null) { onProgress((float)i / (float)infos.Count); } } if (writeNoPrefab) { for (int ii = 0; ii < infos.Count; ++ii) { var spaceNode = infos[ii].Target; for (int oi = 0; oi < spaceNode.Objects.Count; ++oi) { if (PrefabUtility.IsAnyPrefabInstanceRoot(spaceNode.Objects[oi]) == false) { data.AddFromGameObject(spaceNode.Objects[oi]); } } } } if (extractMaterial == true) { ExtractMaterial(data, $"{path}{root.name}"); } HLODDataSerializer.Write(stream, data); } AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate); RootData rootData = AssetDatabase.LoadAssetAtPath <RootData>(filename); m_manager.AddGeneratedResource(rootData); var defaultController = root.AddComponent <DefaultHLODController>(); GameObject hlodRoot = new GameObject("HLODRoot"); hlodRoot.transform.SetParent(root.transform, false); m_manager.AddGeneratedResource(hlodRoot); for (int ii = 0; ii < infos.Count; ++ii) { var spaceNode = infos[ii].Target; var hlodTreeNode = convertedTable[infos[ii].Target]; for (int oi = 0; oi < spaceNode.Objects.Count; ++oi) { GameObject obj = spaceNode.Objects[oi]; GameObject rootGameObject = rootData.GetRootObject(obj.name); if (rootGameObject != null) { GameObject go = PrefabUtility.InstantiatePrefab(rootGameObject) as GameObject; go.transform.SetParent(obj.transform.parent); go.transform.localPosition = obj.transform.localPosition; go.transform.localRotation = obj.transform.localRotation; go.transform.localScale = obj.transform.localScale; int highId = defaultController.AddHighObject(go); hlodTreeNode.HighObjectIds.Add(highId); if (m_manager.IsGeneratedResource(obj)) { m_manager.AddGeneratedResource(go); } else { m_manager.AddConvertedPrefabResource(go); } Object.DestroyImmediate(obj); } else { int highId = defaultController.AddHighObject(obj); hlodTreeNode.HighObjectIds.Add(highId); } } if (infos[ii].WorkingObjects.Count > 0) { GameObject prefab = rootData.GetRootObject(infos[ii].Name); if (prefab == null) { Debug.LogError("Prefab not found: " + infos[ii].Name); } else { GameObject go = PrefabUtility.InstantiatePrefab(prefab) as GameObject; go.transform.SetParent(hlodRoot.transform, false); go.SetActive(false); int lowId = defaultController.AddLowObject(go); hlodTreeNode.LowObjectIds.Add(lowId); m_manager.AddGeneratedResource(go); } } } defaultController.Container = container; defaultController.Root = convertedRootNode; defaultController.CullDistance = cullDistance; defaultController.LODDistance = lodDistance; }
public static IEnumerator Create(HLOD hlod) { try { Stopwatch sw = new Stopwatch(); AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); sw.Reset(); sw.Start(); Bounds bounds = hlod.GetBounds(); List <GameObject> hlodTargets = ObjectUtils.HLODTargets(hlod.gameObject); ISpaceSplitter spliter = new QuadTreeSpaceSplitter(hlod.transform.position, 5.0f, hlod.MinSize); SpaceNode rootNode = spliter.CreateSpaceTree(bounds, hlodTargets, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Splitting space", progress * 0.25f); }); List <HLODBuildInfo> buildInfos = CreateBuildInfo(rootNode, hlod.ThresholdSize); Debug.Log("[HLOD] Splite space: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); ISimplifier simplifier = (ISimplifier)Activator.CreateInstance(hlod.SimplifierType, new object[] { hlod }); for (int i = 0; i < buildInfos.Count; ++i) { yield return(new BranchCoroutine(simplifier.Simplify(buildInfos[i]))); } yield return(new WaitForBranches(progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Simplify meshes", 0.25f + progress * 0.25f); })); Debug.Log("[HLOD] Simplify: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); IBatcher batcher = (IBatcher)Activator.CreateInstance(hlod.BatcherType, new object[] { hlod }); batcher.Batch(buildInfos, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Generating combined static meshes.", 0.5f + progress * 0.25f); }); Debug.Log("[HLOD] Batch: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); try { AssetDatabase.StartAssetEditing(); IStreamingBuilder builder = (IStreamingBuilder)Activator.CreateInstance(hlod.StreamingType, new object[] { hlod }); builder.Build(rootNode, buildInfos, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Storing results.", 0.75f + progress * 0.25f); }); Debug.Log("[HLOD] Build: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); } finally { AssetDatabase.StopAssetEditing(); Debug.Log("[HLOD] Importing: " + sw.Elapsed.ToString("g")); } } finally { EditorUtility.ClearProgressBar(); } //hlod.Root = rootNode; }
public static IEnumerator Create(HLOD hlod) { try { Stopwatch sw = new Stopwatch(); AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); sw.Reset(); sw.Start(); hlod.ConvertedPrefabObjects.Clear(); hlod.GeneratedObjects.Clear(); Bounds bounds = hlod.GetBounds(); List <GameObject> hlodTargets = ObjectUtils.HLODTargets(hlod.gameObject); ISpaceSplitter spliter = new QuadTreeSpaceSplitter(5.0f); SpaceNode rootNode = spliter.CreateSpaceTree(bounds, hlod.ChunkSize, hlod.transform.position, hlodTargets, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Splitting space", progress * 0.25f); }); if (hlodTargets.Count == 0) { EditorUtility.DisplayDialog("Empty HLOD sources.", "There are no objects to be included in the HLOD.", "Ok"); yield break; } using (DisposableList <HLODBuildInfo> buildInfos = CreateBuildInfo(rootNode, hlod.MinObjectSize)) { if (buildInfos.Count == 0 || buildInfos[0].WorkingObjects.Count == 0) { EditorUtility.DisplayDialog("Empty HLOD sources.", "There are no objects to be included in the HLOD.", "Ok"); yield break; } Debug.Log("[HLOD] Splite space: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); ISimplifier simplifier = (ISimplifier)Activator.CreateInstance(hlod.SimplifierType, new object[] { hlod.SimplifierOptions }); for (int i = 0; i < buildInfos.Count; ++i) { yield return(new BranchCoroutine(simplifier.Simplify(buildInfos[i]))); } yield return(new WaitForBranches(progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Simplify meshes", 0.25f + progress * 0.25f); })); Debug.Log("[HLOD] Simplify: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); using (IBatcher batcher = (IBatcher)Activator.CreateInstance(hlod.BatcherType, new object[] { hlod.BatcherOptions })) { batcher.Batch(hlod.transform.position, buildInfos, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Generating combined static meshes.", 0.5f + progress * 0.25f); }); } Debug.Log("[HLOD] Batch: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); IStreamingBuilder builder = (IStreamingBuilder)Activator.CreateInstance(hlod.StreamingType, new object[] { hlod, hlod.StreamingOptions }); builder.Build(rootNode, buildInfos, hlod.gameObject, hlod.CullDistance, hlod.LODDistance, false, true, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Storing results.", 0.75f + progress * 0.25f); }); Debug.Log("[HLOD] Build: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); EditorUtility.SetDirty(hlod.gameObject); } } finally { EditorUtility.ClearProgressBar(); } }
public void Build(SpaceNode rootNode, DisposableList <HLODBuildInfo> infos, GameObject root, float cullDistance, float lodDistance, bool writeNoPrefab, bool extractMaterial, Action <float> onProgress) { dynamic options = m_streamingOptions; string path = options.OutputDirectory; HLODTreeNodeContainer container = new HLODTreeNodeContainer(); HLODTreeNode convertedRootNode = ConvertNode(container, rootNode); //create settings if there is no settings. if (AddressableAssetSettingsDefaultObject.Settings == null) { AddressableAssetSettings.Create(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, AddressableAssetSettingsDefaultObject.kDefaultConfigAssetName, true, true); } var settings = AddressableAssetSettingsDefaultObject.GetSettings(true); var group = GetGroup(settings, options.AddressablesGroupName); m_shaderGuids.Clear(); if (onProgress != null) { onProgress(0.0f); } HLODData.TextureCompressionData compressionData; compressionData.PCTextureFormat = options.PCCompression; compressionData.WebGLTextureFormat = options.WebGLCompression; compressionData.AndroidTextureFormat = options.AndroidCompression; compressionData.iOSTextureFormat = options.iOSCompression; compressionData.tvOSTextureFormat = options.tvOSCompression; string filenamePrefix = $"{path}{root.name}"; if (Directory.Exists(path) == false) { Directory.CreateDirectory(path); } Dictionary <int, HLODData> hlodDatas = new Dictionary <int, HLODData>(); for (int i = 0; i < infos.Count; ++i) { if (hlodDatas.ContainsKey(infos[i].ParentIndex) == false) { HLODData newData = new HLODData(); newData.CompressionData = compressionData; hlodDatas.Add(infos[i].ParentIndex, newData); } HLODData data = hlodDatas[infos[i].ParentIndex]; data.AddFromWokringObjects(infos[i].Name, infos[i].WorkingObjects); data.AddFromWorkingColliders(infos[i].Name, infos[i].Colliders); if (writeNoPrefab) { if (hlodDatas.ContainsKey(i) == false) { HLODData newData = new HLODData(); newData.CompressionData = compressionData; hlodDatas.Add(i, newData); } HLODData prefabData = hlodDatas[i]; var spaceNode = infos[i].Target; for (int oi = 0; oi < spaceNode.Objects.Count; ++oi) { if (PrefabUtility.IsAnyPrefabInstanceRoot(spaceNode.Objects[oi]) == false) { prefabData.AddFromGameObject(spaceNode.Objects[oi]); } } } if (onProgress != null) { onProgress((float)i / (float)infos.Count); } } if (extractMaterial) { ExtractMaterial(hlodDatas, filenamePrefix); } Dictionary <int, RootData> rootDatas = new Dictionary <int, RootData>(); foreach (var item in hlodDatas) { string filename = $"{filenamePrefix}_group{item.Key}.hlod"; using (Stream stream = new FileStream(filename, FileMode.Create)) { HLODDataSerializer.Write(stream, item.Value); stream.Close(); } AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate); RootData rootData = AssetDatabase.LoadAssetAtPath <RootData>(filename); m_manager.AddGeneratedResource(rootData); AddAddress(settings, group, rootData); rootDatas.Add(item.Key, rootData); } var addressableController = root.AddComponent <AddressableHLODController>(); for (int i = 0; i < infos.Count; ++i) { var spaceNode = infos[i].Target; var hlodTreeNode = convertedTable[infos[i].Target]; for (int oi = 0; oi < spaceNode.Objects.Count; ++oi) { int highId = -1; GameObject obj = spaceNode.Objects[oi]; if (PrefabUtility.IsPartOfAnyPrefab(obj) == false) { GameObject rootGameObject = null; if (rootDatas.ContainsKey(i)) { rootGameObject = rootDatas[i].GetRootObject(obj.name); } if (rootGameObject != null) { GameObject go = PrefabUtility.InstantiatePrefab(rootGameObject) as GameObject; go.transform.SetParent(obj.transform.parent); go.transform.localPosition = obj.transform.localPosition; go.transform.localRotation = obj.transform.localRotation; go.transform.localScale = obj.transform.localScale; if (m_manager.IsGeneratedResource(obj)) { m_manager.AddGeneratedResource(go); } else { m_manager.AddConvertedPrefabResource(go); } spaceNode.Objects.Add(go); Object.DestroyImmediate(obj); continue; } } var address = GetAddress(spaceNode.Objects[oi]); if (string.IsNullOrEmpty(address) && PrefabUtility.IsAnyPrefabInstanceRoot(spaceNode.Objects[oi])) { AddAddress(settings, group, spaceNode.Objects[oi]); address = GetAddress(spaceNode.Objects[oi]); } if (address != null) { highId = addressableController.AddHighObject(address, spaceNode.Objects[oi]); } else { highId = addressableController.AddHighObject(spaceNode.Objects[oi]); } hlodTreeNode.HighObjectIds.Add(highId); } { if (rootDatas[infos[i].ParentIndex].GetRootObject(infos[i].Name) != null) { string filename = $"{filenamePrefix}_group{infos[i].ParentIndex}.hlod"; int lowId = addressableController.AddLowObject(filename + "[" + infos[i].Name + "]"); hlodTreeNode.LowObjectIds.Add(lowId); } } } var shaderEntriesAdded = new List <AddressableAssetEntry>(); foreach (var shaderGuid in m_shaderGuids) { if (IsExistsInAddressables(shaderGuid) == false) { shaderEntriesAdded.Add(settings.CreateOrMoveEntry(shaderGuid, group, false, false)); } } settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, shaderEntriesAdded, true); m_shaderGuids.Clear(); addressableController.Container = container; addressableController.Root = convertedRootNode; addressableController.CullDistance = cullDistance; addressableController.LODDistance = lodDistance; }
private static DisposableList <HLODBuildInfo> CreateBuildInfo(SpaceNode root, float minObjectSize) { List <HLODBuildInfo> resultsCandidates = new List <HLODBuildInfo>(); Queue <SpaceNode> trevelQueue = new Queue <SpaceNode>(); Queue <int> parentQueue = new Queue <int>(); Queue <string> nameQueue = new Queue <string>(); Queue <int> levelQueue = new Queue <int>(); trevelQueue.Enqueue(root); parentQueue.Enqueue(-1); levelQueue.Enqueue(0); nameQueue.Enqueue(""); while (trevelQueue.Count > 0) { int currentNodeIndex = resultsCandidates.Count; string name = nameQueue.Dequeue(); SpaceNode node = trevelQueue.Dequeue(); HLODBuildInfo info = new HLODBuildInfo { Name = name, ParentIndex = parentQueue.Dequeue(), Target = node }; for (int i = 0; i < node.GetChildCount(); ++i) { trevelQueue.Enqueue(node.GetChild(i)); parentQueue.Enqueue(currentNodeIndex); nameQueue.Enqueue(name + "_" + (i + 1)); } resultsCandidates.Add(info); //it should add to every parent. List <MeshRenderer> meshRenderers = GetMeshRenderers(node.Objects, minObjectSize); List <Collider> colliders = GetColliders(node.Objects, minObjectSize); int distance = 0; while (currentNodeIndex >= 0) { var curInfo = resultsCandidates[currentNodeIndex]; for (int i = 0; i < meshRenderers.Count; ++i) { curInfo.WorkingObjects.Add(meshRenderers[i].ToWorkingObject(Allocator.Persistent)); curInfo.Distances.Add(distance); } for (int i = 0; i < colliders.Count; ++i) { curInfo.Colliders.Add(colliders[i].ToWorkingCollider()); } currentNodeIndex = curInfo.ParentIndex; distance += 1; } } DisposableList <HLODBuildInfo> results = new DisposableList <HLODBuildInfo>(); for (int i = 0; i < resultsCandidates.Count; ++i) { if (resultsCandidates[i].WorkingObjects.Count > 0) { results.Add(resultsCandidates[i]); } else { resultsCandidates[i].Dispose(); } } return(results); }
public void CreateBuildInfoTest() { List <GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject); ISpaceSplitter spliter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 5.0f, m_hlodComponent.transform.position, hlodTargets, null); using (DisposableList <HLODBuildInfo> ret = (DisposableList <HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { rootNode, 0.0f })) { //only exists nodes are creating info. Assert.AreEqual(ret.Count, 11); Assert.AreEqual(ret[0].Name, ""); Assert.AreEqual(ret[0].ParentIndex, -1); Assert.AreEqual(ret[0].WorkingObjects.Count, 9); Assert.AreEqual(ret[1].Name, "_1"); Assert.AreEqual(ret[1].ParentIndex, 0); Assert.AreEqual(ret[1].WorkingObjects.Count, 2); Assert.AreEqual(ret[2].Name, "_2"); Assert.AreEqual(ret[2].ParentIndex, 0); Assert.AreEqual(ret[2].WorkingObjects.Count, 2); Assert.AreEqual(ret[3].Name, "_3"); Assert.AreEqual(ret[3].ParentIndex, 0); Assert.AreEqual(ret[3].WorkingObjects.Count, 2); Assert.AreEqual(ret[4].Name, "_4"); Assert.AreEqual(ret[4].ParentIndex, 0); Assert.AreEqual(ret[4].WorkingObjects.Count, 2); Assert.AreEqual(ret[5].Name, "_1_1"); Assert.AreEqual(ret[5].ParentIndex, 1); Assert.AreEqual(ret[5].WorkingObjects.Count, 1); Assert.AreEqual(ret[6].Name, "_1_4"); Assert.AreEqual(ret[6].ParentIndex, 1); Assert.AreEqual(ret[6].WorkingObjects.Count, 1); Assert.AreEqual(ret[7].Name, "_2_2"); Assert.AreEqual(ret[7].ParentIndex, 2); Assert.AreEqual(ret[7].WorkingObjects.Count, 1); Assert.AreEqual(ret[8].Name, "_2_3"); Assert.AreEqual(ret[8].ParentIndex, 2); Assert.AreEqual(ret[8].WorkingObjects.Count, 1); Assert.AreEqual(ret[9].Name, "_3_3"); Assert.AreEqual(ret[9].ParentIndex, 3); Assert.AreEqual(ret[9].WorkingObjects.Count, 1); Assert.AreEqual(ret[10].Name, "_4_4"); Assert.AreEqual(ret[10].ParentIndex, 4); Assert.AreEqual(ret[10].WorkingObjects.Count, 1); } //exclude object smaller than 0.5. using (DisposableList <HLODBuildInfo> ret = (DisposableList <HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { rootNode, 0.5f })) { //only exists nodes are creating info. Assert.AreEqual(ret.Count, 10); Assert.AreEqual(ret[0].Name, ""); Assert.AreEqual(ret[0].ParentIndex, -1); Assert.AreEqual(ret[0].WorkingObjects.Count, 8); Assert.AreEqual(ret[1].Name, "_1"); Assert.AreEqual(ret[1].ParentIndex, 0); Assert.AreEqual(ret[1].WorkingObjects.Count, 1); Assert.AreEqual(ret[2].Name, "_2"); Assert.AreEqual(ret[2].ParentIndex, 0); Assert.AreEqual(ret[2].WorkingObjects.Count, 2); Assert.AreEqual(ret[3].Name, "_3"); Assert.AreEqual(ret[3].ParentIndex, 0); Assert.AreEqual(ret[3].WorkingObjects.Count, 2); Assert.AreEqual(ret[4].Name, "_4"); Assert.AreEqual(ret[4].ParentIndex, 0); Assert.AreEqual(ret[4].WorkingObjects.Count, 2); Assert.AreEqual(ret[5].Name, "_1_1"); Assert.AreEqual(ret[5].ParentIndex, 1); Assert.AreEqual(ret[5].WorkingObjects.Count, 1); Assert.AreEqual(ret[6].Name, "_2_2"); Assert.AreEqual(ret[6].ParentIndex, 2); Assert.AreEqual(ret[6].WorkingObjects.Count, 1); Assert.AreEqual(ret[7].Name, "_2_3"); Assert.AreEqual(ret[7].ParentIndex, 2); Assert.AreEqual(ret[7].WorkingObjects.Count, 1); Assert.AreEqual(ret[8].Name, "_3_3"); Assert.AreEqual(ret[8].ParentIndex, 3); Assert.AreEqual(ret[8].WorkingObjects.Count, 1); Assert.AreEqual(ret[9].Name, "_4_4"); Assert.AreEqual(ret[9].ParentIndex, 4); Assert.AreEqual(ret[9].WorkingObjects.Count, 1); } //exclude object smaller than 1. using (DisposableList <HLODBuildInfo> ret = (DisposableList <HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { rootNode, 1.0f })) { //only exists nodes are creating info. Assert.AreEqual(ret.Count, 9); Assert.AreEqual(ret[0].Name, ""); Assert.AreEqual(ret[0].ParentIndex, -1); Assert.AreEqual(ret[0].WorkingObjects.Count, 7); Assert.AreEqual(ret[1].Name, "_1"); Assert.AreEqual(ret[1].ParentIndex, 0); Assert.AreEqual(ret[1].WorkingObjects.Count, 1); Assert.AreEqual(ret[2].Name, "_2"); Assert.AreEqual(ret[2].ParentIndex, 0); Assert.AreEqual(ret[2].WorkingObjects.Count, 1); Assert.AreEqual(ret[3].Name, "_3"); Assert.AreEqual(ret[3].ParentIndex, 0); Assert.AreEqual(ret[3].WorkingObjects.Count, 2); Assert.AreEqual(ret[4].Name, "_4"); Assert.AreEqual(ret[4].ParentIndex, 0); Assert.AreEqual(ret[4].WorkingObjects.Count, 2); Assert.AreEqual(ret[5].Name, "_1_1"); Assert.AreEqual(ret[5].ParentIndex, 1); Assert.AreEqual(ret[5].WorkingObjects.Count, 1); Assert.AreEqual(ret[6].Name, "_2_2"); Assert.AreEqual(ret[6].ParentIndex, 2); Assert.AreEqual(ret[6].WorkingObjects.Count, 1); Assert.AreEqual(ret[7].Name, "_3_3"); Assert.AreEqual(ret[7].ParentIndex, 3); Assert.AreEqual(ret[7].WorkingObjects.Count, 1); Assert.AreEqual(ret[8].Name, "_4_4"); Assert.AreEqual(ret[8].ParentIndex, 4); Assert.AreEqual(ret[8].WorkingObjects.Count, 1); } }
public IEnumerator CreateImpl() { try { using (m_queue = new JobQueue(8)) { Stopwatch sw = new Stopwatch(); AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); sw.Reset(); sw.Start(); EditorUtility.DisplayProgressBar("Bake HLOD", "Initialize Bake", 0.0f); TerrainData data = m_hlod.TerrainData; m_size = data.size; m_heightmap = new Heightmap(data.heightmapResolution, data.heightmapResolution, data.size, data.GetHeights(0, 0, data.heightmapResolution, data.heightmapResolution)); string materialPath = AssetDatabase.GUIDToAssetPath(m_hlod.MaterialGUID); m_terrainMaterial = AssetDatabase.LoadAssetAtPath <Material>(materialPath); if (m_terrainMaterial == null) { m_terrainMaterial = new Material(Shader.Find("Standard")); } m_terrainMaterialInstanceId = m_terrainMaterial.GetInstanceID(); m_terrainMaterialName = m_terrainMaterial.name; using (m_alphamaps = new DisposableList <WorkingTexture>()) using (m_layers = new DisposableList <Layer>()) { for (int i = 0; i < data.alphamapTextures.Length; ++i) { m_alphamaps.Add(new WorkingTexture(Allocator.Persistent, data.alphamapTextures[i])); } for (int i = 0; i < data.terrainLayers.Length; ++i) { m_layers.Add(new Layer(data.terrainLayers[i])); } QuadTreeSpaceSplitter splitter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = splitter.CreateSpaceTree(m_hlod.GetBounds(), m_hlod.ChunkSize * 2.0f, m_hlod.transform.position, null, progress => { }); EditorUtility.DisplayProgressBar("Bake HLOD", "Create mesh", 0.0f); using (DisposableList <HLODBuildInfo> buildInfos = CreateBuildInfo(data, rootNode)) { yield return(m_queue.WaitFinish()); //Write material & textures for (int i = 0; i < buildInfos.Count; ++i) { int curIndex = i; m_queue.EnqueueJob(() => { ISimplifier simplifier = (ISimplifier)Activator.CreateInstance(m_hlod.SimplifierType, new object[] { m_hlod.SimplifierOptions }); simplifier.SimplifyImmidiate(buildInfos[curIndex]); }); } EditorUtility.DisplayProgressBar("Bake HLOD", "Simplify meshes", 0.0f); yield return(m_queue.WaitFinish()); Debug.Log("[TerrainHLOD] Simplify: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); EditorUtility.DisplayProgressBar("Bake HLOD", "Make border", 0.0f); for (int i = 0; i < buildInfos.Count; ++i) { HLODBuildInfo info = buildInfos[i]; m_queue.EnqueueJob(() => { for (int oi = 0; oi < info.WorkingObjects.Count; ++oi) { WorkingObject o = info.WorkingObjects[oi]; int borderVertexCount = m_hlod.BorderVertexCount * Mathf.RoundToInt(Mathf.Pow(2.0f, (float)info.Distances[oi])); using (WorkingMesh m = MakeBorder(o.Mesh, info.Heightmap, borderVertexCount)) { ReampUV(m, info.Heightmap); o.SetMesh(MakeFillHoleMesh(m)); } } }); } yield return(m_queue.WaitFinish()); Debug.Log("[TerrainHLOD] Make Border: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); for (int i = 0; i < buildInfos.Count; ++i) { SpaceNode node = buildInfos[i].Target; HLODBuildInfo info = buildInfos[i]; if (node.HasChild() == false) { SpaceNode parent = node.ParentNode; node.ParentNode = null; GameObject go = new GameObject(buildInfos[i].Name); for (int wi = 0; wi < info.WorkingObjects.Count; ++wi) { WorkingObject wo = info.WorkingObjects[wi]; GameObject targetGO = null; if (wi == 0) { targetGO = go; } else { targetGO = new GameObject(wi.ToString()); targetGO.transform.SetParent(go.transform, false); } List <Material> materials = new List <Material>(); for (int mi = 0; mi < wo.Materials.Count; ++mi) { WorkingMaterial wm = wo.Materials[mi]; if (wm.NeedWrite() == false) { materials.Add(wm.ToMaterial()); continue; } Material mat = new Material(wm.ToMaterial()); string[] textureNames = wm.GetTextureNames(); for (int ti = 0; ti < textureNames.Length; ++ti) { WorkingTexture wt = wm.GetTexture(textureNames[ti]); Texture2D tex = wt.ToTexture(); tex.wrapMode = wt.WrapMode; mat.name = targetGO.name + "_Mat"; mat.SetTexture(textureNames[ti], tex); } mat.EnableKeyword("_NORMALMAP"); materials.Add(mat); } targetGO.AddComponent <MeshFilter>().sharedMesh = wo.Mesh.ToMesh(); targetGO.AddComponent <MeshRenderer>().sharedMaterials = materials.ToArray(); } go.transform.SetParent(m_hlod.transform, false); m_hlod.AddGeneratedResource(go); parent.Objects.Add(go); buildInfos.RemoveAt(i); i -= 1; } } //controller IStreamingBuilder builder = (IStreamingBuilder)Activator.CreateInstance(m_hlod.StreamingType, new object[] { m_hlod, m_hlod.StreamingOptions }); builder.Build(rootNode, buildInfos, m_hlod.gameObject, m_hlod.CullDistance, m_hlod.LODDistance, true, false, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Storing results.", 0.75f + progress * 0.25f); }); Debug.Log("[TerrainHLOD] Build: " + sw.Elapsed.ToString("g")); } } EditorUtility.SetDirty(m_hlod.gameObject); } } finally { EditorUtility.ClearProgressBar(); GC.Collect(); } }