Derelict Assimp not loading mesh properly? (Maybe index buffer)

636 Views Asked by At

I wrote a custom OBJ file importer which worked fairly well however was not robust enough to support everything. I've decided to give AssImp a shot. I followed some tutorials and have set up my code to read in the vertices, tex coords, normals, and indices of an OBJ cube model that I have had success loading with my custom importer. The cube model's faces do not render properly, instead only rendering a few tri's of the cube. The way AssImp handles the data is obviously a bit different than my solution because the normals, positions/vertices, tex coords, and indices do not match my custom solution. I would very much appreciate some insight into why I'm having issues as all of the tutorials I've found have matched my approach. If a picture of the faulty rendered cube would be helpful I can work on getting a screenshot up. Thank you.

My Asset importing class:

module graphics.assimp;

import std.stdio, std.container, std.range;
import core, graphics;
import derelict.assimp3.assimp;

class AssImp
{
    this()
    {
        DerelictASSIMP3.load();
    }
    IndexedModel makeIndexedModel(vec3[] verts, vec3[] norms, vec2[] uvs, uint[] indices)
    {
        IndexedModel model;
        model.pos = verts;
        model.normals = norms;
        model.texCoords = uvs;
        model.indices = indices;

        writeln("verts: ", model.pos);
        writeln("normals: ", model.normals);
        writeln("texCoords: ", model.texCoords);
        writeln("indices: ", model.indices);

        return model;
    }
    Mesh loadMesh(const char* fileName)
    {
        const aiScene* scene = aiImportFile(fileName, aiProcessPreset_TargetRealtime_Fast | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices);
        const aiMesh* mesh = scene.mMeshes[0];

        numVerts = mesh.mNumFaces * 3;

        vertArray = new vec3[mesh.mNumFaces];
        normalArray = new vec3[mesh.mNumFaces];
        uvArray = new vec2[mesh.mNumFaces];
        int indexCount;
        for (uint i = 0; i < mesh.mNumFaces; i++)
        {
            const aiFace face = mesh.mFaces[i];
            indexCount += face.mNumIndices;

            for (int j = 0; j < 3; j++)
            {
                aiVector3D uv = mesh.mTextureCoords[0][face.mIndices[j]];
                uvArray[i] = vec2(uv.x, uv.y);

                aiVector3D normal = mesh.mNormals[face.mIndices[j]];
                normalArray[i] = vec3(normal.x, normal.y, normal.z);

                aiVector3D pos = mesh.mVertices[face.mIndices[j]];
                vertArray[i] = vec3(pos.x, pos.y, pos.z);

                indices.insert(face.mIndices[j]);
            }
        }
        return new Mesh(makeIndexedModel(vertArray, normalArray, uvArray, indices.array));      
    }
private:
    vec3 vertArray[];
    vec3 normalArray[];
    vec2 uvArray[];
    auto indices = make!(Array!uint)();
    int numVerts;
}

The rest of my code is at (Mesh Class is in source/graphics): https://github.com/BennetLeff/PhySim

1

There are 1 best solutions below

0
On

I don't know D so I will only comment on your assimp usage.

How about using more preprocessing options:

aiProcess_SortByPType |
aiProcess_RemoveRedundantMaterials |
aiProcess_PreTransformVertices |
aiProcess_GenUVCoords |
aiProcess_OptimizeMeshes |
aiProcess_OptimizeGraph

This may be not as useful with .obj files, but will become later if you want to read other formats.

Also for a simple .obj file this may be sufficient:

const aiMesh* mesh = scene.mMeshes[0];

But sometimes it picks wrong mesh, so you should iterate recursively using an aiNode* starting from scene.mRootNode and to scene.mNumChildren.

I am 100% sure that mesh.mNumFaces is not the size of the vertex array. You can look at my C++ code, I am sure you will understand the logic.

aiMesh *ptr = nullptr; // Set to mesh you want to process
QVector<float> outVertices, outUVs, outNormals;
QVector<uint> outIndices;


qDebug() << "Mesh name: " << ptr->mName.C_Str();
const uint n_vertices = ptr->mNumVertices;
qDebug() << "Num vertices: " << n_vertices;


outVertices.resize(n_vertices * 3);
float * data = reinterpret_cast<float*>(ptr->mVertices);
copy_n(data, outVertices.size(), outVertices.data());

outUVs.resize(n_vertices * 2);
for(uint i = 0; i < n_vertices; i++)
{
    aiVector3D & vec = ptr->mTextureCoords[0][i];
    outUVs[i*2] = vec.x;
    outUVs[i*2+1] = vec.y;
}

outNormals.resize(n_vertices * 3);
data = reinterpret_cast<float*>(ptr->mNormals);
copy_n(data, outNormals.size(), outNormals.data());


for(uint i = 0; i < ptr->mNumFaces; i++)
{
    aiFace face = ptr->mFaces[i];
    const uint n_indices = face.mNumIndices;
    const uint current_size = outIndices.size();

    outIndices.resize(current_size + n_indices);
    copy_n(face.mIndices, n_indices, outIndices.data() + current_size);
}

QVectors here are flat arrays of float, so it's a bit incomplitable with your code when you use vec3 and vec2.