Automatically transform Skeleton2D calculations so pivots are not needed

This commit is contained in:
clayjohn 2023-01-27 14:55:22 -08:00
parent 0f8f0ab126
commit eb9c2b878a
10 changed files with 92 additions and 4 deletions

View File

@ -440,6 +440,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c); const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
if (cm->mesh_instance.is_valid()) { if (cm->mesh_instance.is_valid()) {
mesh_storage->mesh_instance_check_for_update(cm->mesh_instance); 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; update_skeletons = true;
} }
} }

View File

@ -87,6 +87,16 @@ uniform highp float blend_weight;
uniform lowp float blend_shape_count; uniform lowp float blend_shape_count;
#endif #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) { vec2 signNotZero(vec2 v) {
return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0))); 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.z, bones_a.z, in_weight_attrib.z);
m += GET_BONE_MATRIX(bones.w, bones_a.w, in_weight_attrib.w); 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)); 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 bone_matrix = skeleton_matrix * transpose(bone_matrix) * inverse_matrix;
out_vertex = (vec4(out_vertex, 0.0, 1.0) * bone_matrix).xy;
out_vertex = (bone_matrix * vec4(out_vertex, 0.0, 1.0)).xy;
#endif // USE_SKELETON #endif // USE_SKELETON
#else // MODE_2D #else // MODE_2D

View File

@ -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) { 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]); 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); 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) { 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. // Do last blendshape in the same pass as the Skeleton.
_compute_skeleton(mi, sk, i); _compute_skeleton(mi, sk, i);
can_use_skeleton = false; can_use_skeleton = false;
@ -1201,6 +1216,16 @@ void MeshStorage::update_mesh_instances() {
continue; 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); glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array);
_compute_skeleton(mi, sk, i); _compute_skeleton(mi, sk, i);
} }

View File

@ -163,6 +163,7 @@ struct MeshInstance {
bool weights_dirty = false; bool weights_dirty = false;
SelfList<MeshInstance> weight_update_list; SelfList<MeshInstance> weight_update_list;
SelfList<MeshInstance> array_update_list; SelfList<MeshInstance> array_update_list;
Transform2D canvas_item_transform_2d;
MeshInstance() : MeshInstance() :
weight_update_list(this), array_update_list(this) {} 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_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_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_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; virtual void update_mesh_instances() override;
// TODO: considering hashing versions with multimesh buffer RID. // TODO: considering hashing versions with multimesh buffer RID.

View File

@ -126,6 +126,7 @@ public:
virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {} 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_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_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 {} virtual void update_mesh_instances() override {}
/* MULTIMESH API */ /* MULTIMESH API */

View File

@ -1431,6 +1431,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c); const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
if (cm->mesh_instance.is_valid()) { if (cm->mesh_instance.is_valid()) {
mesh_storage->mesh_instance_check_for_update(cm->mesh_instance); 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; update_skeletons = true;
} }
} }

View File

@ -51,6 +51,15 @@ layout(push_constant, std430) uniform Params {
bool normalized_blend_shapes; bool normalized_blend_shapes;
uint pad0; uint pad0;
uint pad1; 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; 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.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; 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 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));
vertex = (vec4(vertex, 0.0, 1.0) * m).xy; 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; uint dst_offset = index * params.vertex_stride;

View File

@ -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() { void MeshStorage::update_mesh_instances() {
while (dirty_mesh_instance_weights.first()) { while (dirty_mesh_instance_weights.first()) {
MeshInstance *mi = dirty_mesh_instance_weights.first()->self(); 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_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; 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.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.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED;
push_constant.pad0 = 0; push_constant.pad0 = 0;

View File

@ -178,6 +178,7 @@ private:
bool weights_dirty = false; bool weights_dirty = false;
SelfList<MeshInstance> weight_update_list; SelfList<MeshInstance> weight_update_list;
SelfList<MeshInstance> array_update_list; SelfList<MeshInstance> array_update_list;
Transform2D canvas_item_transform_2d;
MeshInstance() : MeshInstance() :
weight_update_list(this), array_update_list(this) {} weight_update_list(this), array_update_list(this) {}
}; };
@ -256,6 +257,14 @@ private:
uint32_t normalized_blend_shapes; uint32_t normalized_blend_shapes;
uint32_t pad0; uint32_t pad0;
uint32_t pad1; 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 { 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_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_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_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; virtual void update_mesh_instances() override;
/* MULTIMESH API */ /* MULTIMESH API */

View File

@ -83,6 +83,7 @@ public:
virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0; 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_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_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; virtual void update_mesh_instances() = 0;
/* MULTIMESH API */ /* MULTIMESH API */