@@ -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];
0 commit comments