Load animations in model loader;

This commit is contained in:
bjorn 2017-11-01 23:10:21 -07:00
parent 28dec31e18
commit 6a6c322eaa
2 changed files with 125 additions and 5 deletions

View File

@ -3,6 +3,7 @@
#include "filesystem/file.h"
#include "math/math.h"
#include "math/mat4.h"
#include "math/quat.h"
#include "math/vec3.h"
#include <limits.h>
#include <stdlib.h>
@ -149,6 +150,7 @@ static void assimpSumChildren(struct aiNode* assimpNode, int* totalChildren) {
static void assimpNodeTraversal(ModelData* modelData, struct aiNode* assimpNode, int* nodeId) {
int currentIndex = *nodeId;
ModelNode* node = &modelData->nodes[currentIndex];
node->name = strndup(assimpNode->mName.data, assimpNode->mName.length);
// Transform
struct aiMatrix4x4 m = assimpNode->mTransformation;
@ -195,6 +197,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
modelData->hasNormals = false;
modelData->hasUVs = false;
modelData->hasVertexColors = false;
modelData->hasBones = false;
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
struct aiMesh* assimpMesh = scene->mMeshes[m];
@ -203,6 +206,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;
}
// Allocate
@ -213,19 +217,25 @@ 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->boneOffset = modelData->stride;
modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(uint8_t);
modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(float);
modelData->vertices.data = malloc(modelData->stride * modelData->vertexCount);
modelData->indices.data = malloc(modelData->indexCount * modelData->indexSize);
vec_init(&modelData->bones);
map_init(&modelData->boneMap);
// Load vertices
ModelVertices vertices = modelData->vertices;
ModelIndices indices = modelData->indices;
int vertex = 0;
int index = 0;
uint32_t vertex = 0;
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;
uint32_t baseVertex = vertex;
// Indices
for (unsigned int f = 0; f < assimpMesh->mNumFaces; f++) {
@ -236,16 +246,20 @@ ModelData* lovrModelDataCreate(Blob* blob) {
if (modelData->indexSize == sizeof(uint16_t)) {
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
indices.shorts[index++] = vertex + assimpFace.mIndices[i];
indices.shorts[index++] = baseVertex + assimpFace.mIndices[i];
}
} else {
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
indices.ints[index++] = vertex + assimpFace.mIndices[i];
indices.ints[index++] = baseVertex + assimpFace.mIndices[i];
}
}
}
// Vertices
for (unsigned int v = 0; v < assimpMesh->mNumVertices; v++) {
ModelVertices vertices = modelData->vertices;
vertices.bytes += vertex * modelData->stride;
*vertices.floats++ = assimpMesh->mVertices[v].x;
*vertices.floats++ = assimpMesh->mVertices[v].y;
*vertices.floats++ = assimpMesh->mVertices[v].z;
@ -288,6 +302,41 @@ ModelData* lovrModelDataCreate(Blob* blob) {
vertex++;
}
// Bones
for (unsigned int b = 0; b < assimpMesh->mNumBones; b++) {
struct aiBone* assimpBone = assimpMesh->mBones[b];
const char* boneName = assimpBone->mName.data;
if (!map_get(&modelData->boneMap, boneName)) {
Bone bone;
bone.name = strndup(boneName, assimpBone->mName.length);
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);
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->boneOffset);
float* weights = (float*) (bones + MAX_BONES_PER_VERTEX);
int boneSlot = 0;
while (weights[boneSlot] > 0) {
boneSlot++;
lovrAssert(boneSlot < MAX_BONES_PER_VERTEX, "Too many bones for vertex %d", vertexIndex);
}
bones[boneSlot] = boneIndex;
weights[boneSlot] = weight;
}
}
}
// Materials
@ -330,6 +379,56 @@ ModelData* lovrModelDataCreate(Blob* blob) {
int nodeIndex = 0;
assimpNodeTraversal(modelData, scene->mRootNode, &nodeIndex);
// Animations
modelData->animationCount = scene->mNumAnimations;
modelData->animations = malloc(modelData->animationCount * sizeof(AnimationData*));
for (int i = 0; i < modelData->animationCount; i++) {
struct aiAnimation* assimpAnimation = scene->mAnimations[i];
AnimationData* animationData = lovrAnimationDataCreate(assimpAnimation->mName.data);
animationData->channelCount = assimpAnimation->mNumChannels;
for (int j = 0; j < animationData->channelCount; j++) {
struct aiNodeAnim* assimpChannel = assimpAnimation->mChannels[j];
AnimationChannel channel;
channel.node = strndup(assimpChannel->mNodeName.data, assimpChannel->mNodeName.length);
vec_init(&channel.positionKeyframes);
vec_init(&channel.rotationKeyframes);
vec_init(&channel.scaleKeyframes);
for (unsigned int k = 0; k < assimpChannel->mNumPositionKeys; k++) {
struct aiVectorKey assimpKeyframe = assimpChannel->mPositionKeys[k];
struct aiVector3D position = assimpKeyframe.mValue;
Keyframe keyframe;
keyframe.time = assimpKeyframe.mTime;
vec3_set(keyframe.data, position.x, position.y, position.z);
vec_push(&channel.positionKeyframes, keyframe);
}
for (unsigned int k = 0; k < assimpChannel->mNumRotationKeys; k++) {
struct aiQuatKey assimpKeyframe = assimpChannel->mRotationKeys[k];
struct aiQuaternion quaternion = assimpKeyframe.mValue;
Keyframe keyframe;
keyframe.time = assimpKeyframe.mTime;
quat_set(keyframe.data, quaternion.x, quaternion.y, quaternion.z, quaternion.w);
vec_push(&channel.rotationKeyframes, keyframe);
}
for (unsigned int k = 0; k < assimpChannel->mNumScalingKeys; k++) {
struct aiVectorKey assimpKeyframe = assimpChannel->mScalingKeys[k];
struct aiVector3D scale = assimpKeyframe.mValue;
Keyframe keyframe;
keyframe.time = assimpKeyframe.mTime;
vec3_set(keyframe.data, scale.x, scale.y, scale.z);
vec_push(&channel.scaleKeyframes, keyframe);
}
map_set(&animationData->channels, channel.node, channel);
}
modelData->animations[i] = animationData;
}
aiReleaseImport(scene);
return modelData;
}
@ -340,6 +439,10 @@ void lovrModelDataDestroy(ModelData* modelData) {
vec_deinit(&modelData->nodes[i].primitives);
}
for (int i = 0; i < modelData->animationCount; i++) {
lovrAnimationDataDestroy(modelData->animations[i]);
}
for (int i = 0; i < modelData->materialCount; i++) {
lovrMaterialDataDestroy(&modelData->materials[i]);
}

View File

@ -1,10 +1,13 @@
#include "filesystem/blob.h"
#include "loaders/animation.h"
#include "loaders/material.h"
#include "util.h"
#include "lib/vec/vec.h"
#pragma once
#define MAX_BONES_PER_VERTEX 4
typedef union {
void* data;
uint8_t* bytes;
@ -25,20 +28,32 @@ typedef struct {
} ModelPrimitive;
typedef struct ModelNode {
const char* name;
float transform[16];
int parent;
vec_uint_t children;
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;
ModelPrimitive* primitives;
vec_bone_t bones;
map_int_t boneMap;
AnimationData** animations;
MaterialData* materials;
ModelVertices vertices;
ModelIndices indices;
int nodeCount;
int primitiveCount;
int animationCount;
int materialCount;
int vertexCount;
int indexCount;
@ -46,6 +61,8 @@ typedef struct {
bool hasNormals;
bool hasUVs;
bool hasVertexColors;
bool hasBones;
size_t boneOffset;
size_t stride;
} ModelData;