void ExtrudeEdge() { // fetch a random perimeter edge connected to the last face extruded List <WingedEdge> wings = WingedEdge.GetWingedEdges(m_Mesh); IEnumerable <WingedEdge> sourceWings = wings.Where(x => x.face == m_LastExtrudedFace); List <Edge> nonManifoldEdges = sourceWings.Where(x => x.opposite == null).Select(y => y.edge.local).ToList(); int rand = (int)Random.Range(0, nonManifoldEdges.Count); Edge sourceEdge = nonManifoldEdges[rand]; // get the direction this edge should extrude in var edgeCenter = Math.Average(m_Mesh.positions, new[] { sourceEdge.a, sourceEdge.b }); var faceCenter = Math.Average(m_Mesh.positions, m_LastExtrudedFace.distinctIndexes); Vector3 dir = (edgeCenter - faceCenter).normalized; // this will be populated with the extruded edge Edge[] extrudedEdges; // perform extrusion extrudedEdges = m_Mesh.Extrude(new Edge[] { sourceEdge }, 0f, false, true); // get the last extruded face m_LastExtrudedFace = m_Mesh.faces.Last(); // translate the vertices m_Mesh.TranslateVertices(extrudedEdges, dir * distance); // rebuild mesh with new geometry added by extrude m_Mesh.ToMesh(); // rebuild mesh normals, textures, collisions, etc m_Mesh.Refresh(); }
private void Carve(Vector3 hitPoint) { int segmentIndexToCarve = 0; Vector3 minPoint = collider.bounds.min; float segmentSize = (float)height / heightSegmentCount; for (int i = 0; i <= heightSegmentCount; i++) { if (hitPoint.x <= minPoint.x + segmentSize * i) { segmentIndexToCarve = i; break; } } List <Face> facesToCarve = new List <Face>(); List <Edge> edgesToCarve = new List <Edge>(); for (int i = 0; i < faceLoopCount; i++) { int index = faceLoopCount * segmentIndexToCarve + i; facesToCarve.Add(mesh.faces[index]); edgesToCarve.AddRange(mesh.faces[index].edges); } mesh.Extrude(facesToCarve, ExtrudeMethod.FaceNormal, -Time.deltaTime / 2); //mesh.Extrude(edgesToCarve, -Time.deltaTime / 2, true, false); mesh.ToMesh(); mesh.Refresh(); }
/// <summary> /// Perform the action. /// </summary> /// <returns>Return a pb_ActionResult indicating the success/failure of action.</returns> public override ActionResult DoAction() { ShadowCastingMode shadowMode = (ShadowCastingMode)EditorPrefs.GetInt("pb_CreateShadowObject_shadowMode", (int)ShadowCastingMode.ShadowsOnly); float extrudeDistance = EditorPrefs.GetFloat("pb_CreateShadowObject_volumeSize", .08f); ExtrudeMethod extrudeMethod = (ExtrudeMethod)EditorPrefs.GetInt("pb_CreateShadowObject_extrudeMethod", (int)ExtrudeMethod.FaceNormal); foreach (ProBuilderMesh mesh in MeshSelection.top) { ProBuilderMesh shadow = GetShadowObject(mesh); if (shadow == null) { continue; } foreach (Face f in shadow.faces) { f.SetIndexes(f.indexes.Reverse().ToArray()); f.manualUV = true; } shadow.Extrude(shadow.faces, extrudeMethod, extrudeDistance); shadow.ToMesh(); shadow.Refresh(); shadow.Optimize(); #if !UNITY_4_6 && !UNITY_4_7 MeshRenderer mr = shadow.gameObject.GetComponent <MeshRenderer>(); mr.shadowCastingMode = shadowMode; if (shadowMode == ShadowCastingMode.ShadowsOnly) { mr.receiveShadows = false; } #endif Collider collider = shadow.GetComponent <Collider>(); while (collider != null) { Object.DestroyImmediate(collider); collider = shadow.GetComponent <Collider>(); } } // Refresh the Editor wireframe and working caches. ProBuilderEditor.Refresh(); return(new ActionResult(ActionResult.Status.Success, "Create Shadow Object")); }
// Extrude en utilisant le probuilder mesh public void Extrude(List <HalfEdge> face, float height) { Vector3[] facePoints = PointsPositionInFaces(face); int[] triangles = Triangulate(face); WingedEdgeMap.PrintArray(triangles); if (Vector3.Cross(facePoints[triangles[1]] - facePoints[triangles[0]], facePoints[triangles[2]] - facePoints[triangles[1]]).y <= 0f) { Array.Reverse(triangles); } WingedEdgeMap.PrintArray(triangles); ProBuilderMesh poly = ProBuilderMesh.Create(facePoints, new Face[] { new Face(triangles) }); poly.Extrude(poly.faces, ExtrudeMethod.FaceNormal, height); poly.ToMesh(); MeshRenderer mr = poly.GetComponent <MeshRenderer>(); mr.material = mat; poly.Refresh(); }
/// <summary> /// Rebuild a mesh from an ordered set of points. /// </summary> /// <param name="mesh">The target mesh. The mesh values will be cleared and repopulated with the shape extruded from points.</param> /// <param name="points">A path of points to triangulate and extrude.</param> /// <param name="extrude">The distance to extrude.</param> /// <param name="flipNormals">If true the faces will be inverted at creation.</param> /// <param name="holePoints">Holes in the polygon. If null this will be ignored.</param> /// <returns>An ActionResult with the status of the operation.</returns> public static ActionResult CreateShapeFromPolygon(this ProBuilderMesh mesh, IList <Vector3> points, float extrude, bool flipNormals, IList <IList <Vector3> > holePoints) { if (mesh == null) { throw new ArgumentNullException("mesh"); } if (points == null || points.Count < 3) { ClearAndRefreshMesh(mesh); return(new ActionResult(ActionResult.Status.NoChange, "Too Few Points")); } Vector3[] vertices = points.ToArray(); Vector3[][] holeVertices = null; if (holePoints != null && holePoints.Count > 0) { holeVertices = new Vector3[holePoints.Count][]; for (int i = 0; i < holePoints.Count; i++) { if (holePoints[i] == null || holePoints[i].Count < 3) { ClearAndRefreshMesh(mesh); return(new ActionResult(ActionResult.Status.NoChange, "Too Few Points in hole " + i)); } holeVertices[i] = holePoints[i].ToArray(); } } List <int> triangles; Log.PushLogLevel(LogLevel.Error); if (Triangulation.TriangulateVertices(vertices, out triangles, holeVertices)) { Vector3[] combinedVertices = null; if (holeVertices != null) { combinedVertices = new Vector3[vertices.Length + holeVertices.Sum(arr => arr.Length)]; Array.Copy(vertices, combinedVertices, vertices.Length); int destinationIndex = vertices.Length; foreach (var hole in holeVertices) { Array.ConstrainedCopy(hole, 0, combinedVertices, destinationIndex, hole.Length); destinationIndex += hole.Length; } } else { combinedVertices = vertices; } int[] indexes = triangles.ToArray(); if (Math.PolygonArea(combinedVertices, indexes) < Mathf.Epsilon) { ClearAndRefreshMesh(mesh); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Polygon Area < Epsilon")); } mesh.Clear(); mesh.positionsInternal = combinedVertices; var newFace = new Face(indexes); mesh.facesInternal = new[] { newFace }; mesh.sharedVerticesInternal = SharedVertex.GetSharedVerticesWithPositions(combinedVertices); mesh.InvalidateCaches(); // check that all points are represented in the triangulation if (newFace.distinctIndexesInternal.Length != combinedVertices.Length) { ClearAndRefreshMesh(mesh); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Triangulation missing points")); } Vector3 nrm = Math.Normal(mesh, mesh.facesInternal[0]); nrm = mesh.gameObject.transform.TransformDirection(nrm); if ((flipNormals ? Vector3.Dot(mesh.gameObject.transform.up, nrm) > 0f : Vector3.Dot(mesh.gameObject.transform.up, nrm) < 0f)) { mesh.facesInternal[0].Reverse(); } if (extrude != 0.0f) { mesh.DuplicateAndFlip(mesh.facesInternal); mesh.Extrude(new Face[] { (flipNormals ? mesh.facesInternal[1] : mesh.facesInternal[0]) }, ExtrudeMethod.IndividualFaces, extrude); if ((extrude < 0f && !flipNormals) || (extrude > 0f && flipNormals)) { foreach (var face in mesh.facesInternal) { face.Reverse(); } } } mesh.ToMesh(); mesh.Refresh(); } else { // clear mesh instead of showing an invalid one ClearAndRefreshMesh(mesh); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Failed Triangulating Points")); } Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Success, "Create Polygon Shape")); }
/// <summary> /// Rebuild a mesh from an ordered set of points. /// </summary> /// <param name="mesh">The target mesh. The mesh values will be cleared and repopulated with the shape extruded from points.</param> /// <param name="points">A path of points to triangulate and extrude.</param> /// <param name="extrude">The distance to extrude.</param> /// <param name="flipNormals">If true the faces will be inverted at creation.</param> /// <returns>An ActionResult with the status of the operation.</returns> public static ActionResult CreateShapeFromPolygon(this ProBuilderMesh mesh, IList <Vector3> points, float extrude, bool flipNormals) { if (mesh == null) { throw new ArgumentNullException("mesh"); } if (points == null || points.Count < 3) { mesh.Clear(); mesh.ToMesh(); mesh.Refresh(); return(new ActionResult(ActionResult.Status.NoChange, "Too Few Points")); } Vector3[] vertices = points.ToArray(); List <int> triangles; Log.PushLogLevel(LogLevel.Error); if (Triangulation.TriangulateVertices(vertices, out triangles, false)) { int[] indexes = triangles.ToArray(); if (Math.PolygonArea(vertices, indexes) < Mathf.Epsilon) { mesh.Clear(); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Polygon Area < Epsilon")); } mesh.Clear(); mesh.positionsInternal = vertices; mesh.facesInternal = new[] { new Face(indexes) }; mesh.sharedVerticesInternal = SharedVertex.GetSharedVerticesWithPositions(vertices); mesh.InvalidateCaches(); Vector3 nrm = Math.Normal(mesh, mesh.facesInternal[0]); if (Vector3.Dot(Vector3.up, nrm) > 0f) { mesh.facesInternal[0].Reverse(); } mesh.DuplicateAndFlip(mesh.facesInternal); mesh.Extrude(new Face[] { mesh.facesInternal[1] }, ExtrudeMethod.IndividualFaces, extrude); if ((extrude < 0f && !flipNormals) || (extrude > 0f && flipNormals)) { foreach (var face in mesh.facesInternal) { face.Reverse(); } } mesh.ToMesh(); mesh.Refresh(); } else { Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Failed Triangulating Points")); } Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Success, "Create Polygon Shape")); }
/// <summary> /// Rebuild a mesh from an ordered set of points. /// </summary> /// <param name="mesh">The target mesh. The mesh values will be cleared and repopulated with the shape extruded from points.</param> /// <param name="points">A path of points to triangulate and extrude.</param> /// <param name="extrude">The distance to extrude.</param> /// <param name="flipNormals">If true the faces will be inverted at creation.</param> /// <param name="cameraLookAt">If the normal of the polygon of the first face is facing in the same direction of the camera lookat it will be inverted at creation, so it is facing the camera.</param> /// <returns>An ActionResult with the status of the operation.</returns> public static ActionResult CreateShapeFromPolygon(this ProBuilderMesh mesh, IList <Vector3> points, float extrude, bool flipNormals, Vector3 cameraLookAt) { if (mesh == null) { throw new ArgumentNullException("mesh"); } if (points == null || points.Count < 3) { ClearAndRefreshMesh(mesh); return(new ActionResult(ActionResult.Status.NoChange, "Too Few Points")); } Vector3[] vertices = points.ToArray(); List <int> triangles; Log.PushLogLevel(LogLevel.Error); if (Triangulation.TriangulateVertices(vertices, out triangles, false)) { int[] indexes = triangles.ToArray(); if (Math.PolygonArea(vertices, indexes) < Mathf.Epsilon) { ClearAndRefreshMesh(mesh); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Polygon Area < Epsilon")); } mesh.Clear(); mesh.positionsInternal = vertices; var newFace = new Face(indexes); mesh.facesInternal = new[] { newFace }; mesh.sharedVerticesInternal = SharedVertex.GetSharedVerticesWithPositions(vertices); mesh.InvalidateCaches(); // check that all points are represented in the triangulation if (newFace.distinctIndexesInternal.Length != vertices.Length) { ClearAndRefreshMesh(mesh); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Triangulation missing points")); } Vector3 nrm = Math.Normal(mesh, mesh.facesInternal[0]); cameraLookAt.Normalize(); if ((flipNormals ? Vector3.Dot(cameraLookAt, nrm) < 0f : Vector3.Dot(cameraLookAt, nrm) > 0f)) { mesh.facesInternal[0].Reverse(); } if (extrude != 0.0f) { mesh.DuplicateAndFlip(mesh.facesInternal); mesh.Extrude(new Face[] { (flipNormals ? mesh.facesInternal[1] : mesh.facesInternal[0]) }, ExtrudeMethod.IndividualFaces, extrude); if ((extrude < 0f && !flipNormals) || (extrude > 0f && flipNormals)) { foreach (var face in mesh.facesInternal) { face.Reverse(); } } } mesh.ToMesh(); mesh.Refresh(); } else { // clear mesh instead of showing an invalid one ClearAndRefreshMesh(mesh); Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Failure, "Failed Triangulating Points")); } Log.PopLogLevel(); return(new ActionResult(ActionResult.Status.Success, "Create Polygon Shape")); }
/// <summary> /// Creates the sphere and loads all the cache information. /// </summary> void Start() { m_AudioSource = GetComponent <AudioSource>(); if (m_AudioSource.clip == null) { missingClipWarning.SetActive(true); } // Create a new sphere. m_ProBuilderMesh = ShapeGenerator.GenerateIcosahedron(PivotLocation.Center, icoRadius, icoSubdivisions); // Assign the default material m_ProBuilderMesh.GetComponent <MeshRenderer>().sharedMaterial = BuiltinMaterials.defaultMaterial; // Shell is all the faces on the new sphere. var shell = m_ProBuilderMesh.faces; // Extrude all faces on the sphere by a small amount. The third boolean parameter // specifies that extrusion should treat each face as an individual, not try to group // all faces together. m_ProBuilderMesh.Extrude(shell, ExtrudeMethod.IndividualFaces, startingExtrusion); // ToMesh builds the mesh positions, submesh, and triangle arrays. Call after adding // or deleting vertices, or changing face properties. m_ProBuilderMesh.ToMesh(); // Refresh builds the normals, tangents, and UVs. m_ProBuilderMesh.Refresh(); m_AnimatedSelections = new ExtrudedSelection[shell.Count]; // Populate the outsides[] cache. This is a reference to the tops of each extruded column, including // copies of the sharedIndices. for (int i = 0; i < shell.Count; ++i) { m_AnimatedSelections[i] = new ExtrudedSelection(m_ProBuilderMesh, shell[i]); } // Store copy of positions array un-modified m_OriginalVertexPositions = m_ProBuilderMesh.positions.ToArray(); // displaced_vertices should mirror sphere mesh vertices. m_DisplacedVertexPositions = new Vector3[m_ProBuilderMesh.vertexCount]; m_UnityMesh = m_ProBuilderMesh.GetComponent <MeshFilter>().sharedMesh; m_Transform = m_ProBuilderMesh.transform; m_FaceLength = (float)m_AnimatedSelections.Length; // Build the waveform ring. m_StartingPosition = m_Transform.position; waveform.positionCount = k_WaveformSampleCount; if (bounceWaveform) { waveform.transform.parent = m_Transform; } m_AudioSource.Play(); }