Пример #1
0
        //If we have a forward and an up reference vector
        //So this is not going to work if we have loops
        //tangent is same as forward
        public InterpolationTransform(MyVector3 position, MyVector3 tangent, MyVector3 up)
        {
            this.position = position;

            MyVector3 biNormal = MyVector3.Normalize(MyVector3.Cross(up, tangent));

            MyVector3 normal = MyVector3.Normalize(MyVector3.Cross(tangent, biNormal));

            this.orientation = Quaternion.LookRotation(tangent.ToVector3(), normal.ToVector3());
        }
        //
        // Quaternion operations
        //

        //Rotate a quaternion some degrees around some axis
        public static MyQuaternion RotateQuaternion(MyQuaternion oldQuaternion, float angleInDegrees, MyVector3 rotationAxis)
        {
            Quaternion rotationQuaternion = Quaternion.AngleAxis(angleInDegrees, rotationAxis.ToVector3());

            //To rotate a quaternion you just multiply it with the rotation quaternion
            //Important that rotationQuaternion is first!
            Quaternion newQuaternion = rotationQuaternion * oldQuaternion.unityQuaternion;

            MyQuaternion myNewQuaternion = new MyQuaternion(newQuaternion);

            return(myNewQuaternion);
        }
Пример #3
0
        //
        // Get a Transform (includes position and orientation) at point t
        //
        public InterpolationTransform GetTransform(float t)
        {
            //Same as when we calculate t
            MyVector3 interpolation_1_2 = _Interpolation.BezierQuadratic(posA, handleB, handleA, t);
            MyVector3 interpolation_2_3 = _Interpolation.BezierQuadratic(posA, posB, handleB, t);

            MyVector3 finalInterpolation = _Interpolation.BezierLinear(interpolation_1_2, interpolation_2_3, t);

            //This direction is always tangent to the curve
            MyVector3 forwardDir = MyVector3.Normalize(interpolation_2_3 - interpolation_1_2);

            //A simple way to get the other directions is to use LookRotation with just forward dir as parameter
            //Then the up direction will always be the world up direction, and it calculates the right direction
            Quaternion orientation = Quaternion.LookRotation(forwardDir.ToVector3());


            InterpolationTransform trans = new InterpolationTransform(finalInterpolation, orientation);

            return(trans);
        }
        //Fill the hole (or holes) in the mesh
        private static HashSet <Hole> FillHoles(HashSet <HalfEdge3> holeEdgesI, HashSet <HalfEdge3> holeEdgesO, OrientedPlane3 orientedCutPlane, Transform meshTrans, MyVector3 planeNormal)
        {
            if (holeEdgesI == null || holeEdgesI.Count == 0)
            {
                Debug.Log("This mesh has no hole");

                return(null);
            }


            //Find all separate holes
            HashSet <List <HalfEdge3> > allHoles = IdentifySeparateHoles(holeEdgesI);

            if (allHoles.Count == 0)
            {
                Debug.LogWarning("Couldn't identify any holes even though we have hole edges");

                return(null);
            }

            //Debug
            //foreach (List<HalfEdge3> hole in allHoles)
            //{
            //    foreach (HalfEdge3 e in hole)
            //    {
            //        Debug.DrawLine(meshTrans.TransformPoint(e.v.position.ToVector3()), Vector3.zero, Color.white, 5f);
            //    }
            //}


            //Fill the hole with a mesh
            HashSet <Hole> holeMeshes = new HashSet <Hole>();

            foreach (List <HalfEdge3> hole in allHoles)
            {
                HalfEdgeData3 holeMeshI = new HalfEdgeData3();
                HalfEdgeData3 holeMeshO = new HalfEdgeData3();

                //Transform vertices to local position of the cut plane to make it easier to triangulate with Ear Clipping
                //Ear CLipping wants vertices in 2d
                List <MyVector2> sortedEdges_2D = new List <MyVector2>();

                Transform planeTrans = orientedCutPlane.planeTrans;

                foreach (HalfEdge3 e in hole)
                {
                    MyVector3 pMeshSpace = e.v.position;

                    //Mesh space to Global space
                    Vector3 pGlobalSpace = meshTrans.TransformPoint(pMeshSpace.ToVector3());

                    //Global space to Plane space
                    Vector3 pPlaneSpace = planeTrans.InverseTransformPoint(pGlobalSpace);

                    //Y is normal direction so should be 0
                    MyVector2 p2D = new MyVector2(pPlaneSpace.x, pPlaneSpace.z);

                    sortedEdges_2D.Add(p2D);
                }


                //Triangulate with Ear Clipping
                HashSet <Triangle2> triangles = _EarClipping.Triangulate(sortedEdges_2D, null, optimizeTriangles: false);

                //Debug.Log($"Number of triangles from Ear Clipping: {triangles.Count}");

                //Transform vertices to mesh space and half-edge data structure
                foreach (Triangle2 t in triangles)
                {
                    //3d space
                    Vector3 p1 = new Vector3(t.p1.x, 0f, t.p1.y);
                    Vector3 p2 = new Vector3(t.p2.x, 0f, t.p2.y);
                    Vector3 p3 = new Vector3(t.p3.x, 0f, t.p3.y);

                    //Plane space to Global space
                    Vector3 p1Global = planeTrans.TransformPoint(p1);
                    Vector3 p2Global = planeTrans.TransformPoint(p2);
                    Vector3 p3Global = planeTrans.TransformPoint(p3);

                    //Global space to Mesh space
                    Vector3 p1Mesh = meshTrans.InverseTransformPoint(p1Global);
                    Vector3 p2Mesh = meshTrans.InverseTransformPoint(p2Global);
                    Vector3 p3Mesh = meshTrans.InverseTransformPoint(p3Global);

                    //For inside mesh
                    MyMeshVertex v1_I = new MyMeshVertex(p1Mesh.ToMyVector3(), planeNormal);
                    MyMeshVertex v2_I = new MyMeshVertex(p2Mesh.ToMyVector3(), planeNormal);
                    MyMeshVertex v3_I = new MyMeshVertex(p3Mesh.ToMyVector3(), planeNormal);

                    //For inside mesh
                    MyMeshVertex v1_O = new MyMeshVertex(p1Mesh.ToMyVector3(), -planeNormal);
                    MyMeshVertex v2_O = new MyMeshVertex(p2Mesh.ToMyVector3(), -planeNormal);
                    MyMeshVertex v3_O = new MyMeshVertex(p3Mesh.ToMyVector3(), -planeNormal);

                    //Now we can finally add this triangle to the half-edge data structure
                    AddTriangleToMesh(v1_I, v2_I, v3_I, holeMeshI, null);
                    AddTriangleToMesh(v1_O, v3_O, v2_O, holeMeshO, null);
                }

                //We also need an edge belonging to the mesh (not hole mesh) to easier merge mesh with hole
                //The hole edges were generated for the Inside mesh
                HalfEdge3 holeEdgeI = hole[0];

                //But we also need an edge for the Outside mesh
                bool foundCorrespondingEdge = false;

                MyVector3 eGoingTo   = holeEdgeI.v.position;
                MyVector3 eGoingFrom = holeEdgeI.prevEdge.v.position;

                foreach (HalfEdge3 holeEdgeO in holeEdgesO)
                {
                    MyVector3 eOppsiteGoingTo   = holeEdgeO.v.position;
                    MyVector3 eOppsiteGoingFrom = holeEdgeO.prevEdge.v.position;

                    if (eOppsiteGoingTo.Equals(eGoingFrom) && eOppsiteGoingFrom.Equals(eGoingTo))
                    {
                        Hole newHoleMesh = new Hole(holeMeshI, holeMeshO, holeEdgeI, holeEdgeO);

                        holeMeshes.Add(newHoleMesh);

                        foundCorrespondingEdge = true;

                        break;
                    }
                }

                if (!foundCorrespondingEdge)
                {
                    Debug.Log("Couldnt find opposite edge in hole, so no hole was added");
                }
            }

            return(holeMeshes);
        }
        //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);
        }
        //Generate a mesh
        public static Mesh GenerateMesh(List <InterpolationTransform> transforms, MeshProfile profile, float profileScale)
        {
            if (profile == null)
            {
                Debug.Log("You need to assign a mesh profile");

                return(null);
            }

            if (transforms == null || transforms.Count <= 1)
            {
                Debug.Log("You need more transforms");

                return(null);
            }


            //Test that the profile is correct
            //InterpolationTransform testTrans = transforms[1];

            //DisplayMeshProfile(profile, testTrans, profileScale);

            //Vertices
            List <Vector3> vertices = new List <Vector3>();

            //Normals
            List <Vector3> normals = new List <Vector3>();

            for (int step = 0; step < transforms.Count; step++)
            {
                InterpolationTransform thisTransform = transforms[step];

                for (int i = 0; i < profile.vertices.Length; i++)
                {
                    MyVector2 localPos2d = profile.vertices[i].point;

                    MyVector3 localPos = new MyVector3(localPos2d.x, localPos2d.y, 0f);

                    MyVector3 pos = thisTransform.LocalToWorld_Pos(localPos * profileScale);

                    vertices.Add(pos.ToVector3());


                    //Normals
                    MyVector2 localNormal2d = profile.vertices[i].normal;

                    MyVector3 localNormal = new MyVector3(localNormal2d.x, localNormal2d.y, 0f);

                    MyVector3 normal = thisTransform.LocalToWorld_Dir(localNormal);

                    normals.Add(normal.ToVector3());
                }
            }

            //Triangles
            List <int> triangles = new List <int>();

            //We connect the first transform with the next transform, ignoring the last transform because it doesnt have a next
            for (int step = 0; step < transforms.Count - 1; step++)
            {
                //The index where this profile starts in the list of all vertices in the entire mesh
                int profileIndexThis = step * profile.vertices.Length;
                //The index where the next profile starts
                int profileIndexNext = (step + 1) * profile.vertices.Length;

                //Each line has 2 points
                for (int line = 0; line < profile.lineIndices.Length; line++)
                {
                    int lineIndexA = profile.lineIndices[line].x;
                    int lineIndexB = profile.lineIndices[line].y;

                    //Now we can identify the vertex we need in the list of all vertices in the entire mesh
                    //The current profile
                    int thisA = profileIndexThis + lineIndexA;
                    int thisB = profileIndexThis + lineIndexB;
                    //The next profile
                    int nextA = profileIndexNext + lineIndexA;
                    int nextB = profileIndexNext + lineIndexB;

                    //Build two triangles
                    triangles.Add(thisA);
                    triangles.Add(nextA);
                    triangles.Add(nextB);

                    triangles.Add(thisB);
                    triangles.Add(thisA);
                    triangles.Add(nextB);
                }
            }

            Mesh mesh = new Mesh();

            mesh.vertices  = vertices.ToArray();
            mesh.triangles = triangles.ToArray();
            mesh.normals   = normals.ToArray();

            //mesh.RecalculateNormals();

            return(mesh);
        }
        public MyVector3 RotateVector(MyVector3 vec)
        {
            Vector3 rotatedVec = unityQuaternion * vec.ToVector3();

            return(rotatedVec.ToMyVector3());
        }
        //Rotate a vector by using a quaternion
        public static MyVector3 RotateVector(MyQuaternion quat, MyVector3 vec)
        {
            Vector3 rotatedVec = quat.unityQuaternion * vec.ToVector3();

            return(rotatedVec.ToMyVector3());
        }
 public MyQuaternion(MyVector3 forward, MyVector3 up)
 {
     this.unityQuaternion = Quaternion.LookRotation(forward.ToVector3(), up.ToVector3());
 }