diff options
author | Rémi Verschelde <rverschelde@gmail.com> | 2023-12-12 00:16:51 +0100 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2023-12-12 00:16:51 +0100 |
commit | 4943b6e6b33486fd2e0abe6d2d476dfb9c17fccf (patch) | |
tree | 566cf2553646e89fda5c60d360bfdd1c672b69a8 | |
parent | 5529d32b5643b12afac8fd7478fe243a3e0f4b86 (diff) | |
parent | 27f71c4e78db2f502d730f5e34a540665c45af27 (diff) | |
download | redot-engine-4943b6e6b33486fd2e0abe6d2d476dfb9c17fccf.tar.gz |
Merge pull request #84451 from ShirenY/FixSkeletonMeshCulling
Transform mesh's AABB to skeleton's space when calculating mesh's bounds
-rw-r--r-- | doc/classes/RenderingServer.xml | 8 | ||||
-rw-r--r-- | drivers/gles3/storage/mesh_storage.cpp | 37 | ||||
-rw-r--r-- | drivers/gles3/storage/mesh_storage.h | 4 | ||||
-rw-r--r-- | scene/2d/polygon_2d.cpp | 30 | ||||
-rw-r--r-- | servers/rendering/renderer_canvas_cull.cpp | 6 | ||||
-rw-r--r-- | servers/rendering/renderer_canvas_cull.h | 2 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp | 37 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/mesh_storage.h | 4 | ||||
-rw-r--r-- | servers/rendering/rendering_server_default.h | 2 | ||||
-rw-r--r-- | servers/rendering_server.cpp | 10 | ||||
-rw-r--r-- | servers/rendering_server.h | 7 |
11 files changed, 122 insertions, 25 deletions
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 9c72abdef0..dd3d190d78 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -925,6 +925,14 @@ [b]Note:[/b] When using the OpenGL backend or when running in headless mode, this function always returns [code]null[/code]. </description> </method> + <method name="debug_canvas_item_get_rect"> + <return type="Rect2" /> + <param index="0" name="item" type="RID" /> + <description> + Returns the bounding rectangle for a canvas item in local space, as calculated by the renderer. This bound is used internally for culling. + [b]Warning:[/b] This function is intended for debugging in the editor, and will pass through and return a zero [Rect2] in exported projects. + </description> + </method> <method name="decal_create"> <return type="RID" /> <description> diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 25e020b892..e5080b39a3 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -351,6 +351,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) s->aabb = new_surface.aabb; s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them. + s->mesh_to_skeleton_xform = p_surface.mesh_to_skeleton_xform; s->uv_scale = new_surface.uv_scale; @@ -572,6 +573,7 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { } sd.bone_aabbs = s.bone_aabbs; + sd.mesh_to_skeleton_xform = s.mesh_to_skeleton_xform; if (mesh->blend_shape_count) { sd.blend_shape_data = Vector<uint8_t>(); @@ -625,15 +627,16 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { for (uint32_t i = 0; i < mesh->surface_count; i++) { AABB laabb; - if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) { - int bs = mesh->surfaces[i]->bone_aabbs.size(); - const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr(); + const Mesh::Surface &surface = *mesh->surfaces[i]; + if ((surface.format & RS::ARRAY_FORMAT_BONES) && surface.bone_aabbs.size()) { + int bs = surface.bone_aabbs.size(); + const AABB *skbones = surface.bone_aabbs.ptr(); int sbs = skeleton->size; ERR_CONTINUE(bs > sbs); const float *baseptr = skeleton->data.ptr(); - bool first = true; + bool found_bone_aabb = false; if (skeleton->use_2d) { for (int j = 0; j < bs; j++) { @@ -653,11 +656,13 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { mtx.basis.rows[1][1] = dataptr[5]; mtx.origin.y = dataptr[7]; - AABB baabb = mtx.xform(skbones[j]); + // Transform bounds to skeleton's space before applying animation data. + AABB baabb = surface.mesh_to_skeleton_xform.xform(skbones[j]); + baabb = mtx.xform(baabb); - if (first) { + if (!found_bone_aabb) { laabb = baabb; - first = false; + found_bone_aabb = true; } else { laabb.merge_with(baabb); } @@ -685,21 +690,29 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { mtx.basis.rows[2][2] = dataptr[10]; mtx.origin.z = dataptr[11]; - AABB baabb = mtx.xform(skbones[j]); - if (first) { + // Transform bounds to skeleton's space before applying animation data. + AABB baabb = surface.mesh_to_skeleton_xform.xform(skbones[j]); + baabb = mtx.xform(baabb); + + if (!found_bone_aabb) { laabb = baabb; - first = false; + found_bone_aabb = true; } else { laabb.merge_with(baabb); } } } + if (found_bone_aabb) { + // Transform skeleton bounds back to mesh's space if any animated AABB applied. + laabb = surface.mesh_to_skeleton_xform.affine_inverse().xform(laabb); + } + if (laabb.size == Vector3()) { - laabb = mesh->surfaces[i]->aabb; + laabb = surface.aabb; } } else { - laabb = mesh->surfaces[i]->aabb; + laabb = surface.aabb; } if (i == 0) { diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index f52a60d067..217c4dabf0 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -106,6 +106,10 @@ struct Mesh { Vector<AABB> bone_aabbs; + // Transform used in runtime bone AABBs compute. + // As bone AABBs are saved in Mesh space, but bones animation is in Skeleton space. + Transform3D mesh_to_skeleton_xform; + Vector4 uv_scale; struct BlendShape { diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index bda7b495e1..ee186de5f1 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -101,7 +101,12 @@ void Polygon2D::_skeleton_bone_setup_changed() { } void Polygon2D::_notification(int p_what) { + if (p_what == NOTIFICATION_TRANSFORM_CHANGED && !Engine::get_singleton()->is_editor_hint()) { + return; // Mesh recreation for NOTIFICATION_TRANSFORM_CHANGED is only needed in editor. + } + switch (p_what) { + case NOTIFICATION_TRANSFORM_CHANGED: case NOTIFICATION_DRAW: { if (polygon.size() < 3) { return; @@ -364,7 +369,30 @@ void Polygon2D::_notification(int p_what) { arr[RS::ARRAY_INDEX] = index_array; - RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + RS::SurfaceData sd; + + if (skeleton_node) { + // Compute transform between mesh and skeleton for runtime AABB compute. + const Transform2D mesh_transform = get_global_transform(); + const Transform2D skeleton_transform = skeleton_node->get_global_transform(); + const Transform2D mesh_to_sk2d = mesh_transform * skeleton_transform.affine_inverse(); + + // Convert 2d transform to 3d. + sd.mesh_to_skeleton_xform.basis.rows[0][0] = mesh_to_sk2d.columns[0][0]; + sd.mesh_to_skeleton_xform.basis.rows[0][1] = mesh_to_sk2d.columns[0][1]; + sd.mesh_to_skeleton_xform.origin.x = mesh_to_sk2d.get_origin().x; + + sd.mesh_to_skeleton_xform.basis.rows[1][0] = mesh_to_sk2d.columns[1][0]; + sd.mesh_to_skeleton_xform.basis.rows[1][1] = mesh_to_sk2d.columns[1][1]; + sd.mesh_to_skeleton_xform.origin.y = mesh_to_sk2d.get_origin().y; + } + + Error err = RS::get_singleton()->mesh_create_surface_data_from_arrays(&sd, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + if (err != OK) { + return; + } + + RS::get_singleton()->mesh_add_surface(mesh, sd); RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(1, 1, 1), texture.is_valid() ? texture->get_rid() : RID()); } diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index c5206017f7..c3958b2c0d 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -2041,6 +2041,12 @@ void RendererCanvasCull::update_visibility_notifiers() { } } +Rect2 RendererCanvasCull::_debug_canvas_item_get_rect(RID p_item) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL_V(canvas_item, Rect2()); + return canvas_item->get_rect(); +} + bool RendererCanvasCull::free(RID p_rid) { if (canvas_owner.owns(p_rid)) { Canvas *canvas = canvas_owner.get_or_null(p_rid); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 0f51abbb26..aabaa42890 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -326,6 +326,8 @@ public: void update_visibility_notifiers(); + Rect2 _debug_canvas_item_get_rect(RID p_item); + bool free(RID p_rid); RendererCanvasCull(); ~RendererCanvasCull(); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index da55b68109..3bc1b476cb 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -430,6 +430,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) s->aabb = new_surface.aabb; s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them. + s->mesh_to_skeleton_xform = p_surface.mesh_to_skeleton_xform; s->uv_scale = new_surface.uv_scale; @@ -617,6 +618,7 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { } sd.bone_aabbs = s.bone_aabbs; + sd.mesh_to_skeleton_xform = s.mesh_to_skeleton_xform; if (s.blend_shape_buffer.is_valid()) { sd.blend_shape_data = RD::get_singleton()->buffer_get_data(s.blend_shape_buffer); @@ -663,15 +665,16 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { for (uint32_t i = 0; i < mesh->surface_count; i++) { AABB laabb; - if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) { - int bs = mesh->surfaces[i]->bone_aabbs.size(); - const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr(); + const Mesh::Surface &surface = *mesh->surfaces[i]; + if ((surface.format & RS::ARRAY_FORMAT_BONES) && surface.bone_aabbs.size()) { + int bs = surface.bone_aabbs.size(); + const AABB *skbones = surface.bone_aabbs.ptr(); int sbs = skeleton->size; ERR_CONTINUE(bs > sbs); const float *baseptr = skeleton->data.ptr(); - bool first = true; + bool found_bone_aabb = false; if (skeleton->use_2d) { for (int j = 0; j < bs; j++) { @@ -691,11 +694,13 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { mtx.basis.rows[1][1] = dataptr[5]; mtx.origin.y = dataptr[7]; - AABB baabb = mtx.xform(skbones[j]); + // Transform bounds to skeleton's space before applying animation data. + AABB baabb = surface.mesh_to_skeleton_xform.xform(skbones[j]); + baabb = mtx.xform(baabb); - if (first) { + if (!found_bone_aabb) { laabb = baabb; - first = false; + found_bone_aabb = true; } else { laabb.merge_with(baabb); } @@ -723,21 +728,29 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { mtx.basis.rows[2][2] = dataptr[10]; mtx.origin.z = dataptr[11]; - AABB baabb = mtx.xform(skbones[j]); - if (first) { + // Transform bounds to skeleton's space before applying animation data. + AABB baabb = surface.mesh_to_skeleton_xform.xform(skbones[j]); + baabb = mtx.xform(baabb); + + if (!found_bone_aabb) { laabb = baabb; - first = false; + found_bone_aabb = true; } else { laabb.merge_with(baabb); } } } + if (found_bone_aabb) { + // Transform skeleton bounds back to mesh's space if any animated AABB applied. + laabb = surface.mesh_to_skeleton_xform.affine_inverse().xform(laabb); + } + if (laabb.size == Vector3()) { - laabb = mesh->surfaces[i]->aabb; + laabb = surface.aabb; } } else { - laabb = mesh->surfaces[i]->aabb; + laabb = surface.aabb; } if (i == 0) { diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index db54816e09..0fc1a6f320 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -120,6 +120,10 @@ private: Vector<AABB> bone_aabbs; + // Transform used in runtime bone AABBs compute. + // As bone AABBs are saved in Mesh space, but bones animation is in Skeleton space. + Transform3D mesh_to_skeleton_xform; + Vector4 uv_scale; RID blend_shape_buffer; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index cd5904f175..dac1275957 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -940,6 +940,8 @@ public: FUNC1(canvas_set_shadow_texture_size, int) + FUNC1R(Rect2, _debug_canvas_item_get_rect, RID) + /* GLOBAL SHADER UNIFORMS */ #undef server_name diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 763989fdd4..6e3368c449 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -1802,6 +1802,14 @@ Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_su } #endif +Rect2 RenderingServer::debug_canvas_item_get_rect(RID p_item) { +#ifdef TOOLS_ENABLED + return _debug_canvas_item_get_rect(p_item); +#else + return Rect2(); +#endif +} + int RenderingServer::global_shader_uniform_type_get_shader_datatype(GlobalShaderParameterType p_type) { switch (p_type) { case RS::GLOBAL_VAR_TYPE_BOOL: @@ -3188,6 +3196,8 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_set_visibility_notifier", "item", "enable", "area", "enter_callable", "exit_callable"), &RenderingServer::canvas_item_set_visibility_notifier); ClassDB::bind_method(D_METHOD("canvas_item_set_canvas_group_mode", "item", "mode", "clear_margin", "fit_empty", "fit_margin", "blur_mipmaps"), &RenderingServer::canvas_item_set_canvas_group_mode, DEFVAL(5.0), DEFVAL(false), DEFVAL(0.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("debug_canvas_item_get_rect", "item"), &RenderingServer::debug_canvas_item_get_rect); + BIND_ENUM_CONSTANT(NINE_PATCH_STRETCH); BIND_ENUM_CONSTANT(NINE_PATCH_TILE); BIND_ENUM_CONSTANT(NINE_PATCH_TILE_FIT); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index fbc67fc84d..c54991d8c3 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -328,6 +328,10 @@ public: Vector<LOD> lods; Vector<AABB> bone_aabbs; + // Transforms used in runtime bone AABBs compute. + // Since bone AABBs is saved in Mesh space, but bones is in Skeleton space. + Transform3D mesh_to_skeleton_xform; + Vector<uint8_t> blend_shape_data; Vector4 uv_scale; @@ -1491,6 +1495,9 @@ public: virtual void canvas_set_shadow_texture_size(int p_size) = 0; + Rect2 debug_canvas_item_get_rect(RID p_item); + virtual Rect2 _debug_canvas_item_get_rect(RID p_item) = 0; + /* GLOBAL SHADER UNIFORMS */ enum GlobalShaderParameterType { |