標籤:connect blog 內容 包含 定義 ued 過程 oid 執行
轉自【翻譯】NeHe OpenGL 教程
前言
聲明,此 NeHe OpenGL教程系列文章由51部落格yarin翻譯(2010-08-19),本部落格為轉載並稍加整理與修改。對NeHe的OpenGL管線教程的編寫,以及yarn的翻譯整理表示感謝。
NeHe OpenGL第三十九課:物理類比
物理類比簡介:
還記得高中的物理吧,直線運動,自由落體運動,彈簧。在這一課裡,我們將創造這一切。
物理類比介紹
如果你很熟悉物理規律,並且想實現它,這篇文章很適合你。
在這篇教程裡,你會建立一個非常簡單的物理引擎,我們將建立以下類:
內容:
位置類
* class Vector3D ---> 用來記錄物體的三維座標的類
力和運動
* class Mass ---> 表示一個物體的物理屬性
類比類
* class Simulation ---> 類比物理規律
類比勻速運動
* class ConstantVelocity : public Simulation ---> 類比勻速運動
類比在力的作用下運動
* class MotionUnderGravitation : public Simulation ---> 類比在引力的作用下運動
* class MassConnectedWithSpring : public Simulation ---> 類比在彈簧的作用下運動
class Mass
{
public:
float m; // 品質
Vector3D pos; // 位置
Vector3D vel; // 速度
Vector3D force; // 力
Mass(float m) // 建構函式
{
this->m = m;
}
...
下面的代碼給物體增加一個力,在初始時這個力為0
void applyForce(Vector3D force)
{
this->force += force; // 增加一個力
}
void init() // 初始時設為0
{
force.x = 0;
force.y = 0;
force.z = 0;
}
...
下面的步驟完成一個類比:
1.設定力
2.應用外力
3.根據力的時間,計算物體的位置和速度
void simulate(float dt)
{
vel += (force / m) * dt; // 更新速度
pos += vel * dt; // 更新位置
}
類比類怎樣運作:
在一個物理類比中,我們按以下規律進行類比,設定力,更新物體的位置和速度,按時間一次又一次的進行類比。下面是它的實現代碼:
class Simulation
{
public:
int numOfMasses; // 物體的個數
Mass** masses; // 指向物體結構的指標
Simulation(int numOfMasses, float m) // 建構函式
{
this->numOfMasses = numOfMasses;
masses = new Mass*[numOfMasses];
for (int a = 0; a < numOfMasses; ++a)
masses[a] = new Mass(m);
}
virtual void release() // 釋放所有的物體
{
for (int a = 0; a < numOfMasses; ++a)
{
delete(masses[a]);
masses[a] = NULL;
}
delete(masses);
masses = NULL;
}
Mass* getMass(int index)
{
if (index < 0 || index >= numOfMasses) // 返回第i個物體
return NULL;
return masses[index];
}
...
(class Simulation continued)
virtual void init() // 初始化所有的物體
{
for (int a = 0; a < numOfMasses; ++a)
masses[a]->init();
}
virtual void solve() //虛函數,在具體的應用中設定各個施加給各個物體的力
{
}
virtual void simulate(float dt) //讓所有的物體類比一步
{
for (int a = 0; a < numOfMasses; ++a)
masses[a]->simulate(dt);
}
...
整個類比的部分被封裝到下面的函數中
(class Simulation continued)
virtual void operate(float dt) // 完整的類比過程
{
init(); // 設定力為0
solve(); // 應用力
simulate(dt); // 類比
}
};
現在我們已經有了一個簡單的物理類比引擎了,它包含有物體和類比兩個類,下面我們基於它們建立三個具體的類比對象:
1. 具有恒定速度的物體
2. 具有恒定加速度的物體
3. 具有與距離成反比的力的物體
在程式中控制一個類比對象:
在我們寫一個具體的類比類之前,讓我們看看如何在程式中類比一個對象,在這個教程裡,類比引擎和操作類比的程式在兩個檔案裡,在程式中我們使用如下的函數,操作類比:
void Update (DWORD milliseconds) // 執行類比
這個函數在每一幀的開始更新,參數為相隔的時間。
void Update (DWORD milliseconds)
{
...
...
...
float dt = milliseconds / 1000.0f; // 轉化為秒
dt /= slowMotionRatio; // 除以類比係數
timeElapsed += dt; // 更新流失的時間
...
在下面的代碼中,我們定義一個處理間隔,沒隔這麼長時間,讓物理引擎類比一次。
...
float maxPossible_dt = 0.1f; // 設定類比間隔
int numOfIterations = (int)(dt / maxPossible_dt) + 1; //計算在流失的時間裡類比的次數
if (numOfIterations != 0)
dt = dt / numOfIterations;
for (int a = 0; a < numOfIterations; ++a) // 類比它們
{
constantVelocity->operate(dt);
motionUnderGravitation->operate(dt);
massConnectedWithSpring->operate(dt);
}
}
下面讓我們來寫著兩個具體的類比類:
1. 具有恒定速度的物體
* class ConstantVelocity : public Simulation ---> 類比一個勻速運動的物體
class ConstantVelocity : public Simulation
{
public:
ConstantVelocity() : Simulation(1, 1.0f)
{
masses[0]->pos = Vector3D(0.0f, 0.0f, 0.0f); // 初始位置為0
masses[0]->vel = Vector3D(1.0f, 0.0f, 0.0f); // 向右運動
}
};
下面我們來建立一個具有恒定加速的物體:
class MotionUnderGravitation : public Simulation
{
Vector3D gravitation; // 加速度
MotionUnderGravitation(Vector3D gravitation) : Simulation(1, 1.0f) // 建構函式
{
this->gravitation = gravitation; // 設定加速度
masses[0]->pos = Vector3D(-10.0f, 0.0f, 0.0f); // 設定位置為左邊-10處
masses[0]->vel = Vector3D(10.0f, 15.0f, 0.0f); // 設定速度為右上
}
...
下面的函數設定施加給物體的力
virtual void solve() // 設定當前的力
{
for (int a = 0; a < numOfMasses; ++a)
masses[a]->applyForce(gravitation * masses[a]->m);
}
下面的類建立一個受到與距離成正比的力的物體:
class MassConnectedWithSpring : public Simulation
{
public:
float springConstant; // 彈性係數
Vector3D connectionPos; // 串連方向
MassConnectedWithSpring(float springConstant) : Simulation(1, 1.0f) // 建構函式
{
this->springConstant = springConstant;
connectionPos = Vector3D(0.0f, -5.0f, 0.0f);
masses[0]->pos = connectionPos + Vector3D(10.0f, 0.0f, 0.0f);
masses[0]->vel = Vector3D(0.0f, 0.0f, 0.0f);
}
...
下面的函數設定當前物體所受到的力:
virtual void solve() // 設定當前的力
{
for (int a = 0; a < numOfMasses; ++a)
{
Vector3D springVector = masses[a]->pos - connectionPos;
masses[a]->applyForce(-springVector * springConstant);
}
}
原文及其個版本原始碼下載:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=39
NeHe OpenGL教程 第三十九課:物理類比