Revamped GLTF model loading as it was wrong by default. Also updated some comments.
GLTF models were loaded only by mesh but they should be loaded recursively by hierarchical nodes because tehre are some static node transformations that are to be applied to the vertices. It also resulted in more meshes being included in some models. It is the correct way of loading GLTF and what is suggested in the official examples. Currenlty limiting to only one scene but more can be included later.
This commit is contained in:
parent
718f83c0b1
commit
3501c86b33
507
src/models.c
507
src/models.c
|
|
@ -4158,6 +4158,253 @@ static bool GLTFReadValue(cgltf_accessor* acc, unsigned int index, void *variabl
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ProcessGLTFMesh(cgltf_data *data, cgltf_mesh* mesh, Model* outModel, Matrix currentTransform, int* primitiveIndex, const char* fileName)
|
||||
{
|
||||
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
||||
{
|
||||
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
||||
{
|
||||
if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_position)
|
||||
{
|
||||
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
|
||||
outModel->meshes[(*primitiveIndex)].vertexCount = (int)acc->count;
|
||||
int bufferSize = outModel->meshes[(*primitiveIndex)].vertexCount*3*sizeof(float);
|
||||
outModel->meshes[(*primitiveIndex)].vertices = RL_MALLOC(bufferSize);
|
||||
outModel->meshes[(*primitiveIndex)].animVertices = RL_MALLOC(bufferSize);
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, outModel->meshes[(*primitiveIndex)].vertices + (a*3), 3, sizeof(float));
|
||||
}
|
||||
}
|
||||
else if (acc->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
int readValue[3];
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 3, sizeof(int));
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(a*3) + 0] = (float)readValue[0];
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(a*3) + 1] = (float)readValue[1];
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(a*3) + 2] = (float)readValue[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short vertices
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF vertices must be float or int", fileName);
|
||||
}
|
||||
|
||||
for (unsigned int v = 0; v < outModel->meshes[(*primitiveIndex)].vertexCount; v++)
|
||||
{
|
||||
Vector3 vertex = {
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(v * 3 + 0)],
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(v * 3 + 1)],
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(v * 3 + 2)],
|
||||
};
|
||||
|
||||
vertex = Vector3Transform(vertex, currentTransform);
|
||||
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(v * 3 + 0)] = vertex.x;
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(v * 3 + 1)] = vertex.y;
|
||||
outModel->meshes[(*primitiveIndex)].vertices[(v * 3 + 2)] = vertex.z;
|
||||
}
|
||||
|
||||
memcpy(outModel->meshes[(*primitiveIndex)].animVertices, outModel->meshes[(*primitiveIndex)].vertices, bufferSize);
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_normal)
|
||||
{
|
||||
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
|
||||
|
||||
int bufferSize = (int)(acc->count*3*sizeof(float));
|
||||
outModel->meshes[(*primitiveIndex)].normals = RL_MALLOC(bufferSize);
|
||||
outModel->meshes[(*primitiveIndex)].animNormals = RL_MALLOC(bufferSize);
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, outModel->meshes[(*primitiveIndex)].normals + (a*3), 3, sizeof(float));
|
||||
}
|
||||
}
|
||||
else if (acc->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
int readValue[3];
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 3, sizeof(int));
|
||||
outModel->meshes[(*primitiveIndex)].normals[(a*3) + 0] = (float)readValue[0];
|
||||
outModel->meshes[(*primitiveIndex)].normals[(a*3) + 1] = (float)readValue[1];
|
||||
outModel->meshes[(*primitiveIndex)].normals[(a*3) + 2] = (float)readValue[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short normals
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
|
||||
}
|
||||
|
||||
for (unsigned int v = 0; v < outModel->meshes[(*primitiveIndex)].vertexCount; v++)
|
||||
{
|
||||
Vector3 normal = {
|
||||
outModel->meshes[(*primitiveIndex)].normals[(v * 3 + 0)],
|
||||
outModel->meshes[(*primitiveIndex)].normals[(v * 3 + 1)],
|
||||
outModel->meshes[(*primitiveIndex)].normals[(v * 3 + 2)],
|
||||
};
|
||||
|
||||
normal = Vector3Transform(normal, currentTransform);
|
||||
|
||||
outModel->meshes[(*primitiveIndex)].normals[(v * 3 + 0)] = normal.x;
|
||||
outModel->meshes[(*primitiveIndex)].normals[(v * 3 + 1)] = normal.y;
|
||||
outModel->meshes[(*primitiveIndex)].normals[(v * 3 + 2)] = normal.z;
|
||||
}
|
||||
|
||||
memcpy(outModel->meshes[(*primitiveIndex)].animNormals, outModel->meshes[(*primitiveIndex)].normals, bufferSize);
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_texcoord)
|
||||
{
|
||||
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
outModel->meshes[(*primitiveIndex)].texcoords = RL_MALLOC(acc->count*2*sizeof(float));
|
||||
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, outModel->meshes[(*primitiveIndex)].texcoords + (a*2), 2, sizeof(float));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short texture coordinates
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF texture coordinates must be float", fileName);
|
||||
}
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints)
|
||||
{
|
||||
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
|
||||
LoadGLTFBoneAttribute(outModel, acc, data, *primitiveIndex);
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_weights)
|
||||
{
|
||||
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
|
||||
|
||||
outModel->meshes[(*primitiveIndex)].boneWeights = RL_MALLOC(acc->count*4*sizeof(float));
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, outModel->meshes[(*primitiveIndex)].boneWeights + (a*4), 4, sizeof(float));
|
||||
}
|
||||
}
|
||||
else if (acc->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
unsigned int readValue[4];
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned int));
|
||||
outModel->meshes[(*primitiveIndex)].boneWeights[(a*4) + 0] = (float)readValue[0];
|
||||
outModel->meshes[(*primitiveIndex)].boneWeights[(a*4) + 1] = (float)readValue[1];
|
||||
outModel->meshes[(*primitiveIndex)].boneWeights[(a*4) + 2] = (float)readValue[2];
|
||||
outModel->meshes[(*primitiveIndex)].boneWeights[(a*4) + 3] = (float)readValue[3];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short weights
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
|
||||
}
|
||||
}
|
||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_color)
|
||||
{
|
||||
cgltf_accessor *acc = mesh->primitives[p].attributes[j].data;
|
||||
outModel->meshes[(*primitiveIndex)].colors = RL_MALLOC(acc->count*4*sizeof(unsigned char));
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
for (int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, outModel->meshes[(*primitiveIndex)].colors + (a*4), 4, sizeof(unsigned char));
|
||||
}
|
||||
}
|
||||
if (acc->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] converting glTF colors to unsigned char", fileName);
|
||||
for (int a = 0; a < acc->count; a++)
|
||||
{
|
||||
unsigned short readValue[4];
|
||||
for (int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned short));
|
||||
// 257 = 65535/255
|
||||
outModel->meshes[(*primitiveIndex)].colors[(a*4) + 0] = (unsigned char)(readValue[0]/257);
|
||||
outModel->meshes[(*primitiveIndex)].colors[(a*4) + 1] = (unsigned char)(readValue[1]/257);
|
||||
outModel->meshes[(*primitiveIndex)].colors[(a*4) + 2] = (unsigned char)(readValue[2]/257);
|
||||
outModel->meshes[(*primitiveIndex)].colors[(a*4) + 3] = (unsigned char)(readValue[3]/257);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF colors must be uchar or ushort", fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cgltf_accessor *acc = mesh->primitives[p].indices;
|
||||
LoadGLTFModelIndices(outModel, acc, *primitiveIndex);
|
||||
|
||||
if (mesh->primitives[p].material)
|
||||
{
|
||||
// Compute the offset
|
||||
outModel->meshMaterial[(*primitiveIndex)] = (int)(mesh->primitives[p].material - data->materials);
|
||||
}
|
||||
else
|
||||
{
|
||||
outModel->meshMaterial[(*primitiveIndex)] = outModel->materialCount - 1;
|
||||
}
|
||||
|
||||
BindGLTFPrimitiveToBones(outModel, data, *primitiveIndex);
|
||||
|
||||
(*primitiveIndex) = (*primitiveIndex) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessGLTFNode(cgltf_data *data, cgltf_node* node, Model* outModel, Matrix currentTransform, int* primitiveIndex, const char* fileName)
|
||||
{
|
||||
Matrix nodeTransform = { node->matrix[0], node->matrix[4], node->matrix[8], node->matrix[12],
|
||||
node->matrix[1], node->matrix[5], node->matrix[9], node->matrix[13],
|
||||
node->matrix[2], node->matrix[6], node->matrix[10], node->matrix[14],
|
||||
node->matrix[3], node->matrix[7], node->matrix[11], node->matrix[15] };
|
||||
|
||||
currentTransform = MatrixMultiply(nodeTransform, currentTransform);
|
||||
|
||||
if(node->mesh != NULL)
|
||||
{
|
||||
ProcessGLTFMesh(data, node->mesh, outModel, currentTransform, primitiveIndex, fileName);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < node->children_count; i++)
|
||||
{
|
||||
ProcessGLTFNode(data, node->children[i], outModel, currentTransform, primitiveIndex, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
static void GetPrimitiveCount(cgltf_node* node, int* outCount)
|
||||
{
|
||||
if(node->mesh != NULL)
|
||||
{
|
||||
*outCount += node->mesh->primitives_count;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < node->children_count; i++)
|
||||
{
|
||||
GetPrimitiveCount(node->children[i], outCount);
|
||||
}
|
||||
}
|
||||
|
||||
// LoadGLTF loads in model data from given filename, supporting both .gltf and .glb
|
||||
static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
|
|
@ -4201,10 +4448,13 @@ static Model LoadGLTF(const char *fileName)
|
|||
result = cgltf_load_buffers(&options, data, fileName);
|
||||
if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
|
||||
|
||||
int primitivesCount = 0;
|
||||
if(data->scenes_count > 1) TRACELOG(LOG_INFO, "MODEL: [%s] Has multiple scenes but only the first one will be loaded", fileName);
|
||||
|
||||
for (unsigned int i = 0; i < data->meshes_count; i++)
|
||||
primitivesCount += (int)data->meshes[i].primitives_count;
|
||||
int primitivesCount = 0;
|
||||
for (unsigned int i = 0; i < data->scene->nodes_count; i++)
|
||||
{
|
||||
GetPrimitiveCount(data->scene->nodes[i], &primitivesCount);
|
||||
}
|
||||
|
||||
// Process glTF data and map to model
|
||||
model.meshCount = primitivesCount;
|
||||
|
|
@ -4220,190 +4470,10 @@ static Model LoadGLTF(const char *fileName)
|
|||
LoadGLTFMaterial(&model, fileName, data);
|
||||
|
||||
int primitiveIndex = 0;
|
||||
|
||||
for (unsigned int i = 0; i < data->meshes_count; i++)
|
||||
for(unsigned int i = 0; i < data->scene->nodes_count; i++)
|
||||
{
|
||||
for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++)
|
||||
{
|
||||
for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++)
|
||||
{
|
||||
if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_position)
|
||||
{
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||
model.meshes[primitiveIndex].vertexCount = (int)acc->count;
|
||||
int bufferSize = model.meshes[primitiveIndex].vertexCount*3*sizeof(float);
|
||||
model.meshes[primitiveIndex].vertices = RL_MALLOC(bufferSize);
|
||||
model.meshes[primitiveIndex].animVertices = RL_MALLOC(bufferSize);
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, model.meshes[primitiveIndex].vertices + (a*3), 3, sizeof(float));
|
||||
}
|
||||
}
|
||||
else if (acc->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
int readValue[3];
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 3, sizeof(int));
|
||||
model.meshes[primitiveIndex].vertices[(a*3) + 0] = (float)readValue[0];
|
||||
model.meshes[primitiveIndex].vertices[(a*3) + 1] = (float)readValue[1];
|
||||
model.meshes[primitiveIndex].vertices[(a*3) + 2] = (float)readValue[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short vertices
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF vertices must be float or int", fileName);
|
||||
}
|
||||
|
||||
memcpy(model.meshes[primitiveIndex].animVertices, model.meshes[primitiveIndex].vertices, bufferSize);
|
||||
}
|
||||
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_normal)
|
||||
{
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||
|
||||
int bufferSize = (int)(acc->count*3*sizeof(float));
|
||||
model.meshes[primitiveIndex].normals = RL_MALLOC(bufferSize);
|
||||
model.meshes[primitiveIndex].animNormals = RL_MALLOC(bufferSize);
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, model.meshes[primitiveIndex].normals + (a*3), 3, sizeof(float));
|
||||
}
|
||||
}
|
||||
else if (acc->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
int readValue[3];
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 3, sizeof(int));
|
||||
model.meshes[primitiveIndex].normals[(a*3) + 0] = (float)readValue[0];
|
||||
model.meshes[primitiveIndex].normals[(a*3) + 1] = (float)readValue[1];
|
||||
model.meshes[primitiveIndex].normals[(a*3) + 2] = (float)readValue[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short normals
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
|
||||
}
|
||||
|
||||
memcpy(model.meshes[primitiveIndex].animNormals, model.meshes[primitiveIndex].normals, bufferSize);
|
||||
}
|
||||
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord)
|
||||
{
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
model.meshes[primitiveIndex].texcoords = RL_MALLOC(acc->count*2*sizeof(float));
|
||||
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, model.meshes[primitiveIndex].texcoords + (a*2), 2, sizeof(float));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short texture coordinates
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF texture coordinates must be float", fileName);
|
||||
}
|
||||
}
|
||||
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_joints)
|
||||
{
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||
LoadGLTFBoneAttribute(&model, acc, data, primitiveIndex);
|
||||
}
|
||||
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_weights)
|
||||
{
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||
|
||||
model.meshes[primitiveIndex].boneWeights = RL_MALLOC(acc->count*4*sizeof(float));
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_32f)
|
||||
{
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, model.meshes[primitiveIndex].boneWeights + (a*4), 4, sizeof(float));
|
||||
}
|
||||
}
|
||||
else if (acc->component_type == cgltf_component_type_r_32u)
|
||||
{
|
||||
unsigned int readValue[4];
|
||||
for (unsigned int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned int));
|
||||
model.meshes[primitiveIndex].boneWeights[(a*4) + 0] = (float)readValue[0];
|
||||
model.meshes[primitiveIndex].boneWeights[(a*4) + 1] = (float)readValue[1];
|
||||
model.meshes[primitiveIndex].boneWeights[(a*4) + 2] = (float)readValue[2];
|
||||
model.meshes[primitiveIndex].boneWeights[(a*4) + 3] = (float)readValue[3];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support normalized unsigned byte/unsigned short weights
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
|
||||
}
|
||||
}
|
||||
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_color)
|
||||
{
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||
model.meshes[primitiveIndex].colors = RL_MALLOC(acc->count*4*sizeof(unsigned char));
|
||||
|
||||
if (acc->component_type == cgltf_component_type_r_8u)
|
||||
{
|
||||
for (int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, model.meshes[primitiveIndex].colors + (a*4), 4, sizeof(unsigned char));
|
||||
}
|
||||
}
|
||||
if (acc->component_type == cgltf_component_type_r_16u)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] converting glTF colors to unsigned char", fileName);
|
||||
for (int a = 0; a < acc->count; a++)
|
||||
{
|
||||
unsigned short readValue[4];
|
||||
for (int a = 0; a < acc->count; a++)
|
||||
{
|
||||
GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned short));
|
||||
// 257 = 65535/255
|
||||
model.meshes[primitiveIndex].colors[(a*4) + 0] = (unsigned char)(readValue[0]/257);
|
||||
model.meshes[primitiveIndex].colors[(a*4) + 1] = (unsigned char)(readValue[1]/257);
|
||||
model.meshes[primitiveIndex].colors[(a*4) + 2] = (unsigned char)(readValue[2]/257);
|
||||
model.meshes[primitiveIndex].colors[(a*4) + 3] = (unsigned char)(readValue[3]/257);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF colors must be uchar or ushort", fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cgltf_accessor *acc = data->meshes[i].primitives[p].indices;
|
||||
LoadGLTFModelIndices(&model, acc, primitiveIndex);
|
||||
|
||||
if (data->meshes[i].primitives[p].material)
|
||||
{
|
||||
// Compute the offset
|
||||
model.meshMaterial[primitiveIndex] = (int)(data->meshes[i].primitives[p].material - data->materials);
|
||||
}
|
||||
else
|
||||
{
|
||||
model.meshMaterial[primitiveIndex] = model.materialCount - 1;
|
||||
}
|
||||
|
||||
BindGLTFPrimitiveToBones(&model, data, primitiveIndex);
|
||||
|
||||
primitiveIndex++;
|
||||
}
|
||||
|
||||
Matrix staticTransform = MatrixIdentity();
|
||||
ProcessGLTFNode(data, data->scene->nodes[i], &model, staticTransform, &primitiveIndex, fileName);
|
||||
}
|
||||
|
||||
cgltf_free(data);
|
||||
|
|
@ -4606,12 +4676,12 @@ static void LoadGLTFBoneAttribute(Model *model, cgltf_accessor *jointsAccessor,
|
|||
}
|
||||
|
||||
static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int primitiveIndex)
|
||||
{
|
||||
if (model->meshes[primitiveIndex].boneIds == NULL && data->nodes_count > 0)
|
||||
{
|
||||
for (unsigned int nodeId = 0; nodeId < data->nodes_count; nodeId++)
|
||||
{
|
||||
if (data->nodes[nodeId].mesh == &(data->meshes[primitiveIndex]))
|
||||
{
|
||||
if (model->meshes[primitiveIndex].boneIds == NULL)
|
||||
{
|
||||
model->meshes[primitiveIndex].boneIds = RL_CALLOC(4 * model->meshes[primitiveIndex].vertexCount, sizeof(int));
|
||||
model->meshes[primitiveIndex].boneWeights = RL_CALLOC(4 * model->meshes[primitiveIndex].vertexCount, sizeof(float));
|
||||
|
|
@ -4628,48 +4698,6 @@ static void BindGLTFPrimitiveToBones(Model* model, const cgltf_data* data, int p
|
|||
model->meshes[primitiveIndex].boneIds[b] = 0;
|
||||
model->meshes[primitiveIndex].boneWeights[b] = 0.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vector3 boundVertex = { 0 };
|
||||
Vector3 boundNormal = { 0 };
|
||||
|
||||
Vector3 outTranslation = { 0 };
|
||||
Quaternion outRotation = { 0 };
|
||||
Vector3 outScale = { 0 };
|
||||
|
||||
int vCounter = 0;
|
||||
int boneCounter = 0;
|
||||
int boneId = 0;
|
||||
|
||||
for (int i = 0; i < model->meshes[primitiveIndex].vertexCount; i++)
|
||||
{
|
||||
boneId = model->meshes[primitiveIndex].boneIds[boneCounter];
|
||||
outTranslation = model->bindPose[boneId].translation;
|
||||
outRotation = model->bindPose[boneId].rotation;
|
||||
outScale = model->bindPose[boneId].scale;
|
||||
|
||||
// Vertices processing
|
||||
boundVertex = (Vector3){ model->meshes[primitiveIndex].vertices[vCounter], model->meshes[primitiveIndex].vertices[vCounter + 1], model->meshes[primitiveIndex].vertices[vCounter + 2] };
|
||||
boundVertex = Vector3Multiply(boundVertex, outScale);
|
||||
boundVertex = Vector3RotateByQuaternion(boundVertex, outRotation);
|
||||
boundVertex = Vector3Add(boundVertex, outTranslation);
|
||||
model->meshes[primitiveIndex].vertices[vCounter] = boundVertex.x;
|
||||
model->meshes[primitiveIndex].vertices[vCounter + 1] = boundVertex.y;
|
||||
model->meshes[primitiveIndex].vertices[vCounter + 2] = boundVertex.z;
|
||||
|
||||
// Normals processing
|
||||
if (model->meshes[primitiveIndex].normals != NULL)
|
||||
{
|
||||
boundNormal = (Vector3){ model->meshes[primitiveIndex].normals[vCounter], model->meshes[primitiveIndex].normals[vCounter + 1], model->meshes[primitiveIndex].normals[vCounter + 2] };
|
||||
boundNormal = Vector3RotateByQuaternion(boundNormal, outRotation);
|
||||
model->meshes[primitiveIndex].normals[vCounter] = boundNormal.x;
|
||||
model->meshes[primitiveIndex].normals[vCounter + 1] = boundNormal.y;
|
||||
model->meshes[primitiveIndex].normals[vCounter + 2] = boundNormal.z;
|
||||
}
|
||||
|
||||
vCounter += 3;
|
||||
boneCounter += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4765,9 +4793,9 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
|
|||
for (unsigned int a = 0; a < data->animations_count; a++)
|
||||
{
|
||||
// gltf animation consists of the following structures:
|
||||
// - nodes - bones
|
||||
// - nodes - bones are part of the node system (the whole node system is animatable)
|
||||
// - channels - single transformation type on a single bone
|
||||
// - node - bone
|
||||
// - node - animatable node
|
||||
// - transformation type (path) - translation, rotation, scale
|
||||
// - sampler - animation samples
|
||||
// - input - points in time this transformation happens
|
||||
|
|
@ -4816,10 +4844,16 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
|
|||
|
||||
for (unsigned int i = 0; i < output->boneCount; i++)
|
||||
{
|
||||
output->framePoses[frame][i].translation = Vector3Zero();
|
||||
output->framePoses[frame][i].rotation = QuaternionIdentity();
|
||||
if (data->nodes[i].has_translation) memcpy(&output->framePoses[frame][i].translation, data->nodes[i].translation, 3 * sizeof(float));
|
||||
else output->framePoses[frame][i].translation = Vector3Zero();
|
||||
|
||||
if (data->nodes[i].has_rotation) memcpy(&output->framePoses[frame][i], data->nodes[i].rotation, 4 * sizeof(float));
|
||||
else output->framePoses[frame][i].rotation = QuaternionIdentity();
|
||||
|
||||
output->framePoses[frame][i].rotation = QuaternionNormalize(output->framePoses[frame][i].rotation);
|
||||
output->framePoses[frame][i].scale = Vector3One();
|
||||
|
||||
if (data->nodes[i].has_scale) memcpy(&output->framePoses[frame][i].scale, data->nodes[i].scale, 3 * sizeof(float));
|
||||
else output->framePoses[frame][i].scale = Vector3One();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4891,8 +4925,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
|
|||
|
||||
if (success)
|
||||
{
|
||||
output->framePoses[frame][boneId].rotation = QuaternionLerp(rotationStart, rotationEnd, lerpPercent);
|
||||
output->framePoses[frame][boneId].rotation = QuaternionNormalize(output->framePoses[frame][boneId].rotation);
|
||||
output->framePoses[frame][boneId].rotation = QuaternionNlerp(rotationStart, rotationEnd, lerpPercent);
|
||||
}
|
||||
}
|
||||
if (channel->target_path == cgltf_animation_path_type_scale)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user