Введение в Физику мягких форм (Перевод) Часть 4

Затем, мы инициализируем моделирование в недавно созданном методе. Мы сначала загружаем куб и сферу. Они будут служить маркерами, чтобы указать оба конца нити. Эти модели загружены, при помощи ModelComponent из нашего основного кода.

(в самом верху Game1.cs)
using SkeelSoftBodyPhysicsTutorial.SoftBody.SimObjects;
(снаружи InitSpringScene() в Game1.cs)
        SimModel stationaryCubeSimObj, movingSphereSimObj;
(внутри InitSpringScene() в Game1.cs)
            //load in a cube and a sphere

            GameModel stationaryCube = modelComponent.LoadGameModel(@»cube»);

            stationaryCube.TranslateY = 5;

            GameModel movingSphere = modelComponent.LoadGameModel(@»sphere»);

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

(в самом верху Game1.cs)
using SkeelSoftBodyPhysicsTutorial.SoftBody.Simulations;
(снаружи InitSpringScene() в Game1.cs)
        Simulation springSim;
(внутри InitSpringScene() в Game1.cs)
            //create a spring sim

            springSim = new
Simulation(this);

Затем, мы упаковываем куб и сферу в SimObjects и добавляем их к моделированию нити. Куб будет управляться нами, таким образом, он будет отмечен как пассивный. Сфера должна управляться моделированием, таким образом, она активна. Масса сферы установлена как 1.0 после метода проб и ошибок, в то время как масса куба установлена случайно (1000.0 в нашем случае), но это не имеет значения, так как это не используется в вычислениях.

(внутри InitSpringScene() в Game1.cs)
            //create sim objects from the loaded models

            float sphereMass = 1.0f;

            movingSphereSimObj = new
SimModel(movingSphere, sphereMass, SimObjectType.ACTIVE);

            springSim.AddSimObject(movingSphereSimObj);

            stationaryCubeSimObj = new
SimModel(stationaryCube, 1000.0f, SimObjectType.PASSIVE);

            springSim.AddSimObject(stationaryCubeSimObj);

Мы потом создаем нить между двумя созданными SimObjects:

(внутри InitSpringScene() в Game1.cs)
            //attach a spring between the sim objects

            float stiffness = 8.0f;

            float damping = 0.1f;

            springSim.AddSpring(stiffness, damping, stationaryCubeSimObj, movingSphereSimObj);

Затем, мы добавляем глобальные силы к системе моделирования. Мы будем использовать гравитационное ускорение Земли (9.81 вниз) для силы тяжести. Для коэффициента силы трения подобрали методом проб и ошибок значение 0.5.

(в самом верху Game1.cs)
using SkeelSoftBodyPhysicsTutorial.SoftBody.ForceGenerators;
(внутри InitSpringScene() в Game1.cs)
            //add in a global force generator: gravity

            Gravity gravity = new
Gravity(new
Vector3(0, -9.81f, 0));

            springSim.AddGlobalForceGenerator(gravity);
            //add in a global force generator: air

            float dragCoefficient = 0.5f;

            Medium air = new
Medium(dragCoefficient);

            springSim.AddGlobalForceGenerator(air);

Теперь мы создаем Integrator и назначаем его на моделирование.

(в самом верху Game1.cs)
using SkeelSoftBodyPhysicsTutorial.SoftBody.Integrators;
(внутри InitSpringScene() в Game1.cs)
            //create an integrator and assign it to the sim

            ForwardEulerIntegrator integrator = new
ForwardEulerIntegrator(this);

            springSim.Integrator = integrator;

Чтобы визуализировать нить, мы будем чертить линию от куба до сферы, которая представляет упругую нить. Строка кода была уже написана, когда мы включали Line3DComponent в game.Components, все что мы должны сделать теперь — установить позиции двух концов, и также цвет линии.

(внутри InitSpringScene() in Game1.cs)
            //init the line from cube to sphere that represents the spring

            line3DComponent.StartPosition = stationaryCube.Translate;

            line3DComponent.EndPosition = movingSphere.Translate;

            line3DComponent.Color = Color.White;

Теперь, мы должны обновить моделирование и линию в методе Update. Все, что мы должны сделать — попросить, чтобы моделирование обновило себя, и затем переместило два конца линии на новые позиции, вычисленные для сферы и объектов моделирования куба.

(внутри Update() в Game1.cs, дополнение к коду жирным шрифтом)
        protected
override
void Update(GameTime gameTime)

        {

            //update the sim

            springSim.Update(gameTime);
            //update line

            line3DComponent.StartPosition = stationaryCubeSimObj.CurrPosition;

            line3DComponent.EndPosition = movingSphereSimObj.CurrPosition;
            base.Update(gameTime);

        }

Если Вы скомпилируете и выполните программу теперь, и у Вас получился стационарный куб и двигающаяся сфера, прикрепленная пружиной, значит моделирование — работает!

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

(метод класса в Game1.cs, дополнение к коду жирный шрифтом)
        protected
override
void Update(GameTime gameTime)

        {

            //poll for input

            HandleInput(gameTime);
            //update the sim

            springSim.Update(gameTime);
            //update line

            line3DComponent.StartPosition = stationaryCubeSimObj.CurrPosition;

            line3DComponent.EndPosition = movingSphereSimObj.CurrPosition;
            base.Update(gameTime);

        }
        private
void HandleInput(GameTime gameTime)

        {

            if (inputComponent.IsKeyHeldDown(Keys.Right))

            {

                stationaryCubeSimObj.CurrPositionX += 0.1f;

            }

            if (inputComponent.IsKeyHeldDown(Keys.Left))

            {

                stationaryCubeSimObj.CurrPositionX -= 0.1f;

            }

            if (inputComponent.IsKeyHeldDown(Keys.Up))

            {

                stationaryCubeSimObj.CurrPositionY += 0.1f;

            }

            if (inputComponent.IsKeyHeldDown(Keys.Down))

            {

                stationaryCubeSimObj.CurrPositionY -= 0.1f;

            }

        }

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

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

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

Загрузите исходные файлы в конце этой главы.

Глава 2. Моделирование Ткани.

Загрузите исходные файлы для начала этой главы.

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

Мягкие тела, вообще, главным образом зависят от того, как Вы соединяете нити(the springs) между вершинами. Каждая вершина модели в состоянии двигаться независимо от других, позволяя модели исказить и изменить форму. Деформируется ли модель как мягкое тело, очень зависит от того, как Вы соединяете нити и атрибуты нитей(the springs and the attributes of the springs). Теперь, когда мы знаем, как создать нити, из предыдущей главы, мы узнаем, как создать гибкость для плоской геометрии(the springs for the plane geometry) в этой главе так, чтобы можно было бы создать моделирование ткани.

К концу этой главы Вы должны быть в состоянии создать ткань, которая выглядит следующим образом:

Видео 5: моделирование ткани, созданное, используя простые нити и ограничения

http://www.youtube.com/watch?v=JncQOCg9FS0&feature=player_embedded

2.1 Ограничения

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

Ограничения — это в основном условия, которым система моделирования должна попытаться удовлетворить. Некоторые примеры ограничений — ограничения длины, где два объекта пытаются сохранять расстояние между собой, и ограничения точки, где объект пытается прикрепиться к определенной точке в пространстве.

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

Видео 6: моделирование ткани без ограничений длины.

Ткань имеет тенденцию быть слишком упругой и весьма непостоянной.

http://www.youtube.com/watch?v=nCrA6eUrXSc&feature=player_embedded

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

Путь, которым мы решаем ограничения – ослабление(by relaxation), очень практичный метод, который работает хорошо для игр. Мы выполним итерации n число раз и при каждой итерации, мы попытаемся заставить каждое ограничение удовлетворять условию. Например, для ограничения точки, мы можем, возможно, сделать цикл с 10 итерациями и при каждой итерации, мы перемещаем объект к целевой позиции, как определено ограничением точки.

Почему тогда мы хотим выполнить итерации n раз и заставить ограничение двигаться к цели неоднократно? Причина в том, что может быть много различных ограничений, которые надо будет выполнять и, пока мы выполняем одно из них, другое может быть нарушено. Вообразите моделирование с двумя связанными ограничениями длины. Во время каждой итерации первое ограничение двигается на расстояние до цели, но, делая так, оно, возможно, увеличивает расстояние до цели второго ограничения. Второе ограничение тогда двигается на свое расстояние до цели и в свою очередь, возможно, заставляет расстояние первого ограничения увеличиваться. Это кажется, что они рассчитывают эффект друг на друга, но в конце каждой итерации, они оба сдвинулись бы до цели на некоторое расстояние (схождение в одной точке гарантируется при правильных условиях). Это — причина, почему мы должны выполнить итерации через n число раз так, чтобы мы медленно ослабили «борьбу» между ограничениями, и они будут медленно сходиться к своим целевым длинам соответственно.

Число выполняемых итераций зависит от того, сколько мощности вы можете выделить для вашей игры. Чем больше итераций, тем лучше ограничения будут выполняться, но вычисления будут требовать больше ресурсов. Число около 10 — 20 часто подходит, чтобы дать удовлетворительный результат, таким образом, обычно нет никакой потребности увеличивать это число до высоких значений, таких как 100. Фактически, в некоторых случаях, одной итерации может быть достаточно. Предполагается, что Вы сократите количество к подходящему значению, которое дает визуально приемлемые результаты.

2.1.1 Интерфейс Ограничения

Создайте папку под названием Constraints в папке SoftBody, и добавьте новый файл класса по имени Constraint.cs. Класс Constraint в основном будет интерфейсом, который делает обязательным для производных классов, осуществление метода SatisfyConstraint.

(Constraint.cs)
namespace SkeelSoftBodyPhysicsTutorial.SoftBody.Constraints

{

    public
interface
Constraint

    {

        void SatisfyConstraint();

    }

}

2.1.2 Ограничение Длины

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

В папке Constraints, добавьте новый файл класса LengthConstraint.cs. Класс LengthConstraint в основном передает два SimObjects и ожидаемое расстояние между ними.

(LengthConstraint.cs)
using Microsoft.Xna.Framework;

using SkeelSoftBodyPhysicsTutorial.SoftBody.SimObjects;
namespace SkeelSoftBodyPhysicsTutorial.SoftBody.Constraints

{

    public
sealed
class
LengthConstraint : Constraint

    {

        private
float length;

        private
SimObject simObj1;

        private
SimObject simObj2;

        public
float Length

        {

            get { return length; }

            set { length = value; }

        }
        //————————————————————
        public LengthConstraint(float length, SimObject simObj1, SimObject simObj2)

        {

            this.length = length;

            this.simObj1 = simObj1;

            this.simObj2 = simObj2;

        }

    }

}

Затем, мы должны осуществить метод SatisfyConstraint. Вспомните, что мы должны удовлетворять ограничениям при каждой итерации. Для ограничений длины это может быть сделано, путем перемещения обоих концов ограничения на расстояние равное половине разнице между текущей и целевой длиной, как показано на Рис. 2.


рис 2: Два конца ограничения длины двигаются к целевой длине в единственной итерации.

Реализация этого дана ниже. В основном мы вычисляем направление и текущее расстояние между двумя SimObjects. Тогда мы нормализуем вектор направления, и перемещаем оба SimObjects на расстояние половины разницы между целевой и текущей длиной в направлении сближения.

(метод класса в LengthConstraint.cs)
        Vector3 direction;

        float currentLength;

        Vector3 moveVector;

        public
void SatisfyConstraint()

        {

            //calculate direction

            direction = simObj2.CurrPosition — simObj1.CurrPosition;
            //calculate current length

            currentLength = direction.Length();
            //check for zero vector

            if (direction != Vector3.Zero)

            {

                //normalize direction vector

                direction.Normalize();
                //move to goal positions

                moveVector = 0.5f * (currentLength — length) * direction;

                simObj1.CurrPosition += moveVector;

                simObj2.CurrPosition += -moveVector;

            }

        }

Реклама
Запись опубликована в рубрике Uncategorized. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s