Model computes bone transforms from Animator;

This commit is contained in:
bjorn 2017-11-06 20:25:08 -08:00
parent 33ff7f2b9c
commit 69b5569f9e
8 changed files with 88 additions and 9 deletions

View File

@ -4,6 +4,36 @@
#include "math/vec3.h"
#include <stdlib.h>
static void poseNode(Model* model, int nodeIndex, mat4 transform) {
ModelNode* node = &model->modelData->nodes[nodeIndex];
float globalTransform[16];
mat4_set(globalTransform, transform);
int* boneIndex = map_get(&model->modelData->boneMap, node->name);
if (!boneIndex) {
mat4_multiply(globalTransform, node->transform);
} else {
Bone* bone = &model->modelData->bones.data[*boneIndex];
mat4 finalTransform = model->pose + (*boneIndex * 16);
float localTransform[16];
mat4_identity(localTransform);
lovrAnimatorEvaluate(model->animator, node->name, localTransform);
mat4_multiply(globalTransform, localTransform);
mat4_identity(finalTransform);
mat4_multiply(finalTransform, model->modelData->inverseRootTransform);
mat4_multiply(finalTransform, globalTransform);
mat4_multiply(finalTransform, bone->offset);
}
for (int i = 0; i < node->children.length; i++) {
poseNode(model, node->children.data[i], globalTransform);
}
}
static void renderNode(Model* model, int nodeIndex) {
ModelNode* node = &model->modelData->nodes[nodeIndex];
Material* currentMaterial = lovrGraphicsGetMaterial();
@ -59,6 +89,14 @@ Model* lovrModelCreate(ModelData* modelData) {
vec_push(&format, attribute);
}
if (modelData->hasBones) {
MeshAttribute bones = { .name = "lovrBones", .type = MESH_INT, .count = 4 };
vec_push(&format, bones);
MeshAttribute weights = { .name = "lovrBoneWeights", .type = MESH_FLOAT, .count = 4 };
vec_push(&format, weights);
}
model->mesh = lovrMeshCreate(modelData->vertexCount, &format, MESH_TRIANGLES, MESH_STATIC);
void* data = lovrMeshMap(model->mesh, 0, modelData->vertexCount, false, true);
memcpy(data, modelData->vertices.data, modelData->vertexCount * modelData->stride);
@ -71,6 +109,10 @@ Model* lovrModelCreate(ModelData* modelData) {
model->materials[i] = lovrMaterialCreate(modelData->materials[i], false);
}
for (int i = 0; i < MAX_BONES; i++) {
mat4_identity(model->pose + (16 * i));
}
vec_deinit(&format);
return model;
}
@ -91,6 +133,16 @@ void lovrModelDraw(Model* model, mat4 transform) {
return;
}
if (model->animator) {
float transform[16];
mat4_identity(transform);
poseNode(model, 0, transform);
Shader* shader = lovrGraphicsGetActiveShader();
if (shader) {
lovrShaderSetMatrix(shader, "lovrBoneTransforms", model->pose, MAX_BONES * 16);
}
}
lovrGraphicsPush();
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
renderNode(model, 0);

View File

@ -1,4 +1,5 @@
#include "loaders/model.h"
#include "loaders/animation.h"
#include "graphics/animator.h"
#include "graphics/material.h"
#include "graphics/mesh.h"
@ -16,6 +17,7 @@ typedef struct {
Mesh* mesh;
Material** materials;
Animator* animator;
float pose[MAX_BONES * 16];
float aabb[6];
bool aabbDirty;
} Model;

View File

@ -97,6 +97,8 @@ static GLuint linkShaders(GLuint vertexShader, GLuint fragmentShader) {
glBindAttribLocation(program, LOVR_SHADER_NORMAL, "lovrNormal");
glBindAttribLocation(program, LOVR_SHADER_TEX_COORD, "lovrTexCoord");
glBindAttribLocation(program, LOVR_SHADER_VERTEX_COLOR, "lovrVertexColor");
glBindAttribLocation(program, LOVR_SHADER_BONES, "lovrBones");
glBindAttribLocation(program, LOVR_SHADER_BONE_WEIGHTS, "lovrBoneWeights");
glLinkProgram(program);
int isLinked;
@ -144,6 +146,10 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
float defaultVertexColor[4] = { 1., 1., 1., 1. };
glVertexAttrib4fv(LOVR_SHADER_VERTEX_COLOR, defaultVertexColor);
// Set default bone weights
float defaultBoneWeights[4] = { 1., 0., 0., 0. };
glVertexAttrib4fv(LOVR_SHADER_BONE_WEIGHTS, defaultBoneWeights);
// Uniform introspection
GLint uniformCount;
int textureSlot = 0;

View File

@ -11,6 +11,8 @@
#define LOVR_SHADER_NORMAL 1
#define LOVR_SHADER_TEX_COORD 2
#define LOVR_SHADER_VERTEX_COLOR 3
#define LOVR_SHADER_BONES 4
#define LOVR_SHADER_BONE_WEIGHTS 5
#define LOVR_MAX_UNIFORM_LENGTH 256
typedef enum {

View File

@ -16,10 +16,13 @@ const char* lovrShaderVertexPrefix = ""
#else
"#version 150 \n"
#endif
"#define MAX_BONES 64 \n"
"in vec3 lovrPosition; \n"
"in vec3 lovrNormal; \n"
"in vec2 lovrTexCoord; \n"
"in vec4 lovrVertexColor; \n"
"in ivec4 lovrBones; \n"
"in vec4 lovrBoneWeights; \n"
"out vec2 texCoord; \n"
"out vec4 vertexColor; \n"
"uniform mat4 lovrModel; \n"
@ -28,6 +31,7 @@ const char* lovrShaderVertexPrefix = ""
"uniform mat4 lovrTransform; \n"
"uniform mat3 lovrNormalMatrix; \n"
"uniform float lovrPointSize; \n"
"uniform mat4 lovrBoneTransforms[MAX_BONES]; \n"
"#line 0 \n";
const char* lovrShaderFragmentPrefix = ""
@ -51,8 +55,12 @@ const char* lovrShaderVertexSuffix = ""
"void main() { \n"
" texCoord = lovrTexCoord; \n"
" vertexColor = lovrVertexColor; \n"
" mat4 boneTransform = lovrBoneTransforms[lovrBones[0]] * lovrBoneWeights[0]; \n"
" boneTransform += lovrBoneTransforms[lovrBones[1]] * lovrBoneWeights[1]; \n"
" boneTransform += lovrBoneTransforms[lovrBones[2]] * lovrBoneWeights[2]; \n"
" boneTransform += lovrBoneTransforms[lovrBones[3]] * lovrBoneWeights[3]; \n"
" gl_PointSize = lovrPointSize; \n"
" gl_Position = position(lovrProjection, lovrTransform, vec4(lovrPosition, 1.0)); \n"
" gl_Position = position(lovrProjection, lovrTransform, boneTransform * vec4(lovrPosition, 1.0)); \n"
"}";
const char* lovrShaderFragmentSuffix = ""

View File

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

View File

@ -157,6 +157,10 @@ static void assimpNodeTraversal(ModelData* modelData, struct aiNode* assimpNode,
aiTransposeMatrix4(&m);
mat4_set(node->transform, (float*) &m);
if (currentIndex == 0) {
mat4_invert(mat4_set(modelData->inverseRootTransform, node->transform));
}
// Primitives
vec_init(&node->primitives);
vec_pusharr(&node->primitives, assimpNode->mMeshes, assimpNode->mNumMeshes);
@ -217,14 +221,15 @@ 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->boneByteOffset = modelData->stride;
modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(uint32_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);
memset(modelData->vertices.data, 0, modelData->stride * modelData->vertexCount);
// Load vertices
ModelIndices indices = modelData->indices;
@ -324,7 +329,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
float weight = assimpBone->mWeights[w].mWeight;
ModelVertices vertices = modelData->vertices;
vertices.bytes += vertexIndex * modelData->stride;
uint32_t* bones = (uint32_t*) (vertices.bytes + modelData->boneOffset);
uint32_t* bones = (uint32_t*) (vertices.bytes + modelData->boneByteOffset);
float* weights = (float*) (bones + MAX_BONES_PER_VERTEX);
int boneSlot = 0;
@ -388,10 +393,11 @@ ModelData* lovrModelDataCreate(Blob* blob) {
modelData->animationData = lovrAnimationDataCreate();
for (unsigned int i = 0; i < scene->mNumAnimations; i++) {
struct aiAnimation* assimpAnimation = scene->mAnimations[i];
float ticksPerSecond = assimpAnimation->mTicksPerSecond;
Animation animation;
animation.name = strdup(assimpAnimation->mName.data);
animation.duration = assimpAnimation->mDuration / (float) assimpAnimation->mTicksPerSecond;
animation.duration = assimpAnimation->mDuration / ticksPerSecond;
animation.channelCount = assimpAnimation->mNumChannels;
map_init(&animation.channels);
@ -408,7 +414,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
struct aiVectorKey assimpKeyframe = assimpChannel->mPositionKeys[k];
struct aiVector3D position = assimpKeyframe.mValue;
Keyframe keyframe;
keyframe.time = assimpKeyframe.mTime;
keyframe.time = assimpKeyframe.mTime / ticksPerSecond;
vec3_set(keyframe.data, position.x, position.y, position.z);
vec_push(&channel.positionKeyframes, keyframe);
}
@ -417,7 +423,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
struct aiQuatKey assimpKeyframe = assimpChannel->mRotationKeys[k];
struct aiQuaternion quaternion = assimpKeyframe.mValue;
Keyframe keyframe;
keyframe.time = assimpKeyframe.mTime;
keyframe.time = assimpKeyframe.mTime / ticksPerSecond;
quat_set(keyframe.data, quaternion.x, quaternion.y, quaternion.z, quaternion.w);
vec_push(&channel.rotationKeyframes, keyframe);
}
@ -426,7 +432,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
struct aiVectorKey assimpKeyframe = assimpChannel->mScalingKeys[k];
struct aiVector3D scale = assimpKeyframe.mValue;
Keyframe keyframe;
keyframe.time = assimpKeyframe.mTime;
keyframe.time = assimpKeyframe.mTime / ticksPerSecond;
vec3_set(keyframe.data, scale.x, scale.y, scale.z);
vec_push(&channel.scaleKeyframes, keyframe);
}

View File

@ -62,8 +62,9 @@ typedef struct {
bool hasUVs;
bool hasVertexColors;
bool hasBones;
size_t boneOffset;
size_t boneByteOffset;
size_t stride;
float inverseRootTransform[16];
} ModelData;
ModelData* lovrModelDataCreate(Blob* blob);