Skip to content

Commit 5155fbc

Browse files
committed
fix(webgl): normalize nearly identical vertices before tessellation
1 parent 8f23e69 commit 5155fbc

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

src/webgl/ShapeBuilder.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,32 @@ export class ShapeBuilder {
313313
}
314314
}
315315

316+
// Normalize nearly identical consecutive vertices to prevent tessellation artifacts
317+
// This addresses numerical precision issues in libtess when consecutive vertices
318+
// have coordinates that are almost (but not exactly) equal (e.g., differing by ~1e-8)
319+
const epsilon = 1e-6;
320+
for (const contour of contours) {
321+
const stride = this.tessyVertexSize;
322+
for (let i = stride; i < contour.length; i += stride) {
323+
const prevX = contour[i - stride];
324+
const prevY = contour[i - stride + 1];
325+
const prevZ = contour[i - stride + 2];
326+
const currX = contour[i];
327+
const currY = contour[i + 1];
328+
const currZ = contour[i + 2];
329+
330+
if (Math.abs(currX - prevX) < epsilon) {
331+
contour[i] = prevX;
332+
}
333+
if (Math.abs(currY - prevY) < epsilon) {
334+
contour[i + 1] = prevY;
335+
}
336+
if (Math.abs(currZ - prevZ) < epsilon) {
337+
contour[i + 2] = prevZ;
338+
}
339+
}
340+
}
341+
316342
const polyTriangles = this._triangulate(contours);
317343

318344
// If there were no valid faces, we still want to use the original vertices

test/unit/visual/cases/webgl.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,4 +693,35 @@ visualSuite('WebGL', function() {
693693
screenshot();
694694
});
695695
});
696+
697+
visualSuite('Tessellation', function() {
698+
visualTest('Handles nearly identical consecutive vertices', function(p5, screenshot) {
699+
p5.createCanvas(100, 100, p5.WEBGL);
700+
p5.pixelDensity(1);
701+
p5.background(255);
702+
p5.fill(0);
703+
p5.noStroke();
704+
705+
// Contours with nearly identical consecutive vertices (as can occur with textToContours)
706+
// Outer contour
707+
p5.beginShape();
708+
p5.vertex(-30, -30, 0);
709+
p5.vertex(30, -30, 0);
710+
p5.vertex(30, 30, 0);
711+
p5.vertex(-30, 30, 0);
712+
713+
// Inner contour (hole) with nearly identical vertices
714+
p5.beginContour();
715+
p5.vertex(-10, -10, 0);
716+
p5.vertex(-10, 10, 0);
717+
// This vertex has x coordinate almost equal to previous (10.00000001 vs 10)
718+
p5.vertex(10.00000001, 10, 0);
719+
p5.vertex(10, -10, 0);
720+
p5.endContour();
721+
722+
p5.endShape(p5.CLOSE);
723+
724+
screenshot();
725+
});
726+
});
696727
});

0 commit comments

Comments
 (0)