⚙️ Фізична симуляція · Комп'ютерна графіка
📅 Квітень 2026⏱ 14 хв🟠 Середній рівень · Останнє оновлення: 3 липня 2026 р.

Position Based Dynamics (PBD): тканина, м'які тіла та обмеження

Тканина, що тріпоче, в Assassin's Creed, деформівні тіла в Baldur's Gate 3 та симуляція волосся в Horizon Forbidden West — усі працюють на одній ідеї: замість обчислення сил та інтегрування законів Ньютона безпосередньо проєктувати позиції частинок, щоб задовольнити геометричні обмеження. Position Based Dynamics жертвує фізичною точністю заради гарантованої стійкості за будь-якого кроку часу — саме того, що потрібно іграм реального часу.

1. Чому б просто не використати сили?

Традиційна симуляція на основі сил (системи маса-пружина, FEM) обчислює сили в поточному стані, а потім інтегрує другий закон Ньютона, щоб оновити позиції та швидкості. Проблема: жорсткі пружини вимагають крихітних кроків часу, щоб лишатися стійкими, а тканина має дуже жорсткі пружини (інакше вона розтягується нереалістично).

Полотно тканини з 10 000 частинок, з'єднаних пружинами з жорсткістю k = 10⁶ Н/м, потребує кроку часу Δt < √(m/k) ≈ 10⁻⁴ с, щоб лишатися стійким за явного інтегрування — 600 підкроків на кадр при 60 fps. Неявне інтегрування потребувало б розв'язання великої розрідженої лінійної системи на кожному підкроці.

Ключова ідея PBD: геометричні обмеження (відстані, об'єми, кути) завжди задовольнянні незалежно від розміру кроку часу. Замість моделювання пружин як сил застосовуй геометричне обмеження безпосередньо, переміщуючи частинки до найближчої конфігурації, що його задовольняє. Немає константи жорсткості → немає умови стійкості → працює будь-який крок часу.

PBD був представлений Мюллером та ін. у статті 2007 року на SIGGRAPH «Position Based Dynamics» і відтоді став домінантним методом для симуляції тканини, волосся та м'яких тіл реального часу в іграх та інструментах візуальних ефектів кіно.

2. Цикл алгоритму PBD

Повний цикл симуляції PBD на кадр такий:

// Головний цикл PBD (Müller et al. 2007) для кожної частинки i: v_i += Δt · (f_ext / m_i) // застосувати зовнішні сили (гравітація, вітер) p_i = x_i + Δt · v_i // передбачити нову позицію згенерувати обмеження зіткнень(x_i, p_i) // виявити перекриття для iter = 1 до solverIterations: // цикл проєкції обмежень для кожного обмеження C_j: projectConstraint(C_j, p_1...p_n) // перемістити передбачені позиції для кожної частинки i: v_i = (p_i - x_i) / Δt // вивести швидкість зі зміни позиції x_i = p_i // зафіксувати позиції застосувати згасання швидкості застосувати тертя / пружність з обмежень зіткнень

Вирішальна властивість: внутрішній цикл змінює лише передбачені позиції p, а не фактичні позиції x. Швидкість відновлюється наприкінці як скінченна різниця. Це означає, що нестійкі коливання не можуть накопичуватися — будь-яка надмірна корекція в p поглинається як зміна швидкості наприкінці кадру, а не повертається до наступної проєкції обмежень.

Кількість solverIterations керує компромісом якість-продуктивність: 1 ітерація швидка, але обмеження задовольняються не повністю; 10-20 ітерацій дають майже жорстку поведінку для структурних обмежень.

3. Типи обмежень

Обмеження — це функція C(p₁, …, pₙ) = 0 (рівність) або ≥ 0 (нерівність), яку мають задовольняти передбачені позиції. Поширені типи обмежень для тканини та м'яких тіл:

Обмеження відстані

Підтримує фіксовану довжину спокою між двома частинками — «реберне» обмеження тканини:

C_dist(p₁, p₂) = |p₁ − p₂| − d_rest = 0 d_rest = початкова довжина ребра (конфігурація спокою) Порушується, коли: поточна відстань ≠ d_rest

Обмеження згинання

Протидіє згинанню вздовж ребра, спільного для двох трикутників. Двогранний кут між двома трикутниками має відповідати куту спокою:

C_bend(p₁, p₂, p₃, p₄) = arccos(n₁ · n₂) − φ_rest = 0 n₁, n₂ = одиничні нормалі двох трикутників, що мають спільне ребро (p₃, p₄) φ_rest = двогранний кут у спокої Альтернативно: використовуй квадратичне формулювання обмеження згинання C = (p₁ − p₄)·(p₂ − p₄) − cos(φ_rest)·|…|·|…| (уникає arccos, дешевше диференціювати)

Обмеження збереження об'єму

Для м'яких тіл (деформівних сіток) повний об'єм тетраедра має зберігатися:

C_vol(p₁, p₂, p₃, p₄) = (1/6) · (p₂−p₁)·((p₃−p₁)×(p₄−p₁)) − V_rest = 0 V_rest = об'єм спокою тетраедра

Обмеження зіткнень

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

C_col(p) = (p − q) · n ≥ 0 q = найближча точка на поверхні зіткнення n = нормаль поверхні в q Задовольняється, коли: частинка на поверхні або над нею

Обмеження узгодження форми

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

4. Проєкція обмежень: основна математика

Маючи порушене обмеження C(p₁,…,pₙ) ≠ 0, як мінімально перемістити частинки, щоб його задовольнити? PBD розв'язує задачу умовної мінімізації: знайти корекції Δpᵢ, що мінімізують ½Σ(1/wᵢ)|Δpᵢ|² за умови C = 0, де wᵢ = 1/mᵢ — обернена маса.

// Загальна формула проєкції обмеження Корекція для частинки i: Δpᵢ = −wᵢ · [C(p₁…pₙ) / Σⱼ wⱼ |∇pⱼ C|²] · ∇pᵢ C Де: wᵢ = 1/mᵢ (обернена маса — нуль для закріплених/статичних частинок) ∇pᵢ C = градієнт функції обмеження за pᵢ C(p) = поточне значення обмеження (величина порушення) Інтуїція: переміщуй кожну частинку вздовж градієнта C, масштабованого її оберненою масою (легші частинки рухаються більше) та величиною порушення (мале C → мала корекція)

Проєкція обмеження відстані (замкнена форма)

// Для C(p₁, p₂) = |p₁ − p₂| − d_rest = 0 n = (p₁ − p₂) / |p₁ − p₂| // одиничний напрямок Δp₁ = −w₁/(w₁+w₂) · (|p₁−p₂| − d_rest) · n Δp₂ = +w₂/(w₁+w₂) · (|p₁−p₂| − d_rest) · n p₁ += Δp₁ p₂ += Δp₂ Якщо обидві частинки мають однакову масу (w₁=w₂=1/m): кожна рухається на половину відстані порушення назустріч іншій. Вони зустрічаються точно посередині надто розтягнутого/стиснутого відрізка.

Цей розв'язок у замкненій формі — причина, чому проєкція обмеження відстані така дешева — лише кілька операцій з рухомою комою на обмеження, без матричної факторизації, без ітеративного розв'язувача. Та сама простота стосується майже всіх типів обмежень PBD: градієнт ∇C аналітичний, а формула проєкції має розв'язок у замкненій формі.

Упорядкування Гаусса-Зейделя: обмеження проєктуються послідовно (не одночасно), і пізніші обмеження бачать корекції, зроблені попередніми — це ітераційна схема Гаусса-Зейделя. Порядок важить для збіжності; випадкове перемішування на кожному кроці ітерації допомагає уникнути систематичного зміщення та покращує збіжність для перевизначених систем.

5. Симуляція тканини за допомогою PBD

Сітка тканини — це регулярна або нерегулярна решітка частинок, з'єднаних трьома наборами обмежень:

// Структура обмежень тканини для сіткової решітки Структурні обмеження: ребра між сусідніми частинками (протидіють розтягуванню/стисканню) ← найбільша жорсткість, потрібно найбільше ітерацій Зсувні обмеження: діагональні ребра поперек кожного чотирикутника (протидіють зсувній деформації — «зморшки» тканини) Обмеження згинання: ребра, що з'єднують наступних-за-найближчими сусідів (протидіють згинанню довкола кожного ребра між двома трикутниками) ← найменша жорсткість, опціональні для тонких тканин Типова кількість частинок: 400 (20×20) для ігрової тканини 10000 (100×100) для кіно Закріплені частинки: встанови wᵢ = 0 (нескінченна маса) → фіксовані точки кріплення (комір, петлі для ременя)

Вітер та самозіткнення обробляються як додаткові сили та обмеження відповідно. Самозіткнення — найдорожча частина: просторовий хеш або BVH знаходить близькі пари частинок, а обмеження-нерівність за відстанню запобігає взаємопроникненню.

Тканина, що звисає на двох шпильках: мінімальна реалізація

// Каркас тканини на JavaScript (~60 рядків основи) const N = 20; // розмір решітки NxN const particles = []; const constraints = []; // Створюємо частинки for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) { particles.push({ pos: [x*0.05, -y*0.05, 0], prev: [x*0.05, -y*0.05, 0], invMass: (y===0 && (x===0 || x===N-1)) ? 0 : 1 // закріплюємо верхні кути }); } // Додаємо обмеження відстані для структурних ребер for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) { if (x+1 < N) addDistConstraint(idx(x,y), idx(x+1,y)); if (y+1 < N) addDistConstraint(idx(x,y), idx(x,y+1)); } function step(dt) { // 1. Передбачення (у стилі Верле: v неявно у різниці pos-prev) for (const p of particles) { if (p.invMass === 0) continue; const v = sub(p.pos, p.prev); p.prev = [...p.pos]; p.pos = add(p.pos, add(v, scale([0, -9.8*dt*dt, 0], 1))); // гравітація } // 2. Проєктуємо обмеження (10 ітерацій) for (let i = 0; i < 10; i++) for (const c of constraints) projectDistance(c); // швидкість неявно (pos - prev)/dt — без явного зберігання швидкості }

Зверніть увагу на інтегрування в стилі Верле: швидкість неявно міститься у різниці pos - prev. Це варіант «XPBD» або «PBD з Верле», що поширено використовується на практиці — він уникає зберігання явних швидкостей і дає автоматичне релеївське згасання, пропорційне швидкості.

6. Жорсткість, ітерації та збіжність

У класичному PBD жорсткість керується лише кількістю ітерацій розв'язувача та параметром жорсткості на обмеження k ∈ [0, 1], що частково масштабує корекцію:

// Масштабування жорсткості в класичному PBD Δpᵢ_effective = k · Δpᵢ_projected k = 1.0 → повна корекція на кожній ітерації (жорстко / майже твердо) k = 0.3 → часткова корекція (м'яко / пружно) Проблема: k залежить від кількості ітерацій! За 1 ітерації: k=0.5 дає певну ефективну жорсткість За 10 ітерацій: k=0.5 дає НАБАГАТО жорсткішу поведінку (бо корекції накопичуються) → Жорсткість у класичному PBD не є незалежною від кроку часу чи ітерацій. Тканина, налаштована для 10 ітерацій, погано поводиться за 5 ітерацій.

Ця залежність від кількості ітерацій — центральна практична проблема класичного PBD. Подвоєння ітерацій робить тканину жорсткішою; половинне зменшення ітерацій (через зміну бюджету продуктивності) робить тканину м'якшою. Художники переналаштовують симуляцію щоразу, коли змінюється бюджет розв'язувача — болісний робочий процес.

Збіжність також повільна для жорстких обмежень у великих сітках — проєкція в стилі Гаусса-Зейделя поширює корекції обмежень зі швидкістю O(1) обмеження на ітерацію, тож хвиля деформації потребує O(N) ітерацій для поширення через N частинок. Техніки для пом'якшення цього:

7. XPBD: розширений PBD з податливістю

XPBD (Macklin et al. 2016) усуває залежність від кількості ітерацій, вводячи параметр податливості α, що є оберненою величиною фізичної жорсткості, та модифікує формулу проєкції множником Лагранжа:

// Проєкція обмеження XPBD α̃ = α / Δt² // масштабована податливість (α = 1/жорсткість) // α=0 → жорстко, α→∞ → немає обмеження Оновлення множника Лагранжа: Δλ = −(C + α̃·λ) / (Σᵢ wᵢ|∇pᵢ C|² + α̃) Корекція частинки: Δpᵢ = wᵢ · Δλ · ∇pᵢ C λ ініціалізується 0 на початку кожного кроку часу. λ накопичується між ітераціями (не скидається на кожній ітерації!) Результат: - Жорсткість тепер керується α (фізичні одиниці: м/Н) - Поведінка незалежна від кроку часу: те саме α дає той самий результат за Δt=1/30 с чи Δt=1/240 с - Поведінка незалежна від ітерацій: більше ітерацій → краща збіжність до того самого фізичного розв'язку, а не жорсткіша поведінка

XPBD — наступник PBD, що використовується в усіх сучасних фізичних рушіях. Chaos Physics в Unreal Engine, NVIDIA PhysX 5 та ECS-тканина Unity — усі реалізують XPBD. Параметр податливості α безпосередньо відповідає фізичним властивостям матеріалу: α ≈ 10⁻⁸ м/Н для майже твердої кістки, α ≈ 10⁻⁴ м/Н для жорсткої тканини, α ≈ 10⁻¹ м/Н для м'якої пружної тканини тіла.

Обмеження на рівні позицій проти рівня швидкостей

XPBD також вводить корекцію обмежень на рівні швидкостей наприкінці циклу розв'язувача (згасання), тож енергію можна коректно розсіювати без покладання на штучне згасання на рівні позицій, що порушує енергетичну модель XPBD. Це уможливлює фізично точне згасання матеріалу як окремий параметр α_damp.

8. Застосування та використання в індустрії

PBD та XPBD — домінантні методи симуляції реального часу в іграх, кіно та медичній симуляції:

Ігри

Кіно та VFX

Медицина та наука

GPU PBD: обмеження тканини можна розфарбувати як граф (несуміжні обмеження не мають спільних частинок і можуть проєктуватися одночасно). За 4-8 проходів кольорів на ітерацію всю сітку тканини можна проєктувати на GPU паралельно за допомогою обчислювальних шейдерів. NVIDIA FleX та Chaos Cloth використовують цей підхід, щоб симулювати 100 000+ частинок на 60 fps на сучасних GPU.

Поєднання в PBD простоти, стійкості та фізичної правдоподібності — навіть без суворої точності — зробило його основою фізичної симуляції реального часу понад 15 років. Модель податливості XPBD тепер скорочує розрив до фізично точної поведінки, роблячи цей метод конкурентним з FEM для багатьох застосувань, де діють мілісекундні бюджети симуляції.