Сбой при экструзии формы в Three.js

Вопрос или проблема

Мой код генерирует форму, состоящую из нескольких круговых дуг. (В координатах концов дуг есть небольшие ошибки округления, поэтому Three.js добавляет некоторые линии между ними.) Эта форма затем экструзируется без фаски.

При некоторых параметрах она отображается нормально:

правильная экструзия

Но в очень редких случаях возникает детерминированный сбой:

сбой при экструзии

Вот соответствующие каркасные модели:

правильная каркасная модель

сбойная каркасная модель

Что здесь может происходить?

Я пытался разобраться в этом, но безуспешно. Если я удаляю некоторые кривые (заменяя их линиями), проблема исчезает, но я не уверен, почему так происходит.

Вот первая форма, экспортированная в 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": []
}

А вот сбойная форма:

{
    "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": []
}

Ответ или решение

Возможные причины артефактов при экструзии форм в Three.js

При создании геометрических форм с помощью библиотеки Three.js, разработчики могут столкнуться с различными артефактами, включая неожиданные изменения в форме, возникающие во время экструзии. Рассмотрим проблему, с которой вы столкнулись, и поищем возможные причины и решения.

Описание проблемы

Ваша ситуация описывает создание формы, в основе которой лежат несколько circular arcs, и вероятность появления артефактов в процессе экструзии данной формы. В некоторых случаях при рендеринге возникают проблемы, которые можно визуально обнаружить на изображениях:

  1. Корректная экструзия (изображение 1).
  2. Глитч при экструзии (изображение 2).

На провявленных вами проводниках также наблюдаются различия, которые подтверждают наличие проблемы в обработке формы.

Возможные причины артефактов

  1. Ошибка округления: Как вы сами упомянули, в координатах концов дуг присутствуют очень небольшие ошибки округления. Эти зависимости могут привести к тому, что формально разные стыковочные точки будут восприниматься Three.js как одинаковые, что может вызвать неожиданные соединения между кривыми.

  2. Количество сегментов: В вашем JSON-коде для формы указано arcLengthDivisions: 200, что означает, что каждая кривая разбивается на 200 сегментов. В зависимости от минимальной длины кривой эта сегментация может привести к ошибкам при обработке углов и соединений. Попробуйте уменьшить это значение и посмотреть, изменит ли это поведение.

  3. Проблемы с замыканием формы: Формы, которые не замкнуты правильно, могут создавать проблемы при экструзии. Проверьте, что все точки соединяются. Если форма не замкнута, это может привести к тому, что Three.js будет добавлять линии между точками на этапе экструзии, что может вызвать артефакты.

  4. Геометрические особенности: Некоторые дуги и линии могут находиться слишком близко друг к другу или в параллельной конфигурации, что может вызвать проблемы в интерпретации формы во время экструзии. Замена дуг на линии, как вы заметили, устраняет проблему, что говорит о взаимосвязи с особенностями экструзионной обработки кривых.

  5. Использование UpdateGeometries: Иногда при изменении формы после ее создания необходимо вызвать метод geometry.computeFaceNormals() и geometry.computeVertexNormals(). Это улучшает отображение и может устранить нежелательные артефакты.

Рекомендации по исправлению

  1. Проверьте, все ли кривые и точки корректно соединяются. Верное соединение всех объектов критично для успешной экструзии.

  2. Экспериментируйте с параметрами arcLengthDivisions и числом сегментов в кривых, чтобы найти оптимальные значения, которые минимизируют визуальные артефакты.

  3. Используйте дополнительные инструменты отладки, такие как console.log(), для отслеживания координат контрольных точек в процессе экструзии. Это может помочь выявить проблемы с округлением.

  4. Проверьте настройки Three.js на предмет параметров отрисовки и математики, которые могут повлиять на алгоритмы экструзии. Постарайтесь использовать более простые Shapes, чтобы анализировать поведение более сложных форм.

  5. Возможно, вам стоит использовать сторонние библиотеки или методы для подготовки и очистки геометрических данных перед экструзией.

Заключение

Изучение и регулировка параметров форм, а также правильное соединение всех частей поможет устранить артефакты при экструзии в Three.js. Уделите особое внимание округлению и стыковке форм, а также другим упомянутым выше факторам, которые могут влиять на результат. Удачи в ваших разработках!

Оцените материал
Добавить комментарий

Капча загружается...