Избегать скручивания артефактов при экструзии сплайнов?

Я пытаюсь прикрепить 2D профили формы к кривой сплайна. В определенных точках сплайна я получаю странные искажающие артефакты в моей геометрии, как показано на рисунке. Как я могу избежать этого, используя уравнения Френе-Фрейма?

Мои текущие расчеты для нормальных, бинормальных и касательных:

forward_tangent_vector = glm::normalize(pointforward - pointmid);
backward_tangent_vector = glm::normalize(pointmid - pointback);
second_order_tangent = glm::normalize(forward_tangent_vector - backward_tangent_vector);
binormal = glm::normalize(glm::cross(forward_tangent_vector,second_order_tangent));
normal = glm::normalize(glm::cross(binormal, forward_tangent_vector));

//translation matrix
T = glm::translate(T, pointmid);

normal_axis = glm::vec3(0, 1, 0);
rotationAxis = glm::cross(normal_axis, forward_tangent_vector);
rotationAngle = glm::acos(glm::dot(normal_axis, forward_tangent_vector));

//rotation matrix
R = glm::rotate(R, glm::degrees(rotationAngle), rotationAxis);

введите описание изображения здесь

2

Решение

Вы стали жертвой теорема о волосяном шаре:

Общая проблема в компьютерной графике состоит в том, чтобы генерировать ненулевой вектор в R3, который ортогонален заданному ненулевому. Не существует единой непрерывной функции, которая могла бы делать это для всех ненулевых векторных входов. Это является следствием теоремы о волосяном шаре. Чтобы увидеть это, рассмотрим данный вектор как радиус сферы и отметим, что нахождение ненулевого вектора, ортогонального заданному, эквивалентно нахождению ненулевого вектора, который касается поверхности той сферы, где он касается радиус. Однако теорема о волосяном шаре гласит, что не существует непрерывной функции, которая могла бы делать это для каждой точки на сфере (то есть для каждого данного вектора).

Также посмотрите это: http://blog.sigfpe.com/2006/10/oriented-fish-and-hairy-balls.html

Проблема заключается в этих двух строках:

normal_axis = glm::vec3(0, 1, 0);
rotationAxis = glm::cross(normal_axis, forward_tangent_vector);

когда forward_tangent_vector коллинеарен с (0,1,0), rotationAxis становится (0,0,0), Вот почему вы получаете удар в трубе.

Что нужно сделать вместо жесткого кодирования (0,1,0), это взять первую производную от сплайна (вектор скорости / тангенса), взять вторую производную от сплайна (вектор ускорения / нормали) и взять их перекрестные произведения (бинормальные). Нормализуйте эти три вектора, и вы получите так называемый Френ-кадр, набор из 3 взаимно перпендикулярных векторов вокруг сплайна.

Обратите внимание, что ваш сплайн должен быть C2-непрерывным, в противном случае вы получите аналогичные «повороты», вызванные разрывами во второй производной (иначе говоря, вектор ускорения / нормали).

Когда у вас есть кадр Frenet, вам нужно просто сменить основу для работы в этой системе координат. Не возиться с glm::rotateпросто поместите единичные векторы x, y, z в матрицу в виде строк (или столбцов? Я не уверен, какое соглашение использует GLM …), и это будет ваша матрица преобразования.

3

Другие решения

Других решений пока нет …