The purpose of this project is to provide the functionality to create custom meshes (polygons) in Unity based on a collection (array) of vertices directly at runtime. These 2D meshes are created along the x- and z-dimensions in the 3D space. Furthermore, the created custom mesh can be extruded (into a 3D prism) along the y-dimension in the 3D space.
Some of my research work required me to visualize country borders (geospatial coordinates; received from various open data sources) as individual meshes (2D polygons / 3D prisms) in the 3D space in Unity. Some examples of the usage of this project are provided beneath in the section Screenshots - SCB Kommun RT90, demonstrating the visualization of all individual municipalities in the country of Sweden.
The Triangulation.cs
class features a partial implementation of the original Triangle and Triangle.NET libraries in order to create render triangles for a custom mesh. The implemented triangulation supports holes in the mesh.
The PolyExtruder.cs
class is responsible for handling the input data and creating all Unity GameObjects (incl. the actual mesh; 2D polygon / 3D prism) using the features provided through Triangulation.cs
class in the process. Created 3D prisms (extruded 2D polygons) consist of three GameObjects, namely 1) the bottom mesh (y = 0), 2) the top mesh (y = dynamically assigned; greater than 0), and 3) the surrounding mesh connecting 1 and 2 on their outline accordingly.
Furthermore, the PolyExtruder.cs
class provides some quality-of-life features, such as:
- select whether the mesh should be 2D (polygon) or 3D (extruded, prism)
- calculation of the mesh's (2D polygon's) area
- calculation of the mesh's (2D polygon's) centroid
- set extrusion length ("height")
- select whether or not to visually display the polygon's outline
The main idea is to visualize the 2D input data along the x- and z-dimensions, while the (potential) extrusion is always conducted along the y-dimension.
The PolyExtruderLight.cs
class is an alternative, lightweight implementation of the original PolyExtruder.cs
class. Instead of keeping three separate meshes (top, bottom, surround) at runtime, it combines these into one mesh that can be more resource-friendly, particularly when working with many meshes / GameObjects. Please inspect the documentation inside the PolyExtruderLight.cs
script for additional information and remarks. Please note that the PolyExtruderLight.cs
class is always setting up the GameObject as an extruded 3D prism.
This project has been built using the following specifications:
- Apple macOS Sonoma 14.7
- Unity 2022.3.20f1 Personal (Apple Silicon, LTS)
Note: Generally, Unity source code should work also within their Windows counterparts. Please check out the above stated dependencies for troubleshooting.
Additional resources used to create this project have been accessed as follows:
- (Original) Triangle library implementation by Jonathan Richard Shewchuk (project web page)
- Triangle.NET by Christian Woltering (CodePlex Archive, GitHub snapshot)
- Using Triangle.NET in Unity (YouTube video; not available anymore as of 2019-06-04)
- Determine order (clockwise vs. counter-clockwise) of input vertices (StackOverflow)
- Polygons and meshes by Paul Bourke (project web page)
- Geo-spatial data about the island of Gotland (Sweden) (Swedish Statistiska centralbyrån (SCB); accessed 2019-02-06)
In order to add the features provided by this project to your Unity project, I recommend to add the assets by simply importing the pre-compiled nicoversity-unity_polyextruder.unitypackage
. Alternatively, the repository directory unity_src
features a directory titled Assets/nicoversity/polyextrude
, which contains all files that should be manually added to the respective Assets
directory of an existing Unity project.
// prepare data and options
Vector2[] MyCustomMeshData = new Vector2[]
{
new Vector2(0.0f, 0.0f),
new Vector2(10.0f, 0.0f),
new Vector2(10.0f, 10.0f),
// ... and more vertices
};
float extrusionHeight = 10.0f;
bool is3D = true;
bool isUsingBottomMeshIn3D = true;
bool isUsingColliders = true;
// create new GameObject (as a child), and further configuration
GameObject polyExtruderGO = new GameObject();
polyExtruderGO.transform.parent = this.transform;
polyExtruderGO.name = "MyCustomMeshName";
// add PolyExtruder script to newly created GameObject,
// keep track of its reference
PolyExtruder polyExtruder = polyExtruderGO.AddComponent<PolyExtruder>();
// configure display of outline (before running the poly extruder)
polyExtruder.isOutlineRendered = true; // default: false
polyExtruder.outlineWidth = 0.1f; // default: 0.01f
polyExtruder.outlineColor = Color.blue; // default: Color.black
// run poly extruder according to input data
polyExtruder.createPrism(polyExtruderGO.name, extrusionHeight, MyCustomMeshData, Color.grey, is3D, isUsingBottomMeshIn3D, isUsingColliders);
// access calculated area and centroid
float area = polyExtruder.polygonArea;
Vector2 centroid = polyExtruder.polygonCentroid;
All Unity scripts in this project are well documented directly within the source code. Please refer directly to the individual scripts to get a better understanding of the implementation.
The imported Unity assets provide three demonstration scenes:
TriangleNET_Test.unity
, illustrating and testing the implementation of theTriangulation.cs
class viaTriangulationTest.cs
script.PolyExtruder_Demo.unity
, illustrating the usage of thePolyExtruder.cs
class viaPolyExtruderDemo.cs
script. ThePolyExtruderDemo.cs
script allows the user to make selections using the Unity Inspector accordingly to a) select an example data set for the custom mesh creation (Triangle, Square, Cross, SCB Kommun RT90 Gotland), b) indicate whether the custom mesh should be created in 2D (polygon) or 3D (prism), c) the length ("height") of the extrusion, and d) whether the extrusion length should be dynamically scaled at runtime (oscillated movement example).PolyExtruderLight_Demo.unity
, illustrating the usage of thePolyExtruderLight.cs
class viaPolyExtruderLightDemo.cs
script, following the same examples as featured in thePolyExtruderDemo.cs
script.
Please refer to these scenes and scripts to learn more about the examples.
Following, some visual impressions of the included example data, visualized using the Triangulation.cs
, PolyExtruder.cs
, and PolyExtruderLight.cs
classes.
Following, some visual impressions of the earlier stated use case of visualizing all municipalities in the country of Sweden (see Background) using the PolyExtruder.cs
class. The data has been received from the Swedish Statistiska centralbyrån (SCB) (accessed: 2019-02-06; Note: The data is not included as part of this project).
A random extrusion length ("height") for each municipality has been applied to emphasize the 3D scenario.
- The function
public static bool triangulate(...)
always returnstrue
. In the future, an error list could be implemented to capture errors that occur during the triangulation process.
- No holes-support for extrusion (3D prism) is implemented. Although the
Triangulation.cs
script supports holes in the 2D polygon mesh, the support for holes as part of thePolyExtruder.cs
class has not been implemented in this version.
- No holes-support for extrusion (3D prism) is implemented. Although the
Triangulation.cs
script supports holes in the 2D polygon mesh, the support for holes as part of thePolyExtruderLight.cs
class has not been implemented in this version. - Compared to the
PolyExtruder.cs
class, theOutline Renderer
feature is currently not implemented. - Compared to the
PolyExtruder.cs
class, theMeshCollider
component is currently not implemented.
- Added an alternative, more lighweight implementation of the
PolyExtruder
class, titledPolyExtruderLight
.PolyExtruderLight
generates one combined mesh (3D prism only) instead of keeping three separate top, bottom, and surround meshes.
- Minor bug fix: The
updateColor()
function in thePolyExtruder.cs
class considers now appropriately the coloring of the bottom mesh component depending on whether or not it exists in the 3D prism condition.
- Minor bug fix: Appropriate type casting (
double
) ofVector2
values incalculateAreaAndCentroid()
function. - Modified the default material to utilize Unity's
Standard
shader instead of the legacyDiffuse
shader.
- Modified
calculateAreaAndCentroid()
function to internally utilizedouble
(instead offloat
) type for area and centroid calculations. - Added feature to conveniently indicate whether or not the bottom mesh component should be attached (only in Prism 3D, i.e.,
is3D = true
). - Added feature to conveniently indicate whether or not
MeshCollider
components should be attached.
- Modified the mesh creation algorithm to use for each vertex the difference between original input vertex and calculated polygon centroid (instead of simply using the original input vertices). This way, the anchor of the generated mesh is correctly located at the coordinate system's origin (0,0), in turn enabling appropriate mesh manipulation at runtime (e.g., via
Scale
property in theGameObject's Transform
). - Unity version upgrade to support 2021.3.16f1 (from prior version 2019.2.17f1; no changes in code required).
- Added feature to allow display of the polygon's outline.
- Upgrade to support Unity version 2019.2.17f1 Personal (from prior version 2019.1.5f1; no changes in the code required).
MIT License, see LICENSE.md