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

2.1.3 Ограничение Точки

Другой полезный тип ограничения — ограничение точки. Ограничение точки пробует прикрепить объект к определенному месту в пространстве. Это полезно для ограничения верхних двух углов нашей ткани. При использовании ограничений точки мы также в состоянии управлять двумя прикрепленными углами, изменяя их соответствующую позицию ограничения.

В папке Constraints, создайте новый файл класса и назовите его PointConstraint.cs.

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

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

{

    public
sealed
class
PointConstraint : Constraint

    {

        private
Vector3 point;

        private
SimObject simObject;

        public
Vector3 Point

        {

            get { return point; }

            set { point = value; }

        }
        public
float PointX

        {

            get { return point.X; }

            set { point.X = value; }

        }
        public
float PointY

        {

            get { return point.Y; }

            set { point.Y = value; }

        }
        public
float PointZ

        {

            get { return point.Z; }

            set { point.Z = value; }

        }
        public
SimObject SimModel

        {

            get { return simObject; }

            set { simObject = value; }

        }
        //——————————————————
        public PointConstraint(Vector3 point, SimObject simObject)

        {

            this.point = point;

            this.simObject = simObject;

        }

    }

}

Теперь мы должны реализовать метод SatisfyConstraint. Чтобы удовлетворить ограничению точки, все, что мы должны делать — это перемещать объект к целевой позиции.

(метод каласса PointConstraint.cs)
        public
void SatisfyConstraint()

        {

            //move to goal position

            simObject.CurrPosition = point;

        }

2.1.4 Обработка Ограничений В Классе Simulation

Теперь, когда у нас есть LengthConstraint и PointConstraint классы, мы должны позволить классу Simulation обрабатывать их.

Во-первых, мы добавим некоторые переменные в Simulation.cs, чтобы следить за Constraints. Это включает в себя список Constraints и constraintIterations переменную, которая определяет, как много итераций через Constraints проходит за временной шаг.

(в самом верху Simulation.cs)
using SkeelSoftBodyPhysicsTutorial.SoftBody.Constraints;
(члены класса в Simulation.cs)
        protected
List<Constraint> constraints = new
List<Constraint>();

        protected
int constraintIterations;

        public
List<Constraint> Constraints

        {

            get { return constraints; }

            set { constraints = value; }

        }
        public
int ConstraintIterations

        {

            get { return constraintIterations; }

            set { constraintIterations = value; }

        }

Теперь мы должны выполнить итерации для ограничения, чтобы ослабить их, как описано в начале Секции 2.1. Эта итерация ослабления должна быть сделана после того, как интегратор вычислил новые объектные позиции, но прежде, чем обновить объекты.

(метод калсса в Simulation.cs, дополнение кода жирным шрифтом)
        public
virtual
void Update(GameTime gameTime)

        {

            //sum all local forces

            foreach (Spring spring in springs)

            {

                spring.ApplyForce(null);  //no need to specify any simObj

            }
            //sum all global forces acting on the objects

            foreach (SimObject simObject in simObjects)

            {

                if (simObject.SimObjectType == SimObjectType.ACTIVE)

                {

                    foreach (ForceGenerator forceGenerator in globalForceGenerators)

                    {

                        forceGenerator.ApplyForce(simObject);

                    }

                }

            }
            foreach (SimObject simObject in simObjects)

            {

                if (simObject.SimObjectType == SimObjectType.ACTIVE)

                {

                    //find acceleration

                    acceleration = simObject.ResultantForce / simObject.Mass;
                    //integrate

                    integrator.Integrate(acceleration, simObject);

                }

            }
            //satisfy constraints

            for (int i = 0; i < constraintIterations; i++)

            {

                foreach (Constraint constraint in constraints)

                {

                    constraint.SatisfyConstraint();

                }

            }
            //update object

            foreach (SimObject simObject in simObjects)

            {

                simObject.Update(gameTime);

            }
            //reset forces on sim objects

            foreach (SimObject simObject in simObjects)

            {

                if (simObject.SimObjectType == SimObjectType.ACTIVE)

                {

                    simObject.ResetForces();

                }

            }

        }

2.2 Verlet (Без Скорости) Интегратор

Пришло время представить другой интегратор, называемый интегратором Verlet. Он известен тем, что быстрее и устойчивее (второй порядок, по сравнению с первым порядком Прямого метода Эйлера), и таким образом является хорошим выбором для игр. Есть несколько вариантов доступных интеграторов Verlet, таких как Скоростной Verlet(Velocity Verlet) и также многошаговый метод под названием скачкообразный Verlet(LeapFrog Verlet). Однако, интегратор Verlet, которым мы интересуемся, является версией, которая полностью опускает скорость объекта в вычислениях.

 

В предыдущей секции мы узнали, как решать ограничения ослаблением. Если Вы осознали, для того чтобы выполнять ограничения, мы просто переместили объекты к их целевым позициям без размышления об их скоростях! Это — то, где интегратор Verlet вступает в действие. Явно опуская скорости в вычислениях, мы можем выполнить простое смещение позиций во время ослабления, не волнуясь о скоростях, и мы все еще будем в состоянии вычислить новые позиции для каждого временного щага.

Уравнение для интеграции Verlet следующие:

x(t + ∆t) = 2 x(t) + x(t — ∆t) + a(t) (∆t)2 [8]

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

Вышеупомянутое уравнение интеграции Verlet может быть модифицировано, чтобы моделировать, силы сопротивления(drag forces) в передающей среде, где d – коэффициент сопротивления между 0 и 1 включительно.

x(t+∆t)=(2–d)x(t)+(1–d)x(t-∆t)+a(t)(∆t)2 [9]

Используя Формулу 9, мы можем не учитывать силы окружающей среды в нашем моделировании позже, так как d переменная в уравнении выше — хорошая замена для этого. Мы будем использовать это измененное уравнение в нашем моделировании.

Теперь давайте начнем осуществлять интегратор Verlet. Чтобы различать интегратор Verlet от других разновидностей, мы назовем этот класс VerletNoVelocityIntegrator. В папке Integrators, создайте новый файл класса по имени VerletNoVelocityIntegrator.cs.

(VerletNoVelocityIntegrator.cs)
using System;

using Microsoft.Xna.Framework;

using SkeelSoftBodyPhysicsTutorial.SoftBody.SimObjects;
namespace SkeelSoftBodyPhysicsTutorial.SoftBody.Integrators

{

    public
sealed
class
VerletNoVelocityIntegrator : Integrator

    {

        private
float drag;

        public
float Drag

        {

            get { return drag; }

            set

            {

                if (value < 0 || value > 1)

                {

                    throw
new
ArgumentException(«Air resistance must be between 0 and 1»);

                }

                drag = value;

            }

        }
        public VerletNoVelocityIntegrator(Game game) : this(game, 0.005f) { }
        public VerletNoVelocityIntegrator(Game game, float drag)

            : base(game)

        {

            this.drag = drag;

        }

    }

}

Этот класс просто берет значение сопротивления в конструкторе. Он будет установлено в 0.005 по умолчанию, если никакое другое значение не будет задано.

Мы теперь должны реализовать обязательный метод Integrate, используя Формулу 9.

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

        public
override
void Integrate(Vector3 acceleration, SimObject simObject)

        {

            newPosition = (2 — drag) * simObject.CurrPosition

                — (1 — drag) * simObject.PrevPosition

                + acceleration * fixedTimeStep * fixedTimeStep;
            simObject.PrevPosition = simObject.CurrPosition;

            simObject.CurrPosition = newPosition;

        }

2.3 Моделирование вершин

Вспомните, что в предыдущей главе, мы упаковали модель в объект моделирования под названием SimModel так, чтобы содержать атрибуты моделирования, такие как позиция, скорость и масса. Для ткани мы заинтересованы в перемещении ее вершин, подразумевая, что объекты моделирования — фактически вершины ткани непосредственно! Мы, таким образом, должны будем создать новый класс моделирования для вершины.

В папке SimObjects, создайте новый файл класса под названием SimVertex.cs.

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

using SkeelSoftBodyPhysicsTutorial.Primitives;
namespace SkeelSoftBodyPhysicsTutorial.SoftBody.SimObjects

{

    public
sealed
class
SimVertex : SimObject

    {

        private
int vertexId;

        private
TexturedPrimitive primitive;

        public
int VertexId

        {

            get { return vertexId; }

            set { vertexId = value; }

        }
        //——————————————————————
        public SimVertex(float mass, SimObjectType simObjectType, int vertexId, TexturedPrimitive primitive)

            : base(mass, simObjectType)

        {

            this.vertexId = vertexId;

            this.primitive = primitive;

            this.currPosition = primitive.GetVertexPosition(vertexId);

            this.prevPosition = currPosition;

        }

    }

}

Класс SimVertex присваивает массив вершин, SimObjectType (активный или пассивный), номер вершины и примитив. Все эта информация позволит нам восстанавливать и устанавливать позиции вершины, когда нам надо. Другая необходимая информация будет исходить из базового класса SimObject.

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

(метод класса в SimVertex.cs)
        public
override
void Update(GameTime gameTime)

        {

            primitive.SetVertexPosition(this.vertexId, this.currPosition);

        }

2.4 Классы моделирования мягкого тела и ткани.

Мы продолжим создавать классы, которые представляют мягкое тело и ткань. Ткань — по существу мягкое тело, таким образом, класс ClothSim, который мы создадим, наследуется от класса SoftBodySim. Сначала давайте начнем с создания класса SoftBodySim. В папке Simulations, создайте новый файл класса SoftBodySim.cs.

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

using SkeelSoftBodyPhysicsTutorial.SoftBody.SimObjects;
namespace SkeelSoftBodyPhysicsTutorial.SoftBody.Simulations

{

    public
class
SoftBodySim : Simulation

    {

        protected
SimVertex[] simVertices;

        public
SimVertex[] SimVertices

        {

            get { return simVertices; }

            set { simVertices = value; }

        }
        //——————————————————————-
        public SoftBodySim(Game game)

            : base(game) { }

    }

}

Класс SoftBodySim наследовался от класса Simulation, и сохраняет список SimVertex.

Затем, для нашего класса ClothSim, создайте новый файл класса ClothSim.cs в папке Simulations.

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

using Microsoft.Xna.Framework.Graphics;

using SkeelSoftBodyPhysicsTutorial.Primitives;

using SkeelSoftBodyPhysicsTutorial.SoftBody.Constraints;

using SkeelSoftBodyPhysicsTutorial.SoftBody.SimObjects;
namespace SkeelSoftBodyPhysicsTutorial.SoftBody.Simulations

{

    public
sealed
class
ClothSim : SoftBodySim

    {

        private
TexturedPlane clothPlane;

        public ClothSim(Game game, TexturedPlane clothPlane, float clothMass,

                        float structStiffness, float structDamping,

                        float shearStiffness, float shearDamping,

                        float bendStiffness, float bendDamping)

            : base(game)

        {

            this.clothPlane = clothPlane;
            //create sim data

            CreateSimVertices(clothPlane, clothMass);
            //connect springs and add constraints

            ConnectSprings(structStiffness, structDamping,

                           shearStiffness, shearDamping,

                           bendStiffness, bendDamping);

        }

    }

}

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

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

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

Логотип WordPress.com

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

Фотография Twitter

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

Фотография Facebook

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

Google+ photo

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

Connecting to %s