mirror of https://github.com/bjornbytes/lovr.git
Model computes bone transforms from Animator;
This commit is contained in:
parent
33ff7f2b9c
commit
69b5569f9e
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define MAX_BONES 64
|
||||
|
||||
typedef struct {
|
||||
double time;
|
||||
float data[4];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue