protected override IEnumerator GetSimplifiedMesh(Utils.WorkingMesh origin, float quality, Action <Utils.WorkingMesh> resultCallback) { var meshSimplifier = new global::UnityMeshSimplifier.MeshSimplifier(); meshSimplifier.Vertices = origin.vertices; meshSimplifier.Normals = origin.normals; meshSimplifier.Tangents = origin.tangents; meshSimplifier.UV1 = origin.uv; meshSimplifier.UV2 = origin.uv2; meshSimplifier.UV3 = origin.uv3; meshSimplifier.UV4 = origin.uv4; meshSimplifier.Colors = origin.colors; var triangles = new int[origin.subMeshCount][]; for (var submesh = 0; submesh < origin.subMeshCount; submesh++) { triangles[submesh] = origin.GetTriangles(submesh); } meshSimplifier.AddSubMeshTriangles(triangles); meshSimplifier.SimplifyMesh(quality); int triCount = 0; for (int i = 0; i < meshSimplifier.SubMeshCount; ++i) { triCount += meshSimplifier.GetSubMeshTriangles(i).Length; } Utils.WorkingMesh nwm = new WorkingMesh(Allocator.Persistent, meshSimplifier.Vertices.Length, triCount, meshSimplifier.SubMeshCount, 0); nwm.name = origin.name; nwm.vertices = meshSimplifier.Vertices; nwm.normals = meshSimplifier.Normals; nwm.tangents = meshSimplifier.Tangents; nwm.uv = meshSimplifier.UV1; nwm.uv2 = meshSimplifier.UV2; nwm.uv3 = meshSimplifier.UV3; nwm.uv4 = meshSimplifier.UV4; nwm.colors = meshSimplifier.Colors; nwm.subMeshCount = meshSimplifier.SubMeshCount; for (var submesh = 0; submesh < nwm.subMeshCount; submesh++) { nwm.SetTriangles(meshSimplifier.GetSubMeshTriangles(submesh), submesh); } if (resultCallback != null) { resultCallback(nwm); } yield break; }
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 ReampUV(WorkingMesh mesh, Heightmap heightmap) { var vertices = mesh.vertices; var uvs = mesh.uv; for (int i = 0; i < mesh.vertexCount; ++i) { Vector2 uv; uv.x = (vertices[i].x - heightmap.Offset.x) / heightmap.Size.x; uv.y = (vertices[i].z - heightmap.Offset.z) / heightmap.Size.z; uvs[i] = uv; //vertices[i]. } mesh.uv = uvs; }
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 void From(WorkingMesh mesh) { m_name = mesh.name; m_vertices = ArrayToBytes(mesh.vertices); m_normals = ArrayToBytes(mesh.normals); m_tangents = ArrayToBytes(mesh.tangents); m_uvs = ArrayToBytes(mesh.uv); m_uvs2 = ArrayToBytes(mesh.uv2); m_uvs3 = ArrayToBytes(mesh.uv3); m_uvs4 = ArrayToBytes(mesh.uv4); m_colors = ArrayToBytes(mesh.colors); m_indices = new List <int[]>(); for (int i = 0; i < mesh.subMeshCount; ++i) { m_indices.Add(mesh.GetTriangles(i)); } }
private Mesh SimplifyMesh(Mesh source, float quality, Action <Mesh> complete) { var simplifiedMesh = new Mesh(); var inputMesh = source.ToWorkingMesh(); var outputMesh = new WorkingMesh(); var meshSimplifier = (IMeshSimplifier)Activator.CreateInstance(AutoLOD.meshSimplifierType); meshSimplifier.Simplify(inputMesh, outputMesh, quality, () => { outputMesh.ApplyToMesh(simplifiedMesh); simplifiedMesh.RecalculateBounds(); if (complete != null) { complete(simplifiedMesh); } }); return(simplifiedMesh); }
private WorkingObject CreateBakedTerrain(string name, Bounds bounds, Heightmap heightmap, int distance) { WorkingObject wo = new WorkingObject(Allocator.Persistent); wo.Name = name; m_queue.EnqueueJob(() => { WorkingMesh mesh = CreateBakedGeometry(name, heightmap, bounds, distance); wo.SetMesh(mesh); }); m_queue.EnqueueJob(() => { WorkingMaterial material = CreateBakedMaterial(name, bounds); wo.Materials.Add(material); }); return(wo); }
private void ConvertMesh(WorkingMesh mesh, DisposableList <WorkingMaterial> materials, TexturePacker.TextureAtlas atlas, string mainTextureName) { var uv = mesh.uv; var updated = new bool[uv.Length]; // Some meshes have submeshes that either aren't expected to render or are missing a material, so go ahead and skip int subMeshCount = Mathf.Min(mesh.subMeshCount, materials.Count); for (int mi = 0; mi < subMeshCount; ++mi) { int[] indices = mesh.GetTriangles(mi); foreach (var i in indices) { if (updated[i] == false) { var uvCoord = uv[i]; var texture = materials[mi].GetTexture(mainTextureName); if (texture == null || texture.GetGUID() == Guid.Empty) { // Sample at center of white texture to avoid sampling edge colors incorrectly uvCoord.x = 0.5f; uvCoord.y = 0.5f; } else { var uvOffset = atlas.GetUV(texture.GetGUID()); uvCoord.x = Mathf.Lerp(uvOffset.xMin, uvOffset.xMax, uvCoord.x); uvCoord.y = Mathf.Lerp(uvOffset.yMin, uvOffset.yMax, uvCoord.y); } uv[i] = uvCoord; updated[i] = true; } } } mesh.uv = uv; }
private WorkingObject CreateBakedTerrain(string name, Bounds bounds, Heightmap heightmap, int distance, bool isLeaf) { WorkingObject wo = new WorkingObject(Allocator.Persistent); wo.Name = name; wo.LightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; m_queue.EnqueueJob(() => { WorkingMesh mesh = CreateBakedGeometry(name, heightmap, bounds, distance); wo.SetMesh(mesh); }); m_queue.EnqueueJob(() => { WorkingMaterial material = CreateBakedMaterial(name, bounds, isLeaf); wo.Materials.Add(material); }); return(wo); }
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 WorkingMesh MakeFillHoleMesh(WorkingMesh source) { int totalTris = 0; List <int[]> newTris = new List <int[]>(); for (int si = 0; si < source.subMeshCount; ++si) { List <int> tris = source.GetTriangles(si).ToList(); List <Vector2Int> edgeList = GetEdgeList(tris); List <EdgeGroup> groups = new List <EdgeGroup>(); for (int i = 0; i < edgeList.Count; ++i) { EdgeGroup group = new EdgeGroup(); group.Begin = edgeList[i].x; group.End = edgeList[i].y; group.EdgeList.Add(edgeList[i]); groups.Add(group); } bool isFinish = false; while (isFinish == false) { isFinish = true; for (int gi1 = 0; gi1 < groups.Count; ++gi1) { for (int gi2 = gi1 + 1; gi2 < groups.Count; ++gi2) { EdgeGroup g1 = groups[gi1]; EdgeGroup g2 = groups[gi2]; if (g1.End == g2.Begin) { g1.End = g2.End; g1.EdgeList.AddRange(g2.EdgeList); groups[gi2] = groups[groups.Count - 1]; groups.RemoveAt(groups.Count - 1); gi2 -= 1; isFinish = false; } else if (g1.Begin == g2.End) { g2.End = g1.End; g2.EdgeList.AddRange(g1.EdgeList); groups[gi1] = groups[gi2]; groups[gi2] = groups[groups.Count - 1]; groups.RemoveAt(groups.Count - 1); gi2 -= 1; isFinish = false; } } } } for (int gi = 0; gi < groups.Count; ++gi) { EdgeGroup group = groups[gi]; for (int ei1 = 1; ei1 < group.EdgeList.Count - 1; ++ei1) { for (int ei2 = ei1 + 1; ei2 < group.EdgeList.Count; ++ei2) { if (group.EdgeList[ei1].x == group.EdgeList[ei2].y) { EdgeGroup ng = new EdgeGroup(); ng.Begin = group.EdgeList[ei1].x; ng.End = group.EdgeList[ei2].y; for (int i = ei1; i <= ei2; ++i) { ng.EdgeList.Add(group.EdgeList[i]); } for (int i = ei2; i >= ei1; --i) { group.EdgeList.RemoveAt(i); } groups.Add(ng); ei1 = 0; // goto first break; } } } } if (groups.Count == 0) { continue; } groups.Sort((g1, g2) => { return(g2.EdgeList.Count - g1.EdgeList.Count); }); //first group( longest group ) is outline. for (int i = 1; i < groups.Count; ++i) { EdgeGroup group = groups[i]; for (int ei = 1; ei < group.EdgeList.Count - 1; ++ei) { tris.Add(group.Begin); tris.Add(group.EdgeList[ei].y); tris.Add(group.EdgeList[ei].x); } } totalTris += tris.Count; newTris.Add(tris.ToArray()); } WorkingMesh mesh = new WorkingMesh(Allocator.Persistent, source.vertexCount, totalTris, source.subMeshCount, 0); mesh.name = source.name; mesh.vertices = source.vertices; mesh.normals = source.normals; mesh.uv = source.uv; for (int i = 0; i < newTris.Count; ++i) { mesh.SetTriangles(newTris[i], i); } return(mesh); }
private WorkingMesh MakeBorder(WorkingMesh source, Heightmap heightmap, int borderCount) { List <Vector3> vertices = source.vertices.ToList(); List <Vector3> normals = source.normals.ToList(); List <Vector2> uvs = source.uv.ToList(); List <int[]> subMeshTris = new List <int[]>(); int maxTris = 0; for (int si = 0; si < source.subMeshCount; ++si) { List <int> tris = source.GetTriangles(si).ToList(); List <Vector2Int> edges = GetEdgeList(tris); HashSet <int> vertexIndces = new HashSet <int>(); List <BorderVertex> edgeVertices = new List <BorderVertex>(); for (int ei = 0; ei < edges.Count; ++ei) { vertexIndces.Add(edges[ei].x); vertexIndces.Add(edges[ei].y); } List <BorderVertex> borderVertices = GenerateBorderVertices(heightmap, borderCount); //calculate closest vertex from border vertices. for (int i = 0; i < borderVertices.Count; ++i) { float closestDistance = Single.MaxValue; BorderVertex v = borderVertices[i]; foreach (var index in vertexIndces) { Vector3 pos = vertices[index]; float dist = Vector3.SqrMagnitude(pos - borderVertices[i].Pos); if (dist < closestDistance) { closestDistance = dist; v.ClosestIndex = index; } } borderVertices[i] = v; } //generate tris int startAddIndex = vertices.Count; for (int bi = 0; bi < borderVertices.Count; ++bi) { int next = (bi == borderVertices.Count - 1) ? 0 : bi + 1; tris.Add(bi + startAddIndex); tris.Add(borderVertices[bi].ClosestIndex); tris.Add(next + startAddIndex); Vector2 uv; uv.x = (borderVertices[bi].Pos.x - heightmap.Offset.x) / heightmap.Size.x; uv.y = (borderVertices[bi].Pos.z - heightmap.Offset.z) / heightmap.Size.z; vertices.Add(borderVertices[bi].Pos); if (m_hlod.UseNormal) { normals.Add(Vector3.up); } else { normals.Add(heightmap.GetInterpolatedNormal(uv.x, uv.y)); } uvs.Add(uv); if (borderVertices[bi].ClosestIndex == borderVertices[next].ClosestIndex) { continue; } tris.Add(borderVertices[bi].ClosestIndex); tris.Add(borderVertices[next].ClosestIndex); tris.Add(next + startAddIndex); } maxTris += tris.Count; subMeshTris.Add(tris.ToArray()); } WorkingMesh mesh = new WorkingMesh(Allocator.Persistent, vertices.Count, maxTris, subMeshTris.Count, 0); mesh.name = source.name; mesh.vertices = vertices.ToArray(); mesh.normals = normals.ToArray(); mesh.uv = uvs.ToArray(); for (int i = 0; i < subMeshTris.Count; ++i) { mesh.SetTriangles(subMeshTris[i], i); } return(mesh); }
public WorkingMesh CombineMesh(Allocator allocator, List <CombineInfo> infos) { //I didn't consider animation mesh combine. int verticesCount = 0; int normalCount = 0; int tangentCount = 0; int UV1Count = 0; int UV2Count = 0; int UV3Count = 0; int UV4Count = 0; int colorCount = 0; int trianglesCount = 0; List <Dictionary <int, int> > remappers = new List <Dictionary <int, int> >(infos.Count); for (int i = 0; i < infos.Count; ++i) { int[] meshIndices = infos[i].Mesh.GetTriangles(infos[i].MeshIndex); Dictionary <int, int> remapper = CalculateMeshRemap(meshIndices); verticesCount += (infos[i].Mesh.vertices.Length > 0) ? remapper.Count : 0; normalCount += (infos[i].Mesh.normals.Length > 0) ? remapper.Count : 0; tangentCount += (infos[i].Mesh.tangents.Length > 0) ? remapper.Count : 0; UV1Count += (infos[i].Mesh.uv.Length > 0) ? remapper.Count : 0; UV2Count += (infos[i].Mesh.uv2.Length > 0) ? remapper.Count : 0; UV3Count += (infos[i].Mesh.uv3.Length > 0) ? remapper.Count : 0; UV4Count += (infos[i].Mesh.uv4.Length > 0) ? remapper.Count : 0; colorCount += (infos[i].Mesh.colors.Length > 0) ? remapper.Count : 0; trianglesCount += meshIndices.Length; remappers.Add(remapper); } WorkingMesh combinedMesh = new WorkingMesh(allocator, verticesCount, trianglesCount, 1, 0); List <Vector3> vertices = new List <Vector3>(verticesCount); List <Vector3> normals = new List <Vector3>(verticesCount); List <Vector4> tangents = new List <Vector4>(verticesCount); List <Vector2> uv1s = new List <Vector2>(verticesCount); List <Vector2> uv2s = new List <Vector2>(verticesCount); List <Vector2> uv3s = new List <Vector2>(verticesCount); List <Vector2> uv4s = new List <Vector2>(verticesCount); List <Color> colors = new List <Color>(colorCount); List <int> triangles = new List <int>(trianglesCount); for (int i = 0; i < infos.Count; ++i) { WorkingMesh mesh = infos[i].Mesh; Dictionary <int, int> remapper = remappers[i]; int startIndex = vertices.Count; if (verticesCount > 0) { FillBuffer(ref vertices, mesh.vertices, remapper, Vector3.zero); for (int vi = startIndex; vi < vertices.Count; ++vi) { vertices[vi] = infos[i].Transform.MultiplyPoint(vertices[vi]); } } if (normalCount > 0) { FillBuffer(ref normals, mesh.normals, remapper, Vector3.up); for (int ni = startIndex; ni < normals.Count; ++ni) { normals[ni] = infos[i].Transform.MultiplyVector(normals[ni]); } } if (tangentCount > 0) { FillBuffer(ref tangents, mesh.tangents, remapper, new Vector4(1, 0, 0, 1)); for (int ti = startIndex; ti < tangents.Count; ++ti) { Vector3 tanVec = new Vector3(tangents[ti].x, tangents[ti].y, tangents[ti].z); tanVec = infos[i].Transform.MultiplyVector(tanVec); Vector4 transTan = new Vector4(tanVec.x, tanVec.y, tanVec.z, tangents[ti].w); tangents[ti] = transTan; } } if (UV1Count > 0) { FillBuffer(ref uv1s, mesh.uv, remapper, Vector2.zero); } if (UV2Count > 0) { FillBuffer(ref uv2s, mesh.uv2, remapper, Vector2.zero); } if (UV3Count > 0) { FillBuffer(ref uv3s, mesh.uv3, remapper, Vector2.zero); } if (UV4Count > 0) { FillBuffer(ref uv4s, mesh.uv4, remapper, Vector2.zero); } if (colorCount > 0) { FillBuffer(ref colors, mesh.colors, remapper, Color.white); } FillIndices(ref triangles, mesh.GetTriangles(infos[i].MeshIndex), remapper, startIndex); } combinedMesh.name = "CombinedMesh"; combinedMesh.vertices = vertices.ToArray(); combinedMesh.normals = normals.ToArray(); combinedMesh.tangents = tangents.ToArray(); combinedMesh.uv = uv1s.ToArray(); combinedMesh.uv2 = uv2s.ToArray(); combinedMesh.uv3 = uv3s.ToArray(); combinedMesh.uv4 = uv4s.ToArray(); combinedMesh.colors = colors.ToArray(); combinedMesh.SetTriangles(triangles.ToArray(), 0); return(combinedMesh); }
public void Simplify(WorkingMesh inputMesh, WorkingMesh outputMesh, float quality) { var isMainThread = MonoBehaviourHelper.IsMainThread(); Renderer renderer = null; UnityCloudJob job = null; string jobName = null; var assembly = typeof(SharedData).Assembly; var cloudJobType = assembly.GetType("Simplygon.Cloud.Yoda.IntegrationClient.CloudJob"); var jobNameField = cloudJobType.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance); lock (executionLock) { const int kSimultaneousJobs = 4; //var processSubscriptionRestrictionsType = assembly.GetType("Simplygon.Cloud.Yoda.Client.ProcessSubscriptionRestrictions23"); //var simultaneousJobsProperty = processSubscriptionRestrictionsType.GetProperty("SimultaneousJobs"); //var accountType = assembly.GetType("Simplygon.Cloud.Yoda.Client.User23"); //var processSubscriptionsRestrictionsProperty = accountType.GetProperty("ProcessSubscriptionRestrictions"); //var processSubscriptionRestrictions = processSubscriptionsRestrictionsProperty.GetValue(SharedData.Instance.Account, null); //var simultaneousJobs = (int)simultaneousJobsProperty.GetValue(processSubscriptionRestrictions, null); while (SharedData.Instance.GeneralManager.JobManager.ProcessingJobCount >= kSimultaneousJobs) { if (!isMainThread) { Thread.Sleep(1000); } } MonoBehaviourHelper.ExecuteOnMainThread(() => { var go = EditorUtility.CreateGameObjectWithHideFlags("Temp", HideFlags.HideAndDontSave, typeof(MeshRenderer), typeof(MeshFilter)); var mf = go.GetComponent <MeshFilter>(); var mesh = new Mesh(); inputMesh.ApplyToMesh(mesh); mf.sharedMesh = mesh; renderer = go.GetComponent <MeshRenderer>(); var material = new Material(Shader.Find("Standard")); var sharedMaterials = new Material[mesh.subMeshCount]; for (int i = 0; i < mesh.subMeshCount; i++) { sharedMaterials[i] = material; } renderer.sharedMaterials = sharedMaterials; renderer.enabled = false; EditorWindow.GetWindow <Window>(); // Must be visible for background processing SharedData.Instance.Settings.SetDownloadAssetsAutomatically(true); var lodChainProperty = typeof(SharedData).GetProperty("LODChain"); var lodChainList = lodChainProperty.GetValue(SharedData.Instance, null) as IList; var lodChain = lodChainList[0]; var processNodeType = assembly.GetType("Simplygon.SPL.v80.Node.ProcessNode"); var processorProperty = processNodeType.GetProperty("Processor"); var processor = processorProperty.GetValue(lodChain, null); var reductionProcessorType = assembly.GetType("Simplygon.SPL.v80.Processor.ReductionProcessor"); var reductionSettingsProperty = reductionProcessorType.GetProperty("ReductionSettings"); var reductionSettingsType = assembly.GetType("Simplygon.SPL.v80.Settings.ReductionSettings"); var reductionSettings = reductionSettingsProperty.GetValue(processor, null); var triangleRatioProperty = reductionSettingsType.GetProperty("TriangleRatio"); triangleRatioProperty.SetValue(reductionSettings, quality, null); jobName = Path.GetRandomFileName().Replace(".", string.Empty); var prefabList = PrefabUtilityEx.GetPrefabsForSelection(new List <GameObject>() { go }); var generalManager = SharedData.Instance.GeneralManager; generalManager.CreateJob(jobName, "myPriority", prefabList, () => { foreach (var j in generalManager.JobManager.Jobs) { var name = (string)jobNameField.GetValue(j.CloudJob); if (name == jobName) { job = j; } } }); }); while (job == null) { if (!isMainThread) { Thread.Sleep(100); } } } while (string.IsNullOrEmpty(job.AssetDirectory)) { if (!isMainThread) { Thread.Sleep(100); } } MonoBehaviourHelper.ExecuteOnMainThread(() => { var customDataType = assembly.GetType("Simplygon.Cloud.Yoda.IntegrationClient.CloudJob+CustomData"); var pendingFolderNameProperty = customDataType.GetProperty("UnityPendingLODFolderName"); var jobCustomDataProperty = cloudJobType.GetProperty("JobCustomData"); var jobCustomData = jobCustomDataProperty.GetValue(job.CloudJob, null); var jobFolderName = pendingFolderNameProperty.GetValue(jobCustomData, null) as string; var lodAssetDir = "Assets/LODs/" + job.AssetDirectory; var mesh = AssetDatabase.LoadAssetAtPath <Mesh>(string.Format("{0}/{1}_LOD1.prefab", lodAssetDir, jobName)); mesh.ApplyToWorkingMesh(outputMesh); //job.CloudJob.StateHandler.RequestJobDeletion(); AssetDatabaseEx.DeletePendingLODFolder(jobFolderName); AssetDatabase.DeleteAsset(lodAssetDir); UnityObject.DestroyImmediate(renderer.gameObject); }); }
protected override IEnumerator GetSimplifiedMesh(Utils.WorkingMesh origin, float quality, Action <Utils.WorkingMesh> resultCallback) { var meshSimplifier = new global::UnityMeshSimplifier.MeshSimplifier(); meshSimplifier.SimplificationOptions = new global::UnityMeshSimplifier.SimplificationOptions { PreserveBorderEdges = m_options.PreserveBorderEdges, PreserveUVSeamEdges = m_options.PreserveUVSeamEdges, PreserveUVFoldoverEdges = m_options.PreserveUVFoldoverEdges, PreserveSurfaceCurvature = m_options.PreserveSurfaceCurvature, EnableSmartLink = m_options.EnableSmartLink, VertexLinkDistance = m_options.VertexLinkDistance, MaxIterationCount = m_options.MaxIterationCount, Agressiveness = m_options.Agressiveness, ManualUVComponentCount = m_options.ManualUVComponentCount, UVComponentCount = m_options.UVComponentCount, }; meshSimplifier.Vertices = origin.vertices; meshSimplifier.Normals = origin.normals; meshSimplifier.Tangents = origin.tangents; meshSimplifier.UV1 = origin.uv; meshSimplifier.UV2 = origin.uv2; meshSimplifier.UV3 = origin.uv3; meshSimplifier.UV4 = origin.uv4; meshSimplifier.Colors = origin.colors; var triangles = new int[origin.subMeshCount][]; for (var submesh = 0; submesh < origin.subMeshCount; submesh++) { triangles[submesh] = origin.GetTriangles(submesh); } meshSimplifier.AddSubMeshTriangles(triangles); meshSimplifier.SimplifyMesh(quality); int triCount = 0; for (int i = 0; i < meshSimplifier.SubMeshCount; ++i) { triCount += meshSimplifier.GetSubMeshTriangles(i).Length; } Utils.WorkingMesh nwm = new WorkingMesh(Allocator.Persistent, meshSimplifier.Vertices.Length, triCount, meshSimplifier.SubMeshCount, 0); nwm.name = origin.name; nwm.vertices = meshSimplifier.Vertices; nwm.normals = meshSimplifier.Normals; nwm.tangents = meshSimplifier.Tangents; nwm.uv = meshSimplifier.UV1; nwm.uv2 = meshSimplifier.UV2; nwm.uv3 = meshSimplifier.UV3; nwm.uv4 = meshSimplifier.UV4; nwm.colors = meshSimplifier.Colors; nwm.subMeshCount = meshSimplifier.SubMeshCount; for (var submesh = 0; submesh < nwm.subMeshCount; submesh++) { nwm.SetTriangles(meshSimplifier.GetSubMeshTriangles(submesh), submesh); } if (resultCallback != null) { resultCallback(nwm); } yield break; }
private WorkingMesh CreateBakedGeometry(string name, Heightmap heightmap, Bounds bounds, int distance) { int borderWidth = CalcBorderWidth(heightmap, distance); int borderWidth2x = borderWidth * 2; WorkingMesh mesh = new WorkingMesh(Allocator.Persistent, heightmap.Width * heightmap.Height, (heightmap.Width - borderWidth2x - 1) * (heightmap.Height - borderWidth2x - 1) * 6, 1, 0); mesh.name = name + "_Mesh"; Vector3[] vertices = new Vector3[(heightmap.Width - borderWidth2x) * (heightmap.Height - borderWidth2x)]; Vector3[] normals = new Vector3[(heightmap.Width - borderWidth2x) * (heightmap.Height - borderWidth2x)]; Vector2[] uvs = new Vector2[(heightmap.Width - borderWidth2x) * (heightmap.Height - borderWidth2x)]; int[] triangles = new int[(heightmap.Width - borderWidth2x - 1) * (heightmap.Height - borderWidth2x - 1) * 6]; int vi = 0; //except boder line for (int z = borderWidth; z < heightmap.Height - borderWidth; ++z) { for (int x = borderWidth; x < heightmap.Width - borderWidth; ++x) { int index = vi++; vertices[index].x = bounds.size.x * (x) / (heightmap.Width - 1) + bounds.min.x; vertices[index].y = heightmap.Size.y * heightmap[z, x]; vertices[index].z = bounds.size.z * (z) / (heightmap.Height - 1) + bounds.min.z; uvs[index].x = (float)x / (heightmap.Width - 1); uvs[index].y = (float)z / (heightmap.Height - 1); if (m_hlod.UseNormal) { normals[index] = Vector3.up; } else { normals[index] = heightmap.GetInterpolatedNormal(uvs[index].x, uvs[index].y); } } } int ii = 0; for (int z = 0; z < heightmap.Height - borderWidth2x - 1; ++z) { for (int x = 0; x < heightmap.Width - borderWidth2x - 1; ++x) { int i00 = z * (heightmap.Width - borderWidth2x) + x; int i10 = z * (heightmap.Width - borderWidth2x) + x + 1; int i01 = (z + 1) * (heightmap.Width - borderWidth2x) + x; int i11 = (z + 1) * (heightmap.Width - borderWidth2x) + x + 1; triangles[ii + 0] = i00; triangles[ii + 1] = i11; triangles[ii + 2] = i10; triangles[ii + 3] = i11; triangles[ii + 4] = i00; triangles[ii + 5] = i01; ii += 6; } } mesh.vertices = vertices; mesh.normals = normals; mesh.uv = uvs; mesh.SetTriangles(triangles, 0); return(mesh); }
static void GenerateMeshLOD(MeshLOD meshLOD, HashSet <int> preprocessMeshes) { // A NOP to make sure we have an instance before launching into threads that may need to execute on the main thread MonoBehaviourHelper.ExecuteOnMainThread(() => { }); WorkingMesh inputMesh = null; var inputMeshID = meshLOD.inputMesh.GetInstanceID(); if (!preprocessMeshes.Contains(inputMeshID)) { inputMesh = meshLOD.inputMesh.ToWorkingMesh(); } var meshSimplifier = (IMeshSimplifier)Activator.CreateInstance(meshSimplifierType); #if !SINGLE_THREADED var worker = new BackgroundWorker(); worker.DoWork += (sender, args) => { // If this mesh is dependent on another mesh, then let it complete first if (inputMesh == null) { while (preprocessMeshes.Contains(inputMeshID)) { Thread.Sleep(100); } MonoBehaviourHelper.ExecuteOnMainThread(() => inputMesh = meshLOD.inputMesh.ToWorkingMesh()); } #endif var outputMesh = new WorkingMesh(); #if UNITY_2017_3_OR_NEWER outputMesh.indexFormat = inputMesh.indexFormat; #endif meshSimplifier.Simplify(inputMesh, outputMesh, meshLOD.quality); #if !SINGLE_THREADED args.Result = outputMesh; }; #endif #if !SINGLE_THREADED worker.RunWorkerCompleted += (sender, args) => #endif { var outMesh = meshLOD.outputMesh; Debug.Log("Completed LOD " + outMesh.name); #if !SINGLE_THREADED var resultMesh = (WorkingMesh)args.Result; #else var resultMesh = outputMesh; #endif resultMesh.name = outMesh.name; resultMesh.ApplyToMesh(outMesh); outMesh.RecalculateBounds(); var outputMeshID = outMesh.GetInstanceID(); if (preprocessMeshes.Remove(outputMeshID)) { Debug.Log("Pre-process mesh complete: " + outputMeshID); } }; #if !SINGLE_THREADED worker.RunWorkerAsync(); #endif }
public void Simplify(WorkingMesh inputMesh, WorkingMesh outputMesh, float quality) { Renderer renderer = null; MonoBehaviourHelper.ExecuteOnMainThread(() => { var go = EditorUtility.CreateGameObjectWithHideFlags("Temp", HideFlags.HideAndDontSave, typeof(MeshRenderer), typeof(MeshFilter)); var mf = go.GetComponent <MeshFilter>(); var mesh = new Mesh(); inputMesh.ApplyToMesh(mesh); mf.sharedMesh = mesh; renderer = go.GetComponent <MeshRenderer>(); var material = new Material(Shader.Find("Standard")); var sharedMaterials = new Material[mesh.subMeshCount]; for (int i = 0; i < mesh.subMeshCount; i++) { sharedMaterials[i] = material; } renderer.sharedMaterials = sharedMaterials; renderer.enabled = false; }); var settings = new InstaLODOptimizeSettings(quality); settings.PercentTriangles = quality; var nativeMeshSettings = new InstaLODNativeMeshOperationSettings(true); nativeMeshSettings.hideSourceGameObjects = false; lock (executionLock) { if (!MonoBehaviourHelper.IsMainThread()) { while (InstaLODNative.currentMeshOperationState != null) { Thread.Sleep(100); } } MonoBehaviourHelper.ExecuteOnMainThread(() => { EditorWindow.GetWindow <InstaLODToolkitWindow>(); // Necessary for background processing InstaLODNative.Optimize(new List <Renderer>() { renderer }, settings, nativeMeshSettings); Selection.activeGameObject = null; // Necessary to avoid errors from InstaLOD trying to add settings component to imported model }); } while (InstaLODNative.currentMeshOperationState != null) { if (MonoBehaviourHelper.IsMainThread()) { InstaLODMainThreadAction.RunMainThreadActions(); } else { Thread.Sleep(100); } } MonoBehaviourHelper.ExecuteOnMainThread(() => { var mf = renderer.GetComponent <MeshFilter>(); mf.sharedMesh.ApplyToWorkingMesh(outputMesh); UnityObject.DestroyImmediate(mf.gameObject); }); }