(Эта статья изначально была опубликована на моем личном веб-сайте. Пожалуйста, прочтите ее там, чтобы получить правильную математическую отрисовку и интерактивные демонстрации.)

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

Если вы рассматриваете кривую, которая является плоской, то есть полностью лежит внутри плоской плоскости, у этой кривой никогда не будет этой проблемы. Представьте, что вы идете по «верхней» стороне поперечного сечения. Вы всегда сможете оставаться в вертикальном положении от начала до конца. Только когда вы выходите из плоскости, вы в конечном итоге указываете в другом направлении по пути и, следовательно, в другом направлении, когда возвращаетесь в исходную точку.

Что дает?

Компенсация несоответствия скручиванием

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

Мы не хотим применять этот поворот резко в одной точке, поэтому мы можем применять его постепенно по всей длине кривой:

Так как же определить, что 180° — это правильное количество несоответствий для компенсации? Просто вычислите кадры минимизации вращения в начале и в конце (что потребует вычисления кадров в середине), затем сравните ориентацию двух кадров. Поскольку первый и последний кадры должны перекрываться, можно просто вычислить угол между опорными векторами r двух кадров.

Поскольку начальный опорный вектор r₀ и конечный вектор rₙ находятся в одном и том же месте, вы можете найти угол между ними, используя скалярное произведение между ними (помните, что векторы являются единичными векторами длины 1):

Здесь θ — сквозной поворот, который мы искали. Мы можем просто линейно интерполировать это общее скручивание по визуализируемым кадрам, поворачивая каждый кадр на долю полного скручивания, пока не будет учтено все скручивание.

Добавлен поворот

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

Что действительно интересно в этих кривых, так это то, что все они «эквивалентны», по крайней мере, при определенных преобразованиях, о которых я расскажу подробнее в следующем посте.

Одна вещь, которую вы, возможно, заметили из приведенного выше расчета скручивания, заключается в том, что диапазон arccos составляет от -180° до 180°. Это имеет смысл, поскольку два вектора могут находиться на расстоянии до 180° друг от друга в одной плоскости. Однако, если вы начнете с небольшого поворота и постепенно трансформируете кривую, вы можете в конечном итоге накапливать поворот по пути.

Самый простой способ увидеть это — «развернуть» петлю в виде восьмерки, которую вы можете увидеть на визуализации ниже:

Мы начинаем с довольно обычной восьмерки, хотя одна из сторон немного смещена, чтобы показать, как будет происходить развертывание. Со временем кривая превращается в круг, но обратите внимание, что произошло с вращением кадров по кругу. Чтобы сохранить взаимную ориентацию рамок по кривой, при раскладывании накопилось 360° скручивания!

Плоский круг может визуализироваться без сквозного скручивания, как и любая плоская кривая. Но демонстрация намекает на то, что восьмерка без поворота и плоский круг без поворота не эквивалентны! По крайней мере, не эквивалентно разворачивающемуся преобразованию, которое мы сделали. Вместо этого восьмерка без закручивания эквивалентна плоскому кругу с закручиванием на 360°.

Этот процесс накопления крутки в ходе трансформации играет большую роль в моем исследовании, о чем я расскажу более подробно в следующем посте.

Идея скручивания кривой занимает центральное место в моем студенческом исследовании. Неплоские кривые могут иметь несовпадающие концы при рендеринге с использованием кадров, минимизирующих вращение, и когда это происходит, к кривой необходимо добавить компенсирующий поворот. Кривые также могут иметь некоторую дополнительную крутку, которую можно применить так же, как компенсирующую крутку.

После того, как концепция скручивания установлена, в следующем посте будет рассказано о том, как скручивание кривой каким-то образом присуще кривой и изменяется только очень специфическим образом при преобразовании кривой.