From 1695cc6be1b725d5a19b8d4f956914ed15de5d20 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sat, 25 Nov 2017 11:59:27 -0800 Subject: [PATCH] Subdivide meshes with high bone counts; --- src/graphics/model.c | 30 ++++++++++++++----------- src/graphics/shaders.c | 2 +- src/loaders/animation.h | 2 -- src/loaders/model.c | 49 +++++++++++++++++++---------------------- src/loaders/model.h | 21 +++++++++--------- 5 files changed, 51 insertions(+), 53 deletions(-) diff --git a/src/graphics/model.c b/src/graphics/model.c index 7f0a382b..dd2236ae 100644 --- a/src/graphics/model.c +++ b/src/graphics/model.c @@ -13,28 +13,32 @@ static void renderNode(Model* model, int nodeIndex) { lovrGraphicsPush(); lovrGraphicsMatrixTransform(MATRIX_MODEL, model->nodeTransforms[nodeIndex]); + float globalInverse[16]; if (model->animator) { - float globalInverse[16]; mat4_set(globalInverse, model->nodeTransforms[nodeIndex]); mat4_invert(globalInverse); - - for (int i = 0; i < model->modelData->bones.length; i++) { - Bone* bone = &model->modelData->bones.data[i]; - int nodeIndex = *(int*) map_get(&model->modelData->nodeMap, bone->name); - - mat4 bonePose = model->pose[i]; - mat4_identity(bonePose); - mat4_set(bonePose, globalInverse); - mat4_multiply(bonePose, model->nodeTransforms[nodeIndex]); - mat4_multiply(bonePose, bone->offset); - } } for (int i = 0; i < node->primitives.length; i++) { ModelPrimitive* primitive = &model->modelData->primitives[node->primitives.data[i]]; + + if (model->animator) { + for (int i = 0; i < primitive->boneCount; i++) { + Bone* bone = &primitive->bones[i]; + int nodeIndex = *(int*) map_get(&model->modelData->nodeMap, bone->name); + + mat4 bonePose = model->pose[i]; + mat4_identity(bonePose); + mat4_set(bonePose, globalInverse); + mat4_multiply(bonePose, model->nodeTransforms[nodeIndex]); + mat4_multiply(bonePose, bone->offset); + } + } + if (useMaterials) { lovrGraphicsSetMaterial(model->materials[primitive->material]); } + lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount); lovrMeshDraw(model->mesh, NULL, (float*) model->pose); } @@ -79,7 +83,7 @@ Model* lovrModelCreate(ModelData* modelData) { vec_push(&format, attribute); } - if (modelData->hasBones) { + if (modelData->skinned) { MeshAttribute bones = { .name = "lovrBones", .type = MESH_INT, .count = 4 }; vec_push(&format, bones); diff --git a/src/graphics/shaders.c b/src/graphics/shaders.c index b447122a..39ee7ae6 100644 --- a/src/graphics/shaders.c +++ b/src/graphics/shaders.c @@ -16,7 +16,7 @@ const char* lovrShaderVertexPrefix = "" #else "#version 150 \n" #endif -"#define MAX_BONES 64 \n" +"#define MAX_BONES 60 \n" "in vec3 lovrPosition; \n" "in vec3 lovrNormal; \n" "in vec2 lovrTexCoord; \n" diff --git a/src/loaders/animation.h b/src/loaders/animation.h index 16da4980..951cbca2 100644 --- a/src/loaders/animation.h +++ b/src/loaders/animation.h @@ -3,8 +3,6 @@ #pragma once -#define MAX_BONES 64 - typedef struct { double time; float data[4]; diff --git a/src/loaders/model.c b/src/loaders/model.c index d36aae4b..d08a0322 100644 --- a/src/loaders/model.c +++ b/src/loaders/model.c @@ -184,7 +184,7 @@ ModelData* lovrModelDataCreate(Blob* blob) { struct aiPropertyStore* propertyStore = aiCreatePropertyStore(); aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE); - unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_OptimizeGraph | aiProcess_FlipUVs; + unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_OptimizeGraph | aiProcess_FlipUVs | aiProcess_SplitByBoneCount; const struct aiScene* scene = aiImportFileExWithProperties(blob->name, flags, &assimpIO, propertyStore); aiReleasePropertyStore(propertyStore); @@ -198,7 +198,7 @@ ModelData* lovrModelDataCreate(Blob* blob) { modelData->hasNormals = false; modelData->hasUVs = false; modelData->hasVertexColors = false; - modelData->hasBones = false; + modelData->skinned = false; for (unsigned int m = 0; m < scene->mNumMeshes; m++) { struct aiMesh* assimpMesh = scene->mMeshes[m]; @@ -207,7 +207,7 @@ ModelData* lovrModelDataCreate(Blob* blob) { modelData->hasNormals |= assimpMesh->mNormals != NULL; modelData->hasUVs |= assimpMesh->mTextureCoords[0] != NULL; modelData->hasVertexColors |= assimpMesh->mColors[0] != NULL; - modelData->hasBones |= assimpMesh->mNumBones > 0; + modelData->skinned |= assimpMesh->mNumBones > 0; } // Allocate @@ -218,14 +218,10 @@ ModelData* lovrModelDataCreate(Blob* blob) { modelData->stride += (modelData->hasNormals ? 3 : 0) * sizeof(float); modelData->stride += (modelData->hasUVs ? 2 : 0) * sizeof(float); modelData->stride += (modelData->hasVertexColors ? 4 : 0) * sizeof(uint8_t); - modelData->boneByteOffset = modelData->stride; - modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(uint32_t); - modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(float); + size_t boneByteOffset = modelData->stride; + modelData->stride += (modelData->skinned ? (4 * sizeof(uint32_t) + 4 * sizeof(float)) : 0); modelData->vertices.data = malloc(modelData->stride * modelData->vertexCount); modelData->indices.data = malloc(modelData->indexCount * modelData->indexSize); - - vec_init(&modelData->bones); - map_init(&modelData->boneMap); memset(modelData->vertices.data, 0, modelData->stride * modelData->vertexCount); // Load vertices @@ -234,9 +230,10 @@ ModelData* lovrModelDataCreate(Blob* blob) { uint32_t index = 0; for (unsigned int m = 0; m < scene->mNumMeshes; m++) { struct aiMesh* assimpMesh = scene->mMeshes[m]; - modelData->primitives[m].material = assimpMesh->mMaterialIndex; - modelData->primitives[m].drawStart = index; - modelData->primitives[m].drawCount = 0; + ModelPrimitive* primitive = &modelData->primitives[m]; + primitive->material = assimpMesh->mMaterialIndex; + primitive->drawStart = index; + primitive->drawCount = 0; uint32_t baseVertex = vertex; // Indices @@ -244,7 +241,7 @@ ModelData* lovrModelDataCreate(Blob* blob) { struct aiFace assimpFace = assimpMesh->mFaces[f]; lovrAssert(assimpFace.mNumIndices == 3, "Only triangular faces are supported"); - modelData->primitives[m].drawCount += assimpFace.mNumIndices; + primitive->drawCount += assimpFace.mNumIndices; if (modelData->indexSize == sizeof(uint16_t)) { for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) { @@ -306,27 +303,23 @@ ModelData* lovrModelDataCreate(Blob* blob) { } // Bones + primitive->boneCount = assimpMesh->mNumBones; + map_init(&primitive->boneMap); for (unsigned int b = 0; b < assimpMesh->mNumBones; b++) { struct aiBone* assimpBone = assimpMesh->mBones[b]; - const char* boneName = assimpBone->mName.data; + Bone* bone = &primitive->bones[b]; - if (!map_get(&modelData->boneMap, boneName)) { - Bone bone; - bone.name = strdup(boneName); - aiTransposeMatrix4(&assimpBone->mOffsetMatrix); - mat4_set(bone.offset, (float*) &assimpBone->mOffsetMatrix); - map_set(&modelData->boneMap, bone.name, modelData->bones.length); - vec_push(&modelData->bones, bone); - } - - uint32_t boneIndex = *map_get(&modelData->boneMap, boneName); + bone->name = strdup(assimpBone->mName.data); + aiTransposeMatrix4(&assimpBone->mOffsetMatrix); + mat4_set(bone->offset, (float*) &assimpBone->mOffsetMatrix); + map_set(&primitive->boneMap, bone->name, b); for (unsigned int w = 0; w < assimpBone->mNumWeights; w++) { uint32_t vertexIndex = baseVertex + assimpBone->mWeights[w].mVertexId; float weight = assimpBone->mWeights[w].mWeight; ModelVertices vertices = modelData->vertices; vertices.bytes += vertexIndex * modelData->stride; - uint32_t* bones = (uint32_t*) (vertices.bytes + modelData->boneByteOffset); + uint32_t* bones = (uint32_t*) (vertices.bytes + boneByteOffset); float* weights = (float*) (bones + MAX_BONES_PER_VERTEX); int boneSlot = 0; @@ -335,7 +328,7 @@ ModelData* lovrModelDataCreate(Blob* blob) { lovrAssert(boneSlot < MAX_BONES_PER_VERTEX, "Too many bones for vertex %d", vertexIndex); } - bones[boneSlot] = boneIndex; + bones[boneSlot] = b; weights[boneSlot] = weight; } } @@ -451,6 +444,10 @@ void lovrModelDataDestroy(ModelData* modelData) { vec_deinit(&modelData->nodes[i].primitives); } + for (int i = 0; i < modelData->primitiveCount; i++) { + map_deinit(&modelData->primitives[i].boneMap); + } + lovrAnimationDataDestroy(modelData->animationData); for (int i = 0; i < modelData->materialCount; i++) { diff --git a/src/loaders/model.h b/src/loaders/model.h index 8284e3ee..311cc686 100644 --- a/src/loaders/model.h +++ b/src/loaders/model.h @@ -7,6 +7,7 @@ #pragma once #define MAX_BONES_PER_VERTEX 4 +#define MAX_BONES 60 typedef union { void* data; @@ -21,10 +22,18 @@ typedef union { uint32_t* ints; } ModelIndices; +typedef struct { + const char* name; + float offset[16]; +} Bone; + typedef struct { int material; int drawStart; int drawCount; + Bone bones[MAX_BONES]; + map_int_t boneMap; + int boneCount; } ModelPrimitive; typedef struct ModelNode { @@ -35,19 +44,10 @@ typedef struct ModelNode { vec_uint_t primitives; } ModelNode; -typedef struct { - const char* name; - float offset[16]; -} Bone; - -typedef vec_t(Bone) vec_bone_t; - typedef struct { ModelNode* nodes; map_int_t nodeMap; ModelPrimitive* primitives; - vec_bone_t bones; - map_int_t boneMap; AnimationData* animationData; MaterialData** materials; ModelVertices vertices; @@ -62,8 +62,7 @@ typedef struct { bool hasNormals; bool hasUVs; bool hasVertexColors; - bool hasBones; - size_t boneByteOffset; + bool skinned; size_t stride; } ModelData;