The Problem:
It seems as if the second GLuint buffer is not being read in properly.
Update: So the problem must be when I try to input the data to the shader. I rewrote the code (the old code is still below) to use swizzling for the index parameter. That was the only way I could get it to work. I would like to use multiple glVertexAttribPointer's, but every time I try to gives me the same undefined results.
What I Am Trying To Do:
I'm testing out very simple skinned animation with a very simplified shader,
#version 330 core
in vec2 model;
in uint jointID;
const int MAX_JOINTS = 10;
uniform mat4 joints[MAX_JOINTS];
void main()
{
gl_Position = joints[jointID] * vec4(model, 0.0f, 1.0f);
}
I input some simple data,
const GLfloat vertices[] =
{
// upper arm
0.0f, 0.0f,
0.4f, 0.0f,
0.4f, 0.2f,
0.0f, 0.0f,
0.4f, 0.2f,
0.0f, 0.2f,
// lower arm
0.4f, 0.0f,
0.8f, 0.0f,
0.8f, 0.2f,
0.4f, 0.0f,
0.8f, 0.2f,
0.4f, 0.2f
};
const GLuint indices[] =
{
// upper arm
0,
1,
1,
0,
1,
0,
// lower arm
1,
1,
1,
1,
1,
1
};
(The first array containing the vertices and the second array containing the corresponding boneID's.) Oddly, the boneID's never seem too equal 1 because when I make the matrix at index 1 some really funky value, the vertices remain untransformed. This leads me to believe that it is a problem with the way I set up my glVertexAttribPointer's,
void SkinnedModel::draw()
{
shaderProgram.use();
glEnableVertexAttribArray(modelLoc);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(modelLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(jointIDLoc);
glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
glUniformMatrix4fv(jointsLoc, 10, GL_FALSE, (GLfloat*)&poseMatrices);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glDisableVertexAttribArray(modelLoc);
glDisableVertexAttribArray(jointIDLoc);
}
I've been banging my head against the desk for the past few hours looking at what seems to be correct code. Anyway, it's probably something dumb I missed. Any help is appreciated.
Here is all the relevant source code (just in case):
SkinnedModel.h
#pragma once
#include "stl/DataTypes.h"
#include "Shader.h"
#include <Dense>
using namespace Eigen;
struct Joint
{
Joint** children;
Joint* parent;
U32 index;
};
class SkinnedModel
{
public:
static void init();
static void destroy();
SkinnedModel();
~SkinnedModel();
void create(const GLfloat* vertices, const GLuint* jointIndices, GLint numVertices, Joint* rootJoint);
void draw();
void rotate(Joint* joint, F32 angle, F32 x, F32 y);
GLuint vertexBuffer;
GLuint indexBuffer;
GLint numVertices;
//GLint numJoints;
Joint* root;
Matrix<GLfloat,4,4> poseMatrices[10];
static ShaderProgram shaderProgram;
static GLuint modelLoc;
static GLuint jointIDLoc;
static GLuint modelViewMatrixLoc;
static GLuint jointsLoc;
};
SkinnedModel.cpp
#include "SkinnedModel.h"
ShaderProgram SkinnedModel::shaderProgram;
GLuint SkinnedModel::modelLoc = -1;
GLuint SkinnedModel::jointIDLoc = -1;
GLuint SkinnedModel::modelViewMatrixLoc = -1;
GLuint SkinnedModel::jointsLoc = -1;
void SkinnedModel::init()
{
ShaderProgramSettings shaderPS;
shaderPS.loadShader("Skinned.v.glsl", ShaderType::VERTEX);
shaderPS.loadShader("Skinned.f.glsl", ShaderType::FRAGMENT);
shaderProgram = shaderPS.create();
shaderProgram.use();
modelLoc = shaderProgram.getAttrib("model");
jointIDLoc = shaderProgram.getAttrib("jointID");
//modelViewMatrixLoc = shaderProgram.getUniform("modelViewMatrix");
jointsLoc = shaderProgram.getUniform("joints");
}
void SkinnedModel::destroy()
{
shaderProgram.destroy();
}
SkinnedModel::SkinnedModel()
{
}
SkinnedModel::~SkinnedModel()
{
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);
}
void SkinnedModel::create(const GLfloat* vertices, const GLuint* jointIndices, GLint numVertices, Joint* rootJoint)
{
this->numVertices = numVertices;
this->root = rootJoint;
for(U32 i=0;i<10;++i)
{
poseMatrices[i] = Matrix<GLfloat,4,4>::Identity();
}
poseMatrices[1] = Matrix<GLfloat,4,4>::Zero(); // <--- This should mess it up!
// Creating buffers
glDeleteBuffers(1, &vertexBuffer);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*2*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glDeleteBuffers(1, &indexBuffer);
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(GLuint), jointIndices, GL_STATIC_DRAW);
}
void SkinnedModel::draw()
{
shaderProgram.use();
glEnableVertexAttribArray(modelLoc);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(modelLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(jointIDLoc);
glBindBuffer(GL_ARRAY_BUFFER, indexBuffer);
glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);
glUniformMatrix4fv(jointsLoc, 10, GL_FALSE, (GLfloat*)&poseMatrices);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glDisableVertexAttribArray(modelLoc);
glDisableVertexAttribArray(jointIDLoc);
}
void SkinnedModel::rotate(Joint* joint, F32 angle, F32 x, F32 y)
{
F32 rcos = cos(angle);
F32 rsin = sin(angle);
Matrix<GLfloat, 4, 4> rotMatrix = Matrix<GLfloat, 4, 4>::Identity();
rotMatrix(0,0) = rcos;
rotMatrix(0,1) = -rsin;
rotMatrix(1,0) = rsin;
rotMatrix(1,1) = rcos;
rotMatrix(0,3) = x-rcos*x+rsin*y;
rotMatrix(1,3) = y-rsin*x-rcos*y;
poseMatrices[joint->index] *= rotMatrix;
}
Game.cpp
void Game::init()
{
GUI::init();
SkinnedModel::init();
getScreen()->setBackgroundColor(1.0f, 1.0f, 1.0f);
const GLfloat vertices[] =
{
// upper arm
0.0f, 0.0f,
0.4f, 0.0f,
0.4f, 0.2f,
0.0f, 0.0f,
0.4f, 0.2f,
0.0f, 0.2f,
// lower arm
0.4f, 0.0f,
0.8f, 0.0f,
0.8f, 0.2f,
0.4f, 0.0f,
0.8f, 0.2f,
0.4f, 0.2f
};
const GLuint indices[] =
{
// upper arm
0,
1,
1,
0,
1,
0,
// lower arm
1,
1,
1,
1,
1,
1
};
upperArm.parent = 0;
upperArm.children = new Joint*[1];
upperArm.children[0] = &lowerArm;
upperArm.index = 0;
lowerArm.parent = &upperArm;
lowerArm.children = 0;
lowerArm.index = 1;
m.create(vertices, indices, 12, &upperArm);
//m.rotate(&lowerArm, PI/4, 0.4f, 0.1f);
//DEBUG("SIZE %i", sizeof(Eigen::Matrix<GLfloat,4,4>));
}
void Game::loop(double dt)
{
m.draw();
}
Update: Apparently if all values for the boneID are set to 1 it never uses 1 in the shader either @.@. So the second array isn't even being read, or it's not being read correctly.