Delaunay - Voronoi Diagram library for Unity

I needed a delaunay library for my own, but didn’t found any that was meeting my requirment, so I ended up porting as3delaunay library to c#. I also added a Lloyd relaxation function to it.

So I though that I could post it. If anyone need it, go ahead it’s completly free.

Download link:csDelaunay Library

It’s pretty straighforward to use, but here is an exemple:

using UnityEngine;
using System.Collections.Generic;

using csDelaunay;

public class VoronoiDiagram : MonoBehaviour {

    // The number of polygons/sites we want
    public int polygonNumber = 200;

    // This is where we will store the resulting data
    private Dictionary<Vector2f, Site> sites;
    private List<Edge> edges;

    void Start() {
        // Create your sites (lets call that the center of your polygons)
        List<Vector2f> points = CreateRandomPoint();
       
        // Create the bounds of the voronoi diagram
        // Use Rectf instead of Rect; it's a struct just like Rect and does pretty much the same,
        // but like that it allows you to run the delaunay library outside of unity (which mean also in another tread)
        Rectf bounds = new Rectf(0,0,512,512);
       
        // There is a two ways you can create the voronoi diagram: with or without the lloyd relaxation
        // Here I used it with 2 iterations of the lloyd relaxation
        Voronoi voronoi = new Voronoi(points,bounds,5);

        // But you could also create it without lloyd relaxtion and call that function later if you want
        //Voronoi voronoi = new Voronoi(points,bounds);
        //voronoi.LloydRelaxation(5);

        // Now retreive the edges from it, and the new sites position if you used lloyd relaxtion
        sites = voronoi.SitesIndexedByLocation;
        edges = voronoi.Edges;

        DisplayVoronoiDiagram();
    }
   
    private List<Vector2f> CreateRandomPoint() {
        // Use Vector2f, instead of Vector2
        // Vector2f is pretty much the same than Vector2, but like you could run Voronoi in another thread
        List<Vector2f> points = new List<Vector2f>();
        for (int i = 0; i < polygonNumber; i++) {
            points.Add(new Vector2f(Random.Range(0,512), Random.Range(0,512)));
        }

        return points;
    }

    // Here is a very simple way to display the result using a simple bresenham line algorithm
    // Just attach this script to a quad
    private void DisplayVoronoiDiagram() {
        Texture2D tx = new Texture2D(512,512);
        foreach (KeyValuePair<Vector2f,Site> kv in sites) {
            tx.SetPixel((int)kv.Key.x, (int)kv.Key.y, Color.red);
        }
        foreach (Edge edge in edges) {
            // if the edge doesn't have clippedEnds, if was not within the bounds, dont draw it
            if (edge.ClippedEnds == null) continue;

            DrawLine(edge.ClippedEnds[LR.LEFT], edge.ClippedEnds[LR.RIGHT], tx, Color.black);
        }
        tx.Apply();

        this.renderer.material.mainTexture = tx;
    }

    // Bresenham line algorithm
    private void DrawLine(Vector2f p0, Vector2f p1, Texture2D tx, Color c, int offset = 0) {
        int x0 = (int)p0.x;
        int y0 = (int)p0.y;
        int x1 = (int)p1.x;
        int y1 = (int)p1.y;
       
        int dx = Mathf.Abs(x1-x0);
        int dy = Mathf.Abs(y1-y0);
        int sx = x0 < x1 ? 1 : -1;
        int sy = y0 < y1 ? 1 : -1;
        int err = dx-dy;
       
        while (true) {
            tx.SetPixel(x0+offset,y0+offset,c);
           
            if (x0 == x1 && y0 == y1) break;
            int e2 = 2*err;
            if (e2 > -dy) {
                err -= dy;
                x0 += sx;
            }
            if (e2 < dx) {
                err += dx;
                y0 += sy;
            }
        }
    }
}


More info on Voronoi Diagram: Voronoi diagram wiki
And lloyd relaxation: Lloyd’s_algorithm wiki

and another time the library download link: csDelaunay Library

12 Likes

I was just in the process of rewriting this to try out some map stuff from the Polygonal Map Gen article by Amitp.

You saved me quite a bit of time. Thank you.

1 Like

Very cool! Does this work with iOS too (AOT compiling)?

It looks like the triangulation is choking somewhere along the line if you try and pass it square or hexagon points. I haven’t had a chance to dig deeper to find out where though. Just a head’s up.

Ok thanks for letting me know. I had only tested it with random point. I’ll try to take a look into it once I can.

I know this thread is a bit old, but I was just working with an implementation of this code, and I wondered if anyone else was having the problem where it only works some of the time. Occasionally, without Lloyd Relaxation applied, the resulting texture is a mess. With the relaxation algorithm, it will throw an error.

Other times it works brilliantly and couldn’t be more perfect for what I’m working on, but I can’t sort out what the issue is.

Thanks in advance!

I have this same problem. Please let me know if you have found a solution. The problem with the error is coming from (Voronoi.cs) the fact that a collection is empty, and there is part of the code attempting to access the last element. region[region.Count - 1] throws an error when region.Count = 0. I don’t know why sometimes this works and sometimes this doesn’t. The other issue you had I remember having too a long time ago. It was an issue with VoronoiDiagram.cs (the code he posted directly here. In it on line 85 there is:
if (x0 == x1 y0 == y1) break;

I am assuming there might have been an html encoding problem? Anyway, i originally filled it in as
if (x0 == x1 || y0 == y1) break;
got wacky results then to :
if (x0 == x1 && y0 == y1) break;
and got expected output. If anyone finds the problem with the collection being empty please let me know! (And the github author perhaps?)

On another note:
I am working on an idea where I would like each polygon to be its own unity object (so that I can work easily with hovering, clicking, changing colors and what not, instead of drawing all the polygons onto one plane. Anyone have any ideas?

Hey everyone. Pardon the dumb question, but after I generate a voronoi diagram as a data structure (e.g.: a series of points / edges / triangles as Vector2’s), how do I actually go about rendering different textures in each tile?

1 Like

https://github.com/jceipek/Unity-delaunay

I’ve successfully implemented this library for meshes creation. Nice!
Had to add corners manually, since there were no corners inside vertices/edges arrays.

But I still getting this error sometimes:
in VoronoiCellVertex.cs

/** this is ONLY an error if all 3 edges existed; otherwise its an expected outcome */
Debug.LogError ("Cannot find another edge from this vertex (" + this + ") that borders cell: " + targetCell);

in such situation diagram looks like this (Gizmos)

you can see unfinished sites on the right.

I can control it with more predictable points. But I would like to choose completely random points at first place.

Update:
https://github.com/adamgit/Unity-delaunay works better but still has same problem

Debug.LogError ("Cannot find another edge from this vertex (" + this + ") that borders cell: " + targetCell);

and yes. map doesn’t look right again

Could somebody help me, please?

I had completly forgotten about that Delaunay implementation I had done, sorry guys.

I finally corrected the error with the Lloyd relaxation (the index out of bounds exception). The GitHub should now be bug free (crossing my fingers).

And yea, exactly just like lordnorth found out

if (x0 == x1  y0 == y1) break;

in the sample code I gave in the main post, was meant to be

if (x0 == x1 && y0 == 1) break;

Corrected it in my post.

If you find any other bug let me know plz. I should now receive email notification if someone post in this thread.

3 Likes

Hello,

As you asked, there is still a bug with “not random” points. I play a bit with random points with no problems, but I try to control the generation with square points and other regular shape but the diagram was messed up !

I’ll give a more detail example in the day.

I give voronoi this list of point (as a List object) :
1,1 3,3 5,5 7,7 7,1 3,5 5,3 1,7

I render the diagram, everything works fine :

I just add a point in the center (coord 4,4), and here is the problem !


(we don’t see the red point at the center because edges are drawing after sites centers)

At first I thought about a scale problem, as my numbers are small, but whatever zoom I apply the problem is still the same. (current textures have x8 zoom)

So here is a test case that show the problem.
I’ll try to find the fix, but if you have an idea and still look by here you surely save me some time !! :smile:
Fortunes algorithm makes me fear !

I just find the problem !
in vertex.cs you’ve got a line to test if halfedge are parallel :

line 85:      if (Math.Pow(-1.0, 10) < determinant && determinant < Math.Pow(1.0, -10)) {

This looks strange, I put

line 85: if (Math.Abs(determinant) < 0.0000000001f) {

And the triangulation doesn’t mess up anymore !!

1 Like

Is there a way to create a mesh from each tile generated by this algorithm?

1 Like

Sorry for bump a really old thread, but I think this is very useful for some things! And I think it’s better to reopen a created thread than create an other one about the same topic.

Well, what I want to say is that I need to fill a site with one color. I mean, set a color to all differents geometric sites. ¿Do you know how?

I don’t know if original author is still watching this topic, but may be someone else also can help me. I used csDelaunay Library by PouletFrit and find some strange bug there. Sometimes, I as far as I could understand, Vertex calculated wrong and I get Site with 0 Edges, some (I think this is the remains of original Edges of the Site) EdgeOrientation and 0 Region points. I couldn’t find a place where this is happening, but may be someone can help me? This situation is more common if I use a lot random points for Site centers, but sometimes it happen even with 300 points.


Another case is that sometimes edge ends also calculated wrong and this leads to really messed up edges in diagram. I think that the cause of these two cases is the same.

Did anyone figure out how to retrieve all the edges of each site, not only the ones within texture space? I’m trying to make the voronoi cells clickable but while it’s easy to do for the inner ones by retrieving their key-value.Value.Edges list, the outer-most ones can’t be processed that way as they only include those few edges that are visible so you can’t close the polygon collider.

Have you tried adding border cells around your graph and ignoring those cells?

Or … this article is rather dense but touches on it: http://blog.ivank.net/fortunes-algorithm-and-implementation.html

Can you select the ‘infinite’ edges of the diagram, iterate through and basically just do a simple triangulation to close it? You would basically be connecting edge pairs together in a clockwise(?) motion around the graph.

for 2017, although marked as not maintained,

this:

https://github.com/jceipek/Unity-delaunay

does seem to be the most reliable / usable Delauney triangulation, for Unity3D !

Has anyone looked through these lately and found the most reliable one?

Hi everyone!
So I’m working on an editor tool that allows the user to draw closed bezier splines and then generates a flat mesh that fills in this shape. I simply walk along these beziers and get a point at regular intervals to define the outline, and figured I could generate a mesh with these. Seems like an easy thing for Delaunay libraries, right?
Unfortunately I’m not much of a programmer and simply can’t wrap my head around how to use these libraries.
I’m currently trying out JCeipek’s library (linked by Fattie up here) but since his demo only shows how to get a Voronoi web and show nothing about the Delaunay part of his library as far as I can tell, I’m not exactly helped with that.
If any of you could tell me what exactly I need to use of these libraries I’d be super grateful.

IDEALLY, I’d like a method int[ ] GenerateTrianglesWithDelaunay(Vector3[ ] verts) that simply takes all my verts and gives me the data I can immediately plug in Unity’s Mesh.Triangles.