Имитация свободного движения без управления телом не подчиняется энергосбережению - PullRequest
0 голосов
/ 27 сентября 2019

Я запустил проект игровой физики-движка в 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);
    }
...