Question

I'm loading a Collada (.dae file) and the model has 2 objects. The first which is a cloth with alot of vertices with a light blue material. And the second a box which the cloth is supposed to fold around as it falls down.

This is supposed to be a 250 frame animation, but I'm not sure if it actually is or not. When I load it into Assimp's aiScene* it says HasAnimation() == 0... It also says that the mesh for the cloth has no color, with the HasVertexColors() == 0 Which has me worried I have to take another look at exporting it. I don't know, maybe you can tell? I'll link it on an external side as it is too large for this post. (Sorry for that)

Falling Cloth (Collada animation .dae): http://pastebin.com/54LkKq8k

My problem is that I don't see the light blue cloth, and the box is black, as in (0, 0, 0)...

Initializing VBO:

void AssimpMesh::initMesh(aiMesh *mesh, MeshData *data) {
    //Buffer for temporary storage of new ids
    GLuint id;

    //Make vertex array
    glGenVertexArrays(1, &id);
    data->meshArray = id;

    //Tell OpenGL to use this array
    glBindVertexArray(id);

    //Assign vertices
    if (mesh->HasPositions()) {
        //Make buffer
        glGenBuffers(1, &id);
        data->buffers.push_back(id);
        data->bufferNames.push_back("Positions");

        //Set buffer data
        glBindBuffer(GL_ARRAY_BUFFER, id);
        glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mVertices[0], GL_STATIC_DRAW);

        //Set shader attribute data
        glEnableVertexAttribArray(VBO_VERTEX);
        glVertexAttribPointer(VBO_VERTEX, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
    }

    //Assign colors
    if (mesh->HasVertexColors(0)) {
        //Make buffer
        glGenBuffers(1, &id);
        data->buffers.push_back(id);
        data->bufferNames.push_back("Colors");

        //Set buffer data
        glBindBuffer(GL_ARRAY_BUFFER, id);
        glBufferData(GL_ARRAY_BUFFER, sizeof(aiColor4D) * mesh->mNumVertices, &mesh->mColors[0], GL_STATIC_DRAW);

        //Set shader attribute data
        glEnableVertexAttribArray(VBO_COLOR);
        glVertexAttribPointer(VBO_COLOR, 4, GL_FLOAT, GL_FALSE, NULL, NULL);
    }

    //Assign texture coords
    if (mesh->HasTextureCoords(0)) {
        //Make buffer
        glGenBuffers(1, &id);
        data->buffers.push_back(id);
        data->bufferNames.push_back("TextureCoords");

        //Set buffer data
        glBindBuffer(GL_ARRAY_BUFFER, id);
        glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mTextureCoords[0], GL_STATIC_DRAW);

        //Set shader attribute data
        glEnableVertexAttribArray(VBO_TEXCORD);
        glVertexAttribPointer(VBO_TEXCORD, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
    }

    //Assign colors
    if (mesh->HasNormals()) {
        //Make buffer
        glGenBuffers(1, &id);
        data->buffers.push_back(id);
        data->bufferNames.push_back("Normals");

        //Set buffer data
        glBindBuffer(GL_ARRAY_BUFFER, id);
        glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mNormals[0], GL_STATIC_DRAW);

        //Set shader attribute data
        glEnableVertexAttribArray(VBO_NORMAL);
        glVertexAttribPointer(VBO_NORMAL, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
    }

    if (mesh->HasFaces()) {
        vector <unsigned int> indices;
        aiFace face;
        for (int i = 0; i < mesh->mNumFaces; i++) {
            face = mesh->mFaces[i];
            for (int j = 0; j < face.mNumIndices; j++) {
                indices.push_back(face.mIndices[j]);
            }
        }

        //Make buffer
        glGenBuffers(1, &id);
        data->buffers.push_back(id);
        data->bufferNames.push_back("Faces");

        //Set buffer data
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &indices.front(), GL_STATIC_DRAW);
    }

    //Unbind vertex array
    glBindVertexArray(NULL);
}

Draw model:

void AssimpMesh::draw() {
    //Draw all vertex arrays
    aiMesh *mesh;
    aiFace face;
    MeshData *data;
    for (int i = 0; i < meshes.size(); i++) {
        mesh = scene->mMeshes[i];
        face = mesh->mFaces[0];
        data = meshes[i];

        //Tell OpenGL to use this array
        glBindVertexArray(data->meshArray);

        //Tell OpenGL which shader to use
        glUseProgram(data->program);

        //Draw the elements of the array
        glDrawElements(GL_TRIANGLES, face.mNumIndices * mesh->mNumFaces, GL_UNSIGNED_INT, 0);
    }

    //Unbind vertex array
    glBindVertexArray(NULL);

    //Unbind shader
    glUseProgram(NULL);
}

Vertex shader:

#version 120

attribute vec3 vertex;
attribute vec4 color;
attribute vec3 texCoord;
attribute vec3 normal;

uniform mat4 transform;

varying vec3 shared_color;
varying vec2 shared_texCoord;
varying vec3 shared_normal;

void main() {
    gl_Position = transform * vec4(vertex, 1.0);

    //Send data to fragment shader
    shared_color = color.xyz;
    shared_texCoord = texCoord.xy;
    shared_normal = (transform * vec4(normal, 0.0)).xyz;
}

Fragment shader:

#version 120

uniform sampler2D diffuse;
uniform int flagTexture;

varying vec3 shared_color;
varying vec2 shared_texCoord;
varying vec3 shared_normal;

void main() {
    vec4 color = vec4(shared_color, 1);
    vec4 texture = texture2D(diffuse, shared_texCoord);
    vec4 finalColor = color;

    if (flagTexture >= 1) {
        finalColor = vec4(mix(color.rgb, texture.bgr, texture.a), 1);
        //finalColor = color * texture;
    }

    float shade = 0;
    if (shade >= 1) {
        vec3 lightPosition = vec3(0, 0, -1);
        float shadowDarkness = 0.8;
        vec3 actualLightPos = vec3(-lightPosition.x, lightPosition.y, lightPosition.z);
        float lightStrength = clamp(dot(actualLightPos, shared_normal), 1 - shadowDarkness, 1.0);
        vec4 litColor = finalColor * lightStrength;
        finalColor = litColor;
    }

    gl_FragColor = finalColor;
}
Was it helpful?

Solution

I see a couple of problems here after looking at the documentation of the library you're using:

  • For the colors, the type you get is aiColor4D. At the name suggests, that's a class containing 4 floats. But you're passing 3 for the size to the corresponding call to glVertexAttribPointer().
  • For the texture coordinates, the type is aiVector3D, which contains 3 floats. But you're passing 2 for the size to the corresponding call to glVertexAttribPointer().
  • aiFace is a class that contains an index count and a pointer to the indices for the face. You can't just pass an array of these guys to glBufferData() as your indices. Effectively, you're passing a sequence of index counts and pointers instead of a sequence of indices.
  • The second argument to glDrawElements() is the number of indices, not the number of triangles.

Let us know how it goes once these are fixed. Another common source of errors is how the vertex attributes are tied to the vertex shader, which is code we don't see here.

OTHER TIPS

1) Does it work?

Did you test it? It looks like it should render correctly, although your deallocation doesn't look right. glDelete* takes a pointer for its second argument; you're passing a reference to the front element.

Change it to this:

for (int i = 0; i < buffers.size(); i++) {
    glDeleteBuffers(buffers[i].size(), &buffers[i].front());
}

glDeleteVertexArrays(meshes.size(), &meshes.front());

2) Is it any good?

It's a pretty standard rendering loop, the speed of it depends almost entirely on how complex your shaders are. ALTHOUGH I would make the change of declaring a pointer outside of the loop then re-assigning it, rather than declaring a new pointer for every mesh:

aiMesh *mesh;
for (int i = 0; i < meshes.size(); i++) {
    mesh = scene->mMeshes[i];

    //Tell OpenGL to use this array
    glBindVertexArray(meshes[i]);

    //Draw the elements of the array
    glDrawElements(GL_TRIANGLES, mesh->mNumFaces, GL_UNSIGNED_INT, 0);
}

3) Extra info

It has a terrible little math library included with it that I would never recommend, but you should know anyway for handling vertices and thing later on (e.g. when you map your buffers later)

So if you want to map your GL_ARRAY_BUFFER to modify the vertices stored, you'd have to use something like this:

glBindVertexArray(the_vao);
aiVector3D *data = reinterpret_cast<aiVector3D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE));

// do all the changes!

glUnmapBuffer(GL_ARRAY_BUFFER);

I looked in the documentation and saw that the HasVertexColors() was not actually the diffuse value from the material i wanted. So I solved this by using the material indexed in the mesh and extracted the diffuse color into an array of size mNumVertices.

unsigned int matId = mesh->mMaterialIndex;
aiMaterial *material = scene->mMaterials[matId];
vector <aiColor3D> colors;
aiColor3D diffuse(0, 0, 0);
material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);

for (int i = 0; i < mesh->mNumVertices; i++) {
    colors.push_back(diffuse);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top