Subdivide meshes with high bone counts;

This commit is contained in:
bjorn 2017-11-25 11:59:27 -08:00
parent 5e2c2e0092
commit 1695cc6be1
5 changed files with 51 additions and 53 deletions

View File

@ -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);

View File

@ -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"

View File

@ -3,8 +3,6 @@
#pragma once
#define MAX_BONES 64
typedef struct {
double time;
float data[4];

View File

@ -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++) {

View File

@ -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;