Я запустил проект игровой физики-движка в DirectX11, используя возможности графического процессора.Для моделирования движения царствующего тела я использую буксирные компьютерные шейдеры: один для обновления позиций тел (на основе инерции тел Ньютона), а другой для расчета нового импульса и момента импульса тел после столкновения.
Моя проблема в том, что по какой-то причине энергия тел меняется после обновления.
Это происходит в первой вычислительной программе без каких-либо столкновений. Я использую следующую формулу для обновления угловой скорости / частоты:
new_angular-velocity = (P*I0^(-1)*P^(-1))*angular_momentum
когда 'P
' - матрица базового преобразования из новой системы главных осей в обычную универсальную систему x
, y
, z
(Это всегда ортонормированный-матрица), 'I0
' - тензор инерции в системе главных осей (диагональная матрица с постоянными значениями), а * angular_momentum
'- постоянная (без столкновения).
Я думаю, что проблема возникла из-за того, что разность угловой скорости и угловой импульс не ортогональны, это происходит только тогда, когда матрица 'I0
' не является скалярным кратным единичной матрицы -когда векторы угловой скорости и углового момента не совпадают.В моем случае энергия вращения тела растет с каждым кадром, и я думаю, что это результат известной следующей формулы: Erotate = dot(w, L)/2
.Это очень странно, потому что первая формула дает только одно конкретное проходимое решение - она не имеет никакой степени свободы, так что ни один вектор угловой скорости не может подчиняться обоим правилам.
Я буду рад услышать некоторые решения илиобъяснения этой проблемы.
Здесь я включаю свой код программы Bodies-interia-compute-program ...
[BodiesInertia.hlsl]
#include "Quaternion.hlsli"//A Functions of basic quaternion's algebra
#define PE_PASSIVE 0
#define PE_ACTIVE 1
struct SolidBody
{
uint phyisics_ativity;//The type of the physics activity(Active or Passive)
float energy;
float B;
float C;
float4x4 inertia_tensor;
float4 position;
float4 orientation;
float4 velocity;
float4 angular_frequency;
float4 angular_momentum;
};
cbuffer ShaderInput
{
uint sys_flags;
uint inputs_num;//Number of the Indexes of the bodies that send to processing
double fps;
};
StructuredBuffer<uint> InProcess_buffer : register(t0);//A read-only gpu-buffer that contain all the indexs of the bodeis that send for processing
RWStructuredBuffer<SolidBody> Bodyes_buffer : register(u1);//Read-write gpu-buffer of all the solid-bodies data
#define body Bodyes_buffer[body_id]
[numthreads(1, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
//Get body index...
uint index = DTid.y * ceil(sqrt(inputs_num)) + DTid.x;
if (index > inputs_num)
return;
uint body_id = InProcess_buffer[index];
float mass = body.inertia_tensor[3][3];
float3 forces = float3(0.0f, 0.0f, 0.0f);
float3 torque = float3(0.0f, 0.0f, 0.0f);
float3x3 P = quat_to_matrix(body.orientation);
float3x3 P_inv = inverse(P);
float3x3 I0 = float3x3( body.inertia_tensor[0][0], body.inertia_tensor[0] [1],body.inertia_tensor[0][2],
body.inertia_tensor[1][0], body.inertia_tensor[1] [1],body.inertia_tensor[1][2],
body.inertia_tensor[2][0], body.inertia_tensor[2][1], body.inertia_tensor[2][2]);
float3x3 I0_inv = inverse(I0);
float3x3 I = mul(P, mul(I0, P_inv));
float3x3 I_inv = mul(P, mul(I0_inv, P_inv));
float3 new_position;
float4 new_orientation;
float3 new_angular_frequency;
float3 new_angular_momentum;
new_position = body.position.xyz + body.velocity.xyz / fps;
new_angular_momentum = body.angular_momentum.xyz + torque / fps;
new_angular_frequency = mul(I_inv, new_angular_momentum);
if (length(new_angular_frequency) > 0)
new_orientation = quat_mul(rotate_quat(length(new_angular_frequency) / fps, new_angular_frequency), body.orientation);
else
new_orientation = body.orientation;
body.position = float4(new_position, 0.0f);
body.orientation = new_orientation;
body.angular_frequency = float4(new_angular_frequency, 0.0f);
body.angular_momentum = float4(new_angular_momentum, 0.0f);
body.energy = 0.5f * dot(new_angular_frequency, new_angular_momentum) + 0.5f * mass * dot(body.velocity.xyz, body.velocity.xyz);
}