Ok, so I'm able to load a basic model with vertices, texture coordinates, and normals and render it without issue.
However, when I try throwing in some bone information, the bone data seems to be getting corrupted (or something?) when I try and manipulate it in the shader.
Here's my code for loading and rendering the data into opengl (setting the shader and sending the view matrix, world matrix, etc are done in another class):
/*
* Mesh.cpp
*
* Created on: 2011-05-08
* Author: jarrett
*/
#include <boost/log/trivial.hpp>
#include "../common/utilities/AssImpUtilities.h"
#include "Mesh.h"
namespace glr {
namespace glw {
Mesh::Mesh(IOpenGlDevice* openGlDevice,
const std::string path,
std::vector< glm::vec3 > vertices,
std::vector< glm::vec3 > normals,
std::vector< glm::vec2 > textureCoordinates,
std::vector< glm::vec4 > colors,
std::vector<VertexBoneData > bones,
BoneData boneData)
: openGlDevice_(openGlDevice), vertices_(vertices), normals_(normals), textureCoordinates_(textureCoordinates), colors_(colors), bones_(bones), boneData_(boneData)
{
BOOST_LOG_TRIVIAL(debug) << "loading mesh into video memory...";
// create our vao
glGenVertexArrays(1, &vaoId_);
glBindVertexArray(vaoId_);
// create our vbos
glGenBuffers(5, &vboIds_[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[0]);
glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(glm::vec3), &vertices_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[1]);
glBufferData(GL_ARRAY_BUFFER, textureCoordinates_.size() * sizeof(glm::vec2), &textureCoordinates_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[2]);
glBufferData(GL_ARRAY_BUFFER, normals_.size() * sizeof(glm::vec3), &normals_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
std::cout << "SIZE: " << vertices_.size() << " " << sizeof(glm::ivec4) << " " << bones_.size() << " " << sizeof(VertexBoneData) << std::endl;
// Convert data into simple vectors, then send to OpenGL
std::vector< glm::ivec4 > boneIds = std::vector< glm::ivec4 >();
std::vector< glm::vec4 > weights = std::vector< glm::vec4 >();
for ( VertexBoneData& d : bones_ )
{
boneIds.push_back( d.boneIds );
weights.push_back( d.weights );
}
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[3]);
glBufferData(GL_ARRAY_BUFFER, boneIds.size() * sizeof(glm::ivec4), &boneIds[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_INT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[4]);
glBufferData(GL_ARRAY_BUFFER, weights.size() * sizeof(glm::vec4), &weights[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Disable our Vertex Array Object
//glEnableVertexAttribArray(0);
// Disable our Vertex Buffer Object
glBindVertexArray(0);
GlError err = openGlDevice_->getGlError();
if (err.type != GL_NONE)
{
// TODO: throw error
BOOST_LOG_TRIVIAL(error) << "Error loading mesh in opengl";
BOOST_LOG_TRIVIAL(error) << "OpenGL error: " << err.name;
}
else
{
BOOST_LOG_TRIVIAL(debug) << "Successfully loaded mesh.";
}
}
Mesh::~Mesh()
{
}
void Mesh::render()
{
glBindVertexArray(vaoId_);
glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
glBindVertexArray(0);
}
BoneData& Mesh::getBoneData()
{
return boneData_;
}
}
}
My actual shader is this:
#version 150 core
struct Light {
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
vec4 direction;
};
in vec3 in_Position;
in vec2 in_Texture;
in vec3 in_Normal;
in ivec4 in_BoneIds;
in vec4 in_BoneWeights;
out vec2 textureCoord;
out vec3 normalDirection;
out vec3 lightDirection;
out float bug;
layout(std140) uniform Lights
{
Light lights[ 1 ];
};
void main() {
gl_Position = pvmMatrix * vec4(in_Position, 1.0);
vec4 lightDirTemp = viewMatrix * lights[0].direction;
textureCoord = in_Texture;
//vec4 normalDirTemp = boneTransform * vec4(in_Normal, 1.0);
//normalDirection = normalize(normalMatrix * normalDirTemp.xyz);
normalDirection = normalize(normalMatrix * in_Normal);
lightDirection = normalize(vec3(lightDirTemp));
// If we have any bugs, should highlight the vertex red or green
bug = 0.0;
float sum = in_BoneWeights[0] + in_BoneWeights[1] + in_BoneWeights[2] + in_BoneWeights[3];
if (sum > 1.5f)
bug = 1.0;
else if (sum < 0.95f)
bug = 2.0;
// disable bug highlighting
//bug = 0.0;
}
If bug = 1.0
, then the vertices are colored red, and if but = 2.0
, then the vertices are colored green. I see all the vertices are colored red right now, which means the sum
is greater than 1.5f
.
I have confirmed that the sum of each set of weights is in fact <= 1.0f
...so how in the world is this not the case in the shader?
Anyone see anything obvious I am missing?
EDIT: Looks like I found the problem - I wasn't calling glBindAttribLocation
on any of my in
variables - after adding:
glBindAttribLocation(programId_, 0, "in_Position");
glBindAttribLocation(programId_, 1, "in_Texture");
glBindAttribLocation(programId_, 2, "in_Color");
glBindAttribLocation(programId_, 3, "in_BoneIds");
glBindAttribLocation(programId_, 4, "in_BoneWeights");
to my shader loading code, it works fine. Odd thing is - I didn't have to do this for the first 3 (position, texture, and color) and it worked fine. But when I added the bone info, I suddenly need this...why?
You need to use glVertexAttribIPointer (...)
to give data to an ivec<N>
vertex attribute. If you thought you were experiencing "corruption" before setting the attribute locations, just wait until you write code in your shader that actually needs the bone IDs... These values will be meaningless because you are using the wrong API call to associate your attribute data with a particular binding location.
The glVertexAttribPointer (...)
variant has no trouble taking a GL_INT
data type, but it is going to convert it to floating-point (and it may normalize fixed-point values in the process, hence the extra parameter). Thus, this variant is expected to supply the data to a vec<N>
vertex attribute, not ivec<N>
.
More concisely, use glVertexAttribIPointer
for integer vertex attributes and glVertexAttribPointer
for floating-point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With