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:
parent
21bb3eb096
commit
b1b78319b5
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue