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

Я пытаюсь прикрепить профили 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);

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


person jaykumarark    schedule 02.04.2016    source источник


Ответы (1)


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

Распространенной проблемой в компьютерной графике является создание ненулевого вектора в 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-непрерывным, иначе вы получите аналогичные «повороты», вызванные разрывами во второй производной (также известной как ускорение / вектор нормали).

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

person Tamás Zahola    schedule 02.04.2016
comment
Ну, проблема в том, что я не могу гарантировать, что кривая будет непрерывной C2. Кривая генерируется алгоритмом, который может обеспечивать или не обеспечивать непрерывную кривую C2. Когда у меня есть матрица tbn, как мне изменить основу этих профилей круга (2d-формы). - person jaykumarark; 02.04.2016
comment
Просто умножьте вершины на эту матрицу. Также не забудьте перевести исходную точку в исходную точку Френе-фрейма. - person Tamás Zahola; 02.04.2016
comment
Использование фреймов Фернета не поможет вам полностью решить эту проблему, поскольку фрейм Френе на невыпуклой кривой меняет направление нормальных полей на противоположное. Чтобы избежать этой проблемы, вам нужно будет использовать кадры, минимизирующие вращение. Этот документ объясняет это faculty.engineering.ucdavis.edu/farouki/wp-content/uploads/ - person sancelot; 09.03.2020