Skip to content

Commit ea2770e

Browse files
committed
Merge pull request #101947 from Rudolph-B/Issue-101750
Add Heightfield mask to GPUParticlesCollisionHeightField3D
2 parents 0746447 + b162c59 commit ea2770e

14 files changed

+113
-1
lines changed

doc/classes/GPUParticlesCollisionHeightField3D.xml

+22
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,33 @@
1212
</description>
1313
<tutorials>
1414
</tutorials>
15+
<methods>
16+
<method name="get_heightfield_mask_value" qualifiers="const">
17+
<return type="bool" />
18+
<param index="0" name="layer_number" type="int" />
19+
<description>
20+
Returns [code]true[/code] if the specified layer of the [member heightfield_mask] is enabled, given a [param layer_number] between [code]1[/code] and [code]20[/code], inclusive.
21+
</description>
22+
</method>
23+
<method name="set_heightfield_mask_value">
24+
<return type="void" />
25+
<param index="0" name="layer_number" type="int" />
26+
<param index="1" name="value" type="bool" />
27+
<description>
28+
Based on [param value], enables or disables the specified layer in the [member heightfield_mask], given a [param layer_number] between [code]1[/code] and [code]20[/code], inclusive.
29+
</description>
30+
</method>
31+
</methods>
1532
<members>
1633
<member name="follow_camera_enabled" type="bool" setter="set_follow_camera_enabled" getter="is_follow_camera_enabled" default="false">
1734
If [code]true[/code], the [GPUParticlesCollisionHeightField3D] will follow the current camera in global space. The [GPUParticlesCollisionHeightField3D] does not need to be a child of the [Camera3D] node for this to work.
1835
Following the camera has a performance cost, as it will force the heightmap to update whenever the camera moves. Consider lowering [member resolution] to improve performance if [member follow_camera_enabled] is [code]true[/code].
1936
</member>
37+
<member name="heightfield_mask" type="int" setter="set_heightfield_mask" getter="get_heightfield_mask" default="1048575">
38+
The visual layers to account for when updating the heightmap. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member heightfield_mask] will be included in the heightmap collision update. By default, all 20 user-visible layers are taken into account for updating the heightmap collision.
39+
[b]Note:[/b] Since the [member heightfield_mask] allows for 32 layers to be stored in total, there are an additional 12 layers that are only used internally by the engine and aren't exposed in the editor. Setting [member heightfield_mask] using a script allows you to toggle those reserved layers, which can be useful for editor plugins.
40+
To adjust [member heightfield_mask] more easily using a script, use [method get_heightfield_mask_value] and [method set_heightfield_mask_value].
41+
</member>
2042
<member name="resolution" type="int" setter="set_resolution" getter="get_resolution" enum="GPUParticlesCollisionHeightField3D.Resolution" default="2">
2143
Higher resolutions can represent small details more accurately in large scenes, at the cost of lower performance. If [member update_mode] is [constant UPDATE_MODE_ALWAYS], consider using the lowest resolution possible.
2244
</member>

doc/classes/RenderingServer.xml

+8
Original file line numberDiff line numberDiff line change
@@ -2893,6 +2893,14 @@
28932893
Sets the signed distance field [param texture] for the 3D GPU particles collision specified by the [param particles_collision] RID. Equivalent to [member GPUParticlesCollisionSDF3D.texture] or [member GPUParticlesAttractorVectorField3D.texture] depending on the [param particles_collision] type.
28942894
</description>
28952895
</method>
2896+
<method name="particles_collision_set_height_field_mask">
2897+
<return type="void" />
2898+
<param index="0" name="particles_collision" type="RID" />
2899+
<param index="1" name="mask" type="int" />
2900+
<description>
2901+
Sets the heightfield [param mask] for the 3D GPU particles heightfield collision specified by the [param particles_collision] RID. Equivalent to [member GPUParticlesCollisionHeightField3D.heightfield_mask].
2902+
</description>
2903+
</method>
28962904
<method name="particles_collision_set_height_field_resolution">
28972905
<return type="void" />
28982906
<param index="0" name="particles_collision" type="RID" />

drivers/gles3/storage/particles_storage.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,18 @@ bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collis
14321432
return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
14331433
}
14341434

1435+
uint32_t ParticlesStorage::particles_collision_get_height_field_mask(RID p_particles_collision) const {
1436+
const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1437+
ERR_FAIL_NULL_V(particles_collision, false);
1438+
return particles_collision->heightfield_mask;
1439+
}
1440+
1441+
void ParticlesStorage::particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) {
1442+
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1443+
ERR_FAIL_NULL(particles_collision);
1444+
particles_collision->heightfield_mask = p_heightfield_mask;
1445+
}
1446+
14351447
Dependency *ParticlesStorage::particles_collision_get_dependency(RID p_particles_collision) const {
14361448
ParticlesCollision *pc = particles_collision_owner.get_or_null(p_particles_collision);
14371449
ERR_FAIL_NULL_V(pc, nullptr);

drivers/gles3/storage/particles_storage.h

+3
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ class ParticlesStorage : public RendererParticlesStorage {
287287
GLuint heightfield_texture = 0;
288288
GLuint heightfield_fb = 0;
289289
Size2i heightfield_fb_size;
290+
uint32_t heightfield_mask = (1 << 20) - 1;
290291

291292
RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
292293

@@ -434,6 +435,8 @@ class ParticlesStorage : public RendererParticlesStorage {
434435
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
435436
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
436437
GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
438+
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override;
439+
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override;
437440

438441
_FORCE_INLINE_ Size2i particles_collision_get_heightfield_size(RID p_particles_collision) const {
439442
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);

scene/3d/gpu_particles_collision_3d.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -721,13 +721,20 @@ void GPUParticlesCollisionHeightField3D::_bind_methods() {
721721
ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &GPUParticlesCollisionHeightField3D::set_update_mode);
722722
ClassDB::bind_method(D_METHOD("get_update_mode"), &GPUParticlesCollisionHeightField3D::get_update_mode);
723723

724+
ClassDB::bind_method(D_METHOD("set_heightfield_mask", "heightfield_mask"), &GPUParticlesCollisionHeightField3D::set_heightfield_mask);
725+
ClassDB::bind_method(D_METHOD("get_heightfield_mask"), &GPUParticlesCollisionHeightField3D::get_heightfield_mask);
726+
727+
ClassDB::bind_method(D_METHOD("set_heightfield_mask_value", "layer_number", "value"), &GPUParticlesCollisionHeightField3D::set_heightfield_mask_value);
728+
ClassDB::bind_method(D_METHOD("get_heightfield_mask_value", "layer_number"), &GPUParticlesCollisionHeightField3D::get_heightfield_mask_value);
729+
724730
ClassDB::bind_method(D_METHOD("set_follow_camera_enabled", "enabled"), &GPUParticlesCollisionHeightField3D::set_follow_camera_enabled);
725731
ClassDB::bind_method(D_METHOD("is_follow_camera_enabled"), &GPUParticlesCollisionHeightField3D::is_follow_camera_enabled);
726732

727733
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
728734
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256 (Fastest),512 (Fast),1024 (Average),2048 (Slow),4096 (Slower),8192 (Slowest)"), "set_resolution", "get_resolution");
729735
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "When Moved (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
730736
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_enabled", "is_follow_camera_enabled");
737+
ADD_PROPERTY(PropertyInfo(Variant::INT, "heightfield_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_heightfield_mask", "get_heightfield_mask");
731738

732739
BIND_ENUM_CONSTANT(RESOLUTION_256);
733740
BIND_ENUM_CONSTANT(RESOLUTION_512);
@@ -790,6 +797,33 @@ GPUParticlesCollisionHeightField3D::UpdateMode GPUParticlesCollisionHeightField3
790797
return update_mode;
791798
}
792799

800+
void GPUParticlesCollisionHeightField3D::set_heightfield_mask(uint32_t p_heightfield_mask) {
801+
heightfield_mask = p_heightfield_mask;
802+
RS::get_singleton()->particles_collision_set_height_field_mask(_get_collision(), p_heightfield_mask);
803+
}
804+
805+
uint32_t GPUParticlesCollisionHeightField3D::get_heightfield_mask() const {
806+
return heightfield_mask;
807+
}
808+
809+
void GPUParticlesCollisionHeightField3D::set_heightfield_mask_value(int p_layer_number, bool p_value) {
810+
ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
811+
ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
812+
uint32_t mask = get_heightfield_mask();
813+
if (p_value) {
814+
mask |= 1 << (p_layer_number - 1);
815+
} else {
816+
mask &= ~(1 << (p_layer_number - 1));
817+
}
818+
set_heightfield_mask(mask);
819+
}
820+
821+
bool GPUParticlesCollisionHeightField3D::get_heightfield_mask_value(int p_layer_number) const {
822+
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
823+
ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
824+
return heightfield_mask & (1 << (p_layer_number - 1));
825+
}
826+
793827
void GPUParticlesCollisionHeightField3D::set_follow_camera_enabled(bool p_enabled) {
794828
follow_camera_mode = p_enabled;
795829
set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS);

scene/3d/gpu_particles_collision_3d.h

+7
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ class GPUParticlesCollisionHeightField3D : public GPUParticlesCollision3D {
225225
};
226226

227227
private:
228+
uint32_t heightfield_mask = (1 << 20) - 1; // Only the first 20 bits are set by default to ignore editor layers.
228229
Vector3 size = Vector3(2, 2, 2);
229230
Resolution resolution = RESOLUTION_1024;
230231
bool follow_camera_mode = false;
@@ -249,6 +250,12 @@ class GPUParticlesCollisionHeightField3D : public GPUParticlesCollision3D {
249250
void set_update_mode(UpdateMode p_update_mode);
250251
UpdateMode get_update_mode() const;
251252

253+
void set_heightfield_mask(uint32_t p_heightfield_mask);
254+
uint32_t get_heightfield_mask() const;
255+
256+
void set_heightfield_mask_value(int p_layer_number, bool p_value);
257+
bool get_heightfield_mask_value(int p_layer_number) const;
258+
252259
void set_follow_camera_enabled(bool p_enabled);
253260
bool is_follow_camera_enabled() const;
254261

servers/rendering/dummy/storage/particles_storage.h

+2
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ class ParticlesStorage : public RendererParticlesStorage {
114114
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {}
115115
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); }
116116
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
117+
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override { return 0; }
118+
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override {}
117119

118120
virtual RID particles_collision_instance_create(RID p_collision) override { return RID(); }
119121
virtual void particles_collision_instance_free(RID p_rid) override {}

servers/rendering/renderer_rd/storage_rd/particles_storage.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,18 @@ void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collisi
18571857
particles_collision->cull_mask = p_cull_mask;
18581858
}
18591859

1860+
uint32_t ParticlesStorage::particles_collision_get_height_field_mask(RID p_particles_collision) const {
1861+
const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1862+
ERR_FAIL_NULL_V(particles_collision, false);
1863+
return particles_collision->heightfield_mask;
1864+
}
1865+
1866+
void ParticlesStorage::particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) {
1867+
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1868+
ERR_FAIL_NULL(particles_collision);
1869+
particles_collision->heightfield_mask = p_heightfield_mask;
1870+
}
1871+
18601872
void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
18611873
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
18621874
ERR_FAIL_NULL(particles_collision);

servers/rendering/renderer_rd/storage_rd/particles_storage.h

+3
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ class ParticlesStorage : public RendererParticlesStorage {
404404
RID heightfield_texture;
405405
RID heightfield_fb;
406406
Size2i heightfield_fb_size;
407+
uint32_t heightfield_mask = (1 << 20) - 1;
407408

408409
RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
409410

@@ -581,6 +582,8 @@ class ParticlesStorage : public RendererParticlesStorage {
581582
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
582583
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
583584
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
585+
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override;
586+
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override;
584587

585588
Dependency *particles_collision_get_dependency(RID p_particles) const;
586589

servers/rendering/renderer_scene_cull.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -3971,15 +3971,19 @@ void RendererSceneCull::render_particle_colliders() {
39713971

39723972
struct CullAABB {
39733973
PagedArray<Instance *> *result;
3974+
uint32_t heightfield_mask;
39743975
_FORCE_INLINE_ bool operator()(void *p_data) {
39753976
Instance *p_instance = (Instance *)p_data;
3976-
result->push_back(p_instance);
3977+
if (p_instance->layer_mask & heightfield_mask) {
3978+
result->push_back(p_instance);
3979+
}
39773980
return false;
39783981
}
39793982
};
39803983

39813984
CullAABB cull_aabb;
39823985
cull_aabb.result = &instance_cull_result;
3986+
cull_aabb.heightfield_mask = RSG::particles_storage->particles_collision_get_height_field_mask(hfpc->base);
39833987
hfpc->scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(hfpc->transformed_aabb, cull_aabb);
39843988
hfpc->scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(hfpc->transformed_aabb, cull_aabb);
39853989

servers/rendering/rendering_server_default.h

+1
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ class RenderingServerDefault : public RenderingServer {
618618
FUNC2(particles_collision_set_attractor_attenuation, RID, real_t)
619619
FUNC2(particles_collision_set_field_texture, RID, RID)
620620
FUNC1(particles_collision_height_field_update, RID)
621+
FUNC2(particles_collision_set_height_field_mask, RID, uint32_t)
621622
FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
622623

623624
/* FOG VOLUME */

servers/rendering/storage/particles_storage.h

+2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ class RendererParticlesStorage {
120120
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field
121121
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0;
122122
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0;
123+
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const = 0;
124+
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) = 0;
123125

124126
//used from 2D and 3D
125127
virtual RID particles_collision_instance_create(RID p_collision) = 0;

servers/rendering_server.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -2745,6 +2745,7 @@ void RenderingServer::_bind_methods() {
27452745

27462746
ClassDB::bind_method(D_METHOD("particles_collision_height_field_update", "particles_collision"), &RenderingServer::particles_collision_height_field_update);
27472747
ClassDB::bind_method(D_METHOD("particles_collision_set_height_field_resolution", "particles_collision", "resolution"), &RenderingServer::particles_collision_set_height_field_resolution);
2748+
ClassDB::bind_method(D_METHOD("particles_collision_set_height_field_mask", "particles_collision", "mask"), &RenderingServer::particles_collision_set_height_field_mask);
27482749

27492750
BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT);
27502751
BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_BOX_ATTRACT);

servers/rendering_server.h

+1
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,7 @@ class RenderingServer : public Object {
857857
};
858858

859859
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, ParticlesCollisionHeightfieldResolution p_resolution) = 0; // For SDF and vector field.
860+
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) = 0;
860861

861862
/* FOG VOLUME API */
862863

0 commit comments

Comments
 (0)