Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul the cull mask internals for Lights, Decals, and Particle Colliders #102399

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/gles3/storage/light_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions drivers/gles3/storage/particles_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,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) {
Expand Down
1 change: 1 addition & 0 deletions drivers/gles3/storage/particles_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ class ParticlesStorage : public RendererParticlesStorage {
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
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);
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/dummy/storage/particles_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class ParticlesStorage : public RendererParticlesStorage {
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {}
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); }
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
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 {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1113,9 +1113,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)))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ class ParticlesStorage : public RendererParticlesStorage {
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override;

Dependency *particles_collision_get_dependency(RID p_particles) const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2698,7 +2698,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) {
Expand Down
44 changes: 39 additions & 5 deletions servers/rendering/renderer_scene_cull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(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);

Expand Down Expand Up @@ -222,6 +227,11 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(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);

Expand Down Expand Up @@ -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<InstanceParticlesCollisionData *>(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);
}
}
}

Expand All @@ -285,6 +298,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(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);

Expand Down Expand Up @@ -339,6 +357,11 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(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);

Expand Down Expand Up @@ -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<InstanceParticlesCollisionData *>(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);
}
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1705,6 +1739,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<InstanceReflectionProbeData *>(p_instance->base_data);

Expand All @@ -1718,6 +1753,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const {
InstanceDecalData *decal = static_cast<InstanceDecalData *>(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<InstanceLightmapData *>(p_instance->base_data);

Expand All @@ -1736,6 +1772,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<InstanceFogVolumeData *>(p_instance->base_data);
scene_render->fog_volume_instance_set_transform(volume->instance, *instance_xform);
Expand Down Expand Up @@ -1927,7 +1964,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;
Expand All @@ -1949,7 +1985,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];
Expand All @@ -1959,7 +1994,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];
Expand Down
9 changes: 6 additions & 3 deletions servers/rendering/renderer_scene_cull.h
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,8 @@ class RendererSceneCull : public RenderingMethod {
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);
Expand Down Expand Up @@ -684,6 +685,7 @@ class RendererSceneCull : public RenderingMethod {
struct InstanceDecalData : public InstanceBaseData {
Instance *owner = nullptr;
RID instance;
uint32_t cull_mask = 0xFFFFFFFF;

HashSet<Instance *> geometries;

Expand All @@ -695,6 +697,7 @@ class RendererSceneCull : public RenderingMethod {

struct InstanceParticlesCollisionData : public InstanceBaseData {
RID instance;
uint32_t cull_mask = 0xFFFFFFFF;
};

struct InstanceFogVolumeData : public InstanceBaseData {
Expand Down Expand Up @@ -728,6 +731,7 @@ class RendererSceneCull : public RenderingMethod {

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
Expand Down Expand Up @@ -846,12 +850,11 @@ class RendererSceneCull : public RenderingMethod {
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();
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/storage/particles_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class RendererParticlesStorage {
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0;
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 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;
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/storage/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class Dependency {
DEPENDENCY_CHANGED_LIGHT,
DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR,
DEPENDENCY_CHANGED_REFLECTION_PROBE,
DEPENDENCY_CHANGED_CULL_MASK,
};

void changed_notify(DependencyChangedNotification p_notification);
Expand Down