diff --git a/doc/classes/VisualInstance.xml b/doc/classes/VisualInstance.xml index b77ad1ae4c2b..f4de58e91edc 100644 --- a/doc/classes/VisualInstance.xml +++ b/doc/classes/VisualInstance.xml @@ -62,6 +62,13 @@ The render layer(s) this [VisualInstance] is drawn on. This object will only be visible for [Camera]s whose cull mask includes the render object this [VisualInstance] is set to. + + The sorting offset used by this [VisualInstance]. Adjusting it to a higher value will make the [VisualInstance] reliably draw on top of other [VisualInstance]s that are otherwise positioned at the same spot. + + + If [code]true[/code], the object is sorted based on the [AABB] center. Sorted based on the global position otherwise. + The [AABB] center based sorting is generally more accurate for 3D models. The position based sorting instead allows to better control the drawing order when working with [Particles] and [CPUParticles]. + diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 83a7fc11c621..5249e0150d4b 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -180,6 +180,24 @@ bool VisualInstance::get_layer_mask_bit(int p_layer) const { return (layers & (1 << p_layer)); } +void VisualInstance::set_sorting_offset(float p_offset) { + sorting_offset = p_offset; + VisualServer::get_singleton()->instance_set_pivot_data(instance, sorting_offset, sorting_use_aabb_center); +} + +float VisualInstance::get_sorting_offset() { + return sorting_offset; +} + +void VisualInstance::set_sorting_use_aabb_center(bool p_enabled) { + sorting_use_aabb_center = p_enabled; + VisualServer::get_singleton()->instance_set_pivot_data(instance, sorting_offset, sorting_use_aabb_center); +} + +bool VisualInstance::is_sorting_use_aabb_center() { + return sorting_use_aabb_center; +} + void VisualInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid); ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base); @@ -190,8 +208,16 @@ void VisualInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit); ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance::get_layer_mask_bit); ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance::get_transformed_aabb); + ClassDB::bind_method(D_METHOD("set_sorting_offset", "offset"), &VisualInstance::set_sorting_offset); + ClassDB::bind_method(D_METHOD("get_sorting_offset"), &VisualInstance::get_sorting_offset); + ClassDB::bind_method(D_METHOD("set_sorting_use_aabb_center", "enabled"), &VisualInstance::set_sorting_use_aabb_center); + ClassDB::bind_method(D_METHOD("is_sorting_use_aabb_center"), &VisualInstance::is_sorting_use_aabb_center); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask"); + + ADD_GROUP("Sorting", "sorting_"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sorting_offset"), "set_sorting_offset", "get_sorting_offset"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sorting_use_aabb_center"), "set_sorting_use_aabb_center", "is_sorting_use_aabb_center"); } void VisualInstance::set_base(const RID &p_base) { @@ -207,6 +233,8 @@ VisualInstance::VisualInstance() { instance = RID_PRIME(VisualServer::get_singleton()->instance_create()); VisualServer::get_singleton()->instance_attach_object_instance_id(instance, get_instance_id()); layers = 1; + sorting_offset = 0.0f; + sorting_use_aabb_center = true; set_notify_transform(true); } diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index 65ad5decab05..0dd826e0da8f 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -43,6 +43,8 @@ class VisualInstance : public CullInstance { RID base; RID instance; uint32_t layers; + float sorting_offset; + bool sorting_use_aabb_center; RID _get_visual_instance_rid() const; @@ -77,6 +79,12 @@ class VisualInstance : public CullInstance { void set_layer_mask_bit(int p_layer, bool p_enable); bool get_layer_mask_bit(int p_layer) const; + void set_sorting_offset(float p_offset); + float get_sorting_offset(); + + void set_sorting_use_aabb_center(bool p_enabled); + bool is_sorting_use_aabb_center(); + VisualInstance(); ~VisualInstance(); }; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 8bdab6bc0a49..48f0c73c1ec6 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -579,6 +579,7 @@ class VisualServerRaster : public VisualServer { BIND2(instance_set_base, RID, RID) BIND2(instance_set_scenario, RID, RID) BIND2(instance_set_layer_mask, RID, uint32_t) + BIND3(instance_set_pivot_data, RID, float, bool) BIND2(instance_set_transform, RID, const Transform &) BIND2(instance_set_interpolated, RID, bool) BIND1(instance_reset_physics_interpolation, RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 676b2f830d71..0ba9395767ae 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -792,6 +792,14 @@ void VisualServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask) instance->layer_mask = p_mask; } +void VisualServerScene::instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) { + Instance *instance = instance_owner.get(p_instance); + ERR_FAIL_COND(!instance); + + instance->sorting_offset = p_sorting_offset; + instance->use_aabb_center = p_use_aabb_center; +} + void VisualServerScene::instance_reset_physics_interpolation(RID p_instance) { Instance *instance = instance_owner.get(p_instance); ERR_FAIL_COND(!instance); @@ -3267,11 +3275,14 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca Instance *ins = instance_cull_result[i]; if (((1 << ins->base_type) & VS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { - Vector3 aabb_center = ins->transformed_aabb.position + (ins->transformed_aabb.size * 0.5); + Vector3 center = ins->transform.origin; + if (ins->use_aabb_center) { + center = ins->transformed_aabb.position + (ins->transformed_aabb.size * 0.5); + } if (p_cam_orthogonal) { - ins->depth = near_plane.distance_to(aabb_center); + ins->depth = near_plane.distance_to(center) - ins->sorting_offset; } else { - ins->depth = p_cam_transform.origin.distance_to(aabb_center); + ins->depth = p_cam_transform.origin.distance_to(center) - ins->sorting_offset; } ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15); } diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 826c1a9bee1f..ef37a6f2bb4e 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -311,6 +311,8 @@ class VisualServerScene { AABB aabb; AABB transformed_aabb; AABB *custom_aabb; // would using aabb directly with a bool be better? + float sorting_offset; + bool use_aabb_center; float extra_margin; uint32_t object_id; @@ -371,6 +373,8 @@ class VisualServerScene { base_data = nullptr; custom_aabb = nullptr; + sorting_offset = 0.0f; + use_aabb_center = false; } ~Instance() { @@ -614,6 +618,7 @@ class VisualServerScene { virtual void instance_set_base(RID p_instance, RID p_base); virtual void instance_set_scenario(RID p_instance, RID p_scenario); virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); + virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center); virtual void instance_set_transform(RID p_instance, const Transform &p_transform); virtual void instance_set_interpolated(RID p_instance, bool p_interpolated); virtual void instance_reset_physics_interpolation(RID p_instance); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index a7e4be342642..cb899359307b 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -485,6 +485,7 @@ class VisualServerWrapMT : public VisualServer { FUNC2(instance_set_base, RID, RID) FUNC2(instance_set_scenario, RID, RID) FUNC2(instance_set_layer_mask, RID, uint32_t) + FUNC3(instance_set_pivot_data, RID, float, bool) FUNC2(instance_set_transform, RID, const Transform &) FUNC2(instance_set_interpolated, RID, bool) FUNC1(instance_reset_physics_interpolation, RID) diff --git a/servers/visual_server.h b/servers/visual_server.h index a3f6878a7c53..f14060de72b1 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -866,6 +866,7 @@ class VisualServer : public Object { virtual void instance_set_base(RID p_instance, RID p_base) = 0; virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; + virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) = 0; virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; virtual void instance_set_interpolated(RID p_instance, bool p_interpolated) = 0; virtual void instance_reset_physics_interpolation(RID p_instance) = 0;