0

My code generates a shape that consists of a few circular arcs. (There are tiny rounding errors in the coordinates of the ends of the arcs, so Three.js adds some lines between them as well.) This shape is then extruded with no bevel.

With some parameters, it renders OK:

correct extrusion

But in very rare cases there is a deterministic glitch:

glitching extrusion

Here are the respective wireframes:

correct wireframe

glitching wireframe

What could be going on here?

I’ve tried to track this down but to no success. If I remove some of the curves (replacing them with lines), the problem disappears, but I am not sure why that is.

Here’s the first shape exported to JSON:

{
    "metadata": {
        "version": 4.6,
        "type": "Curve",
        "generator": "Curve.toJSON"
    },
    "arcLengthDivisions": 200,
    "type": "Shape",
    "autoClose": false,
    "curves": [
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": -1179.686016574916,
            "aY": -233.17944912136764,
            "xRadius": 1472.8745426217185,
            "yRadius": 1472.8745426217185,
            "aStartAngle": 0.1563092807502333,
            "aEndAngle": 0.37953181010917647,
            "aClockwise": false,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                188.3761150579112,
                312.49941458455
            ],
            "v2": [
                188.37611505791125,
                312.49941458455
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 0,
            "aY": -318.92857142857156,
            "xRadius": 658.9285714285717,
            "yRadius": 658.9285714285717,
            "aStartAngle": 1.2808691405245196,
            "aEndAngle": 1.8607235130652742,
            "aClockwise": false,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -188.3761150579116,
                312.49941458455
            ],
            "v2": [
                -188.37611505791142,
                312.49941458454947
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 1179.6860165749115,
            "aY": -233.1794491213663,
            "xRadius": 1472.8745426217138,
            "yRadius": 1472.8745426217138,
            "aStartAngle": 2.762060843480617,
            "aEndAngle": 2.9852833728395605,
            "aClockwise": false,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -275.232060172259,
                -3.8918387769852814
            ],
            "v2": [
                -275.232060172259,
                -3.891838776985317
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": -297.0083950172015,
            "aY": 18.52141044576086,
            "xRadius": 31.249999999999808,
            "yRadius": 31.249999999999808,
            "aStartAngle": 5.48337491763607,
            "aEndAngle": 3.6287844816328425,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -324.6224880276218,
                3.8918387769850895
            ],
            "v2": [
                -324.622488027622,
                3.891838776985111
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 1179.6860165749115,
            "aY": -233.1794491213663,
            "xRadius": 1522.8745426217138,
            "yRadius": 1522.8745426217138,
            "aStartAngle": 2.9852833728395605,
            "aEndAngle": 2.746424854210986,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -225.82360154791877,
                353.0709973002204
            ],
            "v2": [
                -225.82360154791897,
                353.07099730022026
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 0,
            "aY": -318.92857142857156,
            "xRadius": 708.9285714285717,
            "yRadius": 708.9285714285717,
            "aStartAngle": 1.8949874069341703,
            "aEndAngle": 1.246605246655623,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                225.82360154791905,
                353.07099730022014
            ],
            "v2": [
                225.823601547919,
                353.07099730022026
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": -1179.686016574916,
            "aY": -233.17944912136764,
            "xRadius": 1522.8745426217185,
            "yRadius": 1522.8745426217185,
            "aStartAngle": 0.3951677993788066,
            "aEndAngle": 0.1563092807502333,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                324.62248802762224,
                3.891838776985111
            ],
            "v2": [
                324.622488027622,
                3.891838776985354
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 297.00839501720156,
            "aY": 18.521410445761326,
            "xRadius": 31.250000000000057,
            "yRadius": 31.250000000000057,
            "aStartAngle": 5.795993479136534,
            "aEndAngle": 3.9414030431333127,
            "aClockwise": true,
            "aRotation": 0
        }
    ],
    "currentPoint": [
        275.23206017225897,
        -3.8918387769850966
    ],
    "uuid": "ccb56be7-ae30-479a-b055-18c5f3a28126",
    "holes": []
}

And here’s the glitchy one:

{
    "metadata": {
        "version": 4.6,
        "type": "Curve",
        "generator": "Curve.toJSON"
    },
    "arcLengthDivisions": 200,
    "type": "Shape",
    "autoClose": false,
    "curves": [
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": -2620.113751512889,
            "aY": -634.8172998557919,
            "xRadius": 2963.2490852434344,
            "yRadius": 2963.2490852434344,
            "aStartAngle": 0.21406911135034987,
            "aEndAngle": 0.3254884218098156,
            "aClockwise": false,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                187.5489211880722,
                312.7456043979288
            ],
            "v2": [
                187.54892118807243,
                312.7456043979288
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 0,
            "aY": -318.92857142857156,
            "xRadius": 658.9285714285717,
            "yRadius": 658.9285714285717,
            "aStartAngle": 1.2821789217545319,
            "aEndAngle": 1.8594137318352597,
            "aClockwise": false,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -187.54892118807138,
                312.7456043979291
            ],
            "v2": [
                -187.54892118807174,
                312.7456043979312
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 2620.113751512878,
            "aY": -634.8172998557885,
            "xRadius": 2963.249085243423,
            "yRadius": 2963.249085243423,
            "aStartAngle": 2.8161042317799767,
            "aEndAngle": 2.927523542239444,
            "aClockwise": false,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -275.49790976053055,
                -5.310946993933044
            ],
            "v2": [
                -275.497909760531,
                -5.310946993933161
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": -295.9440638544915,
            "aY": 18.32202325455672,
            "xRadius": 31.249999999999766,
            "yRadius": 31.249999999999766,
            "aStartAngle": 5.425615087035946,
            "aEndAngle": 3.571024651032722,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -324.3566384393507,
                5.310946993931816
            ],
            "v2": [
                -324.3566384393507,
                5.31094699393168
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 2620.113751512878,
            "aY": -634.8172998557885,
            "xRadius": 3013.249085243423,
            "yRadius": 3013.249085243423,
            "aStartAngle": 2.927523542239444,
            "aEndAngle": 2.8076709022234576,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                -226.69627707387917,
                352.77710619266134
            ],
            "v2": [
                -226.69627707388003,
                352.7771061926601
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 0,
            "aY": -318.92857142857156,
            "xRadius": 708.9285714285717,
            "yRadius": 708.9285714285717,
            "aStartAngle": 1.8962863159108763,
            "aEndAngle": 1.2453063376789169,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                226.69627707387977,
                352.7771061926602
            ],
            "v2": [
                226.69627707387963,
                352.7771061926602
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": -2620.113751512889,
            "aY": -634.8172998557919,
            "xRadius": 3013.2490852434344,
            "yRadius": 3013.2490852434344,
            "aStartAngle": 0.3339217513663355,
            "aEndAngle": 0.21406911135034987,
            "aClockwise": true,
            "aRotation": 0
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "LineCurve",
            "v1": [
                324.3566384393507,
                5.31094699393168
            ],
            "v2": [
                324.3566384393506,
                5.310946993932236
            ]
        },
        {
            "metadata": {
                "version": 4.6,
                "type": "Curve",
                "generator": "Curve.toJSON"
            },
            "arcLengthDivisions": 200,
            "type": "EllipseCurve",
            "aX": 295.9440638544912,
            "aY": 18.322023254557465,
            "xRadius": 31.25000000000004,
            "yRadius": 31.25000000000004,
            "aStartAngle": 5.853753309736651,
            "aEndAngle": 3.9991628737334275,
            "aClockwise": true,
            "aRotation": 0
        }
    ],
    "currentPoint": [
        275.49790976053043,
        -5.310946993932507
    ],
    "uuid": "4dc984fb-f8b2-4b76-9437-8707ae68a126",
    "holes": []
}
1
  • It seems to be a problem with triangulation. Three.js uses a fork of mapbox/earcut, which has similar problems reported, e.g. github.com/mapbox/earcut/issues/152... Commented Oct 12, 2024 at 16:07

1 Answer 1

0

This is a problem with triangulation.

Three.js uses a fork of earcut. Looking at the open issues, there are a few similar problems. In particular, earcut does not seem to like when a contour crosses itself and forms a hole next to the edge:

earcut problem

(image source)

Based on this information, I hypothesized that my arcs might be overlapping slightly and crossing each other at intersection. This way, holes/loops would form, completed by the lines automatically added by Three.js. To test this theory, I shortened each arc by 0.001 radians and the glitch disappeared.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.