mirror of
https://github.com/bjornbytes/lovr.git
synced 2024-07-04 21:43:34 +00:00
Subdivide meshes with high bone counts;
This commit is contained in:
parent
5e2c2e0092
commit
1695cc6be1
|
@ -13,13 +13,18 @@ static void renderNode(Model* model, int nodeIndex) {
|
||||||
lovrGraphicsPush();
|
lovrGraphicsPush();
|
||||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, model->nodeTransforms[nodeIndex]);
|
lovrGraphicsMatrixTransform(MATRIX_MODEL, model->nodeTransforms[nodeIndex]);
|
||||||
|
|
||||||
if (model->animator) {
|
|
||||||
float globalInverse[16];
|
float globalInverse[16];
|
||||||
|
if (model->animator) {
|
||||||
mat4_set(globalInverse, model->nodeTransforms[nodeIndex]);
|
mat4_set(globalInverse, model->nodeTransforms[nodeIndex]);
|
||||||
mat4_invert(globalInverse);
|
mat4_invert(globalInverse);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < model->modelData->bones.length; i++) {
|
for (int i = 0; i < node->primitives.length; i++) {
|
||||||
Bone* bone = &model->modelData->bones.data[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);
|
int nodeIndex = *(int*) map_get(&model->modelData->nodeMap, bone->name);
|
||||||
|
|
||||||
mat4 bonePose = model->pose[i];
|
mat4 bonePose = model->pose[i];
|
||||||
|
@ -30,11 +35,10 @@ static void renderNode(Model* model, int nodeIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < node->primitives.length; i++) {
|
|
||||||
ModelPrimitive* primitive = &model->modelData->primitives[node->primitives.data[i]];
|
|
||||||
if (useMaterials) {
|
if (useMaterials) {
|
||||||
lovrGraphicsSetMaterial(model->materials[primitive->material]);
|
lovrGraphicsSetMaterial(model->materials[primitive->material]);
|
||||||
}
|
}
|
||||||
|
|
||||||
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
|
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
|
||||||
lovrMeshDraw(model->mesh, NULL, (float*) model->pose);
|
lovrMeshDraw(model->mesh, NULL, (float*) model->pose);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +83,7 @@ Model* lovrModelCreate(ModelData* modelData) {
|
||||||
vec_push(&format, attribute);
|
vec_push(&format, attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modelData->hasBones) {
|
if (modelData->skinned) {
|
||||||
MeshAttribute bones = { .name = "lovrBones", .type = MESH_INT, .count = 4 };
|
MeshAttribute bones = { .name = "lovrBones", .type = MESH_INT, .count = 4 };
|
||||||
vec_push(&format, bones);
|
vec_push(&format, bones);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ const char* lovrShaderVertexPrefix = ""
|
||||||
#else
|
#else
|
||||||
"#version 150 \n"
|
"#version 150 \n"
|
||||||
#endif
|
#endif
|
||||||
"#define MAX_BONES 64 \n"
|
"#define MAX_BONES 60 \n"
|
||||||
"in vec3 lovrPosition; \n"
|
"in vec3 lovrPosition; \n"
|
||||||
"in vec3 lovrNormal; \n"
|
"in vec3 lovrNormal; \n"
|
||||||
"in vec2 lovrTexCoord; \n"
|
"in vec2 lovrTexCoord; \n"
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MAX_BONES 64
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double time;
|
double time;
|
||||||
float data[4];
|
float data[4];
|
||||||
|
|
|
@ -184,7 +184,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
|
|
||||||
struct aiPropertyStore* propertyStore = aiCreatePropertyStore();
|
struct aiPropertyStore* propertyStore = aiCreatePropertyStore();
|
||||||
aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
|
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);
|
const struct aiScene* scene = aiImportFileExWithProperties(blob->name, flags, &assimpIO, propertyStore);
|
||||||
aiReleasePropertyStore(propertyStore);
|
aiReleasePropertyStore(propertyStore);
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
modelData->hasNormals = false;
|
modelData->hasNormals = false;
|
||||||
modelData->hasUVs = false;
|
modelData->hasUVs = false;
|
||||||
modelData->hasVertexColors = false;
|
modelData->hasVertexColors = false;
|
||||||
modelData->hasBones = false;
|
modelData->skinned = false;
|
||||||
|
|
||||||
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
|
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
|
||||||
struct aiMesh* assimpMesh = scene->mMeshes[m];
|
struct aiMesh* assimpMesh = scene->mMeshes[m];
|
||||||
|
@ -207,7 +207,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
modelData->hasNormals |= assimpMesh->mNormals != NULL;
|
modelData->hasNormals |= assimpMesh->mNormals != NULL;
|
||||||
modelData->hasUVs |= assimpMesh->mTextureCoords[0] != NULL;
|
modelData->hasUVs |= assimpMesh->mTextureCoords[0] != NULL;
|
||||||
modelData->hasVertexColors |= assimpMesh->mColors[0] != NULL;
|
modelData->hasVertexColors |= assimpMesh->mColors[0] != NULL;
|
||||||
modelData->hasBones |= assimpMesh->mNumBones > 0;
|
modelData->skinned |= assimpMesh->mNumBones > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate
|
// Allocate
|
||||||
|
@ -218,14 +218,10 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
modelData->stride += (modelData->hasNormals ? 3 : 0) * sizeof(float);
|
modelData->stride += (modelData->hasNormals ? 3 : 0) * sizeof(float);
|
||||||
modelData->stride += (modelData->hasUVs ? 2 : 0) * sizeof(float);
|
modelData->stride += (modelData->hasUVs ? 2 : 0) * sizeof(float);
|
||||||
modelData->stride += (modelData->hasVertexColors ? 4 : 0) * sizeof(uint8_t);
|
modelData->stride += (modelData->hasVertexColors ? 4 : 0) * sizeof(uint8_t);
|
||||||
modelData->boneByteOffset = modelData->stride;
|
size_t boneByteOffset = modelData->stride;
|
||||||
modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(uint32_t);
|
modelData->stride += (modelData->skinned ? (4 * sizeof(uint32_t) + 4 * sizeof(float)) : 0);
|
||||||
modelData->stride += (modelData->hasBones ? 4 : 0) * sizeof(float);
|
|
||||||
modelData->vertices.data = malloc(modelData->stride * modelData->vertexCount);
|
modelData->vertices.data = malloc(modelData->stride * modelData->vertexCount);
|
||||||
modelData->indices.data = malloc(modelData->indexCount * modelData->indexSize);
|
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);
|
memset(modelData->vertices.data, 0, modelData->stride * modelData->vertexCount);
|
||||||
|
|
||||||
// Load vertices
|
// Load vertices
|
||||||
|
@ -234,9 +230,10 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
|
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
|
||||||
struct aiMesh* assimpMesh = scene->mMeshes[m];
|
struct aiMesh* assimpMesh = scene->mMeshes[m];
|
||||||
modelData->primitives[m].material = assimpMesh->mMaterialIndex;
|
ModelPrimitive* primitive = &modelData->primitives[m];
|
||||||
modelData->primitives[m].drawStart = index;
|
primitive->material = assimpMesh->mMaterialIndex;
|
||||||
modelData->primitives[m].drawCount = 0;
|
primitive->drawStart = index;
|
||||||
|
primitive->drawCount = 0;
|
||||||
uint32_t baseVertex = vertex;
|
uint32_t baseVertex = vertex;
|
||||||
|
|
||||||
// Indices
|
// Indices
|
||||||
|
@ -244,7 +241,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
struct aiFace assimpFace = assimpMesh->mFaces[f];
|
struct aiFace assimpFace = assimpMesh->mFaces[f];
|
||||||
lovrAssert(assimpFace.mNumIndices == 3, "Only triangular faces are supported");
|
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)) {
|
if (modelData->indexSize == sizeof(uint16_t)) {
|
||||||
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
|
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
|
||||||
|
@ -306,27 +303,23 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bones
|
// Bones
|
||||||
|
primitive->boneCount = assimpMesh->mNumBones;
|
||||||
|
map_init(&primitive->boneMap);
|
||||||
for (unsigned int b = 0; b < assimpMesh->mNumBones; b++) {
|
for (unsigned int b = 0; b < assimpMesh->mNumBones; b++) {
|
||||||
struct aiBone* assimpBone = assimpMesh->mBones[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->name = strdup(assimpBone->mName.data);
|
||||||
Bone bone;
|
|
||||||
bone.name = strdup(boneName);
|
|
||||||
aiTransposeMatrix4(&assimpBone->mOffsetMatrix);
|
aiTransposeMatrix4(&assimpBone->mOffsetMatrix);
|
||||||
mat4_set(bone.offset, (float*) &assimpBone->mOffsetMatrix);
|
mat4_set(bone->offset, (float*) &assimpBone->mOffsetMatrix);
|
||||||
map_set(&modelData->boneMap, bone.name, modelData->bones.length);
|
map_set(&primitive->boneMap, bone->name, b);
|
||||||
vec_push(&modelData->bones, bone);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t boneIndex = *map_get(&modelData->boneMap, boneName);
|
|
||||||
|
|
||||||
for (unsigned int w = 0; w < assimpBone->mNumWeights; w++) {
|
for (unsigned int w = 0; w < assimpBone->mNumWeights; w++) {
|
||||||
uint32_t vertexIndex = baseVertex + assimpBone->mWeights[w].mVertexId;
|
uint32_t vertexIndex = baseVertex + assimpBone->mWeights[w].mVertexId;
|
||||||
float weight = assimpBone->mWeights[w].mWeight;
|
float weight = assimpBone->mWeights[w].mWeight;
|
||||||
ModelVertices vertices = modelData->vertices;
|
ModelVertices vertices = modelData->vertices;
|
||||||
vertices.bytes += vertexIndex * modelData->stride;
|
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);
|
float* weights = (float*) (bones + MAX_BONES_PER_VERTEX);
|
||||||
|
|
||||||
int boneSlot = 0;
|
int boneSlot = 0;
|
||||||
|
@ -335,7 +328,7 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
||||||
lovrAssert(boneSlot < MAX_BONES_PER_VERTEX, "Too many bones for vertex %d", vertexIndex);
|
lovrAssert(boneSlot < MAX_BONES_PER_VERTEX, "Too many bones for vertex %d", vertexIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bones[boneSlot] = boneIndex;
|
bones[boneSlot] = b;
|
||||||
weights[boneSlot] = weight;
|
weights[boneSlot] = weight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,6 +444,10 @@ void lovrModelDataDestroy(ModelData* modelData) {
|
||||||
vec_deinit(&modelData->nodes[i].primitives);
|
vec_deinit(&modelData->nodes[i].primitives);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < modelData->primitiveCount; i++) {
|
||||||
|
map_deinit(&modelData->primitives[i].boneMap);
|
||||||
|
}
|
||||||
|
|
||||||
lovrAnimationDataDestroy(modelData->animationData);
|
lovrAnimationDataDestroy(modelData->animationData);
|
||||||
|
|
||||||
for (int i = 0; i < modelData->materialCount; i++) {
|
for (int i = 0; i < modelData->materialCount; i++) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MAX_BONES_PER_VERTEX 4
|
#define MAX_BONES_PER_VERTEX 4
|
||||||
|
#define MAX_BONES 60
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
void* data;
|
void* data;
|
||||||
|
@ -21,10 +22,18 @@ typedef union {
|
||||||
uint32_t* ints;
|
uint32_t* ints;
|
||||||
} ModelIndices;
|
} ModelIndices;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
float offset[16];
|
||||||
|
} Bone;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int material;
|
int material;
|
||||||
int drawStart;
|
int drawStart;
|
||||||
int drawCount;
|
int drawCount;
|
||||||
|
Bone bones[MAX_BONES];
|
||||||
|
map_int_t boneMap;
|
||||||
|
int boneCount;
|
||||||
} ModelPrimitive;
|
} ModelPrimitive;
|
||||||
|
|
||||||
typedef struct ModelNode {
|
typedef struct ModelNode {
|
||||||
|
@ -35,19 +44,10 @@ typedef struct ModelNode {
|
||||||
vec_uint_t primitives;
|
vec_uint_t primitives;
|
||||||
} ModelNode;
|
} ModelNode;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char* name;
|
|
||||||
float offset[16];
|
|
||||||
} Bone;
|
|
||||||
|
|
||||||
typedef vec_t(Bone) vec_bone_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ModelNode* nodes;
|
ModelNode* nodes;
|
||||||
map_int_t nodeMap;
|
map_int_t nodeMap;
|
||||||
ModelPrimitive* primitives;
|
ModelPrimitive* primitives;
|
||||||
vec_bone_t bones;
|
|
||||||
map_int_t boneMap;
|
|
||||||
AnimationData* animationData;
|
AnimationData* animationData;
|
||||||
MaterialData** materials;
|
MaterialData** materials;
|
||||||
ModelVertices vertices;
|
ModelVertices vertices;
|
||||||
|
@ -62,8 +62,7 @@ typedef struct {
|
||||||
bool hasNormals;
|
bool hasNormals;
|
||||||
bool hasUVs;
|
bool hasUVs;
|
||||||
bool hasVertexColors;
|
bool hasVertexColors;
|
||||||
bool hasBones;
|
bool skinned;
|
||||||
size_t boneByteOffset;
|
|
||||||
size_t stride;
|
size_t stride;
|
||||||
} ModelData;
|
} ModelData;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue