Линии безье. Рисование кривых Безье

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

Рис. 6-36 Нечетырехугольные куски. (а) Пятиугольный; (b) треугольный.

Возникающие проблемы иллюстрируются на рисунках 6-33-6-35. Большинство из этих проблем можно преодолеть, распространив понятия кривых Безье на поверхности.

Декартово или тензорное произведение поверхности Безье задается в виде

, (6-58)

где и есть базисные функции Бернштейна в параметрических направлениях и (см. уравнения 5-63 и 5-64). Для удобства повторим здесь определение, приведенное ранее в разд. 5-8

, (5-63)

,

. (6-64)

Здесь элементы являются вершинами задающей полигональной сетки, как это показано на рис. 6-37. Индексы и на единицу меньше числа вершин многогранника в направлениях и , соответственно. Для четырехсторонних кусков поверхностей задающая полигональная сетка должна быть топологически прямоугольной, т. е. должна иметь одинаковое количество вершин в каждом «ряду».

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

Степень поверхности в каждом параметрическом направлении на единицу меньше числа вершин задающего многогранника в этом направлении.

Рис. 6-37 Поверхность Безье и вершины характеристического многогранника.

Рис. 6-38 Схема задающей полигональной сетки для поверхности Безье.

Гладкость поверхности в каждом параметрическом направлении на две единицы меньше числа вершин задающего многогранника в этом направлении. Поверхность отображает в общем виде форму задающей полигональной сетки. Совпадают только угловые точки задающей полигональной сетки и поверхности.

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

Поверхность не проявляет свойства затухания изменений. Это свойство не определено и неизвестно для поверхностей двух переменных.

Поверхность инвариантна относительно аффинного преобразования.

Каждая из граничных кривых поверхности Безье является кривой Безье. Запомним этот факт и рассмотрим задающую полигональную сетку для бикубической поверхности Безье размера , изображенную схематично на рис. 6-38. Легко видеть, что направление и величина касательных векторов в угловых точках куска управляются положением соседних точек вдоль сторон сетки. А именно касательные векторы в направлениях в точке управляются вершинами полигональной сетки и , соответственно. Аналогичным образом, вершины полигональной сетки , , , и , управляют касательными векторами в угловых точках , соответственно. Четыре внутренние вершины полигональной сетки, , , и влияют на направление и величину векторов кручения в угловых точках куска поверхности. Следовательно, пользователь может управлять формой куска поверхности, не зная конкретных значений касательных векторов и векторов кручения.

На рис. 6-39 показано несколько бикубических поверхностей Безье и их задающих полигональных сеток. Базовая полигональная сетка имеет размер и отцентрирована относительно начала координат с угловыми точками, находящимися в по , . Компонента у угловых вершин равна нулю. У всех других вершин эта компонента равна пяти. Базовая полигональная сетка и соответствующая ей поверхность Безье изображены на рис. 6-39а. На рис. 6-39 точка является левой угловой вершиной, а - правой угловой вершиной. Заметим, что центральные вершины базовой полигональной сетки образуют плоский крест (показанный затененным). Следовательно, центр получившейся поверхности минимально изогнут, хотя и не плоский.

На рис. 6-39b проиллюстрирован эффект увеличения в 2 раза величины касательного вектора в точке в обоих параметрических направлениях и с помощью перемещения точек и . Вектор кручения не меняется. Отметим увеличение кривизны граничных кривых, отвечающих значениям параметров и , и соответствующее изменение внутренности поверхности.

На рис. 6-39с показано действие изменения направления касательных векторов в точке в обоих параметрических направлениях и с помощью перемещения точек и . Отметим изменение знака кривизны граничной кривой около точки и формы внутренней части поверхности по сравнению с базовой поверхностью.

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

В матричном виде декартово произведение поверхности Безье задается выражением

,

,

,

а матрицы и задаются уравнением (5-70) или (5-71).

Рис. 6-39 Бикубические поверхности Безье. (а) Основная поверхность; (b) эффект изменения величины обоих касательных векторов в ; (с) эффект изменения направления касательного вектора в ; (d) эффект изменения величины вектора кручения в .

Для специального случая бикубической поверхности Безье размера уравнение (6-59) сокращается до

. (6-60)

Поверхность Безье не обязательно должна быть квадратной. Для сетки размера уравнение (6-59) превращается в

. (6-61)

Поверхность Безье размера состоит из полиномиальных кривых четвертой степени в параметрическом направлении и из квадратичных полиномиальных кривых в направлении . Пример такой поверхности Безье показан на рис. 6-40. В данном случае, как это показано на рис. 6-40b, изменение центральной вершины стороны задающей сетки с пятью вершинами не влияет на касательные векторы в угловых точках.

Рис. 6-40 Поверхность Безье размера . (а) Основная поверхность; (b) эффект изменения центральной вершины граничной ломаной с пятью вершинами.

Производные поверхности Безье получаются с помощью формального дифференцирования уравнения (6-58) или (6-59). Если воспользоваться уравнением (6-58), то первые и вторые параметрические производные будут

, (6-62)

, (6-63)

, (6-64)

, (6-65)

, (6-66)

где штрих обозначает дифференцирование относительно параметрической переменной. Производные функций базиса Бернштейна , , и приведены в уравнениях (5-74) и (5-75).

Легко найти соотношение между бикубическими поверхностями Безье и Кунса. Приравнивая уравнения (6-52) и (6-59), получим

где задан уравнением (5-76) и - уравнением (5-70). Следовательно геометрическая матрица бикубической поверхности Кунса задается в терминах полигональной сетки поверхности Безье следующим образом

. (6-67)

Исследование правой нижней подматрицы размера в уравнении (6-67) подтверждает, что четыре центральные вершины задающей полигональной сетки влияют на кручение в угловых точках куска бикубической поверхности Безье. Тем не менее, кручение в угловых точках управляется не только центральными вершинами, но также и соседними касательными векторами. В самом деле, кручение в угловой точке управляется формой неплоского четырехугольника, сформированного угловой точкой, двумя соседними граничными точками и соседней центральной точкой.

Из уравнений (6-62)-(6-64) следует, что

. (6-68)

Аналогичным образом обратное соотношение между матрицами и , выражающее вершины полигональной сетки Безье в терминах параметров бикубической поверхности Кунса, равно

. (6-69)

Более полно концепция поверхности Безье иллюстрируется на следующем примере.

Пример 6-14 Поверхность Безье

Для изображенной на рис. 6-39а поверхности Безье для значений параметров определить координаты точки на поверхности и первые производные в и направлениях. Найти также координаты точки и производные для модифицированной поверхности, показанной на рис. 6-39d. Сравнить полученные результаты. Вершины многогранника поверхности Безье таковы:. Новое значение произведения: и все еще ортогональны, но как их величины, так и направления отличаются. Данные результаты показывают, что вектор кручения в одной угловой точке оказывает трудно уловимое, но существенное влияние на форму всей поверхности.

Приведенное выше обсуждение поверхностей Безье касалось определения и характеристик одного куска поверхности. Для того чтобы получить более сложные поверхности, надо объединить несколько кусков поверхности Безье. Подробное обсуждение этого вопроса лежит вне сферы данной книги. Интересующегося читателя мы отсылаем к и . Проблемы, возникающие при объединении кусков поверхности Безье с обеспечением гладкости вдоль соприкасающихся сторон, иллюстрируются рис. 6-41 на примере объединения двух кусков бикубической поверхности Безье вдоль одной стороны.

Для обеспечения непрерывности или гладкости вдоль границы необходимо, чтобы совпадали две граничные кривые, а следовательно, и две граничные ломаные вдоль края поверхности. Для обеспечения непрерывности векторов наклона или касательных векторов или гладкости вдоль границы куска направление нормали к поверхности вдоль граничной кривой должно быть одинаковым для обоих кусков. Для этого можно использовать два условия. Первое требует, чтобы четыре отрезка полигональной сетки, встречающиеся у границы и пересекающие ее, были коллинеарными, как это показано выделенными линиями на рис. 6-41а. Второе, менее жесткое условие требует, чтобы только три ребра полигональной сетки, встречающиеся в концевых точках граничной кривой, были компланарными, как это показано выделенными линиями на рис. 6-41b.

Аналогичные построения для кубической кривой:

Повторюсь, что можно t* взять произвольный, чтобы разбить кривую в любой точке.

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

Как связать формулы с тем, что мы видим в редакторах векторной графики

В векторных редакторах никаких формул нет. Есть кривые, построенные по контрольным точкам:

Существует 2 основных типа контрольных точек, использующихся в редакторах –

  • Точка с заданием кривизны (Curve) - имеет направляющие (в различных редакторах - handles, tangents, direction points), управляющие формой кривой. Обычно такая точка имеет 2 направляющих.
  • Угловая(Corner) - вершина без направляющих.

Фактически, контрольная точка с заданием кривизны предоставляет информацию о 2 точках, по которым в дальнейшем будет строится кривая Безье. Это позиция самой точки и позиция конца ее направляющей.
Линейная контрольная точка предоставляет лишь 1 точку для построения кривой Безье.

Соотнести изображение с формулами кривых Безье не очень сложно.

  • Каждая кривая Безье строится ровно по 2 контрольным точкам. Т.е. если в редакторе мы видим кривую, содержащую 4 контрольные точки (как в примере выше) – значит, она состоит из 3 кривых Безье, 5 контрольных точек - из 4 кривых Безье и т.д. Исключением являются замкнутая кривые - для них число кривых Безье совпадает с числом контрольных точек.
  • Степень полинома кривой Безье определяется по типам 2 контрольных точек, для которых она построена.

В зависимости от комбинации типов контрольных точке получаем следующие случаи построения кривых Безье:


Создание 2d редактора Безье: стандартные проблемы.

Стандартных проблем две:
  • Как отрисовывать кривые – параметрическую кривую в чистом виде отрисовать сложно. Как правило, используется ее аппроксимация ломаной, вершины которой лежат на кривой. Понятно, что стоить ломаную можно множеством способов. Какой выбрать и почему?
  • Практически во всех векторных редакторах контрольные точки с заданием кривизны подразделяются на 3 типа (названия - из Corel Draw):
    • Cusp – точка имеет 2 полностью независимых направляющих. За счет этого можно формировать острые углы с заданной кривизной
    • Smooth – точка имеет 2 направляющих, которые противоположно направлены
    • Symmetrical – то же самое, что и Smooth, только длины обоих направляющих всегда одинаковы.
    Проблема состоит в конвертировании точек из одного типа в другой.

Решение проблемы построения ломаной по кривой Безье

Решение «в лоб» – «пройтись» по кривой, изменяя параметр t с некоторым шагом, получив таким образом набор точек, лежащих на кривой. Эти точки образуют искомую ломаную.
Недостаток данного метода состоит в том, что кривая будет плохо приближаться на участках с большой кривизной. Подробнее останавливаться не буду, хорошие примеры есть в начале данной статьи

Для качественной аппроксимации кривой лучше использовать адаптивный метод. Метод основывается на рекурсивном разбиении кривой на участки, пока на каждом участке мы не достигнем требуемой нам гладкости кривой. Главная загвоздка кроется как раз в критерии для «достигнем требуемой нам гладкости». О тяжких поисках такого критерия можно почитать в статье по ссылке выше, но критерии автора мне не очень понравились из-за своей неустойчивости и множества частных случаев.

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

Для кубической кривой:


Т.е. кривая считается «достаточно гладкой», когда углы между отрезками, соединяющих ее контрольные точки, становятся «достаточно тупыми» - в данном случае для оценки углов между ними используются cos, посчитанные через скалярное произведение нормализованных векторов отрезков. На практике хорошие результаты давали значения tolerance = 1E-4..1E-2 .

Критерий не работает, если какие-либо из соседних (т.е. например, P0 и P1, P1 и P2) контрольных точек совпадают. Эти частные случаи решаются следующим образом:

  • Если для квадратной кривой P0 P1 P2 совпадают точки P0 P1 или P1 P2 (в программной реализации – находятся на некотором малом расстоянии), квадратичная кривая сводится к линейной, и, следовательно, достаточно добавить к аппроксимирующей ломаной получившийся отрезок линейной кривой.
  • Если для кубической кривой P0 P1 P2 P3 совпадают точки P0 P1 или P1 P2 или P2 P3 (в программной реализации – находятся на некотором малом расстоянии), используется критерий для кубической кривой (совпадающие точки при применении критерия будут рассматриватся как одна).

Мы все знаем что такое кривая. Вот несколько примеров.

Кривые Безье очень просты в использовании, и могут описывать многие формы. Кривые Безье широко используются для представления символов в шрифтах, и форм конструкций транспортных средств. Кривые Безье также используются в редакторах векторной графики для представления различных кривых, и в инструментах 3D-анимации для представления анимационных кривых.

В играх кривые Безье иногда полезны для описания пути: гоночный путь на трассе в гоночной игре, или линии в играх с рисованием линий, таких как Flight Control , или зацикленная траектория парения бабочки, что что живет в мире RPG.

Кривые Безье так популярны, потому что их математическое описания очень компактно, интуитивно понятно и элегантно. Их легко вычислить, легко использовать в более высоких измерениях (3D и выше), и могут быть соединены вместе, чтобы представить любую форму какую вы только можете себе представить.

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

Математическое описание

Начнем с математики. Математически мы можем описать кривую Безье на функцию. Функция принимает параметр . Значение функции есть точка на кривой; она зависит от параметра , и от множества точек, называемых контрольными точками. Первая и последняя контрольные точки являются концами кривой. Как правило, кривая не проходит через другие контрольные точки.

Значение может колебаться от 0 до 1. Значение 0 соответствует начальной точке кривой, значение 1 соответствует конечной точке кривой. Значения в промежутке соответствуют остальным точкам на кривой.

Вот пример простейшего типа кривой Безье, отрезок:

А вот сокращенное обозначение для двух уравнений, которые дают раздельные координаты:

Точки и являются контрольными точками. Когда , правая часть уравнения равна первой контрольной точке - началу отрезка. Когда , получаем точку , вторую контрольную точку - конец отрезка.

Для более интересных форм нам нужно больше контрольных точек. Количество контрольных точек определяет степень кривой. Две контрольные точки необходимы для линейных (первая степень) кривых, таких как отрезок выше. Для второй степени, или квадратичных кривых, нам нужны три контрольные точки.

Вот формула:

Кубические кривые (или кривые третьей степени) являются наиболее часто используюемыми, и поэтому в данном руководстве мы будем обсуждать именно кубические кривые . Для их построения требуется четыре контрольные точки, и возможно вы уже хорошо знакомы с их использованием в пакетах векторной графики (да, те самые кружочки которые используются для изменения формы кривых в программах Freehand или Inkscape и есть нашими контрольными точками).

Желтые линии протянуты в том же направлении, что и касательные на концах кривой. Чем дальше расположены эти желтые сегменты, тем сильнее "натянута" кривая по направлению касательных.

Формула для кубических кривых Безье:

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

Случаи

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

Вот правильные 2D кривые Безье:

Все конечные точки на одинаковом расстоянии друг от друга. 1. Кривая без перегиба, залома или петли. 2. Кривая с перегибом, без заломов или петель. 3. Кривая с заломом. 4. Кривая с петлей. 5. Прямая линия. (В точке перегиба кривая меняет направления сгиба)

Вырожденный случай 5 является самым сложным. Могут быть следующие варианты:

  • нет перекрытий
  • кривая заламывается дважды на одном или обоих концах
  • кривая заламывается трижды тройка где-то между концами

Существует шестой случай, когда все четыре контрольные точки совпадают: в результате кривая вырождается в одну точку. Обратите внимание, что кривая не вырождается в точку когда только конечные точки совпадают - все четыре контрольные точки должны совпадать. Кому интересны технические подробности могут почитать A Geometric Characterization of Parametric Cubic Curves (1.6 MB PDF) авторов Stone и De Rose. Статья Inflection points of a cubic Bezier объясняет, как вычислить точки перегиба, а также предоставляет интерактивные апплеты Java для наглядной иллюстрации.

В 3D, петли и переломы доставляют меньше проблем, так как они проявляются только в том случае, когда все точки лежат в одной плоскости. В 3D всегда можно изменить направление движения прямой (особенно для таких случаев как 2, 4 и 5).

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

Реализация

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

Код приводится на языке C#, но перевести на Java, C + + и большинство других языков не должно принести особых проблем.

(Следующие функции будут работать и в 2D, если Vector3 заменить на Vector2.)

Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { float u = 1 – t; float tt = t* t; float uu = u* u; float uuu = uu * u; float ttt = tt * t; Vector3 p = uuu * p0; //first term p += 3 * uu * t * p1; //second term p += 3 * u * tt * p2; //third term p += ttt * p3; //fourth term return p; }

Рисование кривых Безье

Теперь у нас есть способ вычисления точки на кривой Безье, нам нужен способ рисования кривой.

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

for (int i = 0 ; i <= SEGMENT_COUNT; ++ i) { t = i / (float ) SEGMENT_COUNT; Vector3 pixel = CalculateBezierPoint(t, p0, p1, p2, p3) ; DrawPixel(pixel) ; //assume this function can handle Vector3 }

Этот подход страдает от следующих проблем:

Более продвинутые алгоритмы используют адаптивный прирост чтобы преодолеть эти проблемы. Сглаживание (antialiasing) кривой даст вообще класный результат, делая кривую очень гладкой и четкой. Хорошим источником для рисования кривых (и еще куча полезных тем) является Computer Graphics and Computer Modelling от David Salomon.

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

q0 = CalculateBezierPoint(0 , p0, p1, p2, p3) ; for (int i = 1 ; i <= SEGMENT_COUNT; ++ i) { t = 1 / (float ) SEGMENT_COUNT; q1 = CalculateBezierPoint(t, p0, p1, p2, p3) ; DrawLine(q0, q1) ; q0 = q1; }

Так как теперь нам не нужно волноваться о пропуске пикселей, можно выбрать больший прирост и снизить нагрузку на отрисовку. Но все же трудно выбрать приращение должным образом.

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

Вот алгоритм:

На рисунке ниже показан рабочий пример.

1. Начнем с двух конечных точек и точкой между ними. Мы проверяем угол, образованный между двумя отрезками. Он достаточно мал, поэтому мы добавим между ними точку отрисовки. 2. Затем мы делаем то же самое для левой части кривой. В этом случае угол достаточно велик, так что мы не добавляем точку, и не разбиваем дальше. 3. Мы делаем то же самое для правой части кривой. В этом случае угол достаточно мал, поэтому мы добавляем новые точки для отрисовки, и развиваем отрезок. 4. И 5. Мы делаем то же самое для двух половинок на предыдущем шаге. В каждом случае угол достаточно велик, так что новые точки не добавляются, разбиение также не нужно. 6. Окончательный набор точек используется для рисования кривой.

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

//returns the number of points added. int FindDrawingPoints(float t0, float t1, int insertionIndex, List pointList) { tMid = (t0 + t1) / 2 ; p0 = bezierCurve(t0) ; p1 = bezierCurve(t1) ; if (p0 – p1. sqrMagnitude < MINIMUM_SQR_DISTANCE) { return 0 ; } pMid = bezierCurve(tMid) ; leftDirection = (p0 – pMid) . Normalised ; rightDirection = (p1 – mMid) . Normalised ; if (Dot(leftDirection, rightDirection) > threshold) { int pointsAddedCount = 0 ; pointsAdded += FindDrawingPoints(t0, tMid, insertionIndex, pointList) pointList. insert (insertionIndex + pointsAdded, pMid) ; pointsAdded++; pointsAdded += FindDrawingPoints(tMid, t1, insertionIndex + pointsAdded, pointList) ; return pointsAdded; } return 0 ; }

Следующая функция демонстрирует вызов рекурсивной функции:

void FindPoints() { List pointList = new List() ; p0 = bezierCurve(0 ) ; p1 = bezierCurve(1 ) ; pointList. Add (p0) ; pointList. Add (p1) ; int pointsAdded = FindPoints(0 , 1 , 1 , pointList) ; assert(pointsAdded + 2 == pointsList. Count ) ; //sanity check }

Несколько замечаний:

  • Проверка на минимальное расстояние необходима для предотвращения проблем с нормализацией очень коротких векторов. Она также предотвращает ненужные вычисления.
  • Пороговое значение на удивление близко к -1. Для старта неплохо начать с -0,99.
  • Алгоритм не очень хорошо работает для кривых, которые содержат перегибы или петли. Ниже приведен пример того, что может произойти, если применить его к кривой с перегибом.

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

Склейка кривых вместе: пути Безье

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

  • использовать одну кривую Безье с высокой степенью;
  • разделить кривую на более мелкие сегменты, и использовать кривые Безье низкой степени для каждого сегмента.

Последний тип кривой называется пути Безье. Пути Безье, как правило, более просты и эффективны в использовании, чем кривые высокой степени, поэтому именно этот метод здесь и описывается.

Приведенная здесь реализация является лишь одной из многих возможных. Мы определим класс, который создает список контрольных точек кривых Безье, которые составляют путь Безье. Поскольку сегменты связаны концом-к-концу, начальная и конечная точка соседних кривых совпадают, таким образом мы можем избежать дублирования точек. На рисунке показан пример пути Безье составленого из четырех кривых Безье. В этом случае, список содержит 13 точек, как показано на рисунке слева.

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

class BezierPath { List controlPoints; Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { ... } List GetDrawingPoints() { List drawingPoints = new List() ; for (int i = 0 ; i < controlPoints. Count - 3 ; i+= 3 ) { Vector3 p0 = controlPoints[ i] ; Vector3 p1 = controlPoints[ i + 1 ] ; Vector3 p2 = controlPoints[ i + 2 ] ; Vector3 p3 = controlPoints[ i + 3 ] ; if (i == 0 ) //Only do this for the first endpoint. //When i != 0, this coincides with the end //point of the previous segment { drawingPoints. Add (CalculateBezierPoint(0 , p0, p1, p2, p3) ) ; } for (int j = 1 ; j <= SEGMENTS_PER_CURVE; j++ ) { float t = j / (float ) SEGMENTS_PER_CURVE; drawingPoints. Add (CalculateBezierPoint(t, p0, p1, p2, p3) ) ; } } return drawingPoints; } }

Данный рекурсивный алгоритм легко адаптируется для получения промежуточных точек. Пример вы можете найти в прилагаемом к статье коде.

При реализации путей Безье, вы можете сделать вашу жизнь намного проще, выполнив следующие действия:

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

Ну и напоследок - кривые Безье это очень круто, но не стоит использовать их везде, особенно для представления коротких, практически прямых линий.

  • Большинство 3D движков требуют использовать короткие прямые линии для рендеринга кривых, поэтому вы должны точно представлять себе ценность внедрения отрисовки кривых Безье.
  • Когда движение находится под контролем физики, соответственно резкие изменения скорости и направления практически отсутсвуют. Объекты, как правило, перемещаются путем изменения силы, действующей на объект, и благодаря этому их скорость не может измениться мгновенно. Таким образом, любое движение сглаживается автоматически: любой объект следующий вдоль соединенных прямых линий будет автоматически следовать сглаженому пути - в кривых Безье нет никакой надобности.

Скачать

  • Bezier Curves (64 KB, Unity 3D Project, zipped)
  • BezierPath.cs (C# source code file)

Статья является переводом, ссылка на источник - Bezier Curves for your Games: A Tutorial .
Если вы заметите какие либо неточности в переводе - просьба сообщать об этом письмом на адрес указаный внизу страницы.

радиус-вектора B -кривой

    Фиксируем t . Положим Тогда существует единственное такое, что где

    Для определенного выше индекса если вычисляем единственное ненулевое значение ненормированного B -сплайна первого уровня (m=1) :

    Напомним, что было выбрано на первом шаге, так чтобы При этом, в силу условия знаменатель а в силу условия имеем Следовательно, Для индекса находящегося вне множества значение не вычисляется.

    С помощью соотношений Кокса - де Бура вычисляем все отличные от нуля в точке ненормированные сплайны -го порядка при :


    В частности,

    (6.6)

    где Положив в (6.6) получим

    Лемма 6.5 . Имеет место соотношение :

  1. Вычисляем нормированные сплайны для каждого по формуле (при этом ).

  2. Окончательно вычисляем по формуле

Алгоритм де Бура вычисления радиус-вектора B-кривой

Теорема 6.4 . Радиус-вектор r(t) B -кривой:

может быть вычислен с помощью следующего алгоритма:

Данный алгоритм иллюстрируется следующей диаграммой ():

Поверхности, определяемые матрицами опорных точек и весов

Поверхности Безье

Определение 6.2.1 . Пусть дано (m +1) * (n+1) точек в пространстве образующих прямоугольную матрицу (сетку Безье):

Поверхностью Безье порядка m * n , соответствующей сетке называется поверхность

(6.7)

где E - оператор сдвига вперед по первому индексу, F - оператор сдвига вперед по второму индексу:

Операторы E и F очевидно коммутируют друг с другом: Поэтому т. е. формула (6.7) непротиворечива.

Определение 6.2.2 . Рациональная поверхность Безье, построенная по точкам с весами определяется следующим образом:

(6.8)

Формула (6.8) означает, что мы строим поверхность Безье в по точкам а затем применяем преобразование

Задача 6.2.1 . Наглядно изучить влияние опорных точек и их весов на рациональную поверхность Безье, меняя исходные данные pts (опорные точки) и (их веса) в нижеследующей программе. В матрице весов стоят двумерные векторы, но используется только их первая компонента. Вторая компонента фиксирована. Это связано с неспособностью Mathematica применять функцию BezierFunction к матрицам из скаляров.

Пример 6.2.1 . Рациональная поверхность Безье с возможностью непосредственного управления весами с помощью движков.

In: = DynamicModule [ {pts, a, w0, pw, w, g, f, w6, w7, wl0, wll, i, j, out, ins, u, v, n, pts0}, pts = {{{0, 0, 0}, {0, 1, 0), {0, 2, 0}, {0, 3, 0}}, {{1, 0, 0}, {1, 1, 1}, {1, 2, 1}, {1, 3, 0}}, {{2, 0, 0}, {2, 1, 1}, {2, 2, 1}, {2, 3, 0}}, {{3, 0, 0}, {3, 1, 0}, {3, 2, 0} , {3, 3, 0}}}; pts0 = Flatten ; n = Length ; Row[ {Manipulate ] , {i, 1, 4}, {j, 1, 4}]; pw = Table ] pts [ ] , {i , 1, 4} , { j , 1, 4} ] ; g = BezierFunction; f = BezierFunction; Show[{Graphics3D[{PointSize, Red, Map , Green, Text , pts0[[#]] + {0.01, 0.04, 0.04}] & /@ Range[n]}], Graphics3D[{Gray, Dashed, Line, Line]}], ParametrioPlot3D / g , {u, 0, 1}, {v, 0, 1}, PlotStyle -> FaceForm ] }] , Column[{Control[{{ins, Green, "Внутренний цвет"}, Green}], Control[{{out, Red, "Внешний цвет"}, Red}]}, Right], {{w5, 10}, 1, 100}, {{w6, 10}, 1, 100}, {{w9, 10}, 1, 100}, {{wl0, 10}, 1, 100}] MatrixForm } , " " ] , Initialization: -> (pts = {{{0, 0, 0}, {0, 1, 0}, {0, 2, 0}, {0, 3, 0}}, {{1, 0, 0}, {1, 1, 1}, {1, 2, 1}, {1, 3, 0}}, {{2, 0, 0}, {2, 1, 1}, {2, 2, 1}, {2, 3, 0}}, {{3, 0, 0}, {3, 1, 0}, {3, 2, 0}, {3, 3, 0}}}; pts0 = Flatten ; a = 1; n = Length)]


Геометрический смысл поверхности Безье

Поверхность Безье можно получить следующим образом:

При этом соответствующий оператор перехода от опорной точки, взятой на кривой к следующей опорной точке, взятой на кривой в терминах узлов сетки pij описывается оператором сдвига F по второму индексу. Следовательно,

где m и n - количество шагов по первому и второму индексу соответственно, начиная от угловой точки сетки Безье, 00 - индекс этой угловой точки, с которой мы начинаем образовывать все остальные узлы сетки операторами сдвига E и F . Имеем

(6.9)

(6.10)

Здесь через обозначены четырехугольные листы Безье , построенные из точек p ij, взятых в качестве угловых точек, аналогично формуле (6.9). может быть получена с помощью следующего алгоритма:

Полученная точка и будет точкой с параметрами на рациональной поверхности Безье, построенной по

Деление поверхности Безье

Деление поверхностей Безье целиком основано на делении кривых Безье. Как мы уже знаем, каждая из кривых Безье (обычных или рациональных), построенных по столбцам сетки опорных точек может быть разделена в параметрической точке без изменения ее формы. При таком делении получаются две поверхности Безье (составляющие вкупе исходную поверхность) и соответствующие им две матрицы опорных точек Безье, каждая из которых имеет тот же порядок, что и исходная матрица: и Затем, каждую из получившихся двух поверхностей Безье надо поделить в параметрической точке (с помощью деления кривых Безье, построенных по строкам соответствующих матриц). В итоге получится четыре поверхности Безье и соответствующие им четыре матрицы опорных точек: и Эти четыре поверхности Безье будут лежать на исходной поверхности Безье, делить ее на четыр е части и в совокупности составлять исходную поверхность.

Новые сети опорных точек и получаются из исходной сети по следующим формулам, аналогичным формулам (5.26):




Последние материалы раздела:

Важность Патриотического Воспитания Через Детские Песни
Важность Патриотического Воспитания Через Детские Песни

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

Изменение вида звездного неба в течение суток
Изменение вида звездного неба в течение суток

Тема урока «Изменение вида звездного неба в течение года». Цель урока: Изучить видимое годичное движение Солнца. Звёздное небо – великая книга...

Развитие критического мышления: технологии и методики
Развитие критического мышления: технологии и методики

Критическое мышление – это система суждений, способствующая анализу информации, ее собственной интерпретации, а также обоснованности...