//Display a mesh, which is called from the coroutine when a mesh has changed public void DisplayMesh(HashSet <HalfEdgeFace3> meshDataUnNormalized, MeshFilter mf) { //Generate a mesh MyMesh myMesh = HalfEdgeData3.ConvertToMyMesh("Main visualization mesh", meshDataUnNormalized, MyMesh.MeshStyle.HardEdges); Mesh mesh = myMesh.ConvertToUnityMesh(generateNormals: true); mf.mesh = mesh; //Debug.Log(mesh.triangles.Length); }
void Start() { vertices_Unity = new HashSet <UnityEngine.Vector3>(); for (int i = 0; i < pointCount; i++) { UnityEngine.Vector3 point = srcMesh.mesh.GetRandomPointInsideNonConvex(srcMesh.GetComponent <Renderer>().bounds.center); vertices_Unity.Add(point); } HashSet <Vector3> points = new HashSet <Vector3>(vertices_Unity.Select(x => x.ToMyVector3())); Normalizer3 normalizer = new Normalizer3(new List <Vector3>(points)); HashSet <Vector3> points_normalized = normalizer.Normalize(points); //Convex Hull HalfEdgeData3 convexHull_normalized = _ConvexHull.Iterative_3D(points_normalized, removeUnwantedTriangles: false, normalizer); //HalfEdgeData3 convexHull_unnormalized = _ConvexHull.Iterative_3D(points, removeUnwantedTriangles: false, normalizer); var tmp = convexHull_normalized.ConvertToMyMesh("Triangulated Points", MyMesh.MeshStyle.HardEdges); delaunayMesh = tmp.ConvertToUnityMesh(true); // if (convexHull_normalized == null) // { // Debug.LogError("ConvexHull is null"); // return; // } // HashSet <VoronoiCell3> voronoiCells_normalized = _Voronoi.Delaunay3DToVoronoi(convexHull_normalized); HalfEdgeData3 convexHull = normalizer.UnNormalize(convexHull_normalized); MyMesh myMesh = convexHull.ConvertToMyMesh("convex hull aka delaunay triangulation", MyMesh.MeshStyle.HardEdges); delaunayMesh = myMesh.ConvertToUnityMesh(generateNormals: false); //Voronoi HashSet <VoronoiCell3> voronoiCells = normalizer.UnNormalize(voronoiCells_normalized); //Generate a mesh for each separate cell voronoiCellsMeshes = GenerateVoronoiCellsMeshes(voronoiCells); foreach (var mesh in voronoiCellsMeshes) { GameObject go = new GameObject(); var meshfilter = go.AddComponent <MeshFilter>(); var renderer = go.AddComponent <MeshRenderer>(); renderer.sharedMaterial = material; meshfilter.mesh = mesh; go.transform.parent = gameObject.transform; } //Generate a single mesh for all cells where each vertex has a color belonging to that cell //Now we can display the mesh with an unlit shader where each vertex is associated with a color belonging to that cell //The problem is that the voronoi cell is not a flat surface on the mesh //But it looks flat if we are using an unlit shader // Mesh oneMesh = GenerateAndDisplaySingleMesh(voronoiCellsMeshes); // // if (meshFilter != null) // { // meshFilter.mesh = oneMesh; // } // else // { // Debug.LogError("Meshfilter is null"); // } }
//Generates points, delaunay triangulation, and voronoi diagram public void Generate() { if (radius <= 0f) { radius = 0.01f; } if (numberOfPoints < 4) { numberOfPoints = 4; } //Get random points in 3d space points_Unity = TestAlgorithmsHelpMethods.GenerateRandomPointsOnSphere(seed, radius, numberOfPoints); //To MyVector3 HashSet <MyVector3> points = new HashSet <MyVector3>(points_Unity.Select(x => x.ToMyVector3())); //Normalize Normalizer3 normalizer = new Normalizer3(new List <MyVector3>(points)); HashSet <MyVector3> points_normalized = normalizer.Normalize(points); System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); // // Generate the convex hull, which is the same as the Delaunay triangulation of points on the sphere // //Iterative algorithm timer.Start(); HalfEdgeData3 convexHull_normalized = _ConvexHull.Iterative_3D(points_normalized, removeUnwantedTriangles: false, normalizer); timer.Stop(); Debug.Log($"Generated a 3d convex hull in {timer.ElapsedMilliseconds / 1000f} seconds"); if (convexHull_normalized == null) { return; } // // Generate the voronoi diagram from the delaunay triangulation // timer.Restart(); HashSet <VoronoiCell3> voronoiCells_normalized = _Voronoi.Delaunay3DToVoronoi(convexHull_normalized); timer.Stop(); Debug.Log($"Generated a 3d voronoi diagram in {timer.ElapsedMilliseconds / 1000f} seconds"); if (voronoiCells_normalized == null) { return; } // // Display // //Delaunay HalfEdgeData3 convexHull = normalizer.UnNormalize(convexHull_normalized); MyMesh myMesh = convexHull.ConvertToMyMesh("convex hull aka delaunay triangulation", MyMesh.MeshStyle.HardEdges); delaunayMesh = myMesh.ConvertToUnityMesh(generateNormals: false); //Voronoi HashSet <VoronoiCell3> voronoiCells = normalizer.UnNormalize(voronoiCells_normalized); //Generate a mesh for each separate cell voronoiCellsMeshes = GenerateVoronoiCellsMeshes(voronoiCells); //Generate a single mesh for all cells where each vertex has a color belonging to that cell //Now we can display the mesh with an unlit shader where each vertex is associated with a color belonging to that cell //The problem is that the voronoi cell is not a flat surface on the mesh //But it looks flat if we are using an unlit shader Mesh oneMesh = GenerateAndDisplaySingleMesh(voronoiCellsMeshes); if (meshFilter != null) { meshFilter.mesh = oneMesh; } }
public void SimplifyMesh() { //Has to be sharedMesh if we are using Editor tools Mesh meshToSimplify = meshFilterToSimplify.sharedMesh; // // Change data structure and normalize // //Mesh -> MyMesh MyMesh myMeshToSimplify = new MyMesh(meshToSimplify); //Normalize to 0-1 Normalizer3 normalizer = new Normalizer3(myMeshToSimplify.vertices); //We only need to normalize the vertices myMeshToSimplify.vertices = normalizer.Normalize(myMeshToSimplify.vertices); HalfEdgeData3 myMeshToSimplify_HalfEdge = new HalfEdgeData3(myMeshToSimplify, HalfEdgeData3.ConnectOppositeEdges.Fast); // // Simplify // System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); timer.Start(); HalfEdgeData3 mySimplifiedMesh_HalfEdge = MeshSimplification_QEM.Simplify(myMeshToSimplify_HalfEdge, maxEdgesToContract: 2400, maxError: Mathf.Infinity, normalizeTriangles: true); timer.Stop(); Debug.Log($"It took {timer.ElapsedMilliseconds / 1000f} seconds to simplify the mesh"); // // Change data structure and un-normalize // timer.Reset(); timer.Start(); //From half-edge to mesh MyMesh mySimplifiedMesh = mySimplifiedMesh_HalfEdge.ConvertToMyMesh("Simplified mesh", MyMesh.MeshStyle.HardEdges); //Un-Normalize mySimplifiedMesh.vertices = normalizer.UnNormalize(mySimplifiedMesh.vertices); //Convert to global space Transform trans = meshFilterToSimplify.transform; mySimplifiedMesh.vertices = mySimplifiedMesh.vertices.Select(x => trans.TransformPoint(x.ToVector3()).ToMyVector3()).ToList(); //Convert to mesh Mesh unitySimplifiedMesh = mySimplifiedMesh.ConvertToUnityMesh(generateNormals: true, meshName: "simplified mesh"); //Attach to new game object meshFilterToShowSimplifiedMesh.mesh = unitySimplifiedMesh; timer.Stop(); Debug.Log($"It took {timer.ElapsedMilliseconds / 1000f} seconds to finalize the mesh after simplifying"); }
//Called from editor script public void GenerateHull() { //Get random points in 3d space HashSet <Vector3> points_Unity = TestAlgorithmsHelpMethods.GenerateRandomPoints3D(seed, halfMapSize, numberOfPoints); //HashSet<Vector3> points_Unity = GetCubeTestPoints(); //Points from a mesh /* * Transform meshTrans = constructHullFromThisMesh.transform; * * List<Vector3> vertices = new List<Vector3>(constructHullFromThisMesh.sharedMesh.vertices); * * //Local to global space * List<Vector3> verticesGlobal = vertices.Select(x => meshTrans.TransformPoint(x)).ToList(); * * HashSet<Vector3> points_Unity = new HashSet<Vector3>(verticesGlobal); */ //To stress-test these algorithms, generate points on a sphere because all of those should be on the hull //HashSet<Vector3> points_Unity = TestAlgorithmsHelpMethods.GenerateRandomPointsOnSphere(seed, radius: 1f, numberOfPoints); //To MyVector3 HashSet <MyVector3> points = new HashSet <MyVector3>(points_Unity.Select(x => x.ToMyVector3())); //Normalize Normalizer3 normalizer = new Normalizer3(new List <MyVector3>(points)); HashSet <MyVector3> points_normalized = normalizer.Normalize(points); // // Generate the convex hull // //Algorithm 1. Iterative algorithm System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); timer.Start(); HalfEdgeData3 convexHull_normalized = _ConvexHull.Iterative_3D(points_normalized, removeUnwantedTriangles, normalizer); timer.Stop(); Debug.Log($"Generated a 3d convex hull in {timer.ElapsedMilliseconds / 1000f} seconds with {convexHull_normalized.faces.Count} triangles"); // // Display // //Points //TestAlgorithmsHelpMethods.DisplayPoints(points_Unity, 0.01f, Color.black); //Hull mesh if (convexHull_normalized != null) { HalfEdgeData3 convexHull = normalizer.UnNormalize(convexHull_normalized); MyMesh myMesh = convexHull.ConvertToMyMesh("convex hull", MyMesh.MeshStyle.HardEdges); //To unity mesh Mesh convexHullMesh = myMesh.ConvertToUnityMesh(generateNormals: false, myMesh.meshName); //Using gizmos to display mesh in 3d space gives a bad result //TestAlgorithmsHelpMethods.DisplayMeshWithRandomColors(convexHullMesh, 0); //Better to add it to a gameobject //Use Shaded Wireframe to see the triangles meshFilter.mesh = convexHullMesh; //Points on the hull //These are shining thorugh the mesh //TestAlgorithmsHelpMethods.DisplayMeshCorners(convexHullMesh, 0.01f, Color.black); } }