Question

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.

Was it helpful?

Solution

You need to use glVertexAttribIPointer if you are using integer vertex attributes (i.e. something you have declared in uint or in int etc. in your vertex shader).

replace

glVertexAttribPointer(jointIDLoc, 1, GL_UNSIGNED_INT, GL_FALSE, 0, NULL);

with

glVertexAttribIPointer(jointIDLoc, 1, GL_UNSIGNED_INT, 0, NULL);

(note that glVertexAttribIPointer doesn't take the normalized parameter)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top