Im trying to apply the model's transforms by walking the node heirarchy, but the poses are wrong (im not trying to animate it, just load it in a pose by using the transforms given in the gtlf file)
heres the code for loading the model
int mesh_idx = 0;
void ProcessAssimpMesh(struct aiMesh *mesh, const struct aiScene *scene,
Assimp_mesh **mesh_list, mat4 transform)
{
Assimp_mesh *a_mesh = &(*mesh_list)[mesh_idx];
int ptr = 0;
// 1. ALLOCATE MEMORY for vertices
int vertex_size = 8; // 3 pos + 2 tex + 3 normal
int total_vertices = mesh->mNumVertices * vertex_size;
a_mesh->vertices = (GLfloat*)malloc(sizeof(GLfloat) * total_vertices);
if (!a_mesh->vertices) {
printf("ERROR: Failed to allocate memory for vertices\n");
return;
}
// 2. PROCESS VERTICES
for (size_t i = 0; i < mesh->mNumVertices; i++)
{
// Position
a_mesh->vertices[ptr++] = mesh->mVertices[i].x;
a_mesh->vertices[ptr++] = mesh->mVertices[i].y;
a_mesh->vertices[ptr++] = mesh->mVertices[i].z;
// Texture coordinates
if (mesh->mTextureCoords[0]) {
a_mesh->vertices[ptr++] = mesh->mTextureCoords[0][i].x;
a_mesh->vertices[ptr++] = mesh->mTextureCoords[0][i].y;
} else {
a_mesh->vertices[ptr++] = 0.0f;
a_mesh->vertices[ptr++] = 0.0f;
}
// Normals
if (mesh->mNormals) {
a_mesh->vertices[ptr++] = mesh->mNormals[i].x;
a_mesh->vertices[ptr++] = mesh->mNormals[i].y;
a_mesh->vertices[ptr++] = mesh->mNormals[i].z;
} else {
a_mesh->vertices[ptr++] = 0.0f;
a_mesh->vertices[ptr++] = 0.0f;
a_mesh->vertices[ptr++] = 0.0f;
}
}
a_mesh->vertex_count = ptr;
glm_mat4_identity(a_mesh->transformation);
glm_mat4_copy(transform, a_mesh->transformation);
// 3. PROCESS INDICES
a_mesh->index_count = mesh->mNumFaces * 3;
a_mesh->indices = (unsigned int*)malloc(sizeof(unsigned int) * a_mesh->index_count);
if (a_mesh->indices) {
unsigned int index_ptr = 0;
for (size_t i = 0; i < mesh->mNumFaces; i++) {
a_mesh->indices[index_ptr++] = mesh->mFaces[i].mIndices[0];
a_mesh->indices[index_ptr++] = mesh->mFaces[i].mIndices[1];
a_mesh->indices[index_ptr++] = mesh->mFaces[i].mIndices[2];
}
}
a_mesh->mesh_name = strdup(mesh->mName.data);
a_mesh->identifier = mesh_idx;
mesh_idx++;
}
void convert_backslash_to_frontslash(char *str, int len)
{
for (size_t i = 0; i < len; i++)
{
if (str[i] == '\\')
{
str[i] = '/';
}
}
}
void ProcessMaterialTextures(struct aiMaterial **materials, struct aiMesh *mesh, Assimp_mesh *created_mesh, char *model_path, const struct aiScene *scene)
{
const struct aiMaterial *mat = materials[mesh->mMaterialIndex];
struct aiString path;
aiReturn ok;
ok = aiGetMaterialTexture(
mat, aiTextureType_DIFFUSE, 0, &path, NULL, NULL, NULL, NULL, NULL, NULL
);
if (ok == AI_SUCCESS)
{
if (path.data[0] == '*')
{
printf("Embedded texture\n");
created_mesh->texture.embedded = 1;
int idx = atoi(path.data+1);
if (idx >= 0 && idx < scene->mNumTextures)
{
struct aiTexture *tex = scene->mTextures[idx];
created_mesh->texture.embedded_data = (unsigned char *)tex->pcData;
created_mesh->texture.embedded_len = tex->mWidth;
printf("Created embedded texture %d, data length %d\n", idx, created_mesh->texture.embedded_len);
} else
{
printf("Embedded texture idx out of range\n");
}
} else
{
printf("External texture\n");
created_mesh->texture.texture_id = mesh->mMaterialIndex;
created_mesh->texture.embedded = 0;
char actual_path[4096];
strcpy(actual_path, model_path);
strcat(actual_path, "\\");
strcat(actual_path, path.data);
convert_backslash_to_frontslash(actual_path, 4096);
created_mesh->texture.texture_path = strdup(actual_path);
created_mesh->texture.has_texture = 1;
}
} else
{
printf("mesh %d has no diffuse texture\n", created_mesh->identifier);
created_mesh->texture.has_texture = 0;
}
}
static inline void aimat4x4_to_cglm(const struct aiMatrix4x4 *m, mat4 out)
{
out[0][0] = m->a1; out[0][1] = m->b1; out[0][2] = m->c1; out[0][3] = m->d1;
out[1][0] = m->a2; out[1][1] = m->b2; out[1][2] = m->c2; out[1][3] = m->d2;
out[2][0] = m->a3; out[2][1] = m->b3; out[2][2] = m->c3; out[2][3] = m->d3;
out[3][0] = m->a4; out[3][1] = m->b4; out[3][2] = m->c4; out[3][3] = m->d4;
}
void ProcessAssimpNode(const struct aiScene *scene, const struct aiNode *node, mat4 parentMat, Assimp_mesh **meshes)
{
mat4 local, world; glm_mat4_identity(local); glm_mat4_identity(world);
aimat4x4_to_cglm(&node->mTransformation, local);
glm_mat4_transpose(local);
glm_mat4_mul(local, parentMat, world);
for (size_t i = 0; i < node->mNumMeshes; i++)
{
ProcessAssimpMesh(scene->mMeshes[node->mMeshes[i]], scene, meshes, world);
}
for (size_t i = 0; i < node->mNumChildren; i++)
{
ProcessAssimpNode(scene, node->mChildren[i], world, meshes);
}
}
Assimp_object LoadAssimp(const char *fname)
{
const struct aiScene *scene = aiImportFile(fname,
aiProcess_Triangulate |
aiProcess_CalcTangentSpace |
aiProcess_GenSmoothNormals |
aiProcess_JoinIdenticalVertices |
aiProcess_FlipUVs
);
Assimp_object ass;
Assimp_mesh *meshes = malloc( sizeof(Assimp_mesh) * scene->mNumMeshes );
char model_path[PATH_MAX];
strcpy(model_path, fname);
PathRemoveFileSpecA(model_path);
mat4 test_matrice;
glm_mat4_identity(test_matrice);
//glm_rotate_y(test_matrice, glm_rad(90), test_matrice);
ProcessAssimpNode(scene, scene->mRootNode, test_matrice, &meshes);
for (size_t i = 0; i < scene->mNumMeshes; i++)
{
ProcessMaterialTextures(scene->mMaterials, scene->mMeshes[i], &meshes[i], model_path, scene);
}
ass.meshes = meshes;
ass.n_meshes = scene->mNumMeshes;
aiReleaseImport(scene);
return ass;
}
heres how i create the model to render it
Model_blueprint RendererCreateModelAOS(
GLfloat *vertices, GLsizeiptr vertices_size,
GLint *indices, GLsizeiptr indices_size,
VAOAttribute *vao_attributes, int n_vao_attrs,
char *vertex_shader_path, char *fragment_shader_path
)
{
Model_blueprint model;
model.vertices_size = vertices_size;
model.indices_size = indices_size;
model.vertices = (GLfloat *)malloc(model.vertices_size);
model.indices = (GLint *)malloc(model.indices_size);
if (model.vertices != NULL && model.indices != NULL)
{
memcpy(model.vertices, vertices, model.vertices_size);
memcpy(model.indices, indices, model.indices_size);
} else {printf("Error\n");}
if (model.indices == NULL || model.vertices == NULL)
{
printf("Error\n");
}
char *vertex_shader = LoadShaderFromFile(vertex_shader_path);
char *fragment_shader = LoadShaderFromFile(fragment_shader_path);
GLuint vertex_shader_addr = CreateCompileShader(GL_VERTEX_SHADER, vertex_shader);
GLuint frag_shader_addr = CreateCompileShader(GL_FRAGMENT_SHADER, fragment_shader);
GLuint shaders[2] = {vertex_shader_addr, frag_shader_addr};
GLuint shader_program = ShaderProgramCreateAttachLink(shaders, 2);
DeleteShaders(shaders, 2);
model.shader_program = shader_program;
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
VAOBindVertexArray(VAO);
VBOBindWithData(VBO, model.vertices_size, model.vertices, GL_STATIC_DRAW);
EBOBindWithData(EBO, model.indices_size, model.indices, GL_STATIC_DRAW);
for (size_t i = 0; i < n_vao_attrs; i++)
{
VAOAttribSetAndEnable(vao_attributes[i], VBO);
}
model.VAO = VAO; model.VBO = VBO; model.EBO = EBO;
VBOBindWithData(0, 0, (void *)0, 0);
VAOBindVertexArray(0);
EBOBindWithData(0, 0, (void *)0, 0);
return model;
}
// creates the data for the vbo and ebo
Model_blueprint *RendererCreateModel(Assimp_object ass, char *vertex_shader_path, char *fragment_shader_path)
{
Model_blueprint *models;
models = malloc(sizeof(Model_blueprint) * ass.n_meshes);
VAOAttribute *attribs = VAOCreateVAOAttributeArrays(3);
attribs[0] = (VAOAttribute){0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(0 * sizeof(float))};
attribs[1] = (VAOAttribute){1, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3 * sizeof(float))};
attribs[2] = (VAOAttribute){2, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(5 * sizeof(float))};
printf("Starting to create model\n");
for (size_t i = 0; i < ass.n_meshes; i++)
{
models[i] = RendererCreateModelAOS(
ass.meshes[i].vertices,
ass.meshes[i].vertex_count * sizeof(GLfloat),
ass.meshes[i].indices,
ass.meshes[i].index_count * sizeof(GLuint),
attribs, 3, vertex_shader_path, fragment_shader_path
);
models[i].indices_count = ass.meshes[i].index_count;
models[i].model_name = ass.meshes[i].mesh_name;
glm_mat4_identity(models[i].model);
glm_mat4_copy(ass.meshes[i].transformation, models[i].model);
models[i].texture = 0;
if (ass.meshes[i].texture.has_texture)
{
TextureCreateTexture(&models[i].texture, models[i].shader_program, "tex0", 0, ass.meshes[i].texture.texture_path, ass.meshes[i].texture.embedded, ass.meshes[i].texture);
}
}
return models;
}
heres the rendering loop
while (!glfwWindowShouldClose(window))
{
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glClearColor(0.176, 0.176, 0.188, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Process input
camera_process_keyboard(&cam, window);
camera_process_mouse(&cam, window, WIDTH, HEIGHT);
// Update camera matrices
camera_update_view(&cam);
float aspect = (float)WIDTH/(float)HEIGHT;
camera_update_projection(&cam, 45, aspect, 0.1, 100.0);
glm_mat4_mul(cam.projection, cam.view, camMat);
/*
DRAWING THE MODELS
*/
if (WIREFRAME_MODE)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
for (size_t i = 0; i < n_models; i++)
{
UniformSend4x4Matrix(models[i].shader_program, "camMat", camMat);
UniformSend4x4Matrix(models[i].shader_program, "model", models[i].model);
if (i == selected_model) {
UniformSendVec4(models[i].shader_program, "lightC", selected_color);
} else {
UniformSendVec4(models[i].shader_program, "lightC", c.color);
}
UniformSendVec3(models[i].shader_program, "lightPos", c.position);
if (models[i].texture != 0)
{
TextureBindTexture(models[i], GL_TEXTURE_2D);
}
EBODraw(models[i].indices_count, GL_UNSIGNED_INT, models[i].VAO);
}
UniformSend4x4Matrix(c.shader_program, "camMat", camMat);
UniformSend4x4Matrix(c.shader_program, "model", c.model);
UniformSendVec4(c.shader_program, "lightC", c.color);
EBODraw(ARRAY_LEN(lightIndices), GL_UNSIGNED_INT, c.VAO);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
/*
DRAWING THE GUI
*/
i transform the model in the vertex shader as so
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTex;
layout (location = 2) in vec3 aNormal;
out vec2 texCoord;
out vec3 Normal;
out vec3 currentPos;
uniform mat4 camMat;
uniform mat4 model;
void main()
{
vec4 v4Pos = model * vec4(aPos, 1.0f);
currentPos = v4Pos.xyz;
gl_Position = camMat * v4Pos;
texCoord = aTex;
Normal = mat3(transpose(inverse(model))) * aNormal;
}
any help?
NOTE: i know that i am multiplying the parent and node matrices correctly as if i set a test matrix (glm_rotate_y example) the entire model is rotated correctly, and i know the model cant be broken since other loaders (assimp's viewer, window's model viewer and blender) all load it correctly in the correct pose
but i cant figure out why mine isnt proper, either assimp loads the transforms incorrectly or some other problem in my code