diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index b7cd22de9fc..7d2d7722494 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -209,7 +209,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK); } void LightStorage::light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) { diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp index 599412c5b2d..d3f20880ca3 100644 --- a/drivers/gles3/storage/particles_storage.cpp +++ b/drivers/gles3/storage/particles_storage.cpp @@ -1319,6 +1319,13 @@ void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collisi ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_NULL(particles_collision); particles_collision->cull_mask = p_cull_mask; + particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK); +} + +uint32_t ParticlesStorage::particles_collision_get_cull_mask(RID p_particles_collision) const { + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); + ERR_FAIL_NULL_V(particles_collision, 0); + return particles_collision->cull_mask; } void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) { diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h index 2c96e37a319..662592cea4b 100644 --- a/drivers/gles3/storage/particles_storage.h +++ b/drivers/gles3/storage/particles_storage.h @@ -436,6 +436,7 @@ public: GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override; virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override; + virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override; _FORCE_INLINE_ Size2i particles_collision_get_heightfield_size(RID p_particles_collision) const { ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); diff --git a/servers/rendering/dummy/storage/particles_storage.h b/servers/rendering/dummy/storage/particles_storage.h index a11f25e3a04..e3e7d6aa061 100644 --- a/servers/rendering/dummy/storage/particles_storage.h +++ b/servers/rendering/dummy/storage/particles_storage.h @@ -115,6 +115,7 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; } virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override { return 0; } virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override {} + virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override { return 0; } virtual RID particles_collision_instance_create(RID p_collision) override { return RID(); } virtual void particles_collision_instance_free(RID p_rid) override {} diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index edbebbd14c3..1259538d9dd 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -1120,9 +1120,6 @@ void main() { uvec2 decal_indices = instances.data[draw_call.instance_index].decals; for (uint i = 0; i < sc_decals(); i++) { uint decal_index = (i > 3) ? ((decal_indices.y >> ((i - 4) * 8)) & 0xFF) : ((decal_indices.x >> (i * 8)) & 0xFF); - if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) { - continue; //not masked - } vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index f4398743105..c708ea127ae 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -268,7 +268,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK); } void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) { diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 5765550b100..ffaf8e326aa 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -1850,6 +1850,13 @@ void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collisi ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_NULL(particles_collision); particles_collision->cull_mask = p_cull_mask; + particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK); +} + +uint32_t ParticlesStorage::particles_collision_get_cull_mask(RID p_particles_collision) const { + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); + ERR_FAIL_NULL_V(particles_collision, 0); + return particles_collision->cull_mask; } uint32_t ParticlesStorage::particles_collision_get_height_field_mask(RID p_particles_collision) const { diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index ecd0921a3da..60f4a24bc9f 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -583,6 +583,7 @@ public: RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override; virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override; + virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override; Dependency *particles_collision_get_dependency(RID p_particles) const; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 2a41543410d..f01edd2d2df 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2744,7 +2744,7 @@ void TextureStorage::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_NULL(decal); decal->cull_mask = p_layers; - decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_DECAL); + decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK); } void TextureStorage::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 277ada1e4d0..06eeb427557 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -178,6 +178,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { InstanceLightData *light = static_cast(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); + if (!(light->cull_mask & A->layer_mask)) { + // Early return if the object's layer mask doesn't match the light's cull mask. + return; + } + geom->lights.insert(B); light->geometries.insert(A); @@ -222,6 +227,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { InstanceDecalData *decal = static_cast(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); + if (!(decal->cull_mask & A->layer_mask)) { + // Early return if the object's layer mask doesn't match the decal's cull mask. + return; + } + geom->decals.insert(B); decal->geometries.insert(A); @@ -267,7 +277,10 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { voxel_gi->lights.insert(A); } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { InstanceParticlesCollisionData *collision = static_cast(B->base_data); - RSG::particles_storage->particles_add_collision(A->base, collision->instance); + + if ((collision->cull_mask & A->layer_mask)) { + RSG::particles_storage->particles_add_collision(A->base, collision->instance); + } } } @@ -285,6 +298,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { InstanceLightData *light = static_cast(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); + if (!(light->cull_mask & A->layer_mask)) { + // Early return if the object's layer mask doesn't match the light's cull mask. + return; + } + geom->lights.erase(B); light->geometries.erase(A); @@ -339,6 +357,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { InstanceDecalData *decal = static_cast(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); + if (!(decal->cull_mask & A->layer_mask)) { + // Early return if the object's layer mask doesn't match the decal's cull mask. + return; + } + geom->decals.erase(B); decal->geometries.erase(A); @@ -383,7 +406,10 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { voxel_gi->lights.erase(A); } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { InstanceParticlesCollisionData *collision = static_cast(B->base_data); - RSG::particles_storage->particles_remove_collision(A->base, collision->instance); + + if ((collision->cull_mask & A->layer_mask)) { + RSG::particles_storage->particles_remove_collision(A->base, collision->instance); + } } } @@ -888,6 +914,14 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) return; } + // Particles always need to be unpaired. Geometry may need to be unpaired, but only if lights or decals use pairing. + // Needs to happen before layer mask changes so we can avoid attempting to unpair something that was never paired. + if (instance->base_type == RS::INSTANCE_PARTICLES || + (((geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT)) || (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL))) && ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK))) { + _unpair_instance(instance); + singleton->_instance_queue_update(instance, false, false); + } + instance->layer_mask = p_mask; if (instance->scenario && instance->array_index >= 0) { instance->scenario->instance_data[instance->array_index].layer_mask = p_mask; @@ -1592,6 +1626,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { if (light->max_sdfgi_cascade != max_sdfgi_cascade) { light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario } + light->cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base); } else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { InstanceReflectionProbeData *reflection_probe = static_cast(p_instance->base_data); @@ -1605,6 +1640,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { InstanceDecalData *decal = static_cast(p_instance->base_data); RSG::texture_storage->decal_instance_set_transform(decal->instance, *instance_xform); + decal->cull_mask = RSG::texture_storage->decal_get_cull_mask(p_instance->base); } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { InstanceLightmapData *lightmap = static_cast(p_instance->base_data); @@ -1623,6 +1659,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { heightfield_particle_colliders_update_list.insert(p_instance); } RSG::particles_storage->particles_collision_instance_set_transform(collision->instance, *instance_xform); + collision->cull_mask = RSG::particles_storage->particles_collision_get_cull_mask(p_instance->base); } else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) { InstanceFogVolumeData *volume = static_cast(p_instance->base_data); scene_render->fog_volume_instance_set_transform(volume->instance, *instance_xform); @@ -1818,7 +1855,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { pair.pair_allocator = &pair_allocator; pair.pair_pass = pair_pass; pair.pair_mask = 0; - pair.cull_mask = 0xFFFFFFFF; if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; @@ -1840,7 +1876,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI); pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; } - pair.cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base); } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; @@ -1850,7 +1885,6 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) { pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; - pair.cull_mask = RSG::texture_storage->decal_get_cull_mask(p_instance->base); } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 42a75891966..0e1141761b6 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -508,7 +508,8 @@ public: case Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE: { singleton->_instance_queue_update(instance, true, true); } break; - case Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR: { + case Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR: + case Dependency::DEPENDENCY_CHANGED_CULL_MASK: { //requires repairing if (instance->indexer_id.is_valid()) { singleton->_unpair_instance(instance); @@ -655,6 +656,7 @@ public: struct InstanceDecalData : public InstanceBaseData { Instance *owner = nullptr; RID instance; + uint32_t cull_mask = 0xFFFFFFFF; HashSet geometries; @@ -666,6 +668,7 @@ public: struct InstanceParticlesCollisionData : public InstanceBaseData { RID instance; + uint32_t cull_mask = 0xFFFFFFFF; }; struct InstanceFogVolumeData : public InstanceBaseData { @@ -699,6 +702,7 @@ public: RS::LightBakeMode bake_mode; uint32_t max_sdfgi_cascade = 2; + uint32_t cull_mask = 0xFFFFFFFF; private: // Instead of a single dirty flag, we maintain a count @@ -817,12 +821,11 @@ public: DynamicBVH *bvh2 = nullptr; //some may need to cull in two uint32_t pair_mask; uint64_t pair_pass; - uint32_t cull_mask = 0xFFFFFFFF; // Needed for decals and lights in the mobile and compatibility renderers. _FORCE_INLINE_ bool operator()(void *p_data) { Instance *p_instance = (Instance *)p_data; - 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)) { + if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) { //test is more coarse in indexer p_instance->pair_check = pair_pass; InstancePair *pair = pair_allocator->alloc(); diff --git a/servers/rendering/storage/particles_storage.h b/servers/rendering/storage/particles_storage.h index 900bf4790ad..5f96868d514 100644 --- a/servers/rendering/storage/particles_storage.h +++ b/servers/rendering/storage/particles_storage.h @@ -121,6 +121,7 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const = 0; virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) = 0; + virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const = 0; //used from 2D and 3D virtual RID particles_collision_instance_create(RID p_collision) = 0; diff --git a/servers/rendering/storage/utilities.h b/servers/rendering/storage/utilities.h index 54b84fdf760..74d1cb66da4 100644 --- a/servers/rendering/storage/utilities.h +++ b/servers/rendering/storage/utilities.h @@ -50,6 +50,7 @@ public: DEPENDENCY_CHANGED_LIGHT, DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR, DEPENDENCY_CHANGED_REFLECTION_PROBE, + DEPENDENCY_CHANGED_CULL_MASK, }; void changed_notify(DependencyChangedNotification p_notification);