0
\$\begingroup\$

I'm using Bullet for CollisionDetection. I load a scene from a Collada-File using Assimp. Let's say I want to give every object in the scene a RigidBody with a box as CollisionShape. Right now I first load the vertices of the object from the file into my Model-Object and then store the transformation matrix. After that I create the CollisionShape with the following code:

btVector3 rigidBodyPos;
btCollisionShape* collisionShape;

glm::vec3* minMax = getMinMaxVertexCoords();
glm::vec3 minCoords = minMax[0]; //The minmum/maximum x/y/z values in the Mesh
glm::vec3 maxCoords = minMax[1];
glm::vec3 middleSize = glm::vec3((maxCoords.x - minCoords.x) / 2, (maxCoords.y - minCoords.y) / 2, (maxCoords.z - minCoords.z) / 2);
glm::vec3 middlePos = glm::vec3((maxCoords.x + minCoords.x) / 2, (maxCoords.y + minCoords.y) / 2, (maxCoords.z + minCoords.z) / 2);

collisionShape = new btBoxShape(btVector3(middleSize.x, middleSize.y, middleSize.z));
rigidBodyPos = btVector3(middlePos.x, middlePos.y, middlePos.z);

Here's a look at my getMinMaxVertexCoords():

glm::vec3* Model::getMinMaxVertexCoords() {
    float maxValue = std::numeric_limits<float>::max();
    float minValue = std::numeric_limits<float>::lowest();
    glm::vec3 lowestVec = glm::vec3(maxValue, maxValue, maxValue);
    glm::vec3 highestVec = glm::vec3(minValue, minValue, minValue);
    for (Vertex v : getVertices()){
        //Apply Transform
        glm::vec4 pos = getModelMatrix() * glm::vec4(v.position, 1);
        glm::vec3 homogenizedPos = glm::vec3(pos.x / pos.w, pos.y /     pos.w, pos.z / pos.w);
        lowestVec.x = min(pos.x, lowestVec.x);
        lowestVec.y = min(pos.y, lowestVec.y);
        lowestVec.z = min(pos.z, lowestVec.z);
        highestVec.x = max(pos.x, highestVec.x);
        highestVec.y = max(pos.y, highestVec.y);
        highestVec.z = max(pos.z, highestVec.z);
    }
    glm::vec3 res[2] = { lowestVec, highestVec };
    return res;
}

The problem doing it this way is, if my scene contains a rotated cube, the collisionbox is obviously not rotated, but parallel to the axes.

I tried solving this by applying the transformation matrix only after creating the RigidBody (so when creating the CollisionShape the ModelMatrix is the identity matrix) and then transforming the RigidBody afterwards:

btTransform transform;
transform.setFromOpenGLMatrix(glm::value_ptr(getModelMatrix()));
_rigidBody->setWorldTransform(transform);

The problem with this however is that the box might be rotated now, but if the transformation contains a Scaling - which is very likely - Bullet does not accept it, and my RigidBody basically disappears (no collision is detected anymore).

Does anybody know a solution to this problem?

\$\endgroup\$
0
\$\begingroup\$

I solved the problem myself!

I now create the CollisionShape before applying the transformation. For transforming the RigidBody correctly, I extract the sacling-value from the matrix and give it to _rigidBody->getCollisionShape()->setLocalScaling. I then remove the scaling from the matrix and give that to the setWorldTransform.

Here's my code:

float scaleX = glm::length(glm::vec3(modelMat[0][0], modelMat[0][1], modelMat[0][2]));
float scaleY = glm::length(glm::vec3(modelMat[1][0], modelMat[1][1], modelMat[1][2]));
float scaleZ = glm::length(glm::vec3(modelMat[2][0], modelMat[2][1], modelMat[2][2]));
glm::mat4 matWithoutScale = glm::scale(modelMat, glm::vec3(1.0f / scaleX, 1.0f / scaleY, 1.0f / scaleZ));

_rigidBody->getCollisionShape()->setLocalScaling(btVector3(scaleX, scaleY, scaleZ));
btTransform transform;
transform.setFromOpenGLMatrix(glm::value_ptr(matWithoutScale));
_rigidBody->setWorldTransform(transform);
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.