- add primitive glTF scene support

- fix: glTF material color not correctly loaded
This commit is contained in:
Roy Qu 2022-01-21 18:18:37 +08:00
parent 0ab7bc28f2
commit b52d99f56a
3 changed files with 180 additions and 32 deletions

View File

@ -614,6 +614,7 @@ struct cgltf_node {
cgltf_node** children;
cgltf_size children_count;
cgltf_skin* skin;
int mesh_id;
cgltf_mesh* mesh;
cgltf_camera* camera;
cgltf_light* light;
@ -635,6 +636,7 @@ struct cgltf_node {
typedef struct cgltf_scene {
char* name;
cgltf_node** nodes;
int* node_ids;
cgltf_size nodes_count;
cgltf_extras extras;
cgltf_size extensions_count;
@ -1930,6 +1932,7 @@ void cgltf_free(cgltf_data* data)
{
data->memory.free(data->memory.user_data, data->scenes[i].name);
data->memory.free(data->memory.user_data, data->scenes[i].nodes);
data->memory.free(data->memory.user_data, data->scenes[i].node_ids);
cgltf_free_extensions(data, data->scenes[i].extensions, data->scenes[i].extensions_count);
}
@ -5066,7 +5069,8 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens
{
++i;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
out_node->mesh = CGLTF_PTRINDEX(cgltf_mesh, cgltf_json_to_int(tokens + i, json_chunk));
out_node->mesh_id = cgltf_json_to_int(tokens + i, json_chunk);
out_node->mesh = CGLTF_PTRINDEX(cgltf_mesh, out_node->mesh_id);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "skin") == 0)
@ -5239,9 +5243,12 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token
{
return i;
}
int size = out_scene->nodes_count * sizeof(int);
out_scene->node_ids = (int *)options->memory.alloc(options->memory.user_data, size);
for (cgltf_size k = 0; k < out_scene->nodes_count; ++k)
{
out_scene->node_ids[k] = cgltf_json_to_int(tokens + i, json_chunk);
out_scene->nodes[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
++i;
}

View File

@ -366,11 +366,23 @@ typedef struct Transform {
Vector3 scale; // Scale
} Transform;
// Mode Node
typedef struct ModelNode {
/* Don't support node hierarchy for now
struct ModelNode *parent; // Parent nodes;
struct ModelNode *children; // Children nodes array;
*/
// every primitive in the glTF as a separate raylib mesh, so we need to covert mesh id in glTF to interval
int meshStart; // Start position of the interval in the model mesh array;
int meshEnd; // End position of the interval in the model mesh array;
Transform transform; // Transform for node meshes;
Matrix transformMatrix; // Transform matrix for node meshes;
} ModelNode;
// Scene
typedef struct Scene {
int meshCount; // Number of meshes
int *meshes; // Scene meshes array
Transform *meshTransforms; // transform matrices for meshes
int nodeCount; // Number of nodes
int *nodes; // Scene nodes array
} Scene;
// Bone, skeletal animation bone
@ -389,7 +401,9 @@ typedef struct Model {
Material *materials; // Materials array
int *meshMaterial; // Mesh material number
// Scene data
// Scene and node data
int nodeCount; // Number of nodes;
ModelNode *nodes; // Nodes array;
int sceneCount; // Number of scenes
Scene *scenes; // Scenes array
int scene; // Scene should be displayed
@ -1426,6 +1440,10 @@ RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, floa
RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set)
RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
RLAPI void DrawModelScene(Model model, int scene_id, Vector3 position, float scale, Color tint); // Draw a model's scene (with texture if set)
RLAPI void DrawModelSceneEx(Model model, int scene_id, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model's scene with extended parameters
RLAPI void DrawModelSceneWires(Model model, int scene_id, Vector3 position, float scale, Color tint); // Draw a model's scene wires (with texture if set)
RLAPI void DrawModelSceneWiresEx(Model model, int scene_id, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model's scene wires (with texture if set) with extended parameters
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation

View File

@ -1005,6 +1005,11 @@ void UnloadModel(Model model)
RL_FREE(model.materials);
RL_FREE(model.meshMaterial);
// Unload scenes and nodes
RL_FREE(model.nodes);
for (int i = 0; i < model.sceneCount; i++) RL_FREE(model.scenes[i].nodes);
RL_FREE(model.scenes);
// Unload animation data
RL_FREE(model.bones);
RL_FREE(model.bindPose);
@ -3278,9 +3283,12 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
// Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
model.transform = MatrixMultiply(model.transform, matTransform);
for (int i = 0; i < model.meshCount; i++)
{
if (model.scene >= 0
&& model.scene < model.sceneCount
&& model.scenes[model.scene].nodeCount>0) { // we have a scene to draw
DrawModelSceneEx(model, model.scene, position, rotationAxis, rotationAngle, scale, tint);
} else {
for (int i = 0; i < model.meshCount; i++) {
Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
Color colorTint = WHITE;
@ -3294,6 +3302,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
}
}
}
// Draw a model wires (with texture if set)
void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
@ -3315,6 +3324,69 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
rlDisableWireMode();
}
// Draw a model (with texture if set)
void DrawModelScene(Model model, int scene_id, Vector3 position, float scale, Color tint)
{
Vector3 vScale = { scale, scale, scale };
Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
DrawModelSceneEx(model, scene_id, position, rotationAxis, 0.0f, vScale, tint);
}
// Draw a model with extended parameters
void DrawModelSceneEx(Model model, int scene_id, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
// Calculate transformation matrix from function parameters
// Get transform matrix (rotation -> scale -> translation)
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
// Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
model.transform = MatrixMultiply(model.transform, matTransform);
if (scene_id >= 0
&& scene_id < model.sceneCount) {
for (int i = 0; i < model.scenes[scene_id].nodeCount; i++) {
int node_id = model.scenes[scene_id].nodes[i];
Matrix transform = MatrixMultiply(model.transform, model.nodes[node_id].transformMatrix);
for (int j = model.nodes[node_id].meshStart; j < model.nodes[node_id].meshEnd; j++) {
Color color = model.materials[model.meshMaterial[j]].maps[MATERIAL_MAP_DIFFUSE].color;
Color colorTint = WHITE;
colorTint.r = (unsigned char) ((((float) color.r / 255.0) * ((float) tint.r / 255.0)) * 255.0f);
colorTint.g = (unsigned char) ((((float) color.g / 255.0) * ((float) tint.g / 255.0)) * 255.0f);
colorTint.b = (unsigned char) ((((float) color.b / 255.0) * ((float) tint.b / 255.0)) * 255.0f);
colorTint.a = (unsigned char) ((((float) color.a / 255.0) * ((float) tint.a / 255.0)) * 255.0f);
model.materials[model.meshMaterial[j]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
DrawMesh(model.meshes[j], model.materials[model.meshMaterial[i]], transform);
model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
}
}
}
}
// Draw a model wires (with texture if set)
void DrawModelSceneWires(Model model, int scene_id, Vector3 position, float scale, Color tint)
{
rlEnableWireMode();
DrawModelScene(model, scene_id, position, scale, tint);
rlDisableWireMode();
}
// Draw a model wires (with texture if set) with extended parameters
void DrawModelSceneWiresEx(Model model, int scene_id, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
rlEnableWireMode();
DrawModelSceneEx(model, scene_id, position, rotationAxis, rotationAngle, scale, tint);
rlDisableWireMode();
}
// Draw a billboard
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint)
{
@ -4626,6 +4698,8 @@ static Model LoadGLTF(const char *fileName)
}
Model model = { 0 };
int *mesh_id_starts = NULL;
int *mesh_id_ends = NULL;
// glTF file loading
unsigned int dataSize = 0;
@ -4649,6 +4723,7 @@ static Model LoadGLTF(const char *fileName)
TRACELOG(LOG_DEBUG, " > Buffers count: %i", data->buffers_count);
TRACELOG(LOG_DEBUG, " > Images count: %i", data->images_count);
TRACELOG(LOG_DEBUG, " > Textures count: %i", data->textures_count);
TRACELOG(LOG_DEBUG, " > Nodes count: %1", data->nodes_count);
TRACELOG(LOG_DEBUG, " > Scenes count: %1", data->scenes_count);
// Force reading data buffers (fills buffer_view->buffer->data)
@ -4662,6 +4737,8 @@ static Model LoadGLTF(const char *fileName)
// Load our model data: meshes and materials
model.meshCount = primitivesCount;
mesh_id_starts = RL_CALLOC(data->meshes_count, sizeof(int));
mesh_id_ends = RL_CALLOC(data->meshes_count, sizeof(int));
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int*)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
@ -4694,12 +4771,12 @@ static Model LoadGLTF(const char *fileName)
UnloadImage(imAlbedo);
}
}
// Load base color factor (tint)
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
}
// Load metallic/roughness texture
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
@ -4768,7 +4845,7 @@ static Model LoadGLTF(const char *fileName)
for (unsigned int i = 0, meshIndex = 0; i < data->meshes_count; i++)
{
// NOTE: meshIndex accumulates primitives
mesh_id_starts[i]=meshIndex;
for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++)
{
// NOTE: We only support primitives defined by triangles
@ -4942,21 +5019,65 @@ static Model LoadGLTF(const char *fileName)
meshIndex++; // Move to next mesh
}
mesh_id_ends[i] = meshIndex;
}
// Load node data
model.nodeCount = data->nodes_count;
model.nodes = RL_CALLOC(data->nodes_count, sizeof(ModelNode));
memset(model.nodes,0,data->nodes_count * sizeof(ModelNode));
for (unsigned int i = 0; i < data->nodes_count; i++) {
model.nodes[i].meshStart = mesh_id_starts[data->nodes[i].mesh_id];
model.nodes[i].meshEnd = mesh_id_ends[data->nodes[i].mesh_id];
Matrix matScale;
Matrix matRotation;
Matrix matTranslation;
if (data->nodes[i].has_translation) {
model.nodes[i].transform.translation.x = data->nodes[i].translation[0];
model.nodes[i].transform.translation.y = data->nodes[i].translation[1];
model.nodes[i].transform.translation.z = data->nodes[i].translation[2];
matTranslation = MatrixTranslate(model.nodes[i].transform.translation.x,
model.nodes[i].transform.translation.y,
model.nodes[i].transform.translation.z);
} else
matTranslation = MatrixIdentity();
if (data->nodes[i].has_rotation) {
model.nodes[i].transform.rotation.x = data->nodes[i].rotation[0];
model.nodes[i].transform.rotation.y = data->nodes[i].rotation[1];
model.nodes[i].transform.rotation.z = data->nodes[i].rotation[2];
model.nodes[i].transform.rotation.w = data->nodes[i].rotation[3];
matRotation = QuaternionToMatrix(model.nodes[i].transform.rotation);
} else
matRotation = MatrixIdentity();
if (data->nodes[i].has_scale) {
model.nodes[i].transform.scale.x = data->nodes[i].scale[0];
model.nodes[i].transform.scale.y = data->nodes[i].scale[1];
model.nodes[i].transform.scale.z = data->nodes[i].scale[2];
matScale = MatrixScale(model.nodes[i].transform.scale.x,
model.nodes[i].transform.scale.y,
model.nodes[i].transform.scale.z);
} else {
model.nodes[i].transform.scale.x = 1;
model.nodes[i].transform.scale.y = 1;
model.nodes[i].transform.scale.z = 1;
matScale = MatrixIdentity();
}
model.nodes[i].transformMatrix = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
}
// Load scene data
if (data->scenes_count > 0) {
model.scene = data->scene_id;
model.scenes = (Scene *)malloc(sizeof(Scene) * data->scenes_count);
model.sceneCount = data->scenes_count;
model.scenes = RL_CALLOC(data->scenes_count, sizeof(Scene));
memset(model.scenes, 0, sizeof(Scene) * data->scenes_count);
for (unsigned int i = 0; i < data->scenes_count; i++) {
// TODO: for each nodes, find
if (data->scenes[i].nodes_count>0) {
for (unsigned int j = 0; j < data->scenes[i].nodes_count; j++) {
scenes
}
}
model.scenes[i].nodeCount = data->scenes[i].nodes_count;
model.scenes[i].nodes = RL_CALLOC(data->scenes[i].nodes_count, sizeof(int));
for (unsigned int j = 0; j < data->scenes[i].nodes_count; j++)
model.scenes[i].nodes[j] = data->scenes[i].node_ids[j];
}
}
@ -5010,6 +5131,8 @@ static Model LoadGLTF(const char *fileName)
}
}
*/
RL_FREE(mesh_id_starts);
RL_FREE(mesh_id_ends);
// Free all cgltf loaded data
cgltf_free(data);
}