From 32973094f55c3c610eed100dc28f7fffaac7e444 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Thu, 30 Jun 2022 23:11:32 +0200 Subject: [PATCH] Add a Bake Mask property to GPUParticlesCollisionSDF3D This allows not accounting for certain visible meshes during baking (such as foliage and thin fixtures). This also adds a clarification about transparent materials always being excluded in the OccluderInstance3D documentation. --- doc/classes/GPUParticlesCollisionSDF3D.xml | 20 ++++++++ doc/classes/OccluderInstance3D.xml | 2 +- ..._particles_collision_sdf_editor_plugin.cpp | 2 +- scene/3d/gpu_particles_collision_3d.cpp | 47 ++++++++++++++++++- scene/3d/gpu_particles_collision_3d.h | 9 ++++ 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/doc/classes/GPUParticlesCollisionSDF3D.xml b/doc/classes/GPUParticlesCollisionSDF3D.xml index c9af07288ec..bc8b3c7c113 100644 --- a/doc/classes/GPUParticlesCollisionSDF3D.xml +++ b/doc/classes/GPUParticlesCollisionSDF3D.xml @@ -13,7 +13,27 @@ + + + + + + Returns whether or not the specified layer of the [member bake_mask] is enabled, given a [code]layer_number[/code] between 1 and 32. + + + + + + + + Based on [code]value[/code], enables or disables the specified layer in the [member bake_mask], given a [code]layer_number[/code] between 1 and 32. + + + + + The visual layers to account for when baking the particle collision SDF. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member bake_mask] will be included in the generated particle collision SDF. By default, all objects are taken into account for the particle collision SDF baking. + The collision SDF's extents in 3D units. To improve SDF quality, the [member extents] should be set as small as possible while covering the parts of the scene you need. diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml index abd99dd3aa4..08d12341cd0 100644 --- a/doc/classes/OccluderInstance3D.xml +++ b/doc/classes/OccluderInstance3D.xml @@ -31,7 +31,7 @@ - The visual layers to account for when baking for occluders. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member bake_mask] will be included in the generated occluder mesh. By default, all objects are taken into account for the occluder baking. + The visual layers to account for when baking for occluders. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member bake_mask] will be included in the generated occluder mesh. By default, all objects with [i]opaque[/i] materials are taken into account for the occluder baking. To improve performance and avoid artifacts, it is recommended to exclude dynamic objects, small objects and fixtures from the baking process by moving them to a separate visual layer and excluding this layer in [member bake_mask]. diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp index 643a4704252..b54cb515e46 100644 --- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp @@ -140,7 +140,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake(const Strin if (col_sdf) { Ref bake_img = col_sdf->bake(); if (bake_img.is_null()) { - EditorNode::get_singleton()->show_warning(TTR("Bake Error.")); + EditorNode::get_singleton()->show_warning(TTR("No faces detected during GPUParticlesCollisionSDF3D bake.\nCheck whether there are visible meshes matching the bake mask within its extents.")); return; } diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index da0789ccd55..90c72bba3a8 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -126,6 +126,10 @@ GPUParticlesCollisionBox3D::~GPUParticlesCollisionBox3D() { void GPUParticlesCollisionSDF3D::_find_meshes(const AABB &p_aabb, Node *p_at_node, List &plot_meshes) { MeshInstance3D *mi = Object::cast_to(p_at_node); if (mi && mi->is_visible_in_tree()) { + if ((mi->get_layer_mask() & bake_mask) == 0) { + return; + } + Ref mesh = mi->get_mesh(); if (mesh.is_valid()) { AABB aabb = mesh->get_aabb(); @@ -447,7 +451,7 @@ Ref GPUParticlesCollisionSDF3D::bake() { //compute bvh - ERR_FAIL_COND_V(faces.size() <= 1, Ref()); + ERR_FAIL_COND_V_MSG(faces.size() <= 1, Ref(), "No faces detected during GPUParticlesCollisionSDF3D bake. Check whether there are visible meshes matching the bake mask within its extents."); LocalVector face_pos; @@ -501,6 +505,16 @@ Ref GPUParticlesCollisionSDF3D::bake() { return ret; } +TypedArray GPUParticlesCollisionSDF3D::get_configuration_warnings() const { + TypedArray warnings = Node::get_configuration_warnings(); + + if (bake_mask == 0) { + warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property.")); + } + + return warnings; +} + void GPUParticlesCollisionSDF3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionSDF3D::set_extents); ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionSDF3D::get_extents); @@ -514,9 +528,15 @@ void GPUParticlesCollisionSDF3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &GPUParticlesCollisionSDF3D::set_thickness); ClassDB::bind_method(D_METHOD("get_thickness"), &GPUParticlesCollisionSDF3D::get_thickness); + ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &GPUParticlesCollisionSDF3D::set_bake_mask); + ClassDB::bind_method(D_METHOD("get_bake_mask"), &GPUParticlesCollisionSDF3D::get_bake_mask); + ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &GPUParticlesCollisionSDF3D::set_bake_mask_value); + ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512,suffix:px"), "set_resolution", "get_resolution"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture"); BIND_ENUM_CONSTANT(RESOLUTION_16); @@ -555,6 +575,31 @@ GPUParticlesCollisionSDF3D::Resolution GPUParticlesCollisionSDF3D::get_resolutio return resolution; } +void GPUParticlesCollisionSDF3D::set_bake_mask(uint32_t p_mask) { + bake_mask = p_mask; + update_configuration_warnings(); +} + +uint32_t GPUParticlesCollisionSDF3D::get_bake_mask() const { + return bake_mask; +} + +void GPUParticlesCollisionSDF3D::set_bake_mask_value(int p_layer_number, bool p_value) { + ERR_FAIL_COND_MSG(p_layer_number < 1 || p_layer_number > 20, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number)); + uint32_t mask = get_bake_mask(); + if (p_value) { + mask |= 1 << (p_layer_number - 1); + } else { + mask &= ~(1 << (p_layer_number - 1)); + } + set_bake_mask(mask); +} + +bool GPUParticlesCollisionSDF3D::get_bake_mask_value(int p_layer_number) const { + ERR_FAIL_COND_V_MSG(p_layer_number < 1 || p_layer_number > 20, false, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number)); + return bake_mask & (1 << (p_layer_number - 1)); +} + void GPUParticlesCollisionSDF3D::set_texture(const Ref &p_texture) { texture = p_texture; RID tex = texture.is_valid() ? texture->get_rid() : RID(); diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h index 4b2cb930fa0..712bd015ff2 100644 --- a/scene/3d/gpu_particles_collision_3d.h +++ b/scene/3d/gpu_particles_collision_3d.h @@ -110,6 +110,7 @@ public: private: Vector3 extents = Vector3(1, 1, 1); Resolution resolution = RESOLUTION_64; + uint32_t bake_mask = 0xFFFFFFFF; Ref texture; float thickness = 1.0; @@ -161,6 +162,8 @@ protected: static void _bind_methods(); public: + virtual TypedArray get_configuration_warnings() const override; + void set_thickness(float p_thickness); float get_thickness() const; @@ -170,6 +173,12 @@ public: void set_resolution(Resolution p_resolution); Resolution get_resolution() const; + void set_bake_mask(uint32_t p_mask); + uint32_t get_bake_mask() const; + + void set_bake_mask_value(int p_layer_number, bool p_enable); + bool get_bake_mask_value(int p_layer_number) const; + void set_texture(const Ref &p_texture); Ref get_texture() const;