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.
This commit is contained in:
Hugo Locurcio 2022-06-30 23:11:32 +02:00
parent 20d4c66066
commit 32973094f5
No known key found for this signature in database
GPG Key ID: 39E8F8BE30B0A49C
5 changed files with 77 additions and 3 deletions

View File

@ -13,7 +13,27 @@
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_bake_mask_value" qualifiers="const">
<return type="bool" />
<argument index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member bake_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_bake_mask_value">
<return type="void" />
<argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
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.
</description>
</method>
</methods>
<members>
<member name="bake_mask" type="int" setter="set_bake_mask" getter="get_bake_mask" default="4294967295">
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.
</member>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
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.
</member>

View File

@ -31,7 +31,7 @@
</methods>
<members>
<member name="bake_mask" type="int" setter="set_bake_mask" getter="get_bake_mask" default="4294967295">
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].
</member>
<member name="bake_simplification_distance" type="float" setter="set_bake_simplification_distance" getter="get_bake_simplification_distance" default="0.1">

View File

@ -140,7 +140,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake(const Strin
if (col_sdf) {
Ref<Image> 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;
}

View File

@ -126,6 +126,10 @@ GPUParticlesCollisionBox3D::~GPUParticlesCollisionBox3D() {
void GPUParticlesCollisionSDF3D::_find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->is_visible_in_tree()) {
if ((mi->get_layer_mask() & bake_mask) == 0) {
return;
}
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
@ -447,7 +451,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
//compute bvh
ERR_FAIL_COND_V(faces.size() <= 1, Ref<Image>());
ERR_FAIL_COND_V_MSG(faces.size() <= 1, Ref<Image>(), "No faces detected during GPUParticlesCollisionSDF3D bake. Check whether there are visible meshes matching the bake mask within its extents.");
LocalVector<FacePos> face_pos;
@ -501,6 +505,16 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
return ret;
}
TypedArray<String> GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
TypedArray<String> 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<Texture3D> &p_texture) {
texture = p_texture;
RID tex = texture.is_valid() ? texture->get_rid() : RID();

View File

@ -110,6 +110,7 @@ public:
private:
Vector3 extents = Vector3(1, 1, 1);
Resolution resolution = RESOLUTION_64;
uint32_t bake_mask = 0xFFFFFFFF;
Ref<Texture3D> texture;
float thickness = 1.0;
@ -161,6 +162,8 @@ protected:
static void _bind_methods();
public:
virtual TypedArray<String> 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<Texture3D> &p_texture);
Ref<Texture3D> get_texture() const;