1
0
Fork 0
mirror of https://github.com/bjornbytes/lovr.git synced 2024-07-04 21:43:34 +00:00

Model loads blend shape data and weights;

This commit is contained in:
bjorn 2023-03-14 19:36:09 -07:00
parent 21bb3eb096
commit b1b78319b5
3 changed files with 125 additions and 24 deletions

View file

@ -60,7 +60,7 @@ void lovrModelDataDestroy(void* ref) {
free(model); free(model);
} }
// Note: this code is a scary optimization // Batches allocations for all the ModelData arrays
void lovrModelDataAllocate(ModelData* model) { void lovrModelDataAllocate(ModelData* model) {
size_t totalSize = 0; size_t totalSize = 0;
size_t sizes[15]; size_t sizes[15];
@ -130,6 +130,8 @@ void lovrModelDataFinalize(ModelData* model) {
model->skins[primitive->skin].vertexCount += vertexCount; model->skins[primitive->skin].vertexCount += vertexCount;
model->skinnedVertexCount += vertexCount; model->skinnedVertexCount += vertexCount;
} }
model->blendShapeVertexCount += vertexCount * primitive->blendShapeCount;
model->dynamicVertexCount += primitive->skin != ~0u || primitive->blendShapeCount > 0 ? vertexCount : 0;
model->vertexCount += vertexCount; model->vertexCount += vertexCount;
model->indexCount += primitive->indices ? primitive->indices->count : 0; model->indexCount += primitive->indices ? primitive->indices->count : 0;

View file

@ -214,6 +214,8 @@ typedef struct ModelData {
uint32_t vertexCount; uint32_t vertexCount;
uint32_t skinnedVertexCount; uint32_t skinnedVertexCount;
uint32_t blendShapeVertexCount;
uint32_t dynamicVertexCount;
uint32_t indexCount; uint32_t indexCount;
AttributeType indexType; AttributeType indexType;

View file

@ -189,6 +189,13 @@ typedef struct {
float properties[3][4]; float properties[3][4];
} NodeTransform; } NodeTransform;
typedef struct {
uint32_t node;
uint32_t count;
uint32_t vertexStart;
uint32_t vertexCount;
} BlendGroup;
struct Model { struct Model {
uint32_t ref; uint32_t ref;
ModelInfo info; ModelInfo info;
@ -196,12 +203,17 @@ struct Model {
Buffer* rawVertexBuffer; Buffer* rawVertexBuffer;
Buffer* vertexBuffer; Buffer* vertexBuffer;
Buffer* indexBuffer; Buffer* indexBuffer;
Buffer* blendBuffer;
Buffer* skinBuffer; Buffer* skinBuffer;
Texture** textures; Texture** textures;
Material** materials; Material** materials;
NodeTransform* localTransforms; NodeTransform* localTransforms;
float* globalTransforms; float* globalTransforms;
bool transformsDirty; bool transformsDirty;
float* blendShapeWeights;
float** nodeWeights;
BlendGroup* blendGroups;
uint32_t blendGroupCount;
uint32_t lastReskin; uint32_t lastReskin;
}; };
@ -2765,6 +2777,10 @@ Model* lovrModelCreate(const ModelInfo* info) {
model->info = *info; model->info = *info;
lovrRetain(info->data); lovrRetain(info->data);
for (uint32_t i = 0; i < data->skinCount; i++) {
lovrCheck(data->skins[i].jointCount <= 256, "Currently, the max number of joints per skin is 256");
}
// Materials and Textures // Materials and Textures
model->textures = calloc(data->imageCount, sizeof(Texture*)); model->textures = calloc(data->imageCount, sizeof(Texture*));
model->materials = malloc(data->materialCount * sizeof(Material*)); model->materials = malloc(data->materialCount * sizeof(Material*));
@ -2815,8 +2831,9 @@ Model* lovrModelCreate(const ModelInfo* info) {
} }
// Buffers // Buffers
char* vertices = NULL; char* vertexData = NULL;
char* indices = NULL; char* indexData = NULL;
char* blendData = NULL;
char* skinData = NULL; char* skinData = NULL;
BufferField vertexFormat[] = { BufferField vertexFormat[] = {
@ -2836,7 +2853,24 @@ Model* lovrModelCreate(const ModelInfo* info) {
.fieldCount = COUNTOF(vertexFormat) .fieldCount = COUNTOF(vertexFormat)
}; };
model->vertexBuffer = lovrBufferCreate(&vertexBufferInfo, (void**) &vertices); model->vertexBuffer = lovrBufferCreate(&vertexBufferInfo, (void**) &vertexData);
if (data->blendShapeVertexCount > 0) {
BufferField blendFormat[] = {
{ .length = data->blendShapeVertexCount, .stride = 9 * sizeof(float) },
{ .type = FIELD_F32x3, .offset = 0 },
{ .type = FIELD_F32x3, .offset = 12 },
{ .type = FIELD_F32x3, .offset = 24 }
};
blendFormat[0].children = blendFormat + 1;
blendFormat[0].childCount = COUNTOF(blendFormat) - 1;
model->blendBuffer = lovrBufferCreate(&(BufferInfo) {
.fields = blendFormat,
.fieldCount = COUNTOF(blendFormat)
}, (void**) &blendData);
}
if (data->skinnedVertexCount > 0) { if (data->skinnedVertexCount > 0) {
BufferField skinFormat[] = { BufferField skinFormat[] = {
@ -2852,8 +2886,11 @@ Model* lovrModelCreate(const ModelInfo* info) {
.fields = skinFormat, .fields = skinFormat,
.fieldCount = COUNTOF(skinFormat) .fieldCount = COUNTOF(skinFormat)
}, (void**) &skinData); }, (void**) &skinData);
}
vertexFormat[0].length = data->skinnedVertexCount; // Dynamic vertices are ones that are blended or skinned. They need a copy of the original vertex
if (data->dynamicVertexCount > 0) {
vertexFormat[0].length = data->dynamicVertexCount;
model->rawVertexBuffer = lovrBufferCreate(&vertexBufferInfo, NULL); model->rawVertexBuffer = lovrBufferCreate(&vertexBufferInfo, NULL);
beginFrame(); beginFrame();
@ -2879,25 +2916,33 @@ Model* lovrModelCreate(const ModelInfo* info) {
.length = data->indexCount, .length = data->indexCount,
.stride = indexSize .stride = indexSize
} }
}, (void**) &indices); }, (void**) &indexData);
} }
// Sort primitives by their skin, so there is a single contiguous region of skinned vertices // Primitives are sorted to simplify animation:
// - Skinned primitives come first, ordered by skin
// - Primitives with blend shapes are next
// - Then "non-dynamic" primitives follow
// Within each section primitives are still sorted by their index.
size_t stack = tempPush(); size_t stack = tempPush();
uint64_t* map = tempAlloc(data->primitiveCount * sizeof(uint64_t)); uint64_t* primitiveOrder = tempAlloc(data->primitiveCount * sizeof(uint64_t));
uint32_t* baseVertex = tempAlloc(data->primitiveCount * sizeof(uint32_t));
for (uint32_t i = 0; i < data->primitiveCount; i++) { for (uint32_t i = 0; i < data->primitiveCount; i++) {
map[i] = ((uint64_t) data->primitives[i].skin << 32) | i; uint32_t hi = data->primitives[i].skin;
if (hi == ~0u && data->primitives[i].blendShapeCount > 0) hi--;
primitiveOrder[i] = ((uint64_t) hi << 32) | i;
} }
qsort(map, data->primitiveCount, sizeof(uint64_t), u64cmp); qsort(primitiveOrder, data->primitiveCount, sizeof(uint64_t), u64cmp);
// Draws // Draws
model->draws = calloc(data->primitiveCount, sizeof(Draw)); model->draws = calloc(data->primitiveCount, sizeof(Draw));
lovrAssert(model->draws, "Out of memory"); lovrAssert(model->draws, "Out of memory");
for (uint32_t i = 0, vertexCursor = 0, indexCursor = 0; i < data->primitiveCount; i++) { for (uint32_t i = 0, vertexCursor = 0, indexCursor = 0; i < data->primitiveCount; i++) {
ModelPrimitive* primitive = &data->primitives[map[i] & ~0u]; ModelPrimitive* primitive = &data->primitives[primitiveOrder[i] & ~0u];
Draw* draw = &model->draws[map[i] & ~0u]; Draw* draw = &model->draws[primitiveOrder[i] & ~0u];
switch (primitive->mode) { switch (primitive->mode) {
case DRAW_POINTS: draw->mode = MESH_POINTS; break; case DRAW_POINTS: draw->mode = MESH_POINTS; break;
@ -2920,22 +2965,23 @@ Model* lovrModelCreate(const ModelInfo* info) {
draw->count = primitive->attributes[ATTR_POSITION]->count; draw->count = primitive->attributes[ATTR_POSITION]->count;
} }
baseVertex[i] = vertexCursor;
vertexCursor += primitive->attributes[ATTR_POSITION]->count; vertexCursor += primitive->attributes[ATTR_POSITION]->count;
} }
// Vertices // Vertices
for (uint32_t i = 0; i < data->primitiveCount; i++) { for (uint32_t i = 0; i < data->primitiveCount; i++) {
ModelPrimitive* primitive = &data->primitives[map[i] & ~0u]; ModelPrimitive* primitive = &data->primitives[primitiveOrder[i] & ~0u];
ModelAttribute** attributes = primitive->attributes; ModelAttribute** attributes = primitive->attributes;
uint32_t count = attributes[ATTR_POSITION]->count; uint32_t count = attributes[ATTR_POSITION]->count;
size_t stride = sizeof(ModelVertex); size_t stride = sizeof(ModelVertex);
lovrModelDataCopyAttribute(data, attributes[ATTR_POSITION], vertices + 0, F32, 3, false, count, stride, 0); lovrModelDataCopyAttribute(data, attributes[ATTR_POSITION], vertexData + 0, F32, 3, false, count, stride, 0);
lovrModelDataCopyAttribute(data, attributes[ATTR_NORMAL], vertices + 12, F32, 3, false, count, stride, 0); lovrModelDataCopyAttribute(data, attributes[ATTR_NORMAL], vertexData + 12, F32, 3, false, count, stride, 0);
lovrModelDataCopyAttribute(data, attributes[ATTR_UV], vertices + 24, F32, 2, false, count, stride, 0); lovrModelDataCopyAttribute(data, attributes[ATTR_UV], vertexData + 24, F32, 2, false, count, stride, 0);
lovrModelDataCopyAttribute(data, attributes[ATTR_COLOR], vertices + 32, U8, 4, true, count, stride, 255); lovrModelDataCopyAttribute(data, attributes[ATTR_COLOR], vertexData + 32, U8, 4, true, count, stride, 255);
lovrModelDataCopyAttribute(data, attributes[ATTR_TANGENT], vertices + 36, F32, 3, false, count, stride, 0); lovrModelDataCopyAttribute(data, attributes[ATTR_TANGENT], vertexData + 36, F32, 3, false, count, stride, 0);
vertices += count * stride; vertexData += count * stride;
if (data->skinnedVertexCount > 0 && primitive->skin != ~0u) { if (data->skinnedVertexCount > 0 && primitive->skin != ~0u) {
lovrModelDataCopyAttribute(data, attributes[ATTR_JOINTS], skinData + 0, U8, 4, false, count, 8, 0); lovrModelDataCopyAttribute(data, attributes[ATTR_JOINTS], skinData + 0, U8, 4, false, count, 8, 0);
@ -2944,16 +2990,64 @@ Model* lovrModelCreate(const ModelInfo* info) {
} }
if (primitive->indices) { if (primitive->indices) {
char* indexData = data->buffers[primitive->indices->buffer].data + primitive->indices->offset; char* indices = data->buffers[primitive->indices->buffer].data + primitive->indices->offset;
memcpy(indices, indexData, primitive->indices->count * indexSize); memcpy(indexData, indices, primitive->indices->count * indexSize);
indices += primitive->indices->count * indexSize; indexData += primitive->indices->count * indexSize;
} }
} }
for (uint32_t i = 0; i < data->skinCount; i++) { // Blend shapes
lovrCheck(data->skins[i].jointCount <= 256, "Currently, the max number of joints per skin is 256"); uint32_t blendShapeCount = 0;
for (uint32_t i = 0; i < data->nodeCount; i++) {
if (data->nodes[i].blendShapeCount > 0) {
blendShapeCount += data->nodes[i].blendShapeCount;
model->blendGroupCount++;
}
} }
model->blendGroups = malloc(model->blendGroupCount * sizeof(BlendGroup));
model->blendShapeWeights = malloc(blendShapeCount * sizeof(float));
model->nodeWeights = malloc(data->nodeCount * sizeof(float*));
lovrAssert(model->blendGroups && model->blendShapeWeights && model->nodeWeights, "Out of memory");
float* weights = model->blendShapeWeights;
for (uint32_t i = 0, groupIndex = 0; i < data->nodeCount; i++) {
if (data->nodes[i].blendShapeCount == 0) continue;
ModelNode* node = &data->nodes[i];
BlendGroup* group = &model->blendGroups[groupIndex++];
group->node = i;
group->count = node->blendShapeCount;
group->vertexStart = baseVertex[node->primitiveIndex];
for (uint32_t p = 0; p < node->primitiveCount; p++) {
ModelPrimitive* primitive = &data->primitives[node->primitiveIndex + p];
uint32_t vertexCount = primitive->attributes[ATTR_POSITION]->count;
size_t stride = 9 * sizeof(float);
for (uint32_t b = 0; b < primitive->blendShapeCount; b++) {
ModelBlendData* blendShape = &primitive->blendShapes[b];
lovrModelDataCopyAttribute(data, blendShape->positions, blendData + 0, F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->normals, blendData + 12, F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->tangents, blendData + 24, F32, 3, false, vertexCount, stride, 0);
blendData += vertexCount * stride;
}
group->vertexCount += vertexCount;
}
if (node->blendShapeWeights) {
memcpy(node->blendShapeWeights, weights, node->blendShapeCount * sizeof(float));
} else {
memset(weights, 0, node->blendShapeCount * sizeof(float));
}
model->nodeWeights[i] = weights;
weights += node->blendShapeCount;
}
// Transforms
model->localTransforms = malloc(sizeof(NodeTransform) * data->nodeCount); model->localTransforms = malloc(sizeof(NodeTransform) * data->nodeCount);
model->globalTransforms = malloc(16 * sizeof(float) * data->nodeCount); model->globalTransforms = malloc(16 * sizeof(float) * data->nodeCount);
lovrAssert(model->localTransforms && model->globalTransforms, "Out of memory"); lovrAssert(model->localTransforms && model->globalTransforms, "Out of memory");
@ -2979,6 +3073,9 @@ void lovrModelDestroy(void* ref) {
lovrRelease(model->info.data, lovrModelDataDestroy); lovrRelease(model->info.data, lovrModelDataDestroy);
free(model->localTransforms); free(model->localTransforms);
free(model->globalTransforms); free(model->globalTransforms);
free(model->blendShapeWeights);
free(model->nodeWeights);
free(model->blendGroups);
free(model->draws); free(model->draws);
free(model->materials); free(model->materials);
free(model->textures); free(model->textures);