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();
        }
Beispiel #2
0
    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"));
        }
Beispiel #4
0
    // 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"));
        }
Beispiel #7
0
        /// <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"));
        }
Beispiel #8
0
        /// <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();
        }