From eb9c2b878a8c86a96a2c5013bf15a915df7e1338 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Fri, 27 Jan 2023 14:55:22 -0800 Subject: [PATCH] Automatically transform Skeleton2D calculations so pivots are not needed --- drivers/gles3/rasterizer_canvas_gles3.cpp | 1 + drivers/gles3/shaders/skeleton.glsl | 17 +++++++++++-- drivers/gles3/storage/mesh_storage.cpp | 25 +++++++++++++++++++ drivers/gles3/storage/mesh_storage.h | 2 ++ .../rendering/dummy/storage/mesh_storage.h | 1 + .../renderer_rd/renderer_canvas_render_rd.cpp | 1 + .../renderer_rd/shaders/skeleton.glsl | 17 +++++++++++-- .../renderer_rd/storage_rd/mesh_storage.cpp | 21 ++++++++++++++++ .../renderer_rd/storage_rd/mesh_storage.h | 10 ++++++++ servers/rendering/storage/mesh_storage.h | 1 + 10 files changed, 92 insertions(+), 4 deletions(-) diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index fbe00d22afd2..8888d11a2407 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -440,6 +440,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ const Item::CommandMesh *cm = static_cast(c); if (cm->mesh_instance.is_valid()) { mesh_storage->mesh_instance_check_for_update(cm->mesh_instance); + mesh_storage->mesh_instance_set_canvas_item_transform(cm->mesh_instance, canvas_transform_inverse * ci->final_transform); update_skeletons = true; } } diff --git a/drivers/gles3/shaders/skeleton.glsl b/drivers/gles3/shaders/skeleton.glsl index a1e3c098f427..aad856a5a2f0 100644 --- a/drivers/gles3/shaders/skeleton.glsl +++ b/drivers/gles3/shaders/skeleton.glsl @@ -87,6 +87,16 @@ uniform highp float blend_weight; uniform lowp float blend_shape_count; #endif +#ifdef USE_SKELETON +uniform mediump vec2 skeleton_transform_x; +uniform mediump vec2 skeleton_transform_y; +uniform mediump vec2 skeleton_transform_offset; + +uniform mediump vec2 inverse_transform_x; +uniform mediump vec2 inverse_transform_y; +uniform mediump vec2 inverse_transform_offset; +#endif + vec2 signNotZero(vec2 v) { return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0))); } @@ -164,10 +174,13 @@ void main() { m += GET_BONE_MATRIX(bones.z, bones_a.z, in_weight_attrib.z); m += GET_BONE_MATRIX(bones.w, bones_a.w, in_weight_attrib.w); + mat4 skeleton_matrix = mat4(vec4(skeleton_transform_x, 0.0, 0.0), vec4(skeleton_transform_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(skeleton_transform_offset, 0.0, 1.0)); + mat4 inverse_matrix = mat4(vec4(inverse_transform_x, 0.0, 0.0), vec4(inverse_transform_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(inverse_transform_offset, 0.0, 1.0)); mat4 bone_matrix = mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - //reverse order because its transposed - out_vertex = (vec4(out_vertex, 0.0, 1.0) * bone_matrix).xy; + bone_matrix = skeleton_matrix * transpose(bone_matrix) * inverse_matrix; + + out_vertex = (bone_matrix * vec4(out_vertex, 0.0, 1.0)).xy; #endif // USE_SKELETON #else // MODE_2D diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 71f262af2065..5ba0c5a09c5c 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -997,6 +997,11 @@ void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) { } } +void MeshStorage::mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) { + MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); + mi->canvas_item_transform_2d = p_transform; +} + void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface) { glBindBuffer(GL_ARRAY_BUFFER, p_mi->surfaces[p_surface].vertex_buffers[0]); @@ -1163,6 +1168,16 @@ void MeshStorage::update_mesh_instances() { skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization); if (can_use_skeleton) { + Transform2D transform = mi->canvas_item_transform_2d.affine_inverse() * sk->base_transform_2d; + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::SKELETON_TRANSFORM_X, transform[0], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::SKELETON_TRANSFORM_Y, transform[1], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::SKELETON_TRANSFORM_OFFSET, transform[2], skeleton_shader.shader_version, variant, specialization); + + Transform2D inverse_transform = transform.affine_inverse(); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_X, inverse_transform[0], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_Y, inverse_transform[1], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_OFFSET, inverse_transform[2], skeleton_shader.shader_version, variant, specialization); + // Do last blendshape in the same pass as the Skeleton. _compute_skeleton(mi, sk, i); can_use_skeleton = false; @@ -1201,6 +1216,16 @@ void MeshStorage::update_mesh_instances() { continue; } + Transform2D transform = mi->canvas_item_transform_2d.affine_inverse() * sk->base_transform_2d; + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::SKELETON_TRANSFORM_X, transform[0], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::SKELETON_TRANSFORM_Y, transform[1], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::SKELETON_TRANSFORM_OFFSET, transform[2], skeleton_shader.shader_version, variant, specialization); + + Transform2D inverse_transform = transform.affine_inverse(); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_X, inverse_transform[0], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_Y, inverse_transform[1], skeleton_shader.shader_version, variant, specialization); + skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_OFFSET, inverse_transform[2], skeleton_shader.shader_version, variant, specialization); + glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array); _compute_skeleton(mi, sk, i); } diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index 2efc57462bcf..e1c2bc3f63f1 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -163,6 +163,7 @@ struct MeshInstance { bool weights_dirty = false; SelfList weight_update_list; SelfList array_update_list; + Transform2D canvas_item_transform_2d; MeshInstance() : weight_update_list(this), array_update_list(this) {} }; @@ -423,6 +424,7 @@ public: virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override; virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override; virtual void mesh_instance_check_for_update(RID p_mesh_instance) override; + virtual void mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) override; virtual void update_mesh_instances() override; // TODO: considering hashing versions with multimesh buffer RID. diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index 2d66c225e8c2..aba362c95650 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -126,6 +126,7 @@ public: virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {} virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {} virtual void mesh_instance_check_for_update(RID p_mesh_instance) override {} + virtual void mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) override {} virtual void update_mesh_instances() override {} /* MULTIMESH API */ diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 638fe4426665..0f4fa1b9c480 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1431,6 +1431,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p const Item::CommandMesh *cm = static_cast(c); if (cm->mesh_instance.is_valid()) { mesh_storage->mesh_instance_check_for_update(cm->mesh_instance); + mesh_storage->mesh_instance_set_canvas_item_transform(cm->mesh_instance, canvas_transform_inverse * ci->final_transform); update_skeletons = true; } } diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index f5b233cca053..59c161548c50 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -51,6 +51,15 @@ layout(push_constant, std430) uniform Params { bool normalized_blend_shapes; uint pad0; uint pad1; + + vec2 skeleton_transform_x; + vec2 skeleton_transform_y; + + vec2 skeleton_transform_offset; + vec2 inverse_transform_x; + + vec2 inverse_transform_y; + vec2 inverse_transform_offset; } params; @@ -158,8 +167,12 @@ void main() { m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; - //reverse order because its transposed - vertex = (vec4(vertex, 0.0, 1.0) * m).xy; + mat4 skeleton_matrix = mat4(vec4(params.skeleton_transform_x, 0.0, 0.0), vec4(params.skeleton_transform_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(params.skeleton_transform_offset, 0.0, 1.0)); + mat4 inverse_matrix = mat4(vec4(params.inverse_transform_x, 0.0, 0.0), vec4(params.inverse_transform_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(params.inverse_transform_offset, 0.0, 1.0)); + + m = skeleton_matrix * transpose(m) * inverse_matrix; + + vertex = (m * vec4(vertex, 0.0, 1.0)).xy; } uint dst_offset = index * params.vertex_stride; diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 2015a2fca01f..912488676453 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -930,6 +930,11 @@ void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) { } } +void MeshStorage::mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) { + MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); + mi->canvas_item_transform_2d = p_transform; +} + void MeshStorage::update_mesh_instances() { while (dirty_mesh_instance_weights.first()) { MeshInstance *mi = dirty_mesh_instance_weights.first()->self(); @@ -981,6 +986,22 @@ void MeshStorage::update_mesh_instances() { push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2; + Transform2D transform = mi->canvas_item_transform_2d.affine_inverse() * sk->base_transform_2d; + push_constant.skeleton_transform_x[0] = transform.columns[0][0]; + push_constant.skeleton_transform_x[1] = transform.columns[0][1]; + push_constant.skeleton_transform_y[0] = transform.columns[1][0]; + push_constant.skeleton_transform_y[1] = transform.columns[1][1]; + push_constant.skeleton_transform_offset[0] = transform.columns[2][0]; + push_constant.skeleton_transform_offset[1] = transform.columns[2][1]; + + Transform2D inverse_transform = transform.affine_inverse(); + push_constant.inverse_transform_x[0] = inverse_transform.columns[0][0]; + push_constant.inverse_transform_x[1] = inverse_transform.columns[0][1]; + push_constant.inverse_transform_y[0] = inverse_transform.columns[1][0]; + push_constant.inverse_transform_y[1] = inverse_transform.columns[1][1]; + push_constant.inverse_transform_offset[0] = inverse_transform.columns[2][0]; + push_constant.inverse_transform_offset[1] = inverse_transform.columns[2][1]; + push_constant.blend_shape_count = mi->mesh->blend_shape_count; push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED; push_constant.pad0 = 0; diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index b62da5fd7be0..c92152394123 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -178,6 +178,7 @@ private: bool weights_dirty = false; SelfList weight_update_list; SelfList array_update_list; + Transform2D canvas_item_transform_2d; MeshInstance() : weight_update_list(this), array_update_list(this) {} }; @@ -256,6 +257,14 @@ private: uint32_t normalized_blend_shapes; uint32_t pad0; uint32_t pad1; + float skeleton_transform_x[2]; + float skeleton_transform_y[2]; + + float skeleton_transform_offset[2]; + float inverse_transform_x[2]; + + float inverse_transform_y[2]; + float inverse_transform_offset[2]; }; enum { @@ -548,6 +557,7 @@ public: virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override; virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override; virtual void mesh_instance_check_for_update(RID p_mesh_instance) override; + virtual void mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) override; virtual void update_mesh_instances() override; /* MULTIMESH API */ diff --git a/servers/rendering/storage/mesh_storage.h b/servers/rendering/storage/mesh_storage.h index 704c2e015cd0..76e46a696a69 100644 --- a/servers/rendering/storage/mesh_storage.h +++ b/servers/rendering/storage/mesh_storage.h @@ -83,6 +83,7 @@ public: virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0; virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) = 0; virtual void mesh_instance_check_for_update(RID p_mesh_instance) = 0; + virtual void mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) = 0; virtual void update_mesh_instances() = 0; /* MULTIMESH API */