Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Глава 29. Простая физика — DCEСодержание книги
Похожие статьи вашей тематики
Поиск на нашем сайте
DCE — самое элементарное, что есть из физики в GLScene. Есть, правда, еще FPS Manager, но мы о нем здесь рассказывать не будем. Демка по нему: Demos\behaviours\FPSMovement. Для начала подумаем, зачем он нам? Он нужен для просчета простейшей физики и для обработки столкновений (чтобы персонажи не проходили сквозь стены ну и просто для определения столкновений). Переходим к основной части, постараюсь объяснить всё коротко и ясно. Как сделать так чтобы персонаж не проходил сквозь стены? В начале поместим на форму GLDCEManager из вкладки GLScene Utils. Далее в GLScene Editor’e выбираем нужный объект, справа над списками нажимаем на Behaviours (если их нет, то нажмите на панели инструментов editor’а кнопку с голубой сеткой), далее смотрим в списке, там есть две нужные нам вещи — это DCE static collider и DCE dynamic collider. Static добавляем для статичных объектов, которые в нашей сцене двигаться не будут, но в них будет упираться персонаж — здания, стены и другие препятствия. Dynamic нужен, соответственно, для динамичных объектов, которые будут перемещаться по сцене, и упираться в статичные и другие динамичные объекты. Когда мы добавили коллайдер, то его строчка появляется в списке Behaviours, нажимаем на нее и в Object Inspector’е видим настройки коллайдера
В DCE dynamic collider появляются UseGravity — подчинять ли этот объект гравитации или нет, и SlideOrBounce — будет ли объект при столкновении с другими объектами отскакивать от них. Shape выбирать не придётся, на всех динамических объектах устанавливается форма csEllipsoid. Всё вышесказанное также можно всё сделать с помощью кода: Для статичных объектов: With GetOrCreateDCEStatic(имя нужного объекта) do begin Для динами чных объектов это делается так: with GetOrCreateDCEDynamic(имя нужного объекта) do begin Manager:=GLDCEManager1; BounceFactor:=0.75; Friction:=10; Shape:=csFreeform; end;
На Glactor наложить DCE dynamic collider не получится, поэтому помещаем его в dummy и уже на него накладываем DCE dynamic collider и подгоняем размеры. Для передвижения динамического объекта по сцене запишем в каденсере:
Force: TAffineVector; … Force:= NullVector; if IsKeyDown(Ord('w')) then Force[2]:= 200 else if IsKeyDown(Ord('s')) then Force[2]:= -200; if IsKeyDown(Ord('a')) then Force[0]:= 200 else if IsKeyDown(Ord('d')) then Force[0]:= -200; GetOrCreateDCEDynamic(Player).ApplyAccel(Force);
Прекрасная демка есть в Demos\behaviours\DCEDemo. Статья о DCE: http://www.glscene.ru/content.php?article.104 Глава 30. Физика ODE
Open Dynamics Engine — физический движок, который использовался в таких известных играх как BloodRayne2, Stalker, Racer и во многих других. Есть два различных варианта работы с ODE. В GLScene имеются два встроеных компонента для работы с ODE: GLODEManager и GLODEJointList, но можно работать с чистым ODE. Многие начинающие программисты выбирают встроенные компоненты. Но этот «лёгкий» путь оказывается вовсе не таким. Во-первых, с помощью этих компонентов нельзя написать сложной физики, в лучшем случае выйдет простенькая аркадная гонка. Во-вторых, любому программисту даже при использовании ODEManager’а все равно придется использовать немного (а может и много) чистого кода ODE. Ну и, наконец, физика — второй по сложности расчетов элемент 3D игры после графики, а ODE на VCL работает медленнее, чем без VCL. По этим причинам мы не будем рассматривать здесь встроенные компоненты. К тому же, это ненамного сложнее. Сразу скажу — ODE это не часть GLScene, она не была написана для GLScene, и ODEManager и GLODEJointList является лишь надстройкой над самой библиотекой. Следовательно, можно написать свои компоненты или просто модули, совершенно независимые от встроенных в GLScene. Clear ODE
Для для всех проектов с ODE понадобится модуль ODEImport и, зачастую, ODEGL. Главная цель ODE — рассчитать и обработать взаимодействие предметов в трехмерном мире. Базовое понятие ODE — Мир (dxWorld), в котором находятся все тела. Его необходимо создать в начале. Для этого необходима глобальная переменная типа PdxWorld. Собственно создается мир просто: var World: PdxWorld; World:= dWorldCreate; dWorldSetGravity(World,0,-9.8,0); // также установили гравитацию Для мира можно настроить много параметров (притяжение и т.д.), которые можно найти в официальной документации. Одной программе вряд ли понадобиться более одного мира. В мире могут быть несколько подпространств (dxSpace), нам хватит одного (здесь и далее ODE-переменные делаем глобальными): var Space: PdxSpace; Space:=dHashSpaceCreate(nil); Идем дальше. Реальные твердые объекты имеет форму, в ODE она представлена геометрией (dxGeometry). Создание геометрии: var Geom: PdxGeom; Geom:= dCreateXXX(Space; параметры);
Чтобы придать объекту динамические характеристики, в ODE есть тела (dxBody). Они не имеют формы и размера, но у них есть масса, скорость и т.д. Тела не взаимодействуют друг с другом, на них лишь действуют силы. Создать новое тело также просто: var Body: PdxBody; Body:= dBodyCreate(World); После создания тело нужно присоединить к геометрии, к одному телу можно присоединить много геометрий для задания объектов сложной формы: dGeomSetBody (Geom, Body); Также необходимо создать один служебный объект для определения столкновений: var ContactGroup: TdJointGroupID ContactGroup:= dJointGroupCreate(100);
После создания всех этих вещей можно приступить к определению столкновений. Это делается в OnProgress каденсера. Запишем в него следующий код (physics_time — глобальная переменная с текущим временем в физике, ODE_TIMESTEP — константа, шаг времени в расчетах, обычно ~0,01). // Синхронизируем положение и поворот объекта с // рассчитанными таковыми параметрами геометрии PositionSceneObject(obj,Geom); // За время, потраченное на одну прорисовку сцены, // можно несколько раз просчитать физику. Это и делаем while physics_time<newTime do begin // Проверяем в nearCallback все возможные пары геометрий // в нашем пространстве на предмет наличия столкновений dSpaceCollide(Space,nil,nearCallback); // Проверили, накопили информацию -- просчитываем мир dWorldQuickStep(World,ODE_TIMESTEP); // После просчета очищаем группу контактов // (она заполнялась в dSpaceCollide) dJointGroupEmpty(СontactGroup); // А время идет! physics_time:=physics_time+ODE_TIMESTEP; end;
Вот типичный код процедуры nearCallback с комментариями. procedure nearCallback(data:Pointer; o1,o2:PdxGeom); cdecl; const cCOL_MAX = 12; // Максимальное обрабатываемое количество // точек столкновения для двух тел // Остальные точки игнорируются var i: integer; b1,b2: PdxBody; numc: integer; contacts: array[0..cCOL_MAX-1] of TdContact; contact: TdJointID; begin b1:=dGeomGetBody(o1); b2:=dGeomGetBody(o2); // Если у проверяемых геометрий есть тела, и они // соединены сочленением, то ODE позаботится о них сам if (Assigned(b1))and(Assigned(b2)and(dAreConnected(b1,b2)<>0)) then Exit;
// Устанавливаем параметры для будущих контактов, // которые повлияют на то, как "разойдутся" тела // mu -- трение, bounce -- пружинистость for i:=0 to cCOL_MAX-1 do begin contacts[i].surface.mode:=dContactBounce; contacts[i].surface.mu:=0.7; contacts[i].surface.mu2:=0; contacts[i].surface.bounce:=0; contacts[i].surface.bounce_vel:=0; end;
// Проверяем геометрии на наличие точек соприкосновения и // получаем их количество. В каждой точке будет создан контакт. // Контакт -- сочленение, созданное между телами // для обработки столкновения тел numc:=dCollide(o1,o2,cCOL_MAX,contacts[0].geom,SizeOf(TdContact)); // Если тела столкнулись (есть хоть одна точка столкновения) if (numc>0) then for i:=0 to numc-1 do begin // Создаем контакт contact:=dJointCreateContact(World,ContactGroup,@contacts[i]); // И соединяем им тела dJointAttach(contact,b1,b2); // Далее ODE будет оперировать телами в соответствии // с ранее установленными параметрами контакта // (mu, bounce и т.д.) end; end; Чтобы лучше понять механизм проверки столкновений, приведу выдержку из документации ODE: «Допустим, у нас есть две машины, перемещающиеся по поверхности земли. Каждая машина состоит из множества Геометрий. Если всю Геометрию машин разместить в одном пространстве, то время необходимое на определение столкновения между машинами будет пропорционально общему количеству Геометрии (или даже количеству геометрии в квадрате в зависимости от типа пространства). Увеличить скорость определения столкновений можно, представив каждую машину своим пространством. Геометрию машин разместить в пространстве-машин (car-spaces), а пространства машин разместить в пространстве высшего уровня. На каждом шаге времени dSpaceCollide будет вызываться для пространства высшего уровня. Здесь будет происходить проверка на пересечение пространств-машин между собой (а именно между ограничивающими параллелепипедами) и, если пересечение произошло, будет вызываться функция обратного вызова (nearCallback). Функция обратного вызова затем может проверить геометрию в пространствах-машин с помощью функции dSpaceCollide2. Если машины находятся не рядом, то функция обратного вызова не будет вызываться. Таким образом не будет впустую тратиться время на ненужный тест». Немного поясню. procedure dSpaceCollide (const Space: PdxSpace; data: pointer; callback: TdNearCallback); Определяет геометрию, которая потенциально может столкнуться в пространстве и вызывает nearCallback. Эта процедура определяет, что делать со столкнувшейся геометрией. Указатель data может использоваться для передачи данных, установленных пользоывателем, а если таких данных нет, устанавливайте его в nil. procedure dSpaceCollide2 (o1, o2: PdxGeom; data: pointer; callback: TdNearCallback); отличается от dSpaceCollide только тем, что выясняет столкновение не только между двумя пространствами, но и между двумя геометриями из разных пространств или одной геометрией из одного пространства и всеми геометриями другого, или двумя пространствами. В общем, эта процедура проверяет столкновение всех геометрий друг с другом. Также упомянем сочленения (dxJoint). Они позволяют прикреплять одно тело к другому каким-либо образом. Как, например, в простейшем случае создается машина? Очень просто: для корпуса создается Box, для колес — четыре Sphere. Потом к этому Box’у по углам прикрепляются Sphere’ы. Типы сочленений:
Подробнее о них см. в документации (ссылка в конце статьи). Упомянем только, что, подобно другим объектам, сочленения создаются через dJointCreate***, а их параметры устанавливаюся и получаются через dJointGet*** и dJointSet***. Тела соединяются через dJointAttach. Некоторые параметры сочленений (не все они есть у всех видов!):
dXXXDestroy(объект); где XXX — тип объекта (Body, World, Space, Joint и т.д.).
http://ode.org/doc/russian — официальная документация по ODE на русском языке. Она сильно устарела, но основы остались те же http://glscene.ru/download.php?view.564 — простой и понятный пример для начинающих http://glscene.ru/download.php?view.382 — более полный пример, специально для шутеров http://glscene.ru/content.php?article.85 — статья к предыдущему примеру http://glscene.ru/download.php?view.233 — навороченный пример гонок http://opende.sourceforge.net/wiki —хороший англоязычный обновляемый мануал
Глава 31. Физика Newton
Физический движок Ньютон не сложен в изучении. К тому же, если вы разобрались с ODE, вам будет нетрудно освоить и Ньютон — во многом они похожи (и поэтому опишем его короче). Для работы с ньютоном необходимы Newton.dll и NewtonImport.pas. Как и другие физические движки, Ньютон имеет мир, который создается так: var NewtonWorld: PNewtonWorld; NewtonWorld:= NewtonCreate(nil, nil); В конце работы программы, для освобождения памяти, следует вызвать: NewtonDestroy(NewtonWorld); Симулируется мир командой (ее необходимо прописать в каденсере): NewtonUpdate(NewtonWorld, DeltaTime); Твердое тело в ньютоне имеет тип PNewtonBody. При его создании указываются мир, в который оно вставляется, и коллизия (геометрическая оболочка тела, по которой определяются столкновения). Существует 10 типов коллизий: Null (прозрачная коллизия), Box, Sphere, Cone, Capsule, Cylinder, ChamferCylinder (цилиндр со сглаженными краями), ConvexHull (выпуклая оболочка), TreeCollision ( для GLFreeform — полигональная коллизия произвольной сложности (только для статических объектов)), CompoundCollision — составная коллизия. Создается коллизия функцией NewtonCreateXXX, где XXX — тип коллизии. Масса тела в ньютоне задается процедурой NewtonBodySetMassMatrix(NewtonBody, mass, Ixx, Iyy, Izz); здесь Ixx, Iyy, Izz — моменты инерции для каждой оси. Имитация силы тяжести реализуется callback функцией: procedure ForceAndTorqueCallback(const body: PNewtonBody); cdecl; var Mass: Single; Inertia: TVector3f; Force: TVector3f; begin NewtonBodyGetMassMatrix(Body, @Mass, @Inertia.x, @Inertia.y,@Inertia.z); Force:= V3(0, -9.8 * Mass, 0); NewtonBodyAddForce(Body, @Force.x); end; Эта функция постоянно вызывается для тел, которым она назначена. Назначить ее можно так: NewtonBodySetForceAndTorqueCallBack(NewtonBody, ForceAndTorqueCallBack); Cоздадим, к примеру, куб: procedure NewCube; var NewtonBody: PNewtonBody; Collision: PNewtonCollision; Matrix: TMatrix4f; begin Collision:= NewtonCreateBox(NewtonWorld, 1, 1, 1, nil); NewtonBody:= NewtonCreateBody(NewtonWorld, Collision); NewtonReleaseCollision(NewtonWorld, Collision); NewtonBodySetMassMatrix(NewtonBody, 3, 0.5, 0.5, 0.5); NewtonBodySetForceAndTorqueCallBack(NewtonBody, ForceAndTorqueCallBack); end; Чтобы увидеть, что получилось, в каденсер добавляем: var Matrix: TMatrix4f; NewtonUpdate(Newton,deltaTime); NewtonBodyGetMatrix(NewtonBody, @Matrix[0,0]); GLCube.Matrix:=Matrix; Для изменения положения тела в пространстве, необходимо изменить матрицу трансформации: var Matrix: TMatrix4f; NewtonBodyGetMatrix(NewtonBody, @Matrix[0,0]); Matrix[3,0]:= x; Matrix[3,1]:= y; Matrix[3,2]:= z; NewtonBodySetMatrix(NewtonBody, @Matrix[0,0]);
Ссылки: Официальный сайт: http://www.newtondynamics.com Пример на Newton 2.10: http://www.glscene.ru/download.php?view.471 И статья: http://www.glscene.ru/content.php?article.105 Статья о т.н. материалах Newton: http://www.glscene.ru/content.php?article.108
|
||||||||||||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2016-04-19; просмотров: 485; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 52.15.190.187 (0.009 с.) |