@@ -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