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 void Combine(HLODBuildInfo info, dynamic options) { var renderers = info.renderers; var atlas = m_Packer.GetAtlas(info); var atlasLookup = new Dictionary <Texture2D, Rect>(); for (int i = 0; i < atlas.MultipleTextures.Length; ++i) { atlasLookup[atlas.MultipleTextures[i].textureList[0]] = atlas.UVs[i]; } List <TextureInfo> textureInfoList = options.TextureInfoList; var combineInstances = new List <CombineInstance>(); var combinedMesh = new Mesh(); for (int i = 0; i < info.renderers.Count; ++i) { var mf = info.renderers[i].GetComponent <MeshFilter>(); if (mf == null) { continue; } var mesh = ConvertMesh(mf, info.simplifiedMeshes[i], atlasLookup, textureInfoList[0]); for (int j = 0; j < mesh.subMeshCount; ++j) { var ci = new CombineInstance(); ci.mesh = mesh; ci.subMeshIndex = j; Matrix4x4 mat = mf.transform.localToWorldMatrix; Vector3 position = m_hlod.transform.position; mat.m03 -= position.x; mat.m13 -= position.y; mat.m23 -= position.z; ci.transform = mat; combineInstances.Add(ci); } } combinedMesh.indexFormat = IndexFormat.UInt32; combinedMesh.CombineMeshes(combineInstances.ToArray()); combinedMesh.RecalculateBounds(); var go = new GameObject(info.name); var meshRenderer = go.AddComponent <MeshRenderer>(); var meshFilter = go.AddComponent <MeshFilter>(); go.transform.SetParent(m_hlod.transform); meshFilter.sharedMesh = combinedMesh; meshRenderer.material = GetMaterial(options, atlas.PackedTexture); info.combinedGameObjects.Add(go); }
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 void Combine(Vector3 rootPosition, HLODBuildInfo info) { var materialTable = new Dictionary <string, WorkingMaterial>(); var combineInfos = new Dictionary <string, List <MeshCombiner.CombineInfo> >(); for (int i = 0; i < info.WorkingObjects.Count; ++i) { var materials = info.WorkingObjects[i].Materials; for (int m = 0; m < materials.Count; ++m) { //var mat = materials[m]; MeshCombiner.CombineInfo combineInfo = new MeshCombiner.CombineInfo(); combineInfo.Transform = info.WorkingObjects[i].LocalToWorld; combineInfo.Transform.m03 -= rootPosition.x; combineInfo.Transform.m13 -= rootPosition.y; combineInfo.Transform.m23 -= rootPosition.z; combineInfo.Mesh = info.WorkingObjects[i].Mesh; combineInfo.MeshIndex = m; if (combineInfos.ContainsKey(materials[m].Identifier) == false) { combineInfos.Add(materials[m].Identifier, new List <MeshCombiner.CombineInfo>()); materialTable.Add(materials[m].Identifier, materials[m]); } combineInfos[materials[m].Identifier].Add(combineInfo); } } using (var originWorkingObject = info.WorkingObjects) { DisposableList <WorkingObject> combinedObjects = new DisposableList <WorkingObject>(); info.WorkingObjects = combinedObjects; MeshCombiner combiner = new MeshCombiner(); foreach (var pair in combineInfos) { WorkingMesh combinedMesh = combiner.CombineMesh(Allocator.Persistent, pair.Value); WorkingObject combinedObject = new WorkingObject(Allocator.Persistent); WorkingMaterial material = materialTable[pair.Key].Clone(); combinedMesh.name = info.Name + "_Mesh" + pair.Key; combinedObject.Name = info.Name; combinedObject.SetMesh(combinedMesh); combinedObject.Materials.Add(material); combinedObjects.Add(combinedObject); } } }
private void Combine(HLODBuildInfo info) { var instancesTable = new Dictionary <Material, List <CombineInstance> >(); for (int i = 0; i < info.renderers.Count; ++i) { if (info.renderers[i] == null) { continue; } var materials = info.renderers[i].sharedMaterials; for (int m = 0; m < materials.Length; ++m) { if (instancesTable.ContainsKey(materials[m]) == false) { instancesTable.Add(materials[m], new List <CombineInstance>()); } var instance = new CombineInstance(); Matrix4x4 mat = info.renderers[i].localToWorldMatrix; Vector3 position = m_hlod.transform.position; mat.m03 -= position.x; mat.m13 -= position.y; mat.m23 -= position.z; instance.transform = mat; instance.mesh = info.simplifiedMeshes[i]; instance.subMeshIndex = m; instancesTable[materials[m]].Add(instance); } } foreach (var instances in instancesTable) { var mesh = new Mesh(); mesh.indexFormat = IndexFormat.UInt32; mesh.CombineMeshes(instances.Value.ToArray(), true, true, false); mesh.name = instances.Key.name; var go = new GameObject(info.name + instances.Key.name, typeof(MeshRenderer), typeof(MeshFilter)); go.GetComponent <MeshFilter>().sharedMesh = mesh; go.GetComponent <MeshRenderer>().sharedMaterial = instances.Key; go.transform.SetParent(m_hlod.transform); info.combinedGameObjects.Add(go); } }
private void Combine(Vector3 rootPosition, TexturePacker packer, HLODBuildInfo info, dynamic options) { var atlas = packer.GetAtlas(info); if (atlas == null) { return; } List <TextureInfo> textureInfoList = options.TextureInfoList; List <MeshCombiner.CombineInfo> combineInfos = new List <MeshCombiner.CombineInfo>(); for (int i = 0; i < info.WorkingObjects.Count; ++i) { var obj = info.WorkingObjects[i]; ConvertMesh(obj.Mesh, obj.Materials, atlas, textureInfoList[0].InputName); for (int si = 0; si < obj.Mesh.subMeshCount; ++si) { var ci = new MeshCombiner.CombineInfo(); ci.Mesh = obj.Mesh; ci.MeshIndex = si; ci.Transform = obj.LocalToWorld; ci.Transform.m03 -= rootPosition.x; ci.Transform.m13 -= rootPosition.y; ci.Transform.m23 -= rootPosition.z; combineInfos.Add(ci); } } MeshCombiner combiner = new MeshCombiner(); WorkingMesh combinedMesh = combiner.CombineMesh(Allocator.Persistent, combineInfos); WorkingObject newObj = new WorkingObject(Allocator.Persistent); WorkingMaterial newMat = m_createdMaterials[atlas].Clone(); combinedMesh.name = info.Name + "_Mesh"; newObj.Name = info.Name; newObj.SetMesh(combinedMesh); newObj.Materials.Add(newMat); info.WorkingObjects.Dispose(); info.WorkingObjects = new DisposableList <WorkingObject>(); info.WorkingObjects.Add(newObj); }
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(); } }
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); }