[HELP] move a mesh from rigidBody position

Post Reply
none06
Posts: 3
Joined: Wed Jul 07, 2021 9:42 pm

[HELP] move a mesh from rigidBody position

Post by none06 »

Hello !

I am having trouble moving my mesh from my rigidbody's position.

It looks like there is an offset and i can't find how to calculate it.

For exemple:
My mesh is at (3.0, 2.0, 4.0)
But the rigidbody's transform is(9.0, 8.5, 12.0)
(My mesh size is 5)

Here is how i create my ridigBody:

Code: Select all

const std::vector<glm::vec3> dataSize = getBiggestHitBox();
    this->size = dataSize[0] * glm::vec3(0.5);
    this->center = dataSize[1];
	

    boxCollisionShape = new btBoxShape(btVector3(size.x, size.y, size.z));
    transform.setIdentity();
    transform.setOrigin(btVector3(center.x, center.y, center.z));
    motionState = new btDefaultMotionState(transform);
    rigidBody = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
        weight,
        motionState,
        boxCollisionShape,
        btVector3(0, 0, 0)
    ));
and this is how i calculate the center and size of my mesh:

Code: Select all

GLfloat max_x, max_y, max_z;
    GLfloat min_x = max_x = vertices[0].Position.x;
    GLfloat min_y = max_y = vertices[0].Position.y;
    GLfloat min_z = max_z = vertices[0].Position.z;
    for (int i = 0; i < vertices.size(); i++) {
        if (vertices[i].Position.x < min_x) min_x = vertices[i].Position.x;
        if (vertices[i].Position.x > max_x) max_x = vertices[i].Position.x;
        if (vertices[i].Position.y < min_y) min_y = vertices[i].Position.y;
        if (vertices[i].Position.y > max_y) max_y = vertices[i].Position.y;
        if (vertices[i].Position.z < min_z) min_z = vertices[i].Position.z;
        if (vertices[i].Position.z > max_z) max_z = vertices[i].Position.z;
    }
    glm::vec3 size = glm::vec3(max_x - min_x, max_y - min_y, max_z - min_z);
    glm::vec3 center = glm::vec3((min_x + max_x) / 2, (min_y + max_y) / 2, (min_z + max_z) / 2);

    center += position * glm::vec3(2.0f);

    std::vector<glm::vec3> ret;
    ret.emplace_back(size);
    ret.emplace_back(center);
    return ret;
My goal is to set my mesh position to the rigidBody position
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: [HELP] move a mesh from rigidBody position

Post by drleviathan »

After you compute the center and bounds of your mesh... I don't understand this line:

Code: Select all

center += position * glm::vec3(2.0f);
The value of position is not specified in your code snippet. I assume glm::vec3 is doing a component-wise multiply between the two vectors so what you're really doing is adding 2.0 * position, but I don't understand it.

Also, you said you're trying to
moving my mesh from my rigidbody's position
(perhaps you meant you want to move the mesh to where the rigidbody is?) however what your code appears to be trying to do is moving the rigidbody to where the mesh is. I don't understand.

Usually the way things are supposed to work is: you have a physical body and you have a renderable mesh and you want the two to be in the same spot. When the body is dynamic its transform is updated by the physics simulation and when the body is kinematic its position is updated by logic external to the physics simulation. The MotionState API is designed to act as a "bridge" between the two things: relaying transforms to/from the physics simulation and the external game logic. Rather than use btDefaultMotionState what you're supposed to do is implement your own MyMotionState which derives from the base interface class and overrides the two pure virtual methods therein, like so:

Code: Select all

// getWorldTransform() relays incoming position/rotation to the RigidBody
// and is called on active Kinematic objects at each substep and also          
// once when the btRigidBody is initialized with a btRigidBodyConstructionInfo.
// If you don't want the body's transform to be set by the MotionState at                  
// construction time then give it a null MotionState and then subsequently                                                     
// explicitly call body->setMotionState(motionState)
void MyMotionState::getWorldTransform(btTransform& worldTrans) const {
    m_body->setWorldTransform(worldTrans);
}    

// setWorldTransform() relays outgoing position/rotation to the Renderable
// and is called on active Dynamic objects at each substep
void MyMotionState::setWorldTransform(const btTransform& worldTrans) {        
    m_renderable->setTransform(worldTrans);
}
Finally, a nitpick: when you compute the center and bounds of the mesh you initialize the maxes and mins to vertices[0].Position but then in your for loop you start at i=0 so the very first iteration over the loop is a waste. You should start looping at i=1.
none06
Posts: 3
Joined: Wed Jul 07, 2021 9:42 pm

Re: [HELP] move a mesh from rigidBody position

Post by none06 »

Thank you for your responce.

For the position, it's the start position of my Mesh, so lets say that i want to draw my mesh at (5, 12, 5), I need to multiply the vertices to get my mesh translated. After that, i need to multiply the center by 2, otherwise the boudingbox will not be centered in the middle of my mesh.

this is my boundingbox with center * 2:
Image

this is my boundingbox without center * 2:
Image


"moving my mesh from my rigidbody's position"-> yes sorry i got a little bit confused, I want to move the mesh to where the rigidbody is.

Now i have my own MyMotionState, and thank you for the tip.


My problem is that when I translate my mesh like this:

Code: Select all

 btTransform trans;
 rigidBody->getMotionState()->getWorldTransform(trans);
 glm::vec3 position = glm::vec3(trans.getOrigin().getX(), trans.getOrigin().getY(), trans.getOrigin().getZ());
 
 modelMatrix = glm::translate(glm::mat4(1.0f), position);
My mesh is not at the correct position:
Image
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: [HELP] move a mesh from rigidBody position

Post by drleviathan »

Hrm... there is a transform offset between your mesh and your rigidbody, and this transform includes a scale. The math for applying the offset is tricky: the components of the offset transform have to be applied in a particular order.

The way I like to solve this problem is to store the offset as a data member of MyMotionState and to do the math inside the setWorldTransform() method.
However, in the previous code example I showed I assumed that no math was necessary. Also, I now realize I got the getWorldTransform() implementation totally wrong: it should not set the transform of the body, it should only compute the transform the body should have (Bullet will apply the transform to the body). So please allow me to resubmit a more correct MyMotionState example.

This is what I think it would look like in pseudo-code.

Code: Select all

class MyMotionState : public btMotionState { 
    // Note: we assume no rotational transform between the mesh and the body
    // and only consider translation and scale.
    btVectore m_scaledMeshOffsetToBody;
    btVector3 m_scaleMeshToBody;
    btRigidBody* m_body;
    Renderable* m_renderable;
 
public:
    MyMotionState(btRigidBody* body, Mesh* mesh) : m_body(body), m_renderable(mesh) {
        // Note the negative sign here: we're computing the offset required to go from mesh-frame to body-frame
        btVector3 mesh_center = m_renderable->getMeshCenter();
 
        btVector3 mesh_scale = m_renderable->getMeshBoundsDiagonal();
 
        btTransform identity;
        btVector3 aabb_min, aabb_max;
        btAabb local_aabb = m_body->getShape()->getAabb(identity, aabb_min, aabb_max);
        btVector3 body_scale = aabb_max - aabb_min;
 
        // Note: btVector3 divided by btVector3 is a component-wise inversion
        // ideally you would guard against division by zero here
        // but that is left as an exercise for the reader
        m_scaleMeshToBody = body_scale / mesh_scale;
 
        // Note the negative sign here: it is the offset that must be applied to the mesh
        // to put it where the body is, post scale;
        m_scaledMeshOffsetToBody = - mesh_center * m_scaleMeshToBody;
    }
 
    // getWorldTransform() relays incoming position/rotation to the RigidBody
    // and is called on active Kinematic objects at each substep and also          
    // once when the btRigidBody is initialized with a btRigidBodyConstructionInfo.
    // If you don't want the body's transform to be set by the MotionState at                  
    // construction time then give it a null MotionState and then subsequently                                                     
    // explicitly call body->setMotionState(motionState)
    //
    void MyMotionState::getWorldTransform(btTransform& worldTrans) const {
        // Note: worldTrans is passed by reference
        // it is the duty of MyMotionState to update worldTrans with the correct value the body should have
        // and the Bullet API will apply the transform it gets from this method to the body
 
        // compute worldTrans here, as per scripted motion or some other authority
        worldTrans = ...
    }    
 
    // setWorldTransform() relays outgoing position/rotation to the Renderable
    // and is called on active Dynamic objects at each substep
    //
    void MyMotionState::setWorldTransform(const btTransform& worldTrans) {                                                                                          
        // it is the duty of MyMotionState to use worldTrans to update the renderable                                                                               
        // so that it follows the body
        btVector3 p = worldTrans.getOrigin() + m_scaledMeshOffsetToBody;
        glm::vec3 position(p.getX(), p.getY(), p.getZ());

        // converting btQuaternion to glm::quat is left as an exercise for the reader
        glm::quat rotation = ...

        m_renderable->setTransform(position, rotation);
    }
};
none06
Posts: 3
Joined: Wed Jul 07, 2021 9:42 pm

Re: [HELP] move a mesh from rigidBody position

Post by none06 »

Thank you for your help.

But I think that my problem does not come from that. I just figured out that, when i move my mesh, the bounding box and the mesh does not get "separated", but as soon as I move the camera, the offset appear.

Even if I move just a little the cam, the mesh position and the bounding box position are different.
For testing purposes, in the render loop I set the mesh position to my camera position, but the mesh move way faster than my camera.

I think its probably an openGL error ?
Maybe this is a common mistake from openGL noobies like me ?
Post Reply