Salamosaurus
Salamosaurus

Reputation: 124

How to access assimp model data for collisions?

This seems like a simple task, but I can't seem to figure out how to use the imported data from assimp, to test triangle collisions. I have ascertained that my triangle collision algorithm works fine, and buffering the vertices and indices into an openGL EBO and VBO for drawing works perfectly. I am led to believe it is something with the way I am accessing the data from my std::vector of vertices and indices that is incorrect. Currently I am using the indicies as indexes for the vertices vector.

 void loadModel(std::string path) {
        Assimp::Importer importer;
        const aiScene * scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_JoinIdenticalVertices);
        if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
            printf_s("Assimp loading error \n%s\n", importer.GetErrorString());
            return;
        }
        directory = path.substr(0, path.find_last_of('/'));
        processNode(scene->mRootNode, scene);
    }
    void processNode(aiNode * node, const aiScene * scene) {
        for (unsigned int i = 0; i < node->mNumMeshes; i++) {
            //processes all the nodes meshes
            aiMesh * mesh = scene->mMeshes[node->mMeshes[i]];
            meshes.push_back(processMesh(mesh, scene));
        }
        for (unsigned int i = 0; i < node->mNumChildren; i++) {
            processNode(node->mChildren[i], scene);
        }
    }
    Mesh processMesh(aiMesh * mesh, const aiScene * scene) {
        std::vector<Vertex> vertices;
        std::vector<unsigned int> indices;
        std::vector<Texture> textures;
        for (unsigned int i = 0; i < mesh->mNumVertices; i++)  {
            Vertex vertex;
            glm::vec3 vector;
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.position = vector;
            //get other vertex information
            vertices.push_back(vertex);
            //for all vertices in the mesh, adds the data to a vector
        }
        for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
            aiFace face = mesh->mFaces[i];
            if (face.mNumIndices == 3) {
                indices.push_back(face.mIndices[0]);                    
                indices.push_back(face.mIndices[1]);
                indices.push_back(face.mIndices[2]);
                //for all the indices in each face, add each indice

            }
            else {
                printf("Odd mNumIndices \n");
                //added as a just in case - but in my situation this case is never executed -> all faces are triangles
                for (unsigned int j = 0; j < face.mNumIndices; j++) {
                    indices.push_back(face.mIndices[j]);
                }
            }
        }

Now to access this data I just simply iterate through all the meshes of the model, and for each indice of the mesh I access its corresponding vertex.

bool collision(glm::mat4 worldSpaceTransform, glm::vec3 testVector) {
        for (Mesh mesh : meshes) {
            for (int i = 0; i < mesh.indices.size(); i += 3) {
                //iterate through all faces of the mesh since each face has 3 vertices
                glm::vec3 a = glm::vec3(worldSpaceTransform * glm::vec4(mesh.verticies[mesh.indices[i]].position, 1));
                glm::vec3 b = glm::vec3(worldSpaceTransform * glm::vec4(mesh.verticies[mesh.indices[i + 1]].position, 1));
                glm::vec3 c = glm::vec3(worldSpaceTransform * glm::vec4(mesh.verticies[mesh.indices[i + 2]].position, 1)); 
               //use vector a, b and c (transformed to world space) for collision test with the test vector
               //return true if the test vector collides with the triangle
            }
        }
        return false;
    }

So I have used print statements to output the coordinates of vectors a b and c which should make a triangle. In one case I could not find these exact vectors in the raw .obj file of the model, I have found their x, y and z coordinates but not all together in one vector (yes, when I checked this I printed the local space coordinates). In another, the three vectors that should make a triangle ended up forming a line (two of the three vectors had the same coordinates). Also, I am aware testing a vector with all of the model's primitives is inefficient, but right now I am focusing on getting something working before I look at optimizations. Many of the models are too complex for AABB's so this is the "best" solution I have come up with. So, I am not sure what I am doing wrong here, any tips are much appreciated!

Upvotes: 0

Views: 2469

Answers (1)

KimKulling
KimKulling

Reputation: 2843

The obj-format just stores every vertex once and will reference it in the faces. So Assimp will generate out of these positions the vertices for the rendering itself. And this is the reason that you cannot find the original information from your imported obj-file in the form obj is storing them in the format. Obj is optimized for size, the intermediate format used by assimp is optimized for rendering.

A good strategy to store the collision information strongly depends on your kind of model. For me it worked to generate the local bounding box for the whole model and child-boxes for each mesh stored in the node-graph. SO the following approach may work:

  • Check against the scene-bounding box is your triangle collides with this box
  • If this is the case:
    • Check against all node bounding boxes
    • If you are able to detect a collision: check all triangle of this node within the meshes to find the right one

Upvotes: 1

Related Questions