Ejemplo n.º 1
0
        //3d
        private static MyVector3 GetIntersectionCoordinate(Plane3 plane, Ray3 ray)
        {
            float denominator = MyVector3.Dot(-plane.normal, ray.dir);

            MyVector3 vecBetween = plane.pos - ray.origin;

            float t = MyVector3.Dot(vecBetween, -plane.normal) / denominator;

            MyVector3 intersectionPoint = ray.origin + ray.dir * t;

            return(intersectionPoint);
        }
Ejemplo n.º 2
0
        //Relations of a point to a plane

        //3d
        //Outside means in the planes normal direction
        public static bool IsPointOutsidePlane(Plane3 plane, MyVector3 pointPos)
        {
            float distance = GetSignedDistanceFromPointToPlane(plane, pointPos);

            //To avoid floating point precision issues we can add a small value
            float epsilon = MathUtility.EPSILON;

            if (distance > 0f + epsilon)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        //Is a list of points on one side of a plane?
        public static bool ArePointsOnOneSideOfPlane(List <MyVector3> points, Plane3 plane)
        {
            //First check the first point
            bool isInFront = _Geometry.IsPointOutsidePlane(plane, points[0]);

            for (int i = 1; i < points.Count; i++)
            {
                bool isOtherOutside = _Geometry.IsPointOutsidePlane(plane, points[i]);

                //We have found a point which is not at the same side of the plane as the first point
                if (isInFront != isOtherOutside)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 4
0
        //3d
        public static OutsideOnInside IsPoint_Outside_On_Inside_Plane(Plane3 plane, MyVector3 pointPos)
        {
            float distance = GetSignedDistanceFromPointToPlane(plane, pointPos);

            //To avoid floating point precision issues we can add a small value
            float epsilon = MathUtility.EPSILON;

            if (distance > 0f + epsilon)
            {
                return(OutsideOnInside.Outside);
            }
            else if (distance < 0f - epsilon)
            {
                return(OutsideOnInside.Inside);
            }
            else
            {
                return(OutsideOnInside.On);
            }
        }
Ejemplo n.º 5
0
        //Find a visible triangle from a point
        private static HalfEdgeFace3 FindVisibleTriangleFromPoint(Vector3 p, HashSet <HalfEdgeFace3> triangles)
        {
            HalfEdgeFace3 visibleTriangle = null;

            foreach (HalfEdgeFace3 triangle in triangles)
            {
                //A triangle is visible from a point the point is outside of a plane formed with the triangles position and normal
                Plane3 plane = new Plane3(triangle.edge.v.position, triangle.edge.v.normal);

                bool isPointOutsidePlane = _Geometry.IsPointOutsidePlane(p, plane);

                //We have found a triangle which is visible from the point and should be removed
                if (isPointOutsidePlane)
                {
                    visibleTriangle = triangle;

                    break;
                }
            }

            return(visibleTriangle);
        }
        //Cut a triangle where two vertices are inside and the other vertex is outside
        //Make sure they are sorted clockwise: O1-O2-I1
        //F means that this vertex is outside the plane
        private static void CutTriangleTwoOutside(MyMeshVertex O1, MyMeshVertex O2, MyMeshVertex I1, HalfEdgeData3 newMeshO, HalfEdgeData3 newMeshI, HashSet <HalfEdge3> newEdgesI, HashSet <HalfEdge3> newEdgesO, Plane3 cutPlane)
        {
            //Cut the triangle by using edge-plane intersection
            //Triangles in Unity are ordered clockwise, so form edges that intersects with the plane:
            Edge3 e_O2I1 = new Edge3(O2.position, I1.position);
            //Edge3 e_F1F2 = new Edge3(F1, F2); //Not needed because never intersects with the plane
            Edge3 e_I1O1 = new Edge3(I1.position, O1.position);

            //The positions of the intersection vertices
            MyVector3 pos_O2I1 = _Intersections.GetLinePlaneIntersectionPoint(cutPlane, e_O2I1);
            MyVector3 pos_I1O1 = _Intersections.GetLinePlaneIntersectionPoint(cutPlane, e_I1O1);

            //The normals of the intersection vertices
            float percentageBetween_O2I1 = MyVector3.Distance(O2.position, pos_O2I1) / MyVector3.Distance(O2.position, I1.position);
            float percentageBetween_I1O1 = MyVector3.Distance(I1.position, pos_I1O1) / MyVector3.Distance(I1.position, O1.position);

            MyVector3 normal_O2I1 = _Interpolation.Lerp(O2.normal, I1.normal, percentageBetween_O2I1);
            MyVector3 normal_I1O1 = _Interpolation.Lerp(I1.normal, O1.normal, percentageBetween_I1O1);

            //MyVector3 normal_F2B1 = Vector3.Slerp(F2.normal.ToVector3(), B1.normal.ToVector3(), percentageBetween_F2B1).ToMyVector3();
            //MyVector3 normal_B1F1 = Vector3.Slerp(B1.normal.ToVector3(), F1.normal.ToVector3(), percentageBetween_B1F1).ToMyVector3();

            normal_O2I1 = MyVector3.Normalize(normal_O2I1);
            normal_I1O1 = MyVector3.Normalize(normal_I1O1);

            //The intersection vertices
            MyMeshVertex v_O2I1 = new MyMeshVertex(pos_O2I1, normal_O2I1);
            MyMeshVertex v_I1O1 = new MyMeshVertex(pos_I1O1, normal_I1O1);


            //Form 3 new triangles
            //Outside
            AddTriangleToMesh(v_O2I1, v_I1O1, O2, newMeshO, newEdgesO);
            AddTriangleToMesh(O2, v_I1O1, O1, newMeshO, null);
            //Inside
            AddTriangleToMesh(v_I1O1, v_O2I1, I1, newMeshI, newEdgesI);
        }
        //Should return null if the mesh couldn't be cut because it doesn't intersect with the plane
        //Otherwise it should return two new meshes
        //meshTrans is needed so we can transform the cut plane to the mesh's local space
        public static List <Mesh> CutMesh(Transform meshTrans, OrientedPlane3 orientedCutPlaneGlobal)
        {
            //Validate the input data
            if (meshTrans == null)
            {
                Debug.Log("There's transform to cut");

                return(null);
            }

            Mesh mesh = meshTrans.GetComponent <MeshFilter>().mesh;

            if (mesh == null)
            {
                Debug.Log("There's no mesh to cut");

                return(null);
            }


            //The plane with just a normal
            Plane3 cutPlaneGlobal = orientedCutPlaneGlobal.Plane3;

            //First check if the AABB of the mesh is intersecting with the plane
            //Otherwise we can't cut the mesh, so its a waste of time

            //To get the AABB in world space we need to use the mesh renderer
            MeshRenderer mr = meshTrans.GetComponent <MeshRenderer>();

            if (mr != null)
            {
                AABB3 aabb = new AABB3(mr.bounds);

                //The corners of this box
                HashSet <MyVector3> corners = aabb.GetCorners();

                if (corners != null && corners.Count > 1)
                {
                    //The points are in world space so use the plane in world space
                    if (ArePointsOnOneSideOfPlane(new List <MyVector3>(corners), cutPlaneGlobal))
                    {
                        Debug.Log("This mesh can't be cut because its AABB doesnt intersect with the plane");

                        return(null);
                    }
                }
            }



            //The two meshes we might end up with after the cut
            //One is in front of the plane and another is in back of the plane
            HalfEdgeData3 newMeshO = new HalfEdgeData3();
            HalfEdgeData3 newMeshI = new HalfEdgeData3();

            //The data belonging to the original mesh
            Vector3[] vertices  = mesh.vertices;
            int[]     triangles = mesh.triangles;
            Vector3[] normals   = mesh.normals;

            //Save the new edges we add when cutting triangles that intersects with the plane
            //Need to be edges so we can later connect them with each other to fill the hole
            //And to remove small triangles
            HashSet <HalfEdge3> newEdgesO = new HashSet <HalfEdge3>();
            HashSet <HalfEdge3> newEdgesI = new HashSet <HalfEdge3>();


            //Transform the plane from global space to local space of the mesh
            MyVector3 planePosLocal    = meshTrans.InverseTransformPoint(cutPlaneGlobal.pos.ToVector3()).ToMyVector3();
            MyVector3 planeNormalLocal = meshTrans.InverseTransformDirection(cutPlaneGlobal.normal.ToVector3()).ToMyVector3();

            Plane3 cutPlane = new Plane3(planePosLocal, planeNormalLocal);


            //Loop through all triangles in the original mesh
            for (int i = 0; i < triangles.Length; i += 3)
            {
                //Get the triangle data we need
                int triangleIndex1 = triangles[i + 0];
                int triangleIndex2 = triangles[i + 1];
                int triangleIndex3 = triangles[i + 2];

                //Positions
                Vector3 p1_unity = vertices[triangleIndex1];
                Vector3 p2_unity = vertices[triangleIndex2];
                Vector3 p3_unity = vertices[triangleIndex3];

                MyVector3 p1 = p1_unity.ToMyVector3();
                MyVector3 p2 = p2_unity.ToMyVector3();
                MyVector3 p3 = p3_unity.ToMyVector3();

                //Normals
                MyVector3 n1 = normals[triangleIndex1].ToMyVector3();
                MyVector3 n2 = normals[triangleIndex2].ToMyVector3();
                MyVector3 n3 = normals[triangleIndex3].ToMyVector3();

                //To make it easier to send data to methods
                MyMeshVertex v1 = new MyMeshVertex(p1, n1);
                MyMeshVertex v2 = new MyMeshVertex(p2, n2);
                MyMeshVertex v3 = new MyMeshVertex(p3, n3);


                //First check on which side of the plane these vertices are
                //If they are all on one side we dont have to cut the triangle
                bool is_p1_front = _Geometry.IsPointOutsidePlane(cutPlane, v1.position);
                bool is_p2_front = _Geometry.IsPointOutsidePlane(cutPlane, v2.position);
                bool is_p3_front = _Geometry.IsPointOutsidePlane(cutPlane, v3.position);


                //Build triangles belonging to respective mesh

                //All are outside the plane
                if (is_p1_front && is_p2_front && is_p3_front)
                {
                    AddTriangleToMesh(v1, v2, v3, newMeshO, newEdges: null);
                }
                //All are inside the plane
                else if (!is_p1_front && !is_p2_front && !is_p3_front)
                {
                    AddTriangleToMesh(v1, v2, v3, newMeshI, newEdges: null);
                }
                //The vertices are on different sides of the plane, so we need to cut the triangle into 3 new triangles
                else
                {
                    //We get 6 cases where each vertex is on its own in front or in the back of the plane

                    //p1 is outside
                    if (is_p1_front && !is_p2_front && !is_p3_front)
                    {
                        CutTriangleOneOutside(v1, v2, v3, newMeshO, newMeshI, newEdgesI, newEdgesO, cutPlane);
                    }
                    //p1 is inside
                    else if (!is_p1_front && is_p2_front && is_p3_front)
                    {
                        CutTriangleTwoOutside(v2, v3, v1, newMeshO, newMeshI, newEdgesI, newEdgesO, cutPlane);
                    }

                    //p2 is outside
                    else if (!is_p1_front && is_p2_front && !is_p3_front)
                    {
                        CutTriangleOneOutside(v2, v3, v1, newMeshO, newMeshI, newEdgesI, newEdgesO, cutPlane);
                    }
                    //p2 is inside
                    else if (is_p1_front && !is_p2_front && is_p3_front)
                    {
                        CutTriangleTwoOutside(v3, v1, v2, newMeshO, newMeshI, newEdgesI, newEdgesO, cutPlane);
                    }

                    //p3 is outside
                    else if (!is_p1_front && !is_p2_front && is_p3_front)
                    {
                        CutTriangleOneOutside(v3, v1, v2, newMeshO, newMeshI, newEdgesI, newEdgesO, cutPlane);
                    }
                    //p3 is inside
                    else if (is_p1_front && is_p2_front && !is_p3_front)
                    {
                        CutTriangleTwoOutside(v1, v2, v3, newMeshO, newMeshI, newEdgesI, newEdgesO, cutPlane);
                    }

                    //Something is strange if we end up here...
                    else
                    {
                        Debug.Log("No case was gound where we split triangle into 3 new triangles");
                    }
                }
            }


            //Generate the new meshes only needed the old mesh intersected with the plane
            if (newMeshO.verts.Count == 0 || newMeshI.verts.Count == 0)
            {
                return(null);
            }


            //Find opposite edges to each edge
            //This is a slow process, so should be done only if the mesh is intersecting with the plane
            newMeshO.ConnectAllEdges();
            newMeshI.ConnectAllEdges();

            //Display all edges which have no opposite
            DebugHalfEdge.DisplayEdgesWithNoOpposite(newMeshO.edges, meshTrans, Color.white);
            DebugHalfEdge.DisplayEdgesWithNoOpposite(newMeshI.edges, meshTrans, Color.white);


            //Remove small triangles at the seam where we did the cut because they will cause shading issues if the surface is smooth
            //RemoveSmallTriangles(F_Mesh, newEdges);


            //Split each mesh into separate meshes if the original mesh is not connected, meaning it has islands
            HashSet <HalfEdgeData3> newMeshesO = SeparateMeshIslands(newMeshO);
            HashSet <HalfEdgeData3> newMeshesI = SeparateMeshIslands(newMeshI);


            //Fill the holes in the mesh
            HashSet <Hole> allHoles = FillHoles(newEdgesI, newEdgesO, orientedCutPlaneGlobal, meshTrans, planeNormalLocal);


            //Connect the holes with respective mesh
            AddHolesToMeshes(newMeshesO, newMeshesI, allHoles);


            //Finally generate standardized Unity meshes
            List <Mesh> cuttedUnityMeshes = new List <Mesh>();

            foreach (HalfEdgeData3 meshData in newMeshesO)
            {
                Mesh unityMesh = meshData.ConvertToUnityMesh("Outside mesh", shareVertices: true, generateNormals: false);

                cuttedUnityMeshes.Add(unityMesh);
            }

            foreach (HalfEdgeData3 meshData in newMeshesI)
            {
                Mesh unityMesh = meshData.ConvertToUnityMesh("Inside mesh", shareVertices: true, generateNormals: false);

                cuttedUnityMeshes.Add(unityMesh);
            }



            return(cuttedUnityMeshes);
        }
Ejemplo n.º 8
0
        //Given points and a plane, find the point furthest away from the plane
        private static Vector3 FindPointFurthestAwayFromPlane(HashSet <Vector3> points, Plane3 plane)
        {
            //Cant init by picking the first point in a list because it might be co-planar
            Vector3 bestPoint = default;

            float bestDistance = -Mathf.Infinity;

            foreach (Vector3 p in points)
            {
                float distance = _Geometry.GetSignedDistanceFromPointToPlane(p, plane);

                //Make sure the point is not co-planar
                float epsilon = MathUtility.EPSILON;

                //If distance is around 0
                if (distance > -epsilon && distance < epsilon)
                {
                    continue;
                }

                //Make sure distance is positive
                if (distance < 0f)
                {
                    distance *= -1f;
                }

                if (distance > bestDistance)
                {
                    bestDistance = distance;

                    bestPoint = p;
                }
            }

            return(bestPoint);
        }
Ejemplo n.º 9
0
        //Initialize by making 2 triangles by using three points, so its a flat triangle with a face on each side
        //We could use the ideas from Quickhull to make the start triangle as big as possible
        //Then find a point which is the furthest away as possible from these triangles
        //Add that point and you have a tetrahedron (triangular pyramid)
        public static void BuildFirstTetrahedron(HashSet <Vector3> points, HalfEdgeData3 convexHull)
        {
            //Of all points, find the two points that are furthes away from each other
            Edge3 eFurthestApart = FindEdgeFurthestApart(points);

            //Remove the two points we found
            points.Remove(eFurthestApart.p1);
            points.Remove(eFurthestApart.p2);


            //Find a point which is the furthest away from this edge
            //TODO: Is this point also on the AABB? So we don't have to search all remaining points...
            Vector3 pointFurthestAway = FindPointFurthestFromEdge(eFurthestApart, points);

            //Remove the point
            points.Remove(pointFurthestAway);


            //Display the triangle
            //Debug.DrawLine(eFurthestApart.p1.ToVector3(), eFurthestApart.p2.ToVector3(), Color.white, 1f);
            //Debug.DrawLine(eFurthestApart.p1.ToVector3(), pointFurthestAway.ToVector3(), Color.blue, 1f);
            //Debug.DrawLine(eFurthestApart.p2.ToVector3(), pointFurthestAway.ToVector3(), Color.blue, 1f);


            //Now we can build two triangles
            //It doesnt matter how we build these triangles as long as they are opposite
            //But the normal matters, so make sure it is calculated so the triangles are ordered clock-wise while the normal is pointing out
            Vector3 p1 = eFurthestApart.p1;
            Vector3 p2 = eFurthestApart.p2;
            Vector3 p3 = pointFurthestAway;

            convexHull.AddTriangle(p1, p2, p3);
            convexHull.AddTriangle(p1, p3, p2);

            //Debug.Log(convexHull.faces.Count);

            /*
             * foreach (HalfEdgeFace3 f in convexHull.faces)
             * {
             *  TestAlgorithmsHelpMethods.DebugDrawTriangle(f, Color.white, Color.red);
             * }
             */

            //Find the point which is furthest away from the triangle (this point cant be co-planar)
            List <HalfEdgeFace3> triangles = new List <HalfEdgeFace3>(convexHull.faces);

            //Just pick one of the triangles
            HalfEdgeFace3 triangle = triangles[0];

            //Build a plane
            Plane3 plane = new Plane3(triangle.edge.v.position, triangle.edge.v.normal);

            //Find the point furthest away from the plane
            Vector3 p4 = FindPointFurthestAwayFromPlane(points, plane);

            //Remove the point
            points.Remove(p4);

            //Debug.DrawLine(p1.ToVector3(), p4.ToVector3(), Color.green, 1f);
            //Debug.DrawLine(p2.ToVector3(), p4.ToVector3(), Color.green, 1f);
            //Debug.DrawLine(p3.ToVector3(), p4.ToVector3(), Color.green, 1f);

            //Now we have to remove one of the triangles == the triangle the point is outside of
            HalfEdgeFace3 triangleToRemove = triangles[0];
            HalfEdgeFace3 triangleToKeep   = triangles[1];

            //This means the point is inside the triangle-plane, so we have to switch
            //We used triangle #0 to generate the plane
            if (_Geometry.GetSignedDistanceFromPointToPlane(p4, plane) < 0f)
            {
                triangleToRemove = triangles[1];
                triangleToKeep   = triangles[0];
            }

            //Delete the triangle
            convexHull.DeleteFace(triangleToRemove);

            //Build three new triangles

            //The triangle we keep is ordered clock-wise:
            Vector3 p1_opposite = triangleToKeep.edge.v.position;
            Vector3 p2_opposite = triangleToKeep.edge.nextEdge.v.position;
            Vector3 p3_opposite = triangleToKeep.edge.nextEdge.nextEdge.v.position;

            //But we are looking at it from the back-side,
            //so we add those vertices counter-clock-wise to make the new triangles clock-wise
            convexHull.AddTriangle(p1_opposite, p3_opposite, p4);
            convexHull.AddTriangle(p3_opposite, p2_opposite, p4);
            convexHull.AddTriangle(p2_opposite, p1_opposite, p4);

            //Make sure all opposite edges are connected
            convexHull.ConnectAllEdgesSlow();

            //Debug.Log(convexHull.faces.Count);

            //Display what weve got so far
            //foreach (HalfEdgeFace3 f in convexHull.faces)
            //{
            //    TestAlgorithmsHelpMethods.DebugDrawTriangle(f, Color.white, Color.red);
            //}

            /*
             * //Now we might as well remove all the points that are within the tetrahedron because they are not on the hull
             * //But this is slow if we have many points and none of them are inside
             * HashSet<MyVector3> pointsToRemove = new HashSet<MyVector3>();
             *
             * foreach (MyVector3 p in points)
             * {
             *  bool isWithinConvexHull = _Intersections.PointWithinConvexHull(p, convexHull);
             *
             *  if (isWithinConvexHull)
             *  {
             *      pointsToRemove.Add(p);
             *  }
             * }
             *
             * Debug.Log($"Removed {pointsToRemove.Count} points because they were within the tetrahedron");
             *
             * foreach (MyVector3 p in pointsToRemove)
             * {
             *  points.Remove(p);
             * }
             */
        }
Ejemplo n.º 10
0
        //Find all visible triangles from a point
        //Also find edges on the border between invisible and visible triangles
        public static void FindVisibleTrianglesAndBorderEdgesFromPoint(Vector3 p, HalfEdgeData3 convexHull, out HashSet <HalfEdgeFace3> visibleTriangles, out HashSet <HalfEdge3> borderEdges)
        {
            //Flood-fill from the visible triangle to find all other visible triangles
            //When you cross an edge from a visible triangle to an invisible triangle,
            //save the edge because thhose edge should be used to build triangles with the point
            //These edges should belong to the triangle which is not visible
            borderEdges = new HashSet <HalfEdge3>();

            //Store all visible triangles here so we can't visit triangles multiple times
            visibleTriangles = new HashSet <HalfEdgeFace3>();


            //Start the flood-fill by finding a triangle which is visible from the point
            //A triangle is visible if the point is outside the plane formed at the triangles
            //Another sources is using the signed volume of a tetrahedron formed by the triangle and the point
            HalfEdgeFace3 visibleTriangle = FindVisibleTriangleFromPoint(p, convexHull.faces);

            //If we didn't find a visible triangle, we have some kind of edge case and should move on for now
            if (visibleTriangle == null)
            {
                Debug.LogWarning("Couldn't find a visible triangle so will ignore the point");

                return;
            }


            //The queue which we will use when flood-filling
            Queue <HalfEdgeFace3> trianglesToFloodFrom = new Queue <HalfEdgeFace3>();

            //Add the first triangle to init the flood-fill
            trianglesToFloodFrom.Enqueue(visibleTriangle);

            List <HalfEdge3> edgesToCross = new List <HalfEdge3>();

            int safety = 0;

            while (true)
            {
                //We have visited all visible triangles
                if (trianglesToFloodFrom.Count == 0)
                {
                    break;
                }

                HalfEdgeFace3 triangleToFloodFrom = trianglesToFloodFrom.Dequeue();

                //This triangle is always visible and should be deleted
                visibleTriangles.Add(triangleToFloodFrom);

                //Investigate bordering triangles
                edgesToCross.Clear();

                edgesToCross.Add(triangleToFloodFrom.edge);
                edgesToCross.Add(triangleToFloodFrom.edge.nextEdge);
                edgesToCross.Add(triangleToFloodFrom.edge.nextEdge.nextEdge);

                //Jump from this triangle to a bordering triangle
                foreach (HalfEdge3 edgeToCross in edgesToCross)
                {
                    HalfEdge3 oppositeEdge = edgeToCross.oppositeEdge;

                    if (oppositeEdge == null)
                    {
                        Debug.LogWarning("Found an opposite edge which is null");

                        break;
                    }

                    HalfEdgeFace3 oppositeTriangle = oppositeEdge.face;

                    //Have we visited this triangle before (only test visible triangles)?
                    if (trianglesToFloodFrom.Contains(oppositeTriangle) || visibleTriangles.Contains(oppositeTriangle))
                    {
                        continue;
                    }

                    //Check if this triangle is visible
                    //A triangle is visible from a point the point is outside of a plane formed with the triangles position and normal
                    Plane3 plane = new Plane3(oppositeTriangle.edge.v.position, oppositeTriangle.edge.v.normal);

                    bool isPointOutsidePlane = _Geometry.IsPointOutsidePlane(p, plane);

                    //This triangle is visible so save it so we can flood from it
                    if (isPointOutsidePlane)
                    {
                        trianglesToFloodFrom.Enqueue(oppositeTriangle);
                    }
                    //This triangle is invisible. Since we only flood from visible triangles,
                    //it means we crossed from a visible triangle to an invisible triangle, so save the crossing edge
                    else
                    {
                        borderEdges.Add(oppositeEdge);
                    }
                }


                safety += 1;

                if (safety > 50000)
                {
                    Debug.Log("Stuck in infinite loop when flood-filling visible triangles");

                    break;
                }
            }
        }
        //Remove flat tetrahedrons (a vertex in a triangle)
        private static bool RemoveFlatTetrahedrons(HalfEdgeData3 meshData, Normalizer3 normalizer = null)
        {
            HashSet <HalfEdgeVertex3> vertices = meshData.verts;

            bool foundFlatTetrahedron = false;

            foreach (HalfEdgeVertex3 vertex in vertices)
            {
                HashSet <HalfEdge3> edgesGoingToVertex = vertex.GetEdgesPointingToVertex(meshData);

                if (edgesGoingToVertex.Count == 3)
                {
                    //Find the vertices of the triangle covering this vertex clock-wise
                    HalfEdgeVertex3 v1 = vertex.edge.v;
                    HalfEdgeVertex3 v2 = vertex.edge.prevEdge.oppositeEdge.v;
                    HalfEdgeVertex3 v3 = vertex.edge.oppositeEdge.nextEdge.v;

                    //Build a plane
                    MyVector3 normal = MyVector3.Normalize(MyVector3.Cross(v3.position - v2.position, v1.position - v2.position));

                    Plane3 plane = new Plane3(v1.position, normal);

                    //Find the distance from the vertex to the plane
                    float distance = _Geometry.GetSignedDistanceFromPointToPlane(vertex.position, plane);

                    distance = Mathf.Abs(distance);

                    if (distance < FLAT_TETRAHEDRON_DISTANCE)
                    {
                        //Debug.Log("Found flat tetrahedron");

                        Vector3 p1 = normalizer.UnNormalize(v1.position).ToVector3();
                        Vector3 p2 = normalizer.UnNormalize(v2.position).ToVector3();
                        Vector3 p3 = normalizer.UnNormalize(v3.position).ToVector3();

                        TestAlgorithmsHelpMethods.DebugDrawTriangle(p1, p2, p3, normal.ToVector3(), Color.blue, Color.red);

                        foundFlatTetrahedron = true;

                        //Save the opposite edges
                        HashSet <HalfEdge3> oppositeEdges = new HashSet <HalfEdge3>();

                        oppositeEdges.Add(v1.edge.oppositeEdge);
                        oppositeEdges.Add(v2.edge.oppositeEdge);
                        oppositeEdges.Add(v3.edge.oppositeEdge);

                        //Remove the three triangles
                        foreach (HalfEdge3 e in edgesGoingToVertex)
                        {
                            meshData.DeleteFace(e.face);
                        }

                        //Add the new triangle (could maybe connect it ourselves)
                        HalfEdgeFace3 newTriangle = meshData.AddTriangle(v1.position, v2.position, v3.position, findOppositeEdge: false);

                        meshData.TryFindOppositeEdge(newTriangle.edge, oppositeEdges);
                        meshData.TryFindOppositeEdge(newTriangle.edge.nextEdge, oppositeEdges);
                        meshData.TryFindOppositeEdge(newTriangle.edge.nextEdge.nextEdge, oppositeEdges);

                        break;
                    }
                }
            }

            return(foundFlatTetrahedron);
        }
Ejemplo n.º 12
0
        //
        // Point-plane relations
        //
        //https://gamedevelopment.tutsplus.com/tutorials/understanding-sutherland-hodgman-clipping-for-physics-engines--gamedev-11917
        //Notice that the plane normal doesnt have to be normalized

        //The signed distance from a point to a plane
        //- Positive distance denotes that the point p is on the front side of the plane (in the direction of the plane normal)
        //- Negative means it's on the back side

        //3d
        public static float GetSignedDistanceFromPointToPlane(Plane3 plane, MyVector3 pointPos)
        {
            float distance = MyVector3.Dot(plane.normal, pointPos - plane.pos);

            return(distance);
        }