GLSL not receiving data?

I’m trying to do skeletal animation with assimp and opengl. However, it seems that my vertex shader is not receiving data about the bone weights. I am not sure why this is happening. I am sure that my array of vertices has the data, as I have printed it out before drawing.

I’m really not sure why. Could someone take a look at the relevant code and explain what is going on to me?

My vertex shader


#version 330 core

#define MAX_BONES_PER_VERTEX 5
#define MAX_BONES 256

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
layout (location = 3) in uint[MAX_BONES_PER_VERTEX] boneIDs;
layout (location = 4) in float[MAX_BONES_PER_VERTEX] boneWeights;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 bones[MAX_BONES];

out vec3 Normal;
out vec3 fragPos;
out vec2 TexCoords;

void main() {
    vec4 vertex = vec4(position, 1.0);

    mat4 boneTransform = mat4(1.0, 0.0, 0.0, 0.0,
                              0.0, 1.0, 0.0, 0.0,
                              0.0, 0.0, 1.0, 0.0,
                              0.0, 0.0, 0.0, 1.0);
    for (int i = 0; i < MAX_BONES_PER_VERTEX; i++)
        boneTransform += bones[boneIDs[i]] * boneWeights[i];

    vec4 finalVertex = boneTransform * vertex;

    mat4 normalMatrix = transpose(inverse(model));

    gl_Position = projection * view * model * finalVertex;
    fragPos = vec3(model * vec4(position, 1.0));
    Normal = (normalMatrix * vec4(normal, 1.0)).xyz;
    TexCoords = texCoords;

}



My mesh class:


#ifndef MESH_HPP
#define MESH_HPP

#include <GL/glew.h>

#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>

#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

#include <string>
#include <vector>

#include "../shader.hpp"

#include "vertex.hpp"

using glm::vec3;
using glm::vec2;
using std::vector;
using std::string;

struct Texture {
    GLuint id;
    string type;
    aiString filePath;
};

class Mesh {
public:
    // Mesh Data
    vector<Vertex> vertices;
    vector<GLuint> indices;
    vector<Texture> textures;
    vector<glm::mat4> bones;

    // Constructor
    Mesh(vector<Vertex> verts, vector<GLuint> inds, vector<Texture> texs, vector<glm::mat4> bones, const char* name);

    void draw(Shader&, glm::mat4& model);

    const char* name;

private:
    GLuint VAO, VBO, EBO;
};

inline Mesh::Mesh(vector<Vertex> verts, vector<GLuint> inds, vector<Texture> texs, vector<glm::mat4> b, const char* n):
    vertices(verts),
    indices(inds),
    textures(texs),
    bones(b),
    name(n) {

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);

    // Vertex Positions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // Vertex Normals
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, normal));
    glEnableVertexAttribArray(1);
    // Vertex Texture Coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texCoords));
    glEnableVertexAttribArray(2);
    // Bone IDs
    glVertexAttribIPointer(3, MAX_BONES_PER_VERTEX, GL_INT, sizeof(Vertex), (GLvoid*)offsetof(Vertex, boneIDs));
    glEnableVertexAttribArray(3);
    // Bone Weights
    glVertexAttribPointer(4, MAX_BONES_PER_VERTEX, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, boneWeights));
    glEnableVertexAttribArray(4);

    glBindVertexArray(0);
}

inline void Mesh::draw(Shader& shader, glm::mat4& model) {
    GLuint diffuseNr = 1;
    GLuint specularNr = 1;
    for (GLuint i = 0; i < this->textures.size(); i++) {
        glActiveTexture(GL_TEXTURE0 + i); // Activate proper texture unit before binding
        // Retrieve texture number (the N in diffuse_textureN)
        std::stringstream ss;
        string number;
        string name = textures[i].type;
        if(name == "texture_diffuse")
            ss << diffuseNr++; // Transfer GLuint to stream
        else if(name == "texture_specular")
            ss << specularNr++; // Transfer GLuint to stream
        number = ss.str();

        glUniform1f(glGetUniformLocation(shader.program, ("material." + name + number).c_str()), i);
        glBindTexture(GL_TEXTURE_2D, textures[i].id);
    }

    glActiveTexture(GL_TEXTURE0);

    shader.setUniform("model", model);

    bones[1] = glm::rotate(bones[1], 0.1f, vec3(0.0f, 1.0f, 0.4f));

    for (int i = 0, size = bones.size(); i < size && i < 256; i++) {
        shader.setUniform(("bones[" + std::to_string(i) + ']').c_str(), bones[i]);
    }

    // Draw mesh
    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

#endif // MESH_HPP

My vertex struct:



#ifndef VERTEX_HPP
#define VERTEX_HPP

#include <glm/glm.hpp>

#include <GL/glew.h>

#include <vector>

static constexpr GLuint MAX_BONES_PER_VERTEX = 5;

struct Vertex {
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 texCoords;
    GLuint boneIDs[MAX_BONES_PER_VERTEX];
    GLfloat boneWeights[MAX_BONES_PER_VERTEX];

    Vertex() {
        for (unsigned int i = 0; i < MAX_BONES_PER_VERTEX; i++)
            boneIDs[i] = 0;
    }

    GLint getNextBoneID() {
        for (unsigned int i = 0; i < MAX_BONES_PER_VERTEX; i++)
            if (boneIDs[i] == 0)
                return i;

        return -1;
    }
};
#endif // VERTEX_HPP


If you need more code, I can give it.

[QUOTE=aparker314159;1286645]I’m trying to do skeletal animation with assimp and opengl. However, it seems that my vertex shader is not receiving data about the bone weights. … I’m really not sure why. Could someone take a look at the relevant code and explain what is going on to me?

My vertex shader


#version 330 core

#define MAX_BONES_PER_VERTEX 5
...
layout (location = 3) in uint[MAX_BONES_PER_VERTEX] boneIDs;
layout (location = 4) in float[MAX_BONES_PER_VERTEX] boneWeights;

My mesh class:


    // Vertex Positions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
    ...
    // Vertex Normals
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, normal));
    ...
    // Vertex Texture Coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texCoords));
    ...
    // Bone IDs
    glVertexAttribIPointer(3, MAX_BONES_PER_VERTEX, GL_INT, sizeof(Vertex), (GLvoid*)offsetof(Vertex, boneIDs));
    ...
    // Bone Weights
    glVertexAttribPointer(4, MAX_BONES_PER_VERTEX, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, boneWeights));

[/QUOTE]

I’m fairly sure that arrays passed in vertex attributes don’t work the way you think they do.

You might read about arrays here in the OpenGL Wiki:

Then you might consider 1) limiting max bones/weights per vertex to be 4, and then pass both the vertex bone IDs and the vertex weights into the vertex shader in a single uvec2 (which is basically a 2-D vector of 32-bit unsigned integers), where each value (weight or ID) is encoded using a single unsigned 8-bit integer.

What you’ve got above I think should consume 10 vertex attributes, 20 bytes for the bone IDs, and 20 bytes for the bone weights (40 bytes total). In contrast, encoding the IDs and weights as I suggest will consume 1 vertex attribute and only 8 bytes total.

Related: the 2nd argument to glVertexAttrib*Pointer() is the number of components in a vector type (1…4), not the number of elements in an array of those vectors. I suspect your GL implementation will be throwing GL errors for your passing 5 for this argument (and possibly for other areas of your code). You should check. See OpenGL Error in the OpenGL Wiki.

Also, I think you wanted GL_UNSIGNED_INT on your bone IDs glVertexAttribPointer call, not GL_INT.