Computing entity's velocity


photo

Recommended Posts

Hi all !

I am trying to compute the velocity of an entity within a SendPacketCallback (using the addSendPacketCallback added in 2.14)

 

Configs:

Unigine SDK 2.14

Windows 10

 

IG / Host Setup:

  • A host which updates the entity's rotation every frame (1 host frame is 100ms)
  • The Unigine IG sim with a callback for LOS extended response opcode
  • The CIGI connection is asynchronous
  • Entity smoothing is enabled

 

Here is the code I am using : 

int AppWorldLogic::init()
{
    // init systems, do some optimizations for IG
    Game::setEnabled(1);
    Physics::setEnabled(0);
    Render::setMotionBlur(0);
    Render::setLightsLensFlares(0);

    Render::setWhiteBalance(false);
    Render::setExposureMode(0);
    Render::setExposure(1.0f);

    // clamp framerate to 60 if VSync is off
    if ((App::getFlags() & App::VSYNC) == 0 ||
        (App::getFlags() & App::FULLSCREEN) == 0)
        Render::setMaxFPS(60.0f);

        
    int index = Engine::get()->findPlugin("CIGIConnector");
    // check CIGIConnector plugin load
    if (index != -1)
    {
        // getting the CIGI interface
        _cigi = IG::CIGI::Connector::get();
        _cigi->addSendPacketCallback(IG::CIGI::CIGI_OPCODE_LOS_EXT_RESPONSE, MakeCallback(this, &AppWorldLogic::on_speed_packet_required));
    }

    return 1;
}
void AppWorldLogic::on_speed_packet_required(bool &ret, IG::CIGI::CigiIGPacket *response, IG::CIGI::CigiHostPacket *request, IG::IGIntersection *intersection)
{
    if(intersection)
    {
        ObjectPtr object = intersection->object;
        // Log::message("\tHIT Object => %s\n", intersection->object->getName());

        Math::Vec3 point_world = intersection->point;
        Math::Vec3 prev_point_world = point_world * Math::inverse(object->getWorldTransform()) * object->getOldWorldTransform();
        Math::Vec3 point_velocity = (point_world - prev_point_world) / Game::getIFps();

        Log::message("velocity = {%f,%f,%f}\n\n", point_velocity.x, point_velocity.y, point_velocity.z);
    }
}

The callback is called every ~100ms.

What I expect :

  1. Whenever I enter this callback, the velocity is computed based on the entity previous world transform
  2. I know that the velocity is moving so it should not be equal to (0,0,0)

 

Problem is :

    - When I enter the callback, "object->getOldWorldTransform()" is always equals to "object->GetWorldTransform()" which will set the velocity to (0,0,0).

    - A callback has to compute the velocity independently, meaning I cannot save the position to compute the velocity on the next callback.

 

If you need any more infos feel free to ask.

Best regards,

Antoine

Link to post

the order of the matrix multiplication matters.

Vec3 prev_point_world = (object-> getOldWorldTransform () * inverse (object-> getWorldTransform ())) * point_world;

I checked it works correctly for simple cases. however, getOldTransform may be updated due to the update of the spatial tree.
https://drive.google.com/file/d/1V5axIYmJbNvvjwajF1tykvEeHfXMZINj/view?usp=sharing

tell me more about the scene - what is the object for which you need to get velocity? who moves it, where (update / post_update) does this movement take place?

Sphere.node

Link to post

Hi cash-metall, thank you for your reply.

The object is a cylinder which just rotates on the Z axis. 

It is my CIGI Host who creates it via a CIGIEntityCtrl packet and updates its rotation every 100 milliseconds, increasing it by 30 until 360°.

I don't know -in the Unigine Side- where the movement takes place as I don't control that part, Unigine does so after receiving the packet I send and computing the next position with interpolation. 

 

Do you need to know anything more ?

spinner.node

Link to post

Hello again !

So I downloaded your sphere.node to see if I could make it work.

I tried to use your sphere with a Cigi Communication using Unigine's IG Host.

I enabled the interpolation to have a smooth movement and not a direct teleportation.

Here is the result :

 gifIgHost.gif.c95ef3cd84725267275f7f697c2b73c3.gif

 

As you can see, the pink trail supposed to trace the sphere's movement using the OldWorldTransform is not shown.

This means that when using a Cigi Communication, the OldWorldTransform is not updated correctly and is not usable.

Is there a way for your team to solve this problem ?

Thank you for your time and your help !

Best Regards,

Antoine

  • Like 1
Link to post

yes, interpolation happens in the post-update, but callbacks are processed in the update.
As a result, in the update of the current frame, the position of the entity has not yet been applied.

there are two ways:

1. fast but not universal: make a simple component

class VelocityControl : public ComponentBase
{
    COMPONENT(VelocityControl, ComponentBase)
    COMPONENT_UPDATE(update)

    PROP_NAME("VelocityControl")

    void update()
    {
        auto c_transform = node->getWorldTransform();
        delta = inverse(old_transform) * c_transform;
        linear_velocity = vec3(delta.getTranslate()) / Game::getIFps();
        angular_velocity = Math::decomposeRotationZXY(mat3(delta)) / Game::getIFps();
        old_transform = c_transform;
    }

    Unigine::Math::Mat4 old_transform;
    Unigine::Math::vec3 linear_velocity;
    Unigine::Math::vec3 angular_velocity;
    Unigine::Math::Mat4 delta;

};

which to assign to those objects whose velocities are of interest to us (landing pads ?)
and in the callback it is easy to take

auto vc = ComponentSystem::get()->getComponent<VelocityControl>(object);
if (vc)
{
    linear = vc->delta * point_world;
}

2. universal, but may slow: manual control the previous transformation - in update, bypass all nodes and save the transformations of all object meshes. (maybe some mask optimize to reduce the number of matrix copies)

// each update
Vector<NodePtr> nodes;
World::getNodes(nodes);
for (const auto & node : nodes)
{
    if (node->getType() == Node::OBJECT_MESH_STATIC)
    world_transforms[node->getID()] = node->getWorldTransform();
}

// and take in the callback 
inverse(world_transforms[object->getID()]) * object->getWorldTransform();

 

Link to post