From 413737229268c446bee1c6e19c8e28c7bc3a8913 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Tue, 4 Jul 2023 12:25:57 -0700 Subject: [PATCH] Increase precision and max value of bone matrix floats - I just made up a technique that is probably 30% efficient, this is something to revisit in the future --- armature.glsl | 33 ++++++++---------------- art/art.blend | 4 +-- main.c | 69 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/armature.glsl b/armature.glsl index 804c146..2d24dc6 100644 --- a/armature.glsl +++ b/armature.glsl @@ -24,17 +24,6 @@ float decode_normalized_float32(vec4 v) return sign * (v.z*255.0 + v.y); } -// 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); @@ -45,18 +34,16 @@ void main() { float weight = weights_in[bone_influence_index]; 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); + + mat4 bone_mat; + + for(int row = 0; row < 4; row++) + { + for(int col = 0; col < 4; col++) + { + bone_mat[col][row] = decode_normalized_float32(texture(bones_tex, vec2((0.5 + col*4 + row)/bones_tex_size.x, y_coord))); + } + } vec4 local_position = bone_mat * vec4(pos_in, 1.0f); total_position += local_position * weight; diff --git a/art/art.blend b/art/art.blend index e973f7b..da03571 100644 --- a/art/art.blend +++ b/art/art.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84e78be53e858b252b6db329c4e66ca681bb9e35e9f0b1be0fad1c0bdd9df83c -size 13211972 +oid sha256:a01b027f3e3d00dcd39c735158953e1a8127b686a041d3ed9044d4a0cd857558 +size 13918948 diff --git a/main.c b/main.c index 1e8eb55..401c8c0 100644 --- a/main.c +++ b/main.c @@ -1083,7 +1083,7 @@ 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_width = 16; 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); @@ -2726,7 +2726,9 @@ PixelData encode_normalized_float32(float to_encode) assert(to_return_vector.z < 255.0f); to_return_vector.z /= 255.0f; - // w is unused for now + // w is unused for now, but is 1.0f (and is the alpha channel in Vec4) so that it displays properly as a texture + to_return_vector.w = 1.0f; + PixelData to_return = {0}; @@ -2739,6 +2741,21 @@ PixelData encode_normalized_float32(float to_encode) return to_return; } +float decode_normalized_float32(PixelData encoded) +{ + Vec4 v = {0}; + for(int i = 0; i < 4; i++) + { + v.Elements[i] = (float)encoded.rgba[i] / 255.0f; + } + + float sign = 2.0f * v.x - 1.0f; + + float to_return = sign * (v.z*255.0f + v.y); + + return to_return; +} + void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, float elapsed_time) { @@ -2772,28 +2789,19 @@ void draw_armature(Mat4 view, Mat4 projection, Transform t, Armature *armature, 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); + int bytes_per_column_of_mat = bytes_per_pixel * 4; + int bytes_per_row = bytes_per_pixel * armature->bones_texture_width; + for(int elem = 0; elem < 4; elem++) + { + float after_decoding = decode_normalized_float32(encode_normalized_float32(to_upload.Elements[elem])); + assert(fabsf(after_decoding - to_upload.Elements[elem]) < 0.01f); + } + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*0], encode_normalized_float32(to_upload.Elements[0]).rgba, bytes_per_pixel); + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*1], encode_normalized_float32(to_upload.Elements[1]).rgba, bytes_per_pixel); + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*2], encode_normalized_float32(to_upload.Elements[2]).rgba, bytes_per_pixel); + memcpy(&bones_tex[bytes_per_column_of_mat*col + bytes_per_row*i + bytes_per_pixel*3], encode_normalized_float32(to_upload.Elements[3]).rgba, bytes_per_pixel); } } sg_update_image(armature->bones_texture, &(sg_image_data){ @@ -2991,6 +2999,22 @@ void do_serialization_tests() MD_ReleaseScratch(scratch); } + +void do_float_encoding_tests() +{ + float to_test[] = { + 7.5f, + -2.12f, + 100.2f, + -5.35f, + }; + ARR_ITER(float, to_test) + { + PixelData encoded = encode_normalized_float32(*it); + float decoded = decode_normalized_float32(encoded); + assert(fabsf(decoded - *it) < 0.01f); + } +} #endif Armature armature = {0}; @@ -3064,6 +3088,7 @@ void init(void) do_metadesk_tests(); do_parsing_tests(); do_serialization_tests(); + do_float_encoding_tests(); #endif #ifdef WEB