EdgesGeometry: remove un-closed edges

Is there any way to solve this issue with EdgesGeometry. I want to get rid of the un-closed edges. I modified EdgesGeometry source to discard the Geometry.mergeVertices() to save some iterations. But it also gave me another problem. I get some lines that are never gone no matter what the threshold angle is. This too could be fixed if I somehow remove the unclosed edges. But none of my ideas on tackling this seemed to work perfectly. Any ideas on how I will do it?

initGeometry: function(thresholdAngle, normalSize) {

    normalSize = normalSize === undefined ? 1 : normalSize;

    this.edges = {};
    var edge1, edge2;

    var keys = ['a', 'b', 'c'];
    var key, v1 = new THREE.Vector3(),
        v2 = new THREE.Vector3();
    var face, a, b;

    var vertices = this.object.geometry.vertices;
    var faces = this.object.geometry.faces;

    var normal = new THREE.Vector3();
    var normals = [];

    for (var i = 0; i < faces.length; i++) {

        face = faces[i];

        for (var j = 0; j < 3; j++) {

            a = face[keys[j]];


            normals.push(v1.x, v1.y, v1.z);
            normals.push(v2.x, v2.y, v2.z);


            b = face[keys[(j + 1) % 3]];

            key = createEdgeKey(v1, v2);

            if (this.edges[key]) {

                this.edges[key].face2 = i;

            } else {

                this.edges[key] = {
                    vertex1: a,
                    vertex2: b,
                    face1: i,
                    face2: undefined




    var points = [];

    for (var i = 0; i < vertices.length; i++) {

        points.push(v1.x, v1.y, v1.z);


    var geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(normals, 3));
    this.normalLines.geometry = geometry;

    geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3));
    this.points.geometry = geometry;



updateEdgeLines: function(thresholdAngle) {

    thresholdAngle = thresholdAngle === undefined ? 1 : thresholdAngle;

    var thresholdDot = Math.cos(thresholdAngle * Math.PI / 180);

    var array = [];

    var vertices = this.object.geometry.vertices;
    var faces = this.object.geometry.faces;

    var processedFaces = [];

    for (key in this.edges) {

        var e = this.edges[key];

        if (e.face2 !== undefined && faces[e.face2].normal.dot(faces[e.face1].normal) <= thresholdDot) {
            processedFaces.push(e.face1, e.face2);


    for (key in this.edges) {

        var e = this.edges[key];

        if (e.face2 === undefined || faces[e.face2].normal.dot(faces[e.face1].normal) <= thresholdDot) {

            array.push(vertices[e.vertex1].x, vertices[e.vertex1].y, vertices[e.vertex1].z);
            array.push(vertices[e.vertex2].x, vertices[e.vertex2].y, vertices[e.vertex2].z);



    var geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(array, 3));

    this.edgeLines.geometry = geometry;


EdgesGeometry does not support non-manifold geometries. I suggest you ensure first that this is not the case in your app.

The model is not non-manifold. Due to the way EdgesGeometry works, this issue has to appear. But I don’t think that there is a problem with EdgesGeometry. It does what it is supposed to do, find edges based on a threshold angle. But is there anyway to get rid of the edges that are not in loop?

I managed to come up with something that does the job of detecting regions. I had to use vertex index pair as the edge key (like the EdgesGeometry does) though. I earlier tried to avoid it by making the edge key to be the coordinate of the two points of the edge multiplied by some precision value and then rounded off. It was also weird that I was getting stack overflow messages when I used the coordinates as the key. But everything seems fine after I used the vertex indices as the key.

Here’s how my current code accomplishes region based edge detection.

  1. Calculate the edges (index1, index2, face1, face2) like EgdesGeometry does.
  2. Pick a face and recursively find the faces that are qualified to be in the region surrounded by the face based on a threshold angle and using the edges data calculated before.
  3. During the search, also store the edges, the dot product of whose face1 and face2 normals is lower than cos(angle).
  4. When the search is complete, go through the edges and check if both face1 and face2 of the edge in question exist in the queried face list. If they both are found then that means, the edge is coming in between the region and is not needed, so don’t add it to the geometry.
  5. Go to step 2 if there are more faces left that are yet to be found in some other region.

Edit: There are problems with the recursive approach when there are a lot of faces (call stack being blown!). I would recommend going a loop based approach. I will post a code soon after I finish working on it (for future explorers).

Ok here it is. Using loops and as optimized as I could get it. Works pretty good with any kind of model.

Source: https://github.com/bytezeroseven/THREE.RegionGeometry
Demo: https://bytezeroseven.github.io/THREE.RegionGeometry/

The geometry adds Face3.regionIndex for interactivity. The faces of a region can be accessed using RegionGeometry.regions[ regionIndex ].

The regions and edges can be updated using RegionGeometry.update( thresholdAngle ).

I use it for flood filling the faces in my paint app.

1 Like

i get a “this.setAttribute” is not a function?

You probably have to work with a current three.js version.

ah thats a THREE function, yes i’m using an older version which must be missing it, thanks