PDA

View Full Version : GLSL not receiving data?



aparker314159
04-08-2017, 02:26 PM
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.

Dark Photon
04-08-2017, 06:32 PM
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));


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:

* Vertex_Shader#Multiple_attributes (https://www.khronos.org/opengl/wiki/Vertex_Shader#Multiple_attributes)

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 (https://www.khronos.org/opengl/wiki/GLAPI/glVertexAttribPointer)() 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 (https://www.khronos.org/opengl/wiki/OpenGL_Error) in the OpenGL Wiki.

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