/// <summary> /// Import mesh data from a GameObject's MeshFilter.sharedMesh and MeshRenderer.sharedMaterials. /// </summary> /// <param name="gameObject">The GameObject to search for MeshFilter and MeshRenderer data.</param> /// <param name="importSettings">Optional settings parameter defines import customization properties.</param> /// <returns>True if the mesh data was successfully translated to the ProBuilderMesh target, false if something went wrong.</returns> internal bool Import(GameObject gameObject, MeshImportSettings importSettings = null) { if (gameObject == null) { throw new ArgumentNullException("gameObject"); } MeshFilter meshFilter = gameObject.GetComponent <MeshFilter>(); MeshRenderer mr = gameObject.GetComponent <MeshRenderer>(); if (meshFilter == null || meshFilter.sharedMesh == null) { Log.Error("GameObject does not contain a valid MeshFilter or sharedMesh."); return(false); } try { Import(meshFilter.sharedMesh, mr ? mr.sharedMaterials : null, importSettings); } catch (Exception e) { Log.Warning(e.ToString()); return(false); } return(true); }
public bool Import(GameObject go, MeshImportSettings importSettings = null) { try { m_SourceMesh = go.GetComponent <MeshFilter>().sharedMesh; m_SourceMaterials = go.GetComponent <MeshRenderer>()?.sharedMaterials; Import(importSettings); } catch (Exception e) { Log.Error(e.ToString()); return(false); } return(true); }
/// <summary> /// Imports mesh data from a GameObject's <see cref="UnityEngine.MeshFilter.sharedMesh"/> and /// <see cref="UnityEngine.Renderer.sharedMaterials"/> properties. /// </summary> /// <param name="importSettings">Optional import customization settings.</param> /// <exception cref="NotSupportedException">Import only supports triangle and quad mesh topologies.</exception> public void Import(MeshImportSettings importSettings = null) { if (importSettings == null) { importSettings = k_DefaultImportSettings; } // When importing the mesh is always split into triangles with no vertices shared // between faces. In a later step co-incident vertices are collapsed (eg, before // leaving the Import function). Vertex[] sourceVertices = m_SourceMesh.GetVertices(); List <Vertex> splitVertices = new List <Vertex>(); List <Face> faces = new List <Face>(); // Fill in Faces array with just the position indexes. In the next step we'll // figure out smoothing groups & merging int vertexIndex = 0; int materialCount = m_SourceMaterials != null ? m_SourceMaterials.Length : 0; for (int submeshIndex = 0; submeshIndex < m_SourceMesh.subMeshCount; submeshIndex++) { switch (m_SourceMesh.GetTopology(submeshIndex)) { case MeshTopology.Triangles: { int[] indexes = m_SourceMesh.GetIndices(submeshIndex); for (int tri = 0; tri < indexes.Length; tri += 3) { faces.Add(new Face( new int[] { vertexIndex, vertexIndex + 1, vertexIndex + 2 }, Math.Clamp(submeshIndex, 0, materialCount - 1), AutoUnwrapSettings.tile, Smoothing.smoothingGroupNone, -1, -1, true)); splitVertices.Add(sourceVertices[indexes[tri]]); splitVertices.Add(sourceVertices[indexes[tri + 1]]); splitVertices.Add(sourceVertices[indexes[tri + 2]]); vertexIndex += 3; } } break; case MeshTopology.Quads: { int[] indexes = m_SourceMesh.GetIndices(submeshIndex); for (int quad = 0; quad < indexes.Length; quad += 4) { faces.Add(new Face(new int[] { vertexIndex, vertexIndex + 1, vertexIndex + 2, vertexIndex + 2, vertexIndex + 3, vertexIndex + 0 }, Math.Clamp(submeshIndex, 0, materialCount - 1), AutoUnwrapSettings.tile, Smoothing.smoothingGroupNone, -1, -1, true)); splitVertices.Add(sourceVertices[indexes[quad]]); splitVertices.Add(sourceVertices[indexes[quad + 1]]); splitVertices.Add(sourceVertices[indexes[quad + 2]]); splitVertices.Add(sourceVertices[indexes[quad + 3]]); vertexIndex += 4; } } break; default: throw new NotSupportedException("ProBuilder only supports importing triangle and quad meshes."); } } m_Vertices = splitVertices.ToArray(); m_Destination.Clear(); m_Destination.SetVertices(m_Vertices); m_Destination.faces = faces; m_Destination.sharedVertices = SharedVertex.GetSharedVerticesWithPositions(m_Destination.positionsInternal); m_Destination.sharedTextures = new SharedVertex[0]; if (importSettings.quads) { var newFaces = m_Destination.ToQuads(m_Destination.facesInternal, !importSettings.smoothing); } if (importSettings.smoothing) { Smoothing.ApplySmoothingGroups(m_Destination, m_Destination.facesInternal, importSettings.smoothingAngle, m_Vertices.Select(x => x.normal).ToArray()); // After smoothing has been applied go back and weld coincident vertices created by MergePairs. MergeElements.CollapseCoincidentVertices(m_Destination, m_Destination.facesInternal); } }
/// <summary> /// Import mesh data from a GameObject's MeshFilter.sharedMesh and MeshRenderer.sharedMaterials. /// </summary> /// <param name="originalMesh">The UnityEngine.Mesh to extract attributes from.</param> /// <param name="materials">The materials array corresponding to the originalMesh submeshes.</param> /// <param name="importSettings">Optional settings parameter defines import customization properties.</param> /// <exception cref="NotSupportedException">Import only supports triangle and quad mesh topologies.</exception> public void Import(MeshImportSettings importSettings = null) { if (importSettings == null) { importSettings = k_DefaultImportSettings; } // When importing the mesh is always split into triangles with no vertices shared // between faces. In a later step co-incident vertices are collapsed (eg, before // leaving the Import function). Vertex[] sourceVertices = m_SourceMesh.GetVertices(); List <Vertex> splitVertices = new List <Vertex>(); List <Face> faces = new List <Face>(); // Fill in Faces array with just the position indexes. In the next step we'll // figure out smoothing groups & merging int vertexIndex = 0; int materialCount = m_SourceMaterials != null ? m_SourceMaterials.Length : 0; for (int submeshIndex = 0; submeshIndex < m_SourceMesh.subMeshCount; submeshIndex++) { switch (m_SourceMesh.GetTopology(submeshIndex)) { case MeshTopology.Triangles: { int[] indexes = m_SourceMesh.GetIndices(submeshIndex); for (int tri = 0; tri < indexes.Length; tri += 3) { faces.Add(new Face( new int[] { vertexIndex, vertexIndex + 1, vertexIndex + 2 }, Math.Clamp(submeshIndex, 0, materialCount - 1), AutoUnwrapSettings.tile, Smoothing.smoothingGroupNone, -1, -1, true)); splitVertices.Add(sourceVertices[indexes[tri]]); splitVertices.Add(sourceVertices[indexes[tri + 1]]); splitVertices.Add(sourceVertices[indexes[tri + 2]]); vertexIndex += 3; } } break; case MeshTopology.Quads: { int[] indexes = m_SourceMesh.GetIndices(submeshIndex); for (int quad = 0; quad < indexes.Length; quad += 4) { faces.Add(new Face(new int[] { vertexIndex, vertexIndex + 1, vertexIndex + 2, vertexIndex + 2, vertexIndex + 3, vertexIndex + 0 }, Math.Clamp(submeshIndex, 0, materialCount - 1), AutoUnwrapSettings.tile, Smoothing.smoothingGroupNone, -1, -1, true)); splitVertices.Add(sourceVertices[indexes[quad]]); splitVertices.Add(sourceVertices[indexes[quad + 1]]); splitVertices.Add(sourceVertices[indexes[quad + 2]]); splitVertices.Add(sourceVertices[indexes[quad + 3]]); vertexIndex += 4; } } break; default: throw new NotSupportedException("ProBuilder only supports importing triangle and quad meshes."); } } m_Vertices = splitVertices.ToArray(); m_Destination.Clear(); m_Destination.SetVertices(m_Vertices); m_Destination.faces = faces; m_Destination.sharedVertices = SharedVertex.GetSharedVerticesWithPositions(m_Destination.positionsInternal); m_Destination.sharedTextures = new SharedVertex[0]; HashSet <Face> processed = new HashSet <Face>(); if (importSettings.quads) { List <WingedEdge> wings = WingedEdge.GetWingedEdges(m_Destination, m_Destination.facesInternal, true); // build a lookup of the strength of edge connections between triangle faces Dictionary <EdgeLookup, float> connections = new Dictionary <EdgeLookup, float>(); for (int i = 0; i < wings.Count; i++) { using (var it = new WingedEdgeEnumerator(wings[i])) { while (it.MoveNext()) { var border = it.Current; if (border.opposite != null && !connections.ContainsKey(border.edge)) { float score = GetQuadScore(border, border.opposite); connections.Add(border.edge, score); } } } } List <SimpleTuple <Face, Face> > quads = new List <SimpleTuple <Face, Face> >(); // move through each face and find it's best quad neighbor foreach (WingedEdge face in wings) { if (!processed.Add(face.face)) { continue; } float bestScore = 0f; Face buddy = null; using (var it = new WingedEdgeEnumerator(face)) { while (it.MoveNext()) { var border = it.Current; if (border.opposite != null && processed.Contains(border.opposite.face)) { continue; } float borderScore; // only add it if the opposite face's best score is also this face if (connections.TryGetValue(border.edge, out borderScore) && borderScore > bestScore && face.face == GetBestQuadConnection(border.opposite, connections)) { bestScore = borderScore; buddy = border.opposite.face; } } } if (buddy != null) { processed.Add(buddy); quads.Add(new SimpleTuple <Face, Face>(face.face, buddy)); } } // don't collapse coincident vertices if smoothing is enabled, we need the original normals intact MergeElements.MergePairs(m_Destination, quads, !importSettings.smoothing); } if (importSettings.smoothing) { Smoothing.ApplySmoothingGroups(m_Destination, m_Destination.facesInternal, importSettings.smoothingAngle, m_Vertices.Select(x => x.normal).ToArray()); // After smoothing has been applied go back and weld coincident vertices created by MergePairs. MergeElements.CollapseCoincidentVertices(m_Destination, m_Destination.facesInternal); } }