以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 39-lesson 40 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=54706) |
-- 作者:一分之千 -- 发布时间:10/31/2007 7:44:00 PM -- Lesson 39 Introduction to Physical Simulations If you are familiar to physics and want to start implementing code of physical simulations, this tutorial could help you. In order to benefit from this tutorial you should be familiar to vectoral operations in 3D as well as physical concepts such as force and velocity. In this tutorial you will find a very simple physical simulation engine. Contents of the tutorial is as follows: Contents: The Design: Force and Motion: How A Simulation Should Operate: Operating A Simulation By An Application: Applying Force: The Design: Design of physical simulation engines is not always simple. But there is a simple order of dependency; application depends on simulation toolkit and the simulation toolkit depends on math libraries. Here, we will make use of this simple order. Our purpose is to obtain a container to simulate motion of masses. The simulation toolkit will include an object "class Mass" and an object "class Simulation". "class Simulation" will be our container. When we obtain the Simulation class, we will be able to develop applications. But before that, we need a math library. The library includes only one class "class Vector3D". Vector3D class will be used to represent points, vectors, position, velocity, and force in 3 dimensional space. * class Vector3D ---> An Object To Represent A 3D Vector Or A 3D Point In Space. Vector3D class is the only member of our modest math library. Vector3D holds x, y, and z values and it implements operators for vector arithmetics in 3D. Addition, subtraction, multiplication, and division operators are coded in Vector3D. Since this tutorial focuses on physics, I will not go into details of Vector3D. If you have a look at Physics1.h you will see how simple Vector3D is. Force and Motion: For implementing physical simulations, we should know what a mass is. A mass has a position and a velocity. A mass has weight on Earth, Moon, Mars, and at any place where gravitation exists. Weight is different on different gravitations of different places. But there is one common value for a mass, which is the same in all conditions. This value is also called mass. Mass value of a mass! Mass value represents "how much a mass exists in space"! For example a book is a mass with a weight of say 1 kg on The Earth and with a weight of 0.17 kg on The Moon and has a mass value of 1 kg everywhere. The mass value is designated to be equal to its mass on The Earth. After having understood the mass of a mass, we should go on with force and motion. A mass, with a non-zero velocity in space, moves in the direction of the velocity. Therefore, one reason of the change in position is the velocity. Passing of time is another reason. Change in position depends on how fast a mass moves and how much time has passed. You should have understood until here to go on to the next paragraph. If not, spend some time thinking on the relation between position, velocity and time. Velocity of a mass changes if there is force acting on it. Velocity tends to the direction of the force. This tending is proportional to the force and iversly proportional to mass. The change in velocity per unit time is called acceleration. More the force on a mass, more its acceleration. More the mass value of a mass, less its acceleration. When acceleration is formulated it is: acceleration = force / mass From here we obtain the famous equation: force = mass * acceleration (We will mostly use the acceleration formula) For preparing a physical medium to simulate, you should be aware of the environment that the simulation takes place. The environment in this tutorial is simply empty space waiting to be filled by masses we create. The units of the values to represent masses and time shall be decided firstly. I have decided to use the time unit as seconds and units of position values as meters. Accordingly, unit of velocity becomes meters per second (m/s). And the unit of acceleration becomes meters per second per second (m/s/s)! (this means velocity per second since velocity is meters per second) I have decided the unit of mass values as kilograms (kg). * class Mass ---> An Object To Represent A Mass. Now we are starting to use the theory! We have to write a class to represent a mass. It should hold the mass value, the position, the velocity, and the force applied at an instance. class Mass Mass(float m) // Constructor. ... (class Mass continued) void applyForce(Vector3D force) void init() // This Method Sets The Force Values To Zero. ... 1. Reset the force (see the init() method()) Here, iterating the time is implemented with "The Euler Method". The Euler Method is a simple simulation method. There are more sophisticated methods for simulations. But Euler is good enough for lots of applications. Most of computer and video games use The Euler Method. What this method does is that it calculates the next velocity and next position of a mass according to the force applied and time passed. The itteration is done in void simulate(float dt): (class Mass continued) void simulate(float dt) pos += vel * dt; // Change In Position Is Added To The Position. In a physical simulation, at every iteration, the same process takes place. Forces are set to zero, forces are applied, new positions and new velocities are calculated. This process cycles as long as we want the time to pass. This process is implemented in "class Simulation". * class Simulation ---> A Container Object For Simulating Masses. Simulation class holds masses as its members. The role of the class is to create and delete masses, and maintain the simulation procedure. class Simulation Simulation(int numOfMasses, float m) // Constructor Creates Some Masses With Mass Values m. masses = new Mass*[numOfMasses]; // Create An Array Of Pointers. for (int a = 0; a < numOfMasses; ++a) // We Will Step To Every Pointer In The Array. virtual void release() // Delete The Masses Created. delete(masses); Mass* getMass(int index) return masses[index]; // Get The Mass At The index. ... 1. init() to set forces to zero (class Simulation continued) virtual void init() // This Method Will Call The init() Method Of Every Mass. virtual void solve() // No Implementation Because No Forces Are Wanted In This Basic Container. virtual void simulate(float dt) // Iterate The Masses By The Change In Time. ... (class Simulation continued) virtual void operate(float dt) // The Complete Procedure Of Simulation. 1. Mass with constant velocity Operating A Simulation By An Application: Before we write a specific simulation, we should know how to operate simulations by applications. In this tutorial, the simulation engine and the application to operate the simulations are seperated in two files. In the application file there is a function as: void Update (DWORD milliseconds) // Perform Motion Updates Here. void Update (DWORD milliseconds) float dt = milliseconds / 1000.0f; // Let's Convert milliseconds To Seconds. dt /= slowMotionRatio; // Divide dt By slowMotionRatio And Obtain The New dt. timeElapsed += dt; // Iterate Elapsed Time. ... As an example, in a car racing game, it is convenient to use dt as about 2 to 5 milliseconds for regular car, and 1 to 3 milliseconds for a formula car. In an arcade car simulation it is possible to use dt as about 10 to 200 milliseconds. Less the value of dt, more the CPU ticks we need to catch up the real world time. That is why physical simulations are rarely used in older games. In the code below we define the maximum possible dt as 0.1 seconds (100 milliseconds). With this value we will calculate the number iterations to be made at the current update. We write a formula: int numOfIterations = (int)(dt / maxPossible_dt) + 1; numOfIterations is the number of iterations to be made for a simulation. Say that the application is running with 20 frames per second, which gives dt = 0.05 seconds. Then numOfIterations becomes 1. The simulation will be iterated once by 0.05 seconds. Say dt was 0.12 seconds. Then numOfIterations is 2. Below, just after "int numOfIterations = (int)(dt / maxPossible_dt) + 1;", you should see that dt is calculated once again. There, dt is divided by numOfIterations and it becomes dt = 0.12 / 2 = 0.06. dt was originally more than the maximum possible value 0.1. Now we have dt as 0.06 but we will operate the simulation twice so that we catch up 0.12 seconds as a result. Examine the code below and be sure that you understand the paragraph above. ... float maxPossible_dt = 0.1f; // Say That The Maximum Possible dt Is 0.1 Seconds. int numOfIterations = (int)(dt / maxPossible_dt) + 1; // Calculate Number Of Iterations To Be Made At This Update Depending On maxPossible_dt And dt. for (int a = 0; a < numOfIterations; ++a) // We Need To Iterate Simulations "numOfIterations" Times. 1. Mass with constant velocity Mass with constant velocity does not need any external force. We just have to create 1 mass and set its velocity to (1.0f, 0.0f, 0.0f) so that it moves in the x direction with a velocity of 1 m/s. We will derive a class from Simulation. This class is "class ConstantVelocity": class ConstantVelocity : public Simulation Vector3D(1.0f, 0.0f, 0.0f) * 0.1 = Vector3D(0.1f, 0.0f, 0.0f) At every iteration, the mass moves 0.1 meters to the right. After 10 frames, it will have moved 1.0 meter to the right. The velocity was 1.0 m/s and it moves 1.0 meter in one second. Was that a coincidental or a logical result? If you can't answer this question spend some time thinking about the relation above. When you run the application, you see the mass with constant velocity moving in the x direction. The application provides two modes of motion flow. By pressing F2 you get time flow parallel to the real world. And by pressing F3 you get time flow 10 times slower than the real world time. On the screen you will see lines to represent the coordinate plane. The spacing between these lines is 1 meter. By the use of the lines, you can observe that the mass moves 1 meter in a second when it is set to the real world time mode. And in the slow mode it moves 1 meter in ten seconds. The techique described above is a common one to make the real-time simulations flow parallel to the real world time. To use this technique, you must have strictly decided on the units of your simulation. Applying Force: In the constant velocity simulation, we did not apply any force to the mass. Because we know that if a force acts on a body, it accelerates. When we want accelerating motion, we apply forces. At one operation of a simulation, we apply forces in the "solve" method. When the operation comes to the "simulate" phase, the net force results as the total of forces. The net force determines the motion. Say that you want to apply 1 N force on a mass in the x direction. Then you should write: mass->applyForce(Vector3D(1.0f, 0.0f, 0.0f)); in the "solve" method. If you want to add another force say 2 N in the y direction you should write: mass->applyForce(Vector3D(1.0f, 0.0f, 0.0f)); in the "solve" method. You can add any force in any formulated way and you obtain the motion. In the next application you will see a single force in a formulated way. 2. Mass under gravitational force MotionUnderGravitation class creates a mass and it applies a force to it. This force is the force of gravitation. Force of gravitation is equal to the mass times the gravitational acceleration: F = m * g Gravitational acceleration is the acceleration of free body. On the earth, when you drop an object, it gains 9.81 m/s velocity every second, unless it experiences a force other than the gravitational force. Therefore the gravitational acceleration is constant for all masses on the earth and it is 9.81 m/s/s. (This is independent of the mass. All masses fall with the same acceleration.) MotionUnderGravitation class has such a constructor: class MotionUnderGravitation : public Simulation MotionUnderGravitation(Vector3D gravitation) : Simulation(1, 1.0f) // Constructor Firstly Constructs Its Super Class With 1 Mass And 1 Kg. ... virtual void solve() // Gravitational Force Will Be Applied Therefore We Need A "Solve" Method. 3. Mass connected to a still point by a spring * class MassConnectedWithSpring : public Simulation ---> A Simulation Object That Creates A Mass Connected To A Point By A Spring. In this example, we want to connect a mass to a still point by a spring. The spring should pull the mass towards the connection position, so that it oscillates. In the constructor, MassConnectedWithSpring class sets the connection position and sets the position of the mass. class MassConnectedWithSpring : public Simulation MassConnectedWithSpring(float springConstant) : Simulation(1, 1.0f) // Constructor Firstly Constructs Its Super Class With 1 Mass And 1 Kg. connectionPos = Vector3D(0.0f, -5.0f, 0.0f); // Set The connectionPos. masses[0]->pos = connectionPos + Vector3D(10.0f, 0.0f, 0.0f); // Set The Position Of The Mass 10 Meters To The Right Side Of The connectionPos. ... F = -k * x k is a value to represent how stiff the spring should be. And x is the distance from the mass to the connection position. The negative sign at the formula indicates that this is an attractive force. If it was positive, the spring would push the mass which is not something that we would expect to see. virtual void solve() // The Spring Force Will Be Applied. In this tutorial, I tried to point to the key concepts of physical simulations. If you are interested in physics, you will not have hard time to create new simulations of your own. You can try complicated interactions and obtain very attracive demos and games. The next steps to take will be rigidbody simulations, simple mechanisms and advanced simulation methods. For any comments or questions please contact me: Erkin Tunca (erkintunca@icqmail.com) Jeff Molofee (NeHe) |
-- 作者:一分之千 -- 发布时间:10/31/2007 8:08:00 PM -- 第四十课 怎样模拟一根绳子呢,把它想象成一个个紧密排列的点,怎么样有了思路了吧,在这一课你你将学会怎样建模,简单吧,你能模拟更多。 在这个教程里我们将模拟一段绳索,我们是在39课的基础上进行的。 在物理模拟中,我们必须设置各个物理量,就像它们在自然界中的行为一样。模拟中的运动并不一定和自然界相同,我们使用的运动模型,必须和我们需要模拟的目的有关,目的决定了它的精确度。要知道我们的目标不是模拟原子和分子,也不是模拟成千上万的粒子系。首先我们需要确定我们模拟的目标,才能创建我们的物理模型。它和下面内容相关: 1. 运动的数学表示 1. 运动的数学表示: 这个问题决定了我们使用何种数学方程来模拟运动,使用经典力学还是量子力学。 2. 执行模拟的计算机的速度: 计算机的速度决定了我们可以模拟的精度。 设计绳索的物理模型: 我们在经典力学和高于500Mhz的计算机上模拟这个问题。首先我们需要设定需要的精度,我们使用一系列互相用弹簧连接的质点来模拟绳索,精度决定了我们用多少个点来模拟,当然越多越精确。在下面我决定用50或100个点来模拟绳子一段3或4m长的绳子,换句话说,我们的模拟精度就是3到8厘米。 设计运动模型: 在绳子中,施加给各个质点的力来自于自身的质量和相连的内力(参见大学里的普通力学)。如下我们用"O"表示质点,“—”表示连接质点的弹簧。 弹簧的力学公式如下: 力 = -k * x 上面的公式说明,如果相邻点的距离为平衡距离,那么它们不受到任何力的作用。如果我们设置平衡位置为5cm,那么100个点的绳子长5m。如果相连质点之间的位置小于5cm,它们受到排斥力。 上面的公式只是一个基础,现在我们可以加上摩擦力,如果没有这项,那么绳子将永远动下去。 弹簧类: 这个类包含相连接的两个物体,它们之间具有作用力。 class Spring float springConstant; // 弹性系数 Spring(Mass* mass1, Mass* mass2, this->mass1 = mass1; void solve() // 计算各个物体的受力 Vector3D force; force += -(mass1->vel - mass2->vel) * frictionConstant; // 加上摩擦力 力 = (重力加速度) * 质量 万有引力会作用在每一个质点上,地面也会给每个物体一个作用力。在我们的模型中将考虑绳子和地面之间的接触,地面给绳子向上的力,并提供摩擦力。 设置模拟的初始值 现在我们已经设置好模拟环境了,长度单位是m,时间单位是秒,质量单位是kg。 为了设置初始值,我们必须提供供模拟开始的参数。我们定义一下参数: 1. 重力加速度: 9.81 m/s/s 垂直向下 下面计算绳子受到的力 f = (绳子质量) * (重力加速度) = (4 kg) * (9.81) ~= 40 N 弹簧必须平衡这个力 40 N,它伸长1cm,计算弹性系数: 合力= -k * x = -k * 0.01 m 合力应该为0 : 40 N + (-k * 0.01 meters) = 0 弹性系数 k 为: k = 4000 N / m 设置弹簧的摩擦系数: springFrictionConstant = 0.2 N/(m/s) 下面我们看看这个绳索类: 1. virtual void init() ---> 重置力 2. virtual void solve() ---> 计算各个质点的力 3. virtual void simulate(float dt) ---> 模拟一次 4. virtual void operate(float dt) ---> 执行一次操作 绳索类如下所示 : class RopeSimulation : public Simulation //绳索类 Vector3D gravitation; // 万有引力 Vector3D ropeConnectionPos; // 绳索的连接点 float groundRepulsionConstant; //地面的反作用力 float airFrictionConstant; //空气的摩擦系数 RopeSimulation( this->groundFrictionConstant = groundFrictionConstant; for (int a = 0; a < numOfMasses; ++a) // 设置质点位置 springs = new Spring*[numOfMasses - 1]; void solve() // 计算施加给各个质点的力 for (a = 0; a < numOfMasses; ++a) // 计算各个物体受到的其它的力 if (masses[a]->pos.y < groundHeight) // 计算地面对质点的作用 v = masses[a]->vel; // 返回速度 // 计算地面给质点的力 v = masses[a]->vel; if (v.y < 0) // 计算地面的缓冲力 masses[a]->applyForce(-v * groundAbsorptionConstant); masses[a]->applyForce(force); // 施加地面对质点的力 void simulate(float dt) // 模拟一次 ropeConnectionPos += ropeConnectionVel * dt; // 计算绳子的连接点 if (ropeConnectionPos.y < groundHeight) masses[0]->pos = ropeConnectionPos; // 更新绳子的连接点和速度 void setRopeConnectionVel(Vector3D ropeConnectionVel) RopeSimulation* ropeSimulation = float dt = milliseconds / 1000.0f; // 经过的秒数 float maxPossible_dt = 0.002f; // 模拟间隔 int numOfIterations = (int)(dt / maxPossible_dt) + 1; // 模拟次数 for (int a = 0; a < numOfIterations; ++a) // 执行模拟 我相信这一个教会了你很多,从最开始的模型的建立,到完成最后的代码。有了这个基础,相信你会创造出很多更有意思的代码! |
-- 作者:一分之千 -- 发布时间:10/31/2007 8:14:00 PM -- Lesson 40 Rope Simulation In this tutorial, you will find a simulation of a rope. This simulation is based on the simple physical simulation engine in Lesson 39. In order to benefit from this tutorial, you should know how forces are applied to masses in simulations, how position and velocity of a mass is iterated while the simulation runs, and how 3D vectoral operations are used in physics. If you hesitate on any one of those subjects, read about them from Lesson 39 and other sources, and develop several applications. In physical simulations, the purpose is to form a physical setting, which acts the same as in the natural environment. Motion in simulations cannot always be exactly the same as in the nature. A model to cover the motion, that we aim to simulate, must be put forward to form the physical setting. The model that we create must state, how precise and detailed the motion should be observed from the simulation. Are we aiming to observe the atoms, the electrons or the photons, or are we aiming to observe the approximate motion of a cluster of particles? What is the scale that we want to see? What is the scale of space and time? The scale of space and time to observe is related to: 1. Mathematics of motion 1. Mathematics Of Motion: Here, the mathematics of motion is called "classical mechanics", which is simply representing masses as particles in space and accelerating these masses by forces as the time passes. In the scale that we can observe by naked eye, classical mechanics is valid to use. Therefore, we can use classical mechanics for simulating objects and mechanisms from our daily lives. In Lesson 39, force of gravitation and spring were applied to masses of 1 kg by the use of classical mechanics. In this tutorial, we will use classical mechanics in a rope simulation. 2. Performance Of The Computer We Use For The Simulation: Performance of the computer to run the simulation, determines how detailed we could observe. For example, when simulating a walking man on a slow computer, we would think of eliminating the simulation of fingers. Fingers of the feet surely have an important role. Eventhough, without using the fingers in the simulation, we could obtain a walking human. Maybe the quality of motion would be low, but the calculations would cost less. In the walking human example, performance of the computer forces us to choose the scale as feet and leg and forces us to omit the fingers. Designing The Physical Setting For The Rope: Having classical mechanics (as the mathematics of motion) and a computer with 500 mhz CPU speed (let's choose this as a minimum requirement), we will design the physical setting of a rope simulation. Firstly we have to determine how much detail we want to observe. While implementing the code, we will use Physics1.h from Lesson 39. From Physics1.h, we have a "class Mass" which represents a mass as a point particle. We can make use of that Mass class. If we bind these point-like masses by springs to each other, we can form a physical model to represent a rope. From the model, we can examine how detailed the observed motion of the rope would be. We can deduce that the rope will show the swinging and waving motion, but it would not show the swirling motion. (Imagine swirling like this; say you have a thin rope in between two fingers and you are rubbing your fingers so that the rope gets curly.) We cannot observe swirling because we use point-like particles in the model. Point-like particles cannot turn around an axis, therefore the rope does not get curly. Let's decide to use the model described above and state that our detail is limited as the swinging and waving motion. Let's also state that we want to observe the rope's waving motion as detailed as about 10 cm. This means the rope will show discontinuity under 10 cm. I have chosen these constraints because I want use about 50 or 100 particles (due to performance) in the rope and I want this rope to be about 3 to 4 meters long. Which means there is about 3 to 8 cm between the particles of the rope which is under the discontinuity level we chose (10 cm). Determining The Motion Of Equation: Motion of equation mathematically means a second order differential equation and conceptually means the forces acting in a physical setting. Let's use the conceptual meaning because it sounds better. Determining the motion of equation means determining the forces. In the rope model, the forces will act on the particles which make up the rope. The first force will be the spring tension between these particles. Below, each particle is shown by "O" and the springs are shown as "----": Particle 1 is bounded to 2, 2 to 3, and 3 to 4. We have 4 particles in this rope and 3 springs. The springs are the sources of the force between two particles. Remember that the spring force is formulated as: force = -k * x The spring formula we will use will be very similar to the one above. If we use the above formula as it is, it would cause the rope to wrinkle! Because unless x is zero (x is the distance between two bound masses in our rope model), there is force. Therefore all the particles of the rope would be pulled to each other until x was zero. This is not what we want. Imagine a rope put on a table. We want our rope to stay steady like the rope on the table. Somehow we have to maintain a constant length. To do, the force shall be zero when x was a positive value. Let's write the formula as: force = -k * (x - d) With this formula, it is clear that if the distance between two masses is equal to d, no force will be applied. Let's say that we have 100 particles. If we choose d as 5 cm (0.05 meters), we would have a steady rope of 5 meters when put on a table. When x is more than d, the spring would stretch and when it was less, it would shrink. Now, the formula gives a proper motion, but it needs more. It needs some friction. Unless there is friction, a physical system conserves its energy. If we don't use a friction factor, the rope would never stop swinging. Before going into details of the friction factor let's have a look at the code. Class Spring: The spring class binds two masses and exerts force to each of these masses. class Spring // An Object To Represent A Spring With Inner Friction Binding Two Masses. The Spring float springConstant; // A Constant To Represent The Stiffness Of The Spring Spring(Mass* mass1, Mass* mass2, this->mass1 = mass1; // Set mass1 void solve() // solve() Method: The Method Where Forces Can Be Applied Vector3D force; // Force Initially Has A Zero Value force = -k * (x - d) A vector to represent the distance between the masses in 3D; Vector3D springVector = mass1->pos - mass2->pos; (Vector Between The Two Masses) is found. Then a zero force is created: Vector3D force; Then, the spring force is added to that: force += (springVector / r) * (r - springLength) * (-springConstant); To reach the formula above, we firstly obtain a unit vector for representing just the directional vector between the masses: (springVector / r) Then, with the use of this unit vector we obtain (x - d) part of the formula in 3D by: (springVector / r) * (r - springLength) And we multiply the above 3D vector by; (-springConstant) which stands for -k in the original formula (the negative sign means pull rather than repel). We already have finished the spring tension part of the force. Let's go on to the friction part. This friction is in the spring. The spring tends to loose energy by this force. If you apply force to a mass in the opposite direction that the mass moves, you make the mass get slower. Therefore, the friction force can be stated in terms of the velocity of a mass: friction force = -k * velocity A friction formula could be written differently but this one works fine for our rope model. In this formula only one mass is considered. In the spring we consider two. We can take the difference of the velocities of the two masses and obtain a relative velocity. This will provide an inner friction. (void solve() continued) force += -(mass1->vel - mass2->vel) * frictionConstant; // The Friction Force Is Added To The force Above, the friction force obtained by the relative velocities of the masses is added to the force of the spring. The force is applied to mass1 as it is: mass1->applyForce(force); and the opposite of the force is applied to mass2: mass2->applyForce(-force); In physics, all interactions occur between two particles. A force always acts on two masses in opposite directions. In simulations, if one mass is negligible when compared with the other, force acting on the larger mass can be neglected since the larger mass's acceleration will be small. For example while a gravitational force pulls a small mass down, the mass pulls the earth up, but we neglect the force on the earth. By now, we have written an equation of motion, which is actually the spring forces in the rope. To complete the simulation, we should create an environment, which contains the rope, and consider the external forces acting on the rope. Let's have a gravitational field in this environment. When there is gravitation, masses experience the gravitational force. I would also like to have air friction which is as simple as: friction force = -k * velocity Let's also have a planer surface that we can drag the rope on. So, our equation of motion extends. Gravitation, air friction and the forces from the ground (planer surface) must be added. Gravitational force is simply: force = (gravitational acceleration) * mass Gravitation and air friction will act on every particle on the rope. What about the force from the ground? Force from the ground will act on every mass as well. We should think of a model to represent the ground - rope interaction. My model is an easy one: the ground pushes a mass upwards and exerts a friction force. The force should act on a mass whenever that mass touches the ground. So we will check for that. Setting The Initial Values Of The Simulation By now, our environment is ready for simulating. The units will be meters (for position), seconds (for time), and kg (for weight). To set the initial values, we should define the orientation of the rope before the simulation starts and define the constants. Let's define that the gravity acts in negative y direction by 9.81 m/s/s. Let's place a rope of 4 meters long with 80 particles. Let's have this rope stand horizontal just before the simulation starts. To do, we should put each particle with a 5 cm distance to its neighbor (4 meters / 80 = 0.05 meters = 5 cm). Let's define that the normal spring length (the length that a spring does not exert any force) is 5 cm so that that rope is left without tension at the begining of the simulation. Let's define the total mass of the rope as 4 kg (this is a heavy rope). This gives 0.05 kg (50 grams) for each of the masses. Before going further let's see what we have in hand: 1. gravitational acceleration: 9.81 m/s/s in negative y direction Next, we could find the spring constant. When we hang the rope from one tip, it would surely stretch. The spring at the top of the rope would stretch the most. I wouldn't like this spring to stretch more than 1 cm (0.01cm). The weight that this spring carries is almost all the rope (the particle at the tip is exclusive). The force is: f = (mass of the rope) * (gravitational acceleration) = (4 kg) * (9.81) ~= 40 N Spring force should balance 40 N: spring force = -k * x = -k * 0.01 meters Total of these forces should be zero: 40 N + (-k * 0.01 meters) = 0 From here we obtain k as: k = 4000 N / m To remember more easily, let's assume k as 10000 N / m, which gives a stiffer rope with about 4 mm stretch at the top spring. To find the friction constant in the springs, we should do calculations more complicated than the above. Therefore, I will use the value that I found by trial and error. Which is: springFrictionConstant = 0.2 N/(m/s) 0.2 N/(m/s) springFrictionConstant is fine for our rope to look realistic (this was my opinion after I watched the simulation). Before going on to the air friction and forces from the ground, let's have a look at the RopeSimulation class. This class is derived from the "class Simulation" from Physics1.h which was explained in Lesson 39. class Simulation has four methods to run a simulation. These are: 1. virtual void init() ---> Resets The Forces. 2. virtual void solve() ---> Intended Forces Are Applied. 3. virtual void simulate(float dt) ---> Position And Velocity Are Iterated. 4. virtual void operate(float dt) ---> Method 1., 2., And 3. Are Packed So That They Are Called In A Series. In the RopeSimulation class, we will override solve() and simulate(float dt) because we have a special implementation for the rope. We will apply forces in solve() method, and stabilize one tip of the rope in simulate(float dt) method. class RopeSimulation is derived from class Simulation (from Physics1.h). It simulates a rope with point-like particles bound with springs. The springs have inner friction and normal length. One tip of the rope is stabilized at a point in space called "Vector3D ropeConnectionPos". This point can be moved externally by a method "void setRopeConnectionVel(Vector3D ropeConnectionVel)". RopeSimulation creates air friction and a planer surface (or ground) with a normal in +y direction. RopeSimulation implements the force applied by this surface. In the code, the surface is refered as "ground". The RopeSimulation class starts as follows: class RopeSimulation : public Simulation // An Object To Simulate A Rope Interacting With A Planer Surface And Air Vector3D gravitation; // Gravitational Acceleration (Gravity Will Be Applied To All Masses) Vector3D ropeConnectionPos; // A Point In Space That Is Used To Set The Position Of The float groundRepulsionConstant; // A Constant To Represent How Much The Ground Shall Repel The Masses float airFrictionConstant; // A Constant Of Air Friction Applied To Masses RopeSimulation( // A Long Long Constructor With 11 Parameters Starts Here this->groundFrictionConstant = groundFrictionConstant; for (int a = 0; a < numOfMasses; ++a) // To Set The Initial Positions Of Masses Loop With For(;;) springs = new Spring*[numOfMasses - 1]; // Create [numOfMasses - 1] Pointers For springs void solve() // solve() Is Overriden Because We Have Forces To Be Applied for (a = 0; a < numOfMasses; ++a) // Start A Loop To Apply Forces Which Are Common For All Masses if (masses[a]->pos.y < groundHeight) // Forces From The Ground Are Applied If A Mass Collides With The Ground v = masses[a]->vel; // Get The Velocity // The Velocity In Y-Direction Is Omited Because We Will Apply A Friction Force To Create // Ground Friction Force Is Applied v = masses[a]->vel; // Get The Velocity if (v.y < 0) // Let's Absorb Energy Only When A Mass Collides Towards The Ground // The Absorption Force Is Applied masses[a]->applyForce(force); // The Ground Repulsion Force Is Applied RopeSimulation class simulates the particle at the begining index of the rope. The purpose is to create a medium to swing the rope from one tip. The mass with index "0" is simulated seperately with ropeConnectionPos and ropeConnectionVel values. void simulate(float dt) // simulate(float dt) Is Overriden Because We Want To Simulate ropeConnectionPos += ropeConnectionVel * dt; // Iterate The Positon Of ropeConnectionPos if (ropeConnectionPos.y < groundHeight) // ropeConnectionPos Shall Not Go Under The Ground masses[0]->pos = ropeConnectionPos; // Mass With Index "0" Shall Position At ropeConnectionPos void setRopeConnectionVel(Vector3D ropeConnectionVel) // The Method To Set ropeConnectionVel There are some constants which are not easy to estimate before we run the simulation. The constants I found appropriate are below (taken from Physics2Application.cpp): RopeSimulation* ropeSimulation = Same as Lesson 39, the simulation is operated from the application file (Physics2Application.cpp): float dt = milliseconds / 1000.0f; // Let's Convert Milliseconds To Seconds float maxPossible_dt = 0.002f; // Maximum Possible dt Is 0.002 Seconds int numOfIterations = (int)(dt / maxPossible_dt) + 1; // Calculate Number Of Iterations To Be Made At This Update Depending On maxPossible_dt And dt for (int a = 0; a < numOfIterations; ++a) // We Need To Iterate Simulations "numOfIterations" Times Simulation procedure loads onto the CPU. Therefore, it is recommended to optimize your compiler. In default Visual C++ Release settings, the rope simulation runs more than 10 times faster than Debug. In Debug, the minimum requirement is 500 mhz of CPU speed. In Release, the minimum requirement is much less than that. In this tutorial, a complete simulation is presented. Its physical setting, theory, design, and implementation are mentioned. More advanced simulations look like the one above. The most frequently used concepts are covered with the rope example. This is true for physical simulations in game development as well. Try using physics in your applications and create demos and games of your own. For any comments or questions please contact me: Erkin Tunca (erkintunca@icqmail.com) Jeff Molofee (NeHe) |
-- 作者:hwfchina -- 发布时间:3/18/2008 10:30:00 PM -- 顶~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
-- 作者:hwfchina -- 发布时间:3/18/2008 10:32:00 PM -- 顶~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
-- 作者:skflip -- 发布时间:2/13/2009 11:58:00 AM -- 非常好,网站太棒了,加油,这个好东西能找到,真是不容易,nehe的网站上都下不下来啊 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
187.500ms |