Лінії безья. Малювання кривих Безьє

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

Мал. 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.

Аналогічні побудови для кубічної кривої:

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

Цей алгоритм дуже важливий для рендерингу кривих у редакторі. На його основі, як правило, будують адаптивну ламану, що наближає форму кривої. Цю ламану використовують для малювання кривої.

Як пов'язати формули з тим, що ми бачимо у редакторах векторної графіки

У векторних редакторах жодних формул немає. Є криві, побудовані за контрольними точками:

Існує 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 t tt * t; Vector3 p = uuu * p0; // first term p + = 3 * uu * t * p1; 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.< 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. pointList); return pointsAdded;) return 0; )

Наступна функція демонструє виклик рекурсивної функції:

void FindPoints() ( List pointList = new List() ; p0 = bezierCurve(0 ) ; p1 = bezierCurve(1 ) ; pointList. Add (p0) ; pointList. Add (p1) ; 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 = List () ; for (int i = 0 ;< 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Перший 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)]; BezierFunction; f = BezierFunction; 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 ;


Геометричний зміст поверхні Безьє

Поверхню Безье можна отримати так:

При цьому відповідний оператор переходу від опорної точки, взятої на кривій до наступної опорної точки, взятої на кривій в термінах вузлів сітки pij описується оператором зсуву F другого індексу. Отже,

де m і n - кількість кроків за першим і другим індексом відповідно, починаючи від кутової точки сітки Безьє, 00 - індекс цієї кутової точки, з якої ми починаємо утворювати всі інші вузли сітки операторами зсуву E і F . Маємо

(6.9)

(6.10)

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

Отримана точка і буде точкою з параметрами на раціональній поверхні Безьє, побудованою

Поділ поверхні Безьє

Розподіл поверхонь Безье повністю заснований на розподілі кривих Безье. Як ми вже знаємо, кожна з кривих Безьє (звичайних або раціональних), побудованих по стовпцях сітки опорних точок, може бути розділена в параметричній точці без зміни її форми. При такому розподілі виходять дві поверхні Безьє (що становлять разом вихідну поверхню) і відповідні їм дві матриці опорних точок Безьє, кожна з яких має той же порядок, що і вихідна матриця: і Потім, кожну з двох поверхонь Безьє, що вийшло, треба поділити в параметричній точці ( за допомогою поділу кривих Безье, побудованих рядками відповідних матриць). У результаті вийде чотири поверхні Безьє і відповідні їм чотири матриці опорних точок: Ці чотири поверхні Безье будуть лежати на вихідній поверхні Безье, ділити її на чотири частини і в сукупності становити вихідну поверхню.

Нові мережі опорних точок і виходять з вихідної мережі за такими формулами, аналогічними формулами (5.26):




Останні матеріали розділу:

Валентин Олексійович Соболєв
Валентин Олексійович Соболєв

Заступник секретаря Ради Безпеки РФ з квітня 1999 р. (був знову затверджений на цій посаді у травні 2000 р.); народився 11 березня 1947 р. в аулі.

Сума проекцій сил на вісь
Сума проекцій сил на вісь

У тих випадках, коли на тіло діє більше трьох сил, а також коли невідомі напрямки деяких сил, зручніше під час вирішення завдань користуватися...

Чому неприйнятні уроки статевого «освіти» у школах?
Чому неприйнятні уроки статевого «освіти» у школах?

Статеве виховання в російській школі: чи потрібний нам досвід Америки? Р.Н.Федотова, Н.А.Самарец Малюки ростуть на очах, і, не встигнувши озирнутися, ми...