Репликация кривых Безье Блендера в программе на C ++ - PullRequest
4 голосов
/ 01 апреля 2012

Я пытаюсь экспортировать (3D) кривые Безье из Blender в мою программу на C ++. Я задал соответствующий вопрос некоторое время назад , где мне было успешно направлено использование алгоритма Де Кастельжау для оценки точек (и касательных к этим точкам) вдоль кривой Безье. Это хорошо работает. На самом деле отлично. Я могу экспортировать кривые и оценивать точки вдоль кривой, а также касательную к этим точкам, все в моей программе, используя алгоритм де Кастельжау.

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

Я заметил, что при построении кривых в Blender они не просто бесконечно тонкие линии , они фактически имеют правильную трехмерную ориентацию, определенную в любой точке вдоль них (как показано смещением) стрелки линии "на скриншоте ниже). Я бы хотел повторить, что Блендер делает здесь как можно точнее в моей программе. То есть я хотел бы иметь возможность сформировать матрицу, которая представляет ориентацию в любой точке вдоль кривой Безье 3D (почти точно так же, как это было бы в самом Blender).

enter image description here

Может ли кто-нибудь дать здесь дополнительное руководство, возможно, кто-то с глубоким знанием исходного кода Blender? (Но любой совет приветствуется, опыт Блендер или нет.) Я знаю, что это открытый исходный код, но у меня много проблем с выделением кода, ответственного за эти вычисления кривых, из-за обширности программы.

Ответы [ 3 ]

6 голосов
/ 09 января 2013

Несколько недель назад я нашел решение этой проблемы.Я публикую это здесь, на случай, если кому-то еще это понадобится:

1) Для заданной точки P0 вычислите касательный вектор T0.

Один простой и легкий способ - эточтобы взять следующую точку на кривой, вычесть текущую точку, а затем нормализовать результат:

T0 = normalize(P1 - P0)

Другой, более точный способ получить касательную - это вычислить производную вашей функции кривой Безье.

Затем выберите произвольный вектор V (например, вы можете использовать (0, 0, 1))

Make N0 = crossproduct(T0, V) и B0 = crossproduct(T0, N0) (не забывайте нормализовать векторы результатов после каждогооперация)

Теперь у вас есть начальный набор координат (P0, B0, T0, N0)

enter image description here

Этоисходная ориентация камеры.

2) Затем для вычисления следующих точек и их ориентации:

Рассчитайте T1, используя тот же метод, что и T0

Вот хитрость, новый опорный кадр вычисляется из предыдущего кадра:

N1 = crossproduct(B0, T1)

B1 = crossproduct(T1, N1)

enter image description here

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

Вы можете посмотреть живой пример здесь (не от меня): http://jabtunes.com/labs/3d/webgl_geometry_extrude_splines.html

1 голос
/ 01 апреля 2012

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

Я создал пустой объект для отслеживания кривой и заметил, что он ведет себя аналогично тележке американских горок: его вектор «вверх» коррелировал с центробежной силой, когда он двигался вдоль кривой. Это можно однозначно оценить по локальной форме кривой.

Я не очень хорош в физике, но я бы попытался оценить этот вектор, оценивая две плоскости: первая - ранее упомянутая перпендикулярная плоскость, а вторая - плоскость, состоящая из трех соседних точек сегмента кривой (если кривая не прямая, они образуют треугольник, который описывает ровно одну плоскость). Пересечение этих двух плоскостей даст вам ось, и вам останется только выбрать направление такого вычисленного нормального вектора.

1 голос
/ 01 апреля 2012

Если я правильно понимаю ваш вопрос, вам нужно получить 3 вектора ориентации (слева, спереди, вверх) для любой точки кривой.

Вот простой метод (есть ограничение,(*) см. ниже):

1) Фронтальный вектор:

Рассчитать трехмерную точку на кривой Безье для данной позиции (t).Это точка, для которой мы будем вычислять передний, левый и верхний векторы.Мы назовем это current_point.

Рассчитаем еще одну 3d точку на кривой, рядом с первой (t + 0,01), назовем ее next_point.

Примечание:я не пишу здесь формулу, потому что я вам уже верю, как это сделать.

Затем, чтобы вычислить фронтальный вектор, просто вычтите две вычисленные ранее точки:

vector front = next_point - current_point

Не забудьте нормализовать результат.

2) Левый вектор

Определить временный вектор "вверх"

vector up = vector(0.0f, 1.0f, 0.0f);  

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

vector left = CrossProduct(front, up);

3) Вектор вверх

vector up = CrossProduct(left, front);

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


(*) ПРИМЕЧАНИЕ: это не будет работать во всех случаях.Представьте, что у вас есть петля на кривой, как петля на американских горках.В верхней части цикла ваш вычисленный вектор будет равен (0, 1, 0), в то время как вы, возможно, захотите, чтобы он был (0, -1, 0).Единственный способ решить эту проблему - это иметь две кривые: одну для точек и одну для векторов вверх (из которых можно легко рассчитать левый и передний).

...