Skip to content

Commit 305216f

Browse files
committed
Overhaul the cull mask internals for Lights, Decals, and Particle Colliders
Properly pair and unpair instances based on cull mask to avoid any unnecessary processing and to ensure that changing the cull_mask and layer_mask actually updates culling behavior
1 parent 8f78e75 commit 305216f

13 files changed

+67
-14
lines changed

drivers/gles3/storage/light_storage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
209209
light->cull_mask = p_mask;
210210

211211
light->version++;
212-
light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
212+
light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK);
213213
}
214214

215215
void LightStorage::light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) {

drivers/gles3/storage/particles_storage.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,13 @@ void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collisi
13191319
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
13201320
ERR_FAIL_NULL(particles_collision);
13211321
particles_collision->cull_mask = p_cull_mask;
1322+
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK);
1323+
}
1324+
1325+
uint32_t ParticlesStorage::particles_collision_get_cull_mask(RID p_particles_collision) const {
1326+
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1327+
ERR_FAIL_NULL_V(particles_collision, 0);
1328+
return particles_collision->cull_mask;
13221329
}
13231330

13241331
void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {

drivers/gles3/storage/particles_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ class ParticlesStorage : public RendererParticlesStorage {
436436
GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
437437
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override;
438438
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override;
439+
virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override;
439440

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

servers/rendering/dummy/storage/particles_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class ParticlesStorage : public RendererParticlesStorage {
115115
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
116116
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override { return 0; }
117117
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override {}
118+
virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override { return 0; }
118119

119120
virtual RID particles_collision_instance_create(RID p_collision) override { return RID(); }
120121
virtual void particles_collision_instance_free(RID p_rid) override {}

servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,9 +1120,6 @@ void main() {
11201120
uvec2 decal_indices = instances.data[draw_call.instance_index].decals;
11211121
for (uint i = 0; i < sc_decals(); i++) {
11221122
uint decal_index = (i > 3) ? ((decal_indices.y >> ((i - 4) * 8)) & 0xFF) : ((decal_indices.x >> (i * 8)) & 0xFF);
1123-
if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) {
1124-
continue; //not masked
1125-
}
11261123

11271124
vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz;
11281125
if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) {

servers/rendering/renderer_rd/storage_rd/light_storage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
268268
light->cull_mask = p_mask;
269269

270270
light->version++;
271-
light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
271+
light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK);
272272
}
273273

274274
void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) {

servers/rendering/renderer_rd/storage_rd/particles_storage.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,13 @@ void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collisi
18501850
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
18511851
ERR_FAIL_NULL(particles_collision);
18521852
particles_collision->cull_mask = p_cull_mask;
1853+
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK);
1854+
}
1855+
1856+
uint32_t ParticlesStorage::particles_collision_get_cull_mask(RID p_particles_collision) const {
1857+
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1858+
ERR_FAIL_NULL_V(particles_collision, 0);
1859+
return particles_collision->cull_mask;
18531860
}
18541861

18551862
uint32_t ParticlesStorage::particles_collision_get_height_field_mask(RID p_particles_collision) const {

servers/rendering/renderer_rd/storage_rd/particles_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ class ParticlesStorage : public RendererParticlesStorage {
583583
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
584584
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override;
585585
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override;
586+
virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override;
586587

587588
Dependency *particles_collision_get_dependency(RID p_particles) const;
588589

servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2744,7 +2744,7 @@ void TextureStorage::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
27442744
Decal *decal = decal_owner.get_or_null(p_decal);
27452745
ERR_FAIL_NULL(decal);
27462746
decal->cull_mask = p_layers;
2747-
decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_DECAL);
2747+
decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK);
27482748
}
27492749

27502750
void TextureStorage::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {

servers/rendering/renderer_scene_cull.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
178178
InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
179179
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
180180

181+
if (!(light->cull_mask & A->layer_mask)) {
182+
// Early return if the object's layer mask doesn't match the light's cull mask.
183+
return;
184+
}
185+
181186
geom->lights.insert(B);
182187
light->geometries.insert(A);
183188

@@ -222,6 +227,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
222227
InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);
223228
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
224229

230+
if (!(decal->cull_mask & A->layer_mask)) {
231+
// Early return if the object's layer mask doesn't match the decal's cull mask.
232+
return;
233+
}
234+
225235
geom->decals.insert(B);
226236
decal->geometries.insert(A);
227237

@@ -267,7 +277,10 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
267277
voxel_gi->lights.insert(A);
268278
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
269279
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data);
270-
RSG::particles_storage->particles_add_collision(A->base, collision->instance);
280+
281+
if ((collision->cull_mask & A->layer_mask)) {
282+
RSG::particles_storage->particles_add_collision(A->base, collision->instance);
283+
}
271284
}
272285
}
273286

@@ -285,6 +298,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
285298
InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
286299
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
287300

301+
if (!(light->cull_mask & A->layer_mask)) {
302+
// Early return if the object's layer mask doesn't match the light's cull mask.
303+
return;
304+
}
305+
288306
geom->lights.erase(B);
289307
light->geometries.erase(A);
290308

@@ -339,6 +357,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
339357
InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);
340358
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
341359

360+
if (!(decal->cull_mask & A->layer_mask)) {
361+
// Early return if the object's layer mask doesn't match the decal's cull mask.
362+
return;
363+
}
364+
342365
geom->decals.erase(B);
343366
decal->geometries.erase(A);
344367

@@ -383,7 +406,10 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
383406
voxel_gi->lights.erase(A);
384407
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
385408
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data);
386-
RSG::particles_storage->particles_remove_collision(A->base, collision->instance);
409+
410+
if ((collision->cull_mask & A->layer_mask)) {
411+
RSG::particles_storage->particles_remove_collision(A->base, collision->instance);
412+
}
387413
}
388414
}
389415

@@ -888,6 +914,14 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
888914
return;
889915
}
890916

917+
// Particles always need to be unpaired. Geometry may need to be unpaired, but only if lights or decals use pairing.
918+
// Needs to happen before layer mask changes so we can avoid attempting to unpair something that was never paired.
919+
if (instance->base_type == RS::INSTANCE_PARTICLES ||
920+
(((geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT)) || (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL))) && ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK))) {
921+
_unpair_instance(instance);
922+
singleton->_instance_queue_update(instance, false, false);
923+
}
924+
891925
instance->layer_mask = p_mask;
892926
if (instance->scenario && instance->array_index >= 0) {
893927
instance->scenario->instance_data[instance->array_index].layer_mask = p_mask;
@@ -1592,6 +1626,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
15921626
if (light->max_sdfgi_cascade != max_sdfgi_cascade) {
15931627
light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario
15941628
}
1629+
light->cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base);
15951630
} else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) {
15961631
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
15971632

@@ -1605,6 +1640,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
16051640
InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data);
16061641

16071642
RSG::texture_storage->decal_instance_set_transform(decal->instance, *instance_xform);
1643+
decal->cull_mask = RSG::texture_storage->decal_get_cull_mask(p_instance->base);
16081644
} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
16091645
InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data);
16101646

@@ -1623,6 +1659,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
16231659
heightfield_particle_colliders_update_list.insert(p_instance);
16241660
}
16251661
RSG::particles_storage->particles_collision_instance_set_transform(collision->instance, *instance_xform);
1662+
collision->cull_mask = RSG::particles_storage->particles_collision_get_cull_mask(p_instance->base);
16261663
} else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) {
16271664
InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(p_instance->base_data);
16281665
scene_render->fog_volume_instance_set_transform(volume->instance, *instance_xform);
@@ -1818,7 +1855,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
18181855
pair.pair_allocator = &pair_allocator;
18191856
pair.pair_pass = pair_pass;
18201857
pair.pair_mask = 0;
1821-
pair.cull_mask = 0xFFFFFFFF;
18221858

18231859
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
18241860
pair.pair_mask |= 1 << RS::INSTANCE_LIGHT;
@@ -1840,7 +1876,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
18401876
pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI);
18411877
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
18421878
}
1843-
pair.cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base);
18441879
} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
18451880
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
18461881
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
@@ -1850,7 +1885,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
18501885
} else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) {
18511886
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
18521887
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
1853-
pair.cull_mask = RSG::texture_storage->decal_get_cull_mask(p_instance->base);
18541888
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
18551889
pair.pair_mask = (1 << RS::INSTANCE_PARTICLES);
18561890
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];

servers/rendering/renderer_scene_cull.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ class RendererSceneCull : public RenderingMethod {
508508
case Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE: {
509509
singleton->_instance_queue_update(instance, true, true);
510510
} break;
511-
case Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR: {
511+
case Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR:
512+
case Dependency::DEPENDENCY_CHANGED_CULL_MASK: {
512513
//requires repairing
513514
if (instance->indexer_id.is_valid()) {
514515
singleton->_unpair_instance(instance);
@@ -655,6 +656,7 @@ class RendererSceneCull : public RenderingMethod {
655656
struct InstanceDecalData : public InstanceBaseData {
656657
Instance *owner = nullptr;
657658
RID instance;
659+
uint32_t cull_mask = 0xFFFFFFFF;
658660

659661
HashSet<Instance *> geometries;
660662

@@ -666,6 +668,7 @@ class RendererSceneCull : public RenderingMethod {
666668

667669
struct InstanceParticlesCollisionData : public InstanceBaseData {
668670
RID instance;
671+
uint32_t cull_mask = 0xFFFFFFFF;
669672
};
670673

671674
struct InstanceFogVolumeData : public InstanceBaseData {
@@ -699,6 +702,7 @@ class RendererSceneCull : public RenderingMethod {
699702

700703
RS::LightBakeMode bake_mode;
701704
uint32_t max_sdfgi_cascade = 2;
705+
uint32_t cull_mask = 0xFFFFFFFF;
702706

703707
private:
704708
// Instead of a single dirty flag, we maintain a count
@@ -817,12 +821,11 @@ class RendererSceneCull : public RenderingMethod {
817821
DynamicBVH *bvh2 = nullptr; //some may need to cull in two
818822
uint32_t pair_mask;
819823
uint64_t pair_pass;
820-
uint32_t cull_mask = 0xFFFFFFFF; // Needed for decals and lights in the mobile and compatibility renderers.
821824

822825
_FORCE_INLINE_ bool operator()(void *p_data) {
823826
Instance *p_instance = (Instance *)p_data;
824827

825-
if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type)) && (cull_mask & p_instance->layer_mask)) {
828+
if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) {
826829
//test is more coarse in indexer
827830
p_instance->pair_check = pair_pass;
828831
InstancePair *pair = pair_allocator->alloc();

servers/rendering/storage/particles_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class RendererParticlesStorage {
121121
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0;
122122
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const = 0;
123123
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) = 0;
124+
virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const = 0;
124125

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

servers/rendering/storage/utilities.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Dependency {
5050
DEPENDENCY_CHANGED_LIGHT,
5151
DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR,
5252
DEPENDENCY_CHANGED_REFLECTION_PROBE,
53+
DEPENDENCY_CHANGED_CULL_MASK,
5354
};
5455

5556
void changed_notify(DependencyChangedNotification p_notification);

0 commit comments

Comments
 (0)