Releases: andywiecko/BurstTriangulator
v3.9.1
📝 Changelog
Fixed
- Fixes a false positive result in the edge–edge intersection test for non-intersecting, nearly collinear edges (#384).
This fix primarily addressesfloat2precision issues (when usingdouble2the issue was not detected).
These checks will be improved in the future with robust-predicates implementation.
Full Changelog: v3.9.0...v3.9.1
v3.9.0
✨ What's new?
The UnsafeTriangulator<T>.PlantHoleSeeds extension now provides also an option to generate a mapping from the initial triangles (t1) to the triangles after planting seeds (t2). The condition t1[3*i + k] == t2[mapping[3*i + k]] (for t2. If mapping[i] == -1, then the corresponding triangle i no longer exists in t2.
See example below:
var t = new UnsafeTriangulator<double2>();
using var triangles1 = new NativeList<int>(Allocator.Persistent);
t.Triangulate(input, output: new(){ Triangles = triangles1, ... }, args.Default(), Allocator.Persistent);
using var mapping = new NativeList<int>(Allocator.Persistent);
using var triangles2 = new NativeList<int>(Allocator.Persistent);
triangles2.CopyFrom(triangles1);
t.PlantHoleSeeds(new(){ Triangles = triangles2, ... }, Allocator.Persistent, mapping: mapping);
// The result:
// - `triangles1`: the initial triangles buffer before planting seeds.
// - `triangles2`: the triangles after planting seeds.
// - `mapping`: `triangles1` → `triangles2`.For more changes, see the changelog below.
📝 Changelog
Added
- Added
mappingfor thePlantingHoleSeedsextension inUnsafeTriangulator<T2>. This optional buffer provides a mapping between the initial triangles and triangles after planting hole seeds. - Added a utility for calculating the axis-aligned bounding box of a given collection of points (
Utilities.BoundingBox). - Added a utility for calculating the center of mass (COM) of a given collection of points, assuming equal weights for all positions (
Utilities.CenterOfMass).
Changed
- Extended
UnsafeTriangulator<T2>.ConstrainEdgeto replace theargsparameter with explicit options:sloanMaxItersandverbose. The previous overload usingargsis now marked with the[Obsolete]attribute. - Extended
UnsafeTriangulator<T2>.PlantHoleSeedsto replace theargsandinputparameters with explicit options:autoHolesAndBoundary,restoreBoundary, andholeSeeds. The previous overload usingargsandinputis now marked with the[Obsolete]attribute.
Fixed
- "Support" for triangulation with empty position buffer with enabled pre-processors.
Full Changelog: v3.8.0...v3.9.0
v3.8.0
✨ What's new?
The package has officially reached 300 stars ⭐ — thank you all for the incredible support!
This release introduces a powerful new feature: the α-shape filter.
It's especially useful for mesh reconstruction or procedurally generated maps.
👉 Read the full blog post for more insights.
Example usage:
using var positions = new NativeArray<double2>(..., Allocator.Persistent);
using var triangulator = new Triangulator(Allocator.Persistent)
{
Input = { Positions = positions },
Settings = { UseAlphaShapeFilter = true, AlphaShapeSettings = { Alpha = 0.1f, ... }},
};
triangulator.Run();📘 Check the documentation for detailed usage and examples.
📝 Changelog
Added
-
$\alpha$ -shape filter forTriangulator<T>and corresponding extensions forUnsafeTriangulator<T>. Enable this via theUseAlphaShapeFilterinTriangulatorSettings. Additional configuration is available throughAlphaShapeSettings. Options include:-
ProtectPointsprevents triangle removal if it would leave any of its points unassigned to a triangle; -
ProtectConstraintsensures triangles with constrained edges are preserved; -
PreventWindmillsavoids formation of windmill structures.
-
-
GeneratePointTriangleCountutility inUtilities. This method fills an input buffer with the count of triangles each vertex index participates in, based on a given triangle index buffer.
Full Changelog: v3.7.0...v3.8.0
v3.7.0
✨ What's new?
This release introduces several triangle mesh-related utilities. For more details, refer to the utilities documentation:
The most notable addition is the Retriangulate extension, along with the corresponding RetriangulateMeshJob. This utility allows you to retriangulate an existing UnityEngine.Mesh, which is particularly useful for mesh refinement.
Example usage:
mesh.Retriangulate(
settings: new()
{
AutoHolesAndBoundary = true,
RefineMesh = true,
RefinementThresholds = { Angle = 0, Area = 1e-2f }
},
axisInput: Axis.XZ,
uvMap: UVMap.Planar,
);📝 Changelog
Added
- Several triangle mesh related utilities, including:
GenerateHalfedges;GenerateTriangleColors;InsertSubMesh;NextHalfedge;Retriangulate, an extension forUnityEngine.Mesh;RetriangulateMeshJob.
TriangulatorandTriangulator<T>now implementINativeDisposable.
Fixed
- Safety handles for
NativeLists inUnsafeTriangulator.
Full Changelog: v3.6.0...v3.7.0
v3.6.0
✨ What's new?
Welcome to 2025! After the first month of the year, a new release of BurstTriangulator has arrived! This update finally supplements dynamic triangulation with the constrain edges method. Refinement performance has improved, and several small fixes have been made.
📈 Enhanced refinement performance
By replacing NativeQueue with NativeQueueList, I've managed to increase refinement performance by up to 50% (depending on the input). See the benchmarks attached below for details. Read the manual for test case specification.
🆕 ConstrainEdge
The ConstrainEdge extension allows you to constrain the edge (pi, pj). This is particularly useful for dynamic triangulation, enabling users to insert a path dynamically while constraining its edges.
Warning
This method is restricted to bulk mesh, meaning the constrained edge must not intersect any holes.
Additionally, the optional parameter ignoreForPlantingSeeds ignores the halfedges corresponding to (pi, pj) from during the seed planting step.
Here's an example demonstrating how to use the ConstrainEdge extension:
using var inputPositions = new NativeArray<double2>(..., Allocator.Persistent);
var output = new NativeOutputData<double2>
{
Positions = inputPositions,
};
using var status = new NativeReference<Status>(Status.OK, Allocator.Persistent);
using var outputPositions = new NativeList<double2>(Allocator.Persistent);
using var triangles = new NativeList<int>(Allocator.Persistent);
using var halfedges = new NativeList<int>(Allocator.Persistent);
using var constrainedHalfedges = new NativeList<bool>(Allocator.Persistent);
using var ignoredHalfedgesForPlantingSeeds = new NativeList<bool>(Allocator.Persistent);
var output = new NativeOutputData<double2>
{
Status = status,
Positions = outputPositions,
Triangles = triangles,
Halfedges = halfedges,
ConstrainedHalfedges = constrainedHalfedges,
IgnoredHalfedgesForPlantingSeeds = ignoredHalfedgesForPlantingSeeds,
};
var args = Args.Default();
var t = new UnsafeTriangulator<double2>();
t.Triangulate(input, output, args, Allocator.Persistent);
t.ConstrainEdge(output, pi: 0, pj: 1, args, allocator: Allocator.Persistent, ignoreForPlantingSeeds: true);📝 Changelog
Added
ConstrainEdgeextension forUnsafeTriangulator<T>. Edges can now be constrained dynamically.NativeInputData<T>andNativeOutputData<T>, which are essentiallyLowLevel.Unsafe.InputData<T>andLowLevel.Unsafe.OutputData<T>. This change resolves ambiguity between managed and unmanaged input/output data.- (Internal)
NativeQueueList<T>, an alternative implementation toUnity.Collections.NativeQueue<T>. This wrapper is more stable and faster, though it consumes more memory.
Changed
- Improved the performance of the refinement step. Depending on the input, speedups of up to 50% can be observed!
- Various documentation (summary/manual/scripting API) tweaks.
Deprecated
LowLevel.Unsafe.InputData<T>andLowLevel.Unsafe.OutputData<T>have been deprecated. UseNativeInputData<T>andNativeOutputData<T>instead.
Fixed
- A rare issue causing an editor crash when reloading the domain, apparently caused by
NativeQueue. This has been resolved by replacingNativeQueuewith the internalNativeQueueList<T>implementation.
Full Changelog: v3.5.0...v3.6.0
v3.5.0
❄️🎅🎄 Winter Update ❄️🎅🎄
Ho ho ho! This is the final release of BurstTriangulator for 2024, but don't worry—more updates are coming in 2025! Thank you all for your support; it’s wonderful to see the community actively using this package.
Looking ahead to next year, I'm excited to announce the planned release of the first BurstTriangulator addon package, which will introduce utilities for pathfinding in triangular meshes. Additionally, I plan to resume development of my PBD2D engine. Stay tuned for more updates, and I wish you all success with your fantastic projects!
Best,
Andrzej
✨ What's new?
🆕 Dynamic Triangulation Completed
This update introduces two essential methods for the UnsafeTriangulator, enabling full support for dynamic triangulation:
DynamicSplitHalfedgeallows point insertion by splitting a selected halfedge ᵈᵒᶜˢ,DynamicRemoveBulkPointfacilitates the removal of points from the mesh bulk ᵈᵒᶜˢ.
Learn more in the documentation.
📈 Enhanced refinement performance
The Bowyer-Watson point insertion algorithm has been refactored, resulting in an approximate 25% performance improvement during the refinement step and dynamic triangulation routines.
Performance Benchmarks:
In addition, a new benchmark has been introduced using Lake Superior as the input dataset—a commonly used test case for this package. This more general test suite provides better benchmarking for arbitrary input data compared to the original unit box refinement test case.
📝 Changelog
Added
DynamicSplitHalfedgeextension forUnsafeTriangulator, enabling point insertion by splitting a selected halfedge.DynamicRemoveBulkPointextension forUnsafeTriangulator, facilitating the removal of points from the mesh bulk.
Changed
- Refactor Bower-Watson point insertion algorithm to achieve approximately a 25% performance improvement during the refinement step and dynamic triangulation routines.
- Optimized planting seeds job for slightly increased performance and reduced memory allocation.
- (Internal) Various refactors to improve code clarity and maintainability.
Full Changelog: v3.4.0...v3.5.0
v3.4.0
🎃 Halloween Update 🎃
✨ What's new?
🆕 Dynamic triangulation
This release introduces basic support for dynamic triangulation with the new DynamicInsertPoint extension. It allows for dynamically inserting a point into a triangulation within a specified triangle using barycentric coordinates. Future updates will expand functionality to include additional extensions for splitting a halfedge and removing specific points, as well as, updates will increase performance related to point insertion/removal.
Here's an example snippet showcasing triangulation followed by a dynamic point insertion:
var t = new UnsafeTriangulator<float2>();
using var positions = new NativeArray<float2>(..., Allocator.Persistent);
using var constraints = new NativeArray<int>(..., Allocator.Persistent);
var input = new InputData<float2> { Positions = positions, ConstraintEdges = constraints };
using var outputPositions = new NativeList<float2>(Allocator.Persistent);
using var triangles = new NativeList<int>(Allocator.Persistent);
using var halfedges = new NativeList<int>(Allocator.Persistent);
using var constrainedHalfedges = new NativeList<bool>(Allocator.Persistent);
var output = new OutputData<float2> { Positions = outputPositions, Triangles = triangles, Halfedges = halfedges, ConstrainedHalfedges = constrainedHalfedges };
t.Triangulate(input, output, args: Args.Default(autoHolesAndBoundary: true), Allocator.Persistent);
// Insert a new point in triangle with index 42 at the center (barycentric coordinates: [⅓, ⅓, ⅓]).
t.DynamicInsertPoint(output, tId: 42, bar: 1f / 3, allocator: Allocator.Persistent);Learn more in the manual.
🆕 Online demo
To better demonstrate the package's capabilities, we've prepared a small online demo, available here.
📈 Enhanced refinement performance
To support dynamic triangulation, we refactored portions of the refinement process, resulting in a nearly 2x performance improvement after recent fixes and optimizations.
📈 Improved editor compatibility
TriangulationSettings is now better suited with UnityEditor, enhancing the user experience when configuring settings in the editor.
🔧 Important refinement fixes
This release addresses two key issues related to refinement.
- Fixed a rare issue that could produce invalid results, especially in cases where the input data included clustered subsegments, which occasionally caused points to appear outside the triangulation domain.
- Resolved an issue where refinement with constraints would ignore boundaries if no holes were present.
📝 Changelog
Added
- Dynamic triangulation support. Introduced
DynamicInsertPointextension forUnsafeTriangulatorto support dynamic point insertion. - A new demo scene to better illustrate the functionality in the documentation.
Changed
- Improved support for
TriangulatorSettingsinUnityEditorby adding a missing backing field, a setter, and editor-related attributes for properties. - Refinement step optimization. Refactored the refinement step to enhance performance and simplify the code.
Fixed
- Refinement with constraints without holes. Corrected an issue where refinement with constraints would ignore boundaries when holes were absent.
- Invalid refinement results. Fixed a rare issue where refinement could produce invalid results, especially when input data included subsegment clusters, leading to points appearing outside the triangulation domain.
Full Changelog: v3.3.0...v3.4.0
v3.3.0
✨ What's new?
🆕 Ignored constraints for seed planting
This feature is especially useful when the user wants to include a constraint but does not wish to enable any planting hole mechanism for that edge. Consider the following example input:
using var positions = new NativeArray<double2>(..., Allocator.Persistent);
using var constraintEdges = new NativeArray<int>(..., Allocator.Persistent);
using var ignoreConstraint = new NativeArray<bool>(..., Allocator.Persistent);
using var triangulator = new Triangulator(Allocator.Persistent)
{
Input = {
Positions = positions,
ConstraintEdges = constraintEdges,
IgnoreConstraintForPlantingSeeds = ignoreConstraint,
},
Settings = { AutoHolesAndBoundary = true, },
};
triangulator.Run();
var triangles = triangulator.Output.Triangles;In this example, the red constraint is set to true in IgnoreConstraintForPlantingSeeds. As a result, a hole is not generated from red constraint, and the edge remains part of the final triangulation.
📈 Faster hole planting
The complexity has improved from
Below is a benchmark for Constrained Delaunay triangulation with the auto-holes option enabled. As a test case, we use a square containing hole squares (denoted by #holes). Reference timings for the auto-holes option disabled are marked with a dashed line.
Co-authored-by: @HalfVoxel
🔧Fix overflow for int2
Overflow for int2 coordinates for large coordinates with differences around
Example input which failed to triangulate correctly before this release can be seen below:
Co-authored-by: @HalfVoxel
🆕 Status error codes
New flags have been added to the Status enum for enhanced error handling during triangulation. Users can now catch errors during validation more effectively. Note: The Status enum is now decorated with the [Flags]. To check if no errors occurred, use
if (status != Status.OK)
{
return;
}Read more at project's documentation.
📝 Changelog
Added
- Ignored constraints for seed planting. Users can now ignore specific constraints during the seed planting process. This is especially useful when constraining edges without creating hole boundaries. This option can be set using
Input.IgnoreConstraintForPlantingSeeds. Additionally, post-triangulation verification can be done withOutput.IgnoredHalfedgesForPlantingSeeds, which provides a list of booleans indicating whether a given halfedge was ignored during seed planting. - Status error codes. New flags have been added to the
Statusenum for enhanced error handling during triangulation. Users can now catch errors during validation more effectively. Note: TheStatusenum is now decorated with the[Flags]. To check if no errors occurred, usestatus == Status.OK.
Changed
- Faster hole planting. The complexity has improved from 𝒪(n²) to 𝒪(n), making hole planting almost free compared to the Delaunay step.
- Improved validation. All input data buffers are now validated. Additionally, some unconfigured settings can trigger log warnings.
Fixed
- Integer overflow for
int2coordinates. Resolved an overflow issue for large coordinates with differences around ~2²⁰.
Full Changelog: v3.2.1...v3.3.0
v3.2.1
🌿 Green Release1
Hi!
It's me again! Today's small release focuses on updates to the API documentation, with many additional lines of code (~0.6k LOC) added for improvements.
Best,
Andrzej
📝 Changelog
Changed
- Significant updates to the API documentation.
- (Internal) Miscellaneous changes.
Deprecated
- The
OutputData(Triangulator<T2>)constructor is now obsolete. It will be made internal in future versions.
Fixed
- Resolved a potential issue causing an infinite loop during the
PlantingSeedStepwithAutoHolesAndBoundary.
Full Changelog: v3.2.0...v3.2.1
-
I hope that you also have comments in green in your IDE. ↩
v3.2.0
✨ What's new?
As the holidays come to an end, we're excited to announce a new release of the Burst Triangulator!
🆕 New generic types support!
In this version, there is finally support for the int2 and fp2 (fixed-point Q31.32) types. These types are crucial as they ensure that the triangulation result is independent of the hardware architecture, making them suitable for use in scenarios such as lockstep simulations (e.g., in multiplayer RTS games).
The supported features for each type in this version are as follows:
| type | delaunay | constraints | holes | refinement | preprocessors | notes |
|---|---|---|---|---|---|---|
| float2 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
| Vector2 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | Via float2 reinterpret |
| double2 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
| fp2 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | Requires additional package1 |
| int2 | ✔️ | ✔️ | 🟡2 | ❌ | 🟡3 | Support up to |
Below the benchmark:
📝 Changelog
Added
- Support for additional types:
Vector2,int2, andfp2(fixed-point in Q31.32 format). Note:fp2requires an optional dependency. Refer to the manual for more details. - (Internal) Introduced
TrianglesComparerto simplify triangle assertions in tests. Argsis now blittable and can be used in Burst-compiled static methods.- Enhanced validation logs to include position information.
Changed
- (Internal) Various simplifications, minor performance improvements, refactoring, and additional code comments.
Deprecated
AsNativeArray()andManagedInputhave been deprecated for safety reasons. UseAsNativeArray(out Handle handle)instead. Refer to the manual for more information.
Fixed
- Corrected the refinement of concentric shells segment splitting factor alpha.
- Fixed safety issues with
AsNativeArray. - Fully collinear input is now handled correctly.
Full Changelog: v3.1.0...v3.2.0
-
This feature is available through an optional dependency. Users must install
com.danielmansson.mathematics.fixedpoint. More info in the documentation. ↩ -
In the current implementation, holes are fully supported with
Settings.AutoHolesAndBoundary. However, manual holes withint2coordinates may not guarantee that the given hole can be created. An additional extension is planned in the future to support holes with manual floating-point precision forint2. ↩ -
Support for
Preprocessor.COMwith translation only is available. ↩











