Upload bone transforms as texture, drastically increases max bone count

from 4
main
parent 414df982a1
commit 053ff80c39

@ -13,8 +13,20 @@ uniform vs_params {
mat4 model;
mat4 view;
mat4 projection;
mat4 bones[4];
vec2 bones_tex_size;
};
uniform sampler2D bones_tex;
// in textures, color elements are delivered as unsigend normalize floats
// in [0, 1]. This makes them into [-1, 1] as the bone matrices require
// such values to be correct
vec4 make_signed_again(vec4 v) {
v.x = 2.0 * v.x - 1.0;
v.y = 2.0 * v.y - 1.0;
v.z = 2.0 * v.z - 1.0;
v.w = 2.0 * v.w - 1.0;
return v;
}
void main() {
vec4 total_position = vec4(0.0f);
@ -25,7 +37,20 @@ void main() {
int index = int(index_float * 65535.0);
float weight = weights_in[i];
vec4 local_position = bones[index] * vec4(pos_in, 1.0f);
float y_coord = (0.5 + index)/bones_tex_size.y;
vec4 col0 = texture(bones_tex, vec2((0.5 + 0)/bones_tex_size.x, y_coord));
vec4 col1 = texture(bones_tex, vec2((0.5 + 1)/bones_tex_size.x, y_coord));
vec4 col2 = texture(bones_tex, vec2((0.5 + 2)/bones_tex_size.x, y_coord));
vec4 col3 = texture(bones_tex, vec2((0.5 + 3)/bones_tex_size.x, y_coord));
col0 = make_signed_again(col0);
col1 = make_signed_again(col1);
col2 = make_signed_again(col2);
col3 = make_signed_again(col3);
mat4 bone_mat = mat4(col0, col1, col2, col3);
vec4 local_position = bone_mat * vec4(pos_in, 1.0f);
total_position += local_position * weight;
}

@ -972,7 +972,10 @@ typedef struct
ArmatureVertex *vertices;
MD_u64 vertices_length;
sg_buffer loaded_buffer;
sg_image bones_texture;
MD_String8 name;
int bones_texture_width;
int bones_texture_height;
} Armature;
Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armature_name)
@ -1080,6 +1083,19 @@ Armature load_armature(MD_Arena *arena, MD_String8 binary_file, MD_String8 armat
.label = (const char*)nullterm(arena, MD_S8Fmt(arena, "%.*s-vertices", MD_S8VArg(armature_name))).str,
});
to_return.bones_texture_width = 4;
to_return.bones_texture_height = (int)to_return.bones_length;
Log("Amrature %.*s has bones texture size (%d, %d)\n", MD_S8VArg(armature_name), to_return.bones_texture_width, to_return.bones_texture_height);
to_return.bones_texture = sg_make_image(&(sg_image_desc) {
.width = to_return.bones_texture_width,
.height = to_return.bones_texture_height,
.pixel_format = SG_PIXELFORMAT_RGBA8,
.min_filter = SG_FILTER_NEAREST,
.mag_filter = SG_FILTER_NEAREST,
.usage = SG_USAGE_STREAM,
});
// a sanity check
SLICE_ITER(Bone, to_return.bones)
{
@ -2643,9 +2659,15 @@ int num_vertices = 0;
void draw_placed(Mat4 view, Mat4 projection, PlacedMesh *cur)
{
sg_apply_pipeline(state.threedee_pip);
Mesh *drawing = cur->draw_with;
state.threedee_bind.fs_images[SLOT_threedee_tex] = image_gigatexture;
ARR_ITER(sg_image, state.threedee_bind.vs_images)
{
*it = (sg_image){0};
}
state.threedee_bind.vertex_buffers[0] = drawing->loaded_buffer;
sg_apply_pipeline(state.threedee_pip);
sg_apply_bindings(&state.threedee_bind);
Mat4 model = transform_to_mat(cur->t);
@ -2685,9 +2707,8 @@ Mat4 get_animated_bone_transform(Bone *bone, float time)
void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, float elapsed_time)
{
state.threedee_bind.vertex_buffers[0] = armature->loaded_buffer;
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
sg_apply_pipeline(state.armature_pip);
sg_apply_bindings(&state.threedee_bind);
Mat4 model = transform_to_mat(t);
@ -2695,6 +2716,11 @@ void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature,
memcpy(params.model, (float*)&model, sizeof(model));
memcpy(params.view, (float*)&view, sizeof(view));
memcpy(params.projection, (float*)&projection, sizeof(projection));
params.bones_tex_size[0] = (float)armature->bones_texture_width;
params.bones_tex_size[1] = (float)armature->bones_texture_height;
int bones_tex_size = 4 * armature->bones_texture_width * armature->bones_texture_height;
MD_u8 *bones_tex = MD_ArenaPush(scratch.arena, bones_tex_size);
for(MD_u64 i = 0; i < armature->bones_length; i++)
{
@ -2708,13 +2734,48 @@ void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature,
final = MulM4(get_animated_bone_transform(cur_in_hierarchy, elapsed_time), final);
}
memcpy(params.bones[i], (float*)&final, sizeof(final));
for(int col = 0; col < 4; col++)
{
Vec4 to_upload = final.Columns[col];
assert(-1.1f <= to_upload.x && to_upload.x <= 1.1f);
assert(-1.1f <= to_upload.y && to_upload.y <= 1.1f);
assert(-1.1f <= to_upload.z && to_upload.z <= 1.1f);
assert(-1.1f <= to_upload.w && to_upload.w <= 1.1f);
// make them normalized
to_upload.x = to_upload.x/2.0f + 0.5f;
to_upload.y = to_upload.y/2.0f + 0.5f;
to_upload.z = to_upload.z/2.0f + 0.5f;
to_upload.w = to_upload.w/2.0f + 0.5f;
to_upload.x = clamp01(to_upload.x);
to_upload.y = clamp01(to_upload.y);
to_upload.z = clamp01(to_upload.z);
to_upload.w = clamp01(to_upload.w);
int bytes_per_pixel = 4;
int bytes_per_row = bytes_per_pixel * 4;
bones_tex[bytes_per_pixel*col + bytes_per_row*i + 0] = (MD_u8)(to_upload.x * 255.0);
bones_tex[bytes_per_pixel*col + bytes_per_row*i + 1] = (MD_u8)(to_upload.y * 255.0);
bones_tex[bytes_per_pixel*col + bytes_per_row*i + 2] = (MD_u8)(to_upload.z * 255.0);
bones_tex[bytes_per_pixel*col + bytes_per_row*i + 3] = (MD_u8)(to_upload.w * 255.0);
}
}
sg_update_image(armature->bones_texture, &(sg_image_data){
.subimage[0][0] = (sg_range){bones_tex, bones_tex_size},
});
state.threedee_bind.vertex_buffers[0] = armature->loaded_buffer;
state.threedee_bind.vs_images[SLOT_armature_bones_tex] = armature->bones_texture;
state.threedee_bind.fs_images[SLOT_armature_tex] = image_gigatexture;
sg_apply_bindings(&state.threedee_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_armature_vs_params, &SG_RANGE(params));
num_draw_calls += 1;
num_vertices += (int)armature->vertices_length;
sg_draw(0, (int)armature->vertices_length, 1);
MD_ReleaseScratch(scratch);
}

Loading…
Cancel
Save