@@ -178,6 +178,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
178
178
InstanceLightData *light = static_cast <InstanceLightData *>(B->base_data );
179
179
InstanceGeometryData *geom = static_cast <InstanceGeometryData *>(A->base_data );
180
180
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
+
181
186
geom->lights .insert (B);
182
187
light->geometries .insert (A);
183
188
@@ -222,6 +227,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
222
227
InstanceDecalData *decal = static_cast <InstanceDecalData *>(B->base_data );
223
228
InstanceGeometryData *geom = static_cast <InstanceGeometryData *>(A->base_data );
224
229
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
+
225
235
geom->decals .insert (B);
226
236
decal->geometries .insert (A);
227
237
@@ -267,7 +277,10 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
267
277
voxel_gi->lights .insert (A);
268
278
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
269
279
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
+ }
271
284
}
272
285
}
273
286
@@ -285,6 +298,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
285
298
InstanceLightData *light = static_cast <InstanceLightData *>(B->base_data );
286
299
InstanceGeometryData *geom = static_cast <InstanceGeometryData *>(A->base_data );
287
300
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
+
288
306
geom->lights .erase (B);
289
307
light->geometries .erase (A);
290
308
@@ -339,6 +357,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
339
357
InstanceDecalData *decal = static_cast <InstanceDecalData *>(B->base_data );
340
358
InstanceGeometryData *geom = static_cast <InstanceGeometryData *>(A->base_data );
341
359
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
+
342
365
geom->decals .erase (B);
343
366
decal->geometries .erase (A);
344
367
@@ -383,7 +406,10 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
383
406
voxel_gi->lights .erase (A);
384
407
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
385
408
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
+ }
387
413
}
388
414
}
389
415
@@ -888,6 +914,14 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
888
914
return ;
889
915
}
890
916
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
+
891
925
instance->layer_mask = p_mask;
892
926
if (instance->scenario && instance->array_index >= 0 ) {
893
927
instance->scenario ->instance_data [instance->array_index ].layer_mask = p_mask;
@@ -1592,6 +1626,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
1592
1626
if (light->max_sdfgi_cascade != max_sdfgi_cascade) {
1593
1627
light->max_sdfgi_cascade = max_sdfgi_cascade; // should most likely make sdfgi dirty in scenario
1594
1628
}
1629
+ light->cull_mask = RSG::light_storage->light_get_cull_mask (p_instance->base );
1595
1630
} else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) {
1596
1631
InstanceReflectionProbeData *reflection_probe = static_cast <InstanceReflectionProbeData *>(p_instance->base_data );
1597
1632
@@ -1605,6 +1640,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
1605
1640
InstanceDecalData *decal = static_cast <InstanceDecalData *>(p_instance->base_data );
1606
1641
1607
1642
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 );
1608
1644
} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
1609
1645
InstanceLightmapData *lightmap = static_cast <InstanceLightmapData *>(p_instance->base_data );
1610
1646
@@ -1623,6 +1659,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
1623
1659
heightfield_particle_colliders_update_list.insert (p_instance);
1624
1660
}
1625
1661
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 );
1626
1663
} else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) {
1627
1664
InstanceFogVolumeData *volume = static_cast <InstanceFogVolumeData *>(p_instance->base_data );
1628
1665
scene_render->fog_volume_instance_set_transform (volume->instance , *instance_xform);
@@ -1818,7 +1855,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
1818
1855
pair.pair_allocator = &pair_allocator;
1819
1856
pair.pair_pass = pair_pass;
1820
1857
pair.pair_mask = 0 ;
1821
- pair.cull_mask = 0xFFFFFFFF ;
1822
1858
1823
1859
if ((1 << p_instance->base_type ) & RS::INSTANCE_GEOMETRY_MASK) {
1824
1860
pair.pair_mask |= 1 << RS::INSTANCE_LIGHT;
@@ -1840,7 +1876,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
1840
1876
pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI);
1841
1877
pair.bvh2 = &p_instance->scenario ->indexers [Scenario::INDEXER_VOLUMES];
1842
1878
}
1843
- pair.cull_mask = RSG::light_storage->light_get_cull_mask (p_instance->base );
1844
1879
} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
1845
1880
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
1846
1881
pair.bvh = &p_instance->scenario ->indexers [Scenario::INDEXER_GEOMETRY];
@@ -1850,7 +1885,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
1850
1885
} else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) {
1851
1886
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK;
1852
1887
pair.bvh = &p_instance->scenario ->indexers [Scenario::INDEXER_GEOMETRY];
1853
- pair.cull_mask = RSG::texture_storage->decal_get_cull_mask (p_instance->base );
1854
1888
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
1855
1889
pair.pair_mask = (1 << RS::INSTANCE_PARTICLES);
1856
1890
pair.bvh = &p_instance->scenario ->indexers [Scenario::INDEXER_GEOMETRY];
0 commit comments