Това е част I от нашата поредица от три части по физика на видеоигрите. За останалата част от тази серия вижте:
Част II: Откриване на сблъсък за твърди обекти
Част III: Симулация на ограничено твърдо тяло
Симулацията на физика е област в рамките на компютърните науки, която има за цел да възпроизведе физически явления с помощта на компютър. Като цяло тези симулации прилагат числени методи към съществуващи теории, за да се получат резултати, които са възможно най-близки до това, което наблюдаваме в реалния свят. Това ни позволява, както напреднали разработчици на игри , за да се предскаже и внимателно да се анализира как нещо ще се държи, преди да го изгради, което е почти винаги по-просто и по-евтино за изпълнение.
Обхватът на приложения на физическите симулации е огромен. Най-ранните компютри вече се използват за извършване на физически симулации - например за прогнозиране на балистичното движение на снарядите във военните. Той също така е основен инструмент в гражданското и автомобилното инженерство, който показва как биха се държали определени структури при събития като земетресение или автомобилна катастрофа. И не спира дотук. Можем да симулираме неща като астрофизика, относителност и много други безумни неща, които можем да наблюдаваме сред чудесата на природата.
Симулирането на физика във видеоигрите е много често, тъй като повечето игри са вдъхновени от нещата, които имаме в реалния свят . Много игри разчитат изцяло на физическата симулация, за да бъдат забавни. Това означава, че тези игри изискват стабилна симулация, която няма да се счупи или забави и това обикновено не е тривиално за постигане.
Във всяка игра интерес представляват само определени физически ефекти. Динамиката на твърдо тяло - движението и взаимодействието на твърди, негъвкави предмети - е най-популярният вид ефект, симулиран в игрите. Това е така, защото повечето обекти, с които взаимодействаме в реалния живот, са доста твърди и симулирането на твърди тела е относително просто (макар че, както ще видим, това не означава, че е пешеходна пътека). Няколко други игри обаче изискват симулация на по-сложни обекти, като деформируеми тела, течности, магнитни обекти и т.н.
В тази поредица от уроци по физика на видеоигри ще се изследва симулация на твърдо тяло, като се започне с простото твърдо движение на тялото в тази статия и след това се обхванат взаимодействията между телата чрез сблъсъци и ограничения в следващите вноски. Най-често срещаните уравнения, използвани в съвременните двигатели на физиката на играта като Box2D , Физика на куршума и Физика на бурундук ще бъдат представени и обяснени.
Във физиката на видеоигрите искаме да анимираме обекти на екрана и да им дадем реалистично физическо поведение. Това се постига с базирана на физиката процедурна анимация, която представлява анимация, произведена от числени изчисления, приложени към теоретичните закони на физиката.
Анимациите се създават чрез последователно показване на поредица от изображения, като обектите се придвижват леко от едно изображение към следващото. Когато изображенията се показват в бърза последователност, ефектът е очевидно плавно и непрекъснато движение на обектите. По този начин, за да анимираме обектите във физическа симулация, трябва да актуализираме физическото състояние на обектите (напр. Позиция и ориентация), съгласно законите на физиката няколко пъти в секунда, и да прерисуваме екрана след всяка актуализация.
The двигател по физика е софтуерният компонент, който изпълнява физическата симулация. Той получава спецификация на телата, които ще бъдат симулирани, плюс някои конфигурационни параметри и тогава симулацията може да бъде пристъпи . Всяка стъпка премества симулацията напред с няколко части от секундата и резултатите могат да бъдат показани на екрана след това. Имайте предвид, че двигателите на физиката извършват само числена симулация. Какво се прави с резултатите може да зависи от изискванията на играта. Не винаги е така, че резултатите от всяка стъпка искат да бъдат изтеглени на екрана.
Движението на твърди тела може да се моделира с помощта нютонова механика , който е основан на известния Исак Нютон Три закона на движението :
Инерция : Ако върху даден обект не се прилага сила, неговата скорост (скорост и посока на движение) не трябва да се променя.
Сила, маса и ускорение : Силата, действаща върху обект, е равна на масата на обекта, умножена по неговото ускорение (скорост на промяна на скоростта). Това се дава от формулата F = ма .
Действие и реакция : „За всяко действие има еднаква и противоположна реакция.“ С други думи, когато всяко тяло упражнява сила върху друго, второто тяло упражнява сила със същата величина и противоположна посока на първото.
Въз основа на тези три закона можем да направим физически двигател, който да може да възпроизведе динамичното поведение, с което сме толкова запознати, и по този начин да създадем завладяващо преживяване за играча.
Следващата диаграма показва общ преглед на високо ниво на общата процедура на физическия двигател:
За да се разбере как работят физическите симулации, е от решаващо значение да имате основно разбиране за векторите и техните операции. Ако вече сте запознати с векторната математика, прочетете. Но ако не сте или искате да се поправите, отделете минута, за да прегледате приложение в края на тази статия.
Добра стъпка към разбирането на симулацията на твърдо тяло е да започнете с частици. Симулирането на частици е по-просто от симулирането на твърди тела и ние можем да симулираме последните, използвайки същите принципи, но добавяйки обем и форма на частиците.
Частицата е просто точка в пространството, която има вектор на позиция, вектор на скоростта и маса. Според Първия закон на Нютон скоростта му ще се промени само когато върху него се приложи сила. Когато неговият вектор на скоростта има ненулева дължина, позицията му ще се промени с течение на времето.
За да симулираме система от частици, първо трябва да създадем масив от частици с начално състояние. Всяка частица трябва да има фиксирана маса, първоначално положение в пространството и начална скорост. След това трябва да започнем основния цикъл на симулацията, където за всяка частица трябва да изчислим силата, която в момента действа върху нея, да актуализираме нейната скорост от ускорението, произведено от силата, и след това да актуализираме нейното положение въз основа на скоростта току-що изчислихме.
Силата може да идва от различни източници в зависимост от вида на симулацията. Това може да бъде гравитация, вятър или магнетизъм, наред с други - или може да бъде комбинация от тях. Това може да бъде глобална сила, като постоянна гравитация, или може да бъде сила между частици, като привличане или отблъскване.
За да накараме симулацията да работи с реалистични темпове, стъпката от времето, която „симулираме“, трябва да бъде същата като реалното количество време, изминало от последната стъпка на симулация. Тази стъпка от време обаче може да се мащабира, за да накара симулацията да работи по-бързо, или да се намали, за да се изпълни в забавен каданс.
Да предположим, че имаме една частица с маса м , позиция стр ( т i)и скорост v ( т i)в един миг от време т i. Сила е ( т i)се прилага върху тази частица по това време. Положението и скоростта на тази частица в бъдеще т i + 1, стр ( т i + 1)и v ( т i + 1)съответно може да се изчисли с:
От техническа гледна точка това, което правим тук, е интегриране на числово обикновено диференциално уравнение на движение на частица, използвайки полуимплицитния метод на Ойлер, който е методът, който повечето двигатели на физиката на играта използват поради своята простота и приемлива точност за малки стойности на период от време, DT . The Основи на диференциалното уравнение лекционни бележки от удивителното Физическо моделиране: Принципи и практика разбира се, от д-р. Анди Уиткин и Дейвид Бараф е хубава статия за по-задълбочен поглед върху числената методология на този метод.
Следва пример за симулация на частици на езика C.
#define NUM_PARTICLES 1 // Two dimensional vector. typedef struct { float x; float y; } Vector2; // Two dimensional particle. typedef struct { Vector2 position; Vector2 velocity; float mass; } Particle; // Global array of particles. Particle particles[NUM_PARTICLES]; // Prints all particles' position to the output. We could instead draw them on screen // in a more interesting application. void PrintParticles() { for (int i = 0; i position.x, particle->position.y); } } // Initializes all particles with random positions, zero velocities and 1kg mass. void InitializeParticles() { for (int i = 0; i mass * -9.81}; } void RunSimulation() { float totalSimulationTime = 10; // The simulation will run for 10 seconds. float currentTime = 0; // This accumulates the time that has passed. float dt = 1; // Each step will take one second. InitializeParticles(); PrintParticles(); while (currentTime mass}; particle->velocity.x += acceleration.x * dt; particle->velocity.y += acceleration.y * dt; particle->position.x += particle->velocity.x * dt; particle->position.y += particle->velocity.y * dt; } PrintParticles(); currentTime += dt; } }
Ако се обадите на RunSimulation
функция (за една частица) тя ще отпечата нещо като:
particle[0] (-8.00, 57.00) particle[0] (-8.00, 47.19) particle[0] (-8.00, 27.57) particle[0] (-8.00, -1.86) particle[0] (-8.00, -41.10) particle[0] (-8.00, -90.15) particle[0] (-8.00, -149.01) particle[0] (-8.00, -217.68) particle[0] (-8.00, -296.16) particle[0] (-8.00, -384.45) particle[0] (-8.00, -482.55)
Както можете да видите, частицата започва от (-8, 57)
позиция и след това | | + _ | координатите започнаха да падат все по-бързо и по-бързо, защото се ускоряваха надолу под силата на гравитацията.
Следващата анимация дава визуално представяне на последователност от три стъпки на една симулирана частица:
Първоначално в т = 0, частицата е при стр 0. След стъпка се движи в посоката на своя вектор на скоростта v 0сочеше. В следващата стъпка сила е единсе прилага към него и векторът на скоростта започва да се променя така, сякаш е изтеглен по посока на силовия вектор. В следващите две стъпки силовият вектор променя посоката, но продължава да дърпа частицата нагоре.
ДА СЕ твърдо тяло е твърдо вещество, което не може да се деформира. Такива твърди вещества не съществуват в реалния свят - дори най-твърдите материали деформират поне много малко количество, когато към тях се приложи някаква сила - но твърдото тяло е полезен модел на физика за разработчиците на игри, който опростява изследването на динамиката на твърди вещества, където можем да пренебрегнем деформациите.
Твърдото тяло е като продължение на частица, защото има също маса, положение и скорост. Освен това той има обем и форма и така може да се върти. Това добавя повече сложност, отколкото звучи, особено в три измерения.
Твърдо тяло естествено се върти около него център на масата , а положението на твърдо тяло се счита за положението на неговия център на маса. Определяме началното състояние на твърдото тяло с центъра на масата в началото и ъгъла на въртене нула. Неговото положение и въртене по всяко време т ще бъде компенсиране на първоначалното състояние.
Центърът на масата е средната точка на разпределението на масата на тялото. Ако си представите, че твърдо тяло с маса М е направен от н малки частици, всяка с маса м iи местоположение r iвътре в тялото, центърът на масата може да се изчисли като:
Тази формула показва, че центърът на масата е средната стойност на позициите на частиците, претеглени от тяхната маса. Ако плътността на тялото е еднаква през целия, центърът на масата е същият като геометричния център на формата на тялото, известен също като центроид . Двигателите на физиката на играта обикновено поддържат само еднаква плътност, така че геометричният център може да се използва като център на масата.
Твърдите тела обаче не са изградени от ограничен брой дискретни частици, те са непрекъснато . Поради тази причина трябва да го изчислим с помощта на неразделна вместо крайна сума, по следния начин:
където r е вектор на позицията на всяка точка, и(rho) е функция, която дава плътността във всяка точка в тялото. По същество този интеграл прави същото като крайната сума, но го прави в непрекъснат обем V .
Тъй като твърдо тяло може да се върти, трябва да го представим ъглова свойства, които са аналогични на линейните свойства на частицата. В две измерения твърдото тяло може да се върти само около оста, която сочи от екрана, поради което се нуждаем само от един скалар, който да представя неговата ориентация. Обикновено използваме радиани (които преминават от 0 до 2Пиза пълен кръг) като единица тук вместо ъгли (които преминават от 0 до 360 за пълен кръг), тъй като това опростява изчисленията.
За да се върти, твърдо тяло се нуждае от малко ъглова скорост , което е скалар с единица радиани в секунда и което обикновено се представя с гръцката буква ω (омега). За да придобие ъглова скорост обаче, тялото трябва да получи някаква въртелива сила, която ние наричаме въртящ момент , представена от гръцката буква τ (тау). По този начин Вторият закон на Нютон, приложен към ротацията, е:
където а (алфа) е ъгловото ускорение и Аз е момент на инерция .
При въртенията моментът на инерция е аналогичен на масата при линейно движение. Той определя колко трудно е да се промени ъгловата скорост на твърдо тяло. В две измерения той е скаларен и се определя като:
където V означава, че този интеграл трябва да се изпълнява за всички точки в целия обем на тялото, r е вектора на позицията на всяка точка спрямо оста на въртене, r 2е всъщност точният продукт на r със себе си ие функция, която дава плътността във всяка точка в тялото.
Например моментът на инерция на двумерна кутия с маса м , ширина в и височина з за неговия центроид е:
Тук можете да намерите списък с формули за изчисляване на момента на инерцията за куп фигури около различни оси.
Когато сила се приложи към точка върху твърдо тяло, тя може да доведе до въртящ момент. В два измерения въртящият момент е скаларен, а въртящият момент τ генерирани от сила е приложена в точка на тялото, която има вектор на отместване r от центъра на масата е:
където θ (theta) е най-малкият ъгъл между е и r .
Предишната формула е точно формулата за дължината на кръстосаното произведение между тях r и е . По този начин в три измерения можем да направим това:
Двумерна симулация може да се разглежда като триизмерна симулация, при която всички твърди тела са тънки и плоски и всичко се случва на xy -plane, което означава, че няма движение в с -ос. Това означава, че е и r винаги са в xy самолет и така τ винаги ще има нула х и Y. компоненти, защото кръстосаният продукт винаги ще бъде перпендикулярен на xy -самолет. Това от своя страна означава, че винаги ще бъде успоредно на с -ос. По този начин само с компонент на кръстосаните въпроси. Това, което води до това, е, че изчисляването на въртящия момент в две измерения може да бъде опростено до:
Невероятно е как добавянето на само още едно измерение към симулацията прави нещата значително по-сложни. В три измерения ориентацията на твърдо тяло трябва да бъде представена с a кватернион , което е един вид вектор от четири елемента. Моментът на инерция е представен от матрица 3x3, наречена инерционен тензор , което не е постоянно, тъй като зависи от твърдата ориентация на тялото и по този начин варира във времето, докато тялото се върти. За да научите всички подробности за 3D симулация на твърдо тяло, можете да проверите отличното Симулация на твърдо тяло I - Неограничена динамика на твърдо тяло , която също е част от Уиткин и Бараф Физическо моделиране: Принципи и практика разбира се.
Алгоритъмът на симулация е много подобен на този на симулацията на частици. Трябва само да добавим формата и ротационните свойства на твърдите тела:
y
Обажда се #define NUM_RIGID_BODIES 1 // 2D box shape. Physics engines usually have a couple different classes of shapes // such as circles, spheres (3D), cylinders, capsules, polygons, polyhedrons (3D)... typedef struct { float width; float height; float mass; float momentOfInertia; } BoxShape; // Calculates the inertia of a box shape and stores it in the momentOfInertia variable. void CalculateBoxInertia(BoxShape *boxShape) { float m = boxShape->mass; float w = boxShape->width; float h = boxShape->height; boxShape->momentOfInertia = m * (w * w + h * h) / 12; } // Two dimensional rigid body typedef struct { Vector2 position; Vector2 linearVelocity; float angle; float angularVelocity; Vector2 force; float torque; BoxShape shape; } RigidBody; // Global array of rigid bodies. RigidBody rigidBodies[NUM_RIGID_BODIES]; // Prints the position and angle of each body on the output. // We could instead draw them on screen. void PrintRigidBodies() { for (int i = 0; i position.x, rigidBody->position.y, rigidBody->angle); } } // Initializes rigid bodies with random positions and angles and zero linear and angular velocities. // They're all initialized with a box shape of random dimensions. void InitializeRigidBodies() { for (int i = 0; i position = (Vector2){arc4random_uniform(50), arc4random_uniform(50)}; rigidBody->angle = arc4random_uniform(360)/360.f * M_PI * 2; rigidBody->linearVelocity = (Vector2){0, 0}; rigidBody->angularVelocity = 0; BoxShape shape; shape.mass = 10; shape.width = 1 + arc4random_uniform(2); shape.height = 1 + arc4random_uniform(2); CalculateBoxInertia(&shape); rigidBody->shape = shape; } } // Applies a force at a point in the body, inducing some torque. void ComputeForceAndTorque(RigidBody *rigidBody) { Vector2 f = (Vector2){0, 100}; rigidBody->force = f; // r is the 'arm vector' that goes from the center of mass to the point of force application Vector2 r = (Vector2){rigidBody->shape.width / 2, rigidBody->shape.height / 2}; rigidBody->torque = r.x * f.y - r.y * f.x; } void RunRigidBodySimulation() { float totalSimulationTime = 10; // The simulation will run for 10 seconds. float currentTime = 0; // This accumulates the time that has passed. float dt = 1; // Each step will take one second. InitializeRigidBodies(); PrintRigidBodies(); while (currentTime
за едно твърдо тяло извежда своето положение и ъгъл, по следния начин:
RunRigidBodySimulation
Тъй като се прилага възходяща сила от 100 нютона, самоY.промени в координатите. Силата не се прилага директно върху центъра на масата и по този начин предизвиква въртящ момент, което води до увеличаване на ъгъла на въртене (въртене обратно на часовниковата стрелка).
Графичният резултат е подобен на анимацията на частиците, но сега имаме фигури, които се движат и въртят.
Това е неограничен симулация, тъй като телата могат да се движат свободно и те не си взаимодействат помежду си - те не се сблъскват. Симулациите без сблъсъци са доста скучни и не особено полезни. В следващата част от тази серия ще говорим за откриване на сблъсък и как да разрешим сблъсък, след като бъде открит.
ДА СЕ вектор е субект, който има дължина (или по-формално a величина ) и а посока . Той може да бъде представен интуитивно в Декартова координатна система , където го разлагаме на два компонента, х и Y. , в двумерно пространство или три компонента, х , Y. , и с , в триизмерно пространство.
Представяме вектор с удебелен малък регистър и неговите компоненти чрез редовен идентичен знак с индекса на компонентите. Например:
представлява двуизмерен вектор. Всеки компонент е разстоянието от началото в съответната координатна ос.
Физическите двигатели обикновено имат свои собствени леки, силно оптимизирани математически библиотеки. The Физика на куршума например, двигателят има отделена математическа библиотека, наречена Линейна математика които могат да се използват самостоятелно без нито една от функциите за симулация на физика на Bullet. Той има класове, които представляват обекти като вектори и матрици, и се използва SIMD инструкции, ако са налични.
Някои от основните алгебрични операции, които действат върху вектори, са разгледани по-долу.
Дължината или величината на оператора е представена от|| ||. Дължината на вектор може да бъде изчислена от неговите компоненти с помощта на известния Питагорова теорема за правоъгълни триъгълници. Например в две части:
Когато даден вектор е отрицателен, дължината остава същата, но посоката се променя в точно обратното. Например, като се има предвид:
отрицанието е:
Векторите могат да се добавят или изваждат един от друг. Изваждането на два вектора е същото като добавянето на един към отрицанието на другия. В тези операции ние просто добавяме или изваждаме всеки компонент:
Полученият вектор може да бъде визуализиран като сочещ към същата точка, която биха направили двата оригинални вектора, ако са свързани от край до край:
Когато даден вектор се умножи по скалар (за целите на този урок скаларът е просто всяко реално число), дължината на вектора се променя с тази сума. Ако скаларът е отрицателен, той също така насочва вектора в обратна посока.
The точков продукт операторът взема два вектора и извежда скаларно число. Определя се като:
къдетоострове ъгълът между двата вектора. Изчислително е много по-лесно да се изчисли с помощта на компонентите на векторите, т.е.:
Стойността на точковото произведение е еквивалентна на дължината на проекция на вектора да се върху вектора б , умножено по дължината на б . Това действие също може да се обърне, като се вземе дължината на проекцията на б върху да се , и умножавайки по дължината на да се , давайки същия резултат. Това означава, че точковият продукт е комутативна - точковото произведение на да се с б е същото като точковото произведение на б с да се . Едно полезно свойство на точковото произведение е, че стойността му е нула, ако векторите са ортогонални (ъгълът между тях е 90 градуса), тъй катоcos 90 = 0.
В три измерения можем също да умножим два вектора, за да изведем друг вектор, използвайки кръстосан продукт оператор. Определя се като:
и дължината на кръстосания продукт е:
къдетоострове най-малкият ъгъл между да се и б . Резултатът е вектор ° С това е ортогонално (перпендикулярно) и на двете да се и б . Ако да се и б са успоредни, т.е. ъгълът между тях е нула или 180 градуса, ° С ще бъде нулев вектор, защотоsin 0 = sin 180 = 0.
За разлика от точковия продукт, кръстосаният продукт не е комутативен. Редът на елементите в кръстосания продукт е важен, тъй като:
Посоката на резултата може да се определи от правило на дясната ръка . Отворете дясната си ръка и насочете показалеца си в същата посока на да се и ориентирайте ръката си по такъв начин, че когато правите юмрук пръстите ви да се движат право към б през най-малкия ъгъл между тези вектори. Сега палецът ви сочи в посока да се × б .