Search code examples
c++openglvboassimp

Can you do this with vertex arrays OpenGL 4.4?


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;
}

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.