I’m using Cal3d to add some skeletal animation to my openGL graphics project. After loading a model, I’m having trouble extracting the vertex, normal, UV, and face data in order draw the model correctly.
Here is the function I’m using to load the model, which I believe is correct:
bool LoadHero() {
//Clear();
bool Ret = false;
myCoreModel = new CalCoreModel("My Hero");
if (!myCoreModel->loadCoreSkeleton("/linux_files/class/cs4250/ogldev/Content/data/hero/hero.csf"))
{
return false;
}
idleAnimationId = myCoreModel->loadCoreAnimation("/linux_files/class/cs4250/ogldev/Content/data/hero/hero_idle.caf");
if ((idleAnimationId == -1))
{
return false;
}
BodyMeshId = myCoreModel->loadCoreMesh("/linux_files/class/cs4250/ogldev/Content/data/hero/hero.cmf");
if ((BodyMeshId == -1))
{
return false;
}
armLeftMaterialID = myCoreModel->loadCoreMaterial("/linux_files/class/cs4250/ogldev/Content/data/hero/hero_mat0.xrf");
if ((armLeftMaterialID == -1))
{
return false;
}
// load all textures and store their identifier as user-data in the corresponding core material map
int materialId;
for (materialId = 0; materialId < myCoreModel->getCoreMaterialCount(); materialId++)
{
// get the current core material
pCoreMaterial = myCoreModel->getCoreMaterial(materialId);
// loop through all the maps of the current core material
int mapId;
for (mapId = 0; mapId < pCoreMaterial->getMapCount(); mapId++)
{
// get the filename of the map
std::string strFilename;
strFilename = pCoreMaterial->getMapFilename(mapId);
std::string filepath = "/linux_files/class/cs4250/ogldev/Content/data/hero/";
strFilename = filepath + strFilename;
// load the texture from the file
Texture *tmp = new Texture(GL_TEXTURE_2D, strFilename);
if (!tmp->Load()) {
printf("here");
//return false;
}
Cal::UserData textureId = (Cal::UserData)tmp->getTexID();
// store the texture id in the user data of the map
pCoreMaterial->setMapUserData(mapId, textureId);
}
}
myModel = new CalModel(myCoreModel);
if (!myModel->attachMesh(BodyMeshId))
{
return false;
}
return true;
}
And copied here is the code which I am using to extract the vertex, normal, UV, and face data, then draw the mesh. Nothing is appearing on screen where the hero should be drawn.
bool heroRender() {
// get the renderer of the model
pCalRenderer = new CalRenderer(myModel->getRenderer());
// begin the rendering loop
if (!pCalRenderer->beginRendering())
{
return false;
}
// get the number of meshes
int meshCount;
meshCount = pCalRenderer->getMeshCount();
// loop through all meshes of the model
int meshId;
for (meshId = 0; meshId < meshCount; meshId++)
{
// Create the VAO
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
// Create the buffers for the vertices attributes
glGenBuffers(ARRAY_SIZE_IN_ELEMENTS(m_Buffers), m_Buffers);
// get the number of submeshes
int submeshCount;
submeshCount = pCalRenderer->getSubmeshCount(meshId);
std::vector<BasicMeshEntry> m_Entries;
std::vector<Texture*> m_Textures;
m_Entries.resize(submeshCount);
//m_Textures.resize(pCalRenderer->getMapCount);
vector<Vector3f> Positions;
vector<Vector3f> Normals;
vector<Vector2f> TexCoords;
vector<unsigned int> Indices;
unsigned int NumVertices = 0;
unsigned int NumIndices = 0;
// loop through all submeshes of the mesh
int submeshId;
for (submeshId = 0; submeshId < submeshCount; submeshId++)
{
// select mesh and submesh for further data access
if (pCalRenderer->selectMeshSubmesh(meshId, submeshId))
{
/*// get the material colors
unsigned char ambientColor[4], diffuseColor[4], specularColor[4];
pCalRenderer->getAmbientColor(&ambientColor[0]);
pCalRenderer->getDiffuseColor(&diffuseColor[0]);
pCalRenderer->getSpecularColor(&specularColor[0]);
// get the material shininess factor
float shininess;
shininess = pCalRenderer->getShininess();
// get the transformed vertices of the submesh
static float meshVertices[30000][3];
int vertexCount;
vertexCount = pCalRenderer->getVertices(&meshVertices[0][0]);*/
//m_Entries[submeshId].MaterialIndex = pCalRenderer->getMapUserData(0);
m_Entries[submeshId].NumIndices = pCalRenderer->getFaceCount() *3;
m_Entries[submeshId].BaseVertex = NumVertices;
m_Entries[submeshId].BaseIndex = NumIndices;
NumVertices += pCalRenderer->getVertexCount();
NumIndices += m_Entries[submeshId].NumIndices;
}
}
// Reserve space in the vectors for the vertex attributes and indices
Positions.reserve(NumVertices);
Normals.reserve(NumVertices);
TexCoords.reserve(NumVertices);
Indices.reserve(NumIndices);
// Initialize the meshes in the scene one by one
for (unsigned int i = 0; i < m_Entries.size(); i++) {
if (pCalRenderer->selectMeshSubmesh(meshId, i)) {
InitMesh(pCalRenderer, Positions, Normals, TexCoords, Indices);
}
}
/*if (!InitMaterials(pScene, Filename)) {
return false;
}*/
// Generate and populate the buffers with vertex attributes and the indices
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[POS_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Positions[0]) * Positions.size(), &Positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(POSITION_LOCATION);
glVertexAttribPointer(POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexCoords[0]) * TexCoords.size(), &TexCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(TEX_COORD_LOCATION);
glVertexAttribPointer(TEX_COORD_LOCATION, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[NORMAL_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Normals[0]) * Normals.size(), &Normals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(NORMAL_LOCATION);
glVertexAttribPointer(NORMAL_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Buffers[INDEX_BUFFER]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices[0]) * Indices.size(), &Indices[0], GL_STATIC_DRAW);
glBindVertexArray(m_VAO);
for (unsigned int i = 0; i < m_Entries.size(); i++) {
//const unsigned int MaterialIndex = m_Entries[i].MaterialIndex;
//assert(MaterialIndex < m_Textures.size());
/*if (m_Textures[MaterialIndex]) {
m_Textures[MaterialIndex]->Bind(COLOR_TEXTURE_UNIT);
}*/
glDrawElementsBaseVertex(GL_TRIANGLES,
m_Entries[i].NumIndices,
GL_UNSIGNED_INT,
(void*)(sizeof(unsigned int) * m_Entries[i].BaseIndex),
m_Entries[i].BaseVertex);
}
// Make sure the VAO is not changed from the outside
glBindVertexArray(0);
}
// end the rendering of the model
pCalRenderer->endRendering();
}
void InitMesh(CalRenderer* pCalRenderer, vector<Vector3f>& Positions, vector<Vector3f>& Normals, vector<Vector2f>& TexCoords, vector<unsigned int>& Indices)
{
// get the transformed vertices of the submesh
static float meshVertices[30000][3];
int vertexCount = pCalRenderer->getVertices(&meshVertices[0][0]);
// get the transformed normals of the submesh
static float meshNormals[30000][3];
pCalRenderer->getNormals(&meshNormals[0][0]);
// get the texture coordinates of the submesh
// (only for the first map as example, others can be accessed in the same way though)
static float meshTextureCoordinates[30000][2];
int textureCoordinateCount = pCalRenderer->getTextureCoordinates(0, &meshTextureCoordinates[0][0]);
// get the faces of the submesh
static int meshFaces[50000][3];
int faceCount = pCalRenderer->getFaces(&meshFaces[0][0]);
// Populate the vertex attribute vectors
for (unsigned int i = 0; i < vertexCount; i++) {
Positions.push_back(Vector3f(meshVertices[i][0], meshVertices[i][1], meshVertices[i][2]));
Normals.push_back(Vector3f(meshNormals[i][0], meshNormals[i][1], meshNormals[i][2]));
TexCoords.push_back(Vector2f(meshTextureCoordinates[i][0], meshTextureCoordinates[i][1]));
}
// Populate the index buffer
for (unsigned int i = 0; i < faceCount; i++) {
Indices.push_back(meshFaces[i][0]);
Indices.push_back(meshFaces[i][1]);
Indices.push_back(meshFaces[i][2]);
}
}
I think the issue lies in how I’m extracting indices from the faces, but I’m not sure how to fix it. There are very few resources on integrating cal3d into openGL online, so any help would be appreciated.