diff options
Diffstat (limited to 'servers')
20 files changed, 347 insertions, 289 deletions
diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 6af4783fa5..82343e0402 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -38,6 +38,9 @@ DisplayServer *DisplayServer::singleton = nullptr; bool DisplayServer::hidpi_allowed = false; +bool DisplayServer::window_early_clear_override_enabled = false; +Color DisplayServer::window_early_clear_override_color = Color(0, 0, 0, 0); + DisplayServer::DisplayServerCreate DisplayServer::server_create_functions[DisplayServer::MAX_SERVERS] = { { "headless", &DisplayServerHeadless::create_func, &DisplayServerHeadless::get_rendering_drivers_func } }; @@ -315,6 +318,23 @@ void DisplayServer::tts_post_utterance_event(TTSUtteranceEvent p_event, int p_id } } +bool DisplayServer::_get_window_early_clear_override(Color &r_color) { + if (window_early_clear_override_enabled) { + r_color = window_early_clear_override_color; + return true; + } else if (RenderingServer::get_singleton()) { + r_color = RenderingServer::get_singleton()->get_default_clear_color(); + return true; + } else { + return false; + } +} + +void DisplayServer::set_early_window_clear_color_override(bool p_enabled, Color p_color) { + window_early_clear_override_enabled = p_enabled; + window_early_clear_override_color = p_color; +} + void DisplayServer::mouse_set_mode(MouseMode p_mode) { WARN_PRINT("Mouse is not supported by this display server."); } diff --git a/servers/display_server.h b/servers/display_server.h index 0e4c8aa172..f8ade60aca 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -217,6 +217,16 @@ public: virtual bool is_dark_mode() const { return false; }; virtual Color get_accent_color() const { return Color(0, 0, 0, 0); }; +private: + static bool window_early_clear_override_enabled; + static Color window_early_clear_override_color; + +protected: + static bool _get_window_early_clear_override(Color &r_color); + +public: + static void set_early_window_clear_color_override(bool p_enabled, Color p_color = Color(0, 0, 0, 0)); + enum MouseMode { MOUSE_MODE_VISIBLE, MOUSE_MODE_HIDDEN, diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp index a174ceadac..2dbb59a323 100644 --- a/servers/extensions/physics_server_2d_extension.cpp +++ b/servers/extensions/physics_server_2d_extension.cpp @@ -37,6 +37,8 @@ bool PhysicsDirectSpaceState2DExtension::is_body_excluded_from_query(const RID & thread_local const HashSet<RID> *PhysicsDirectSpaceState2DExtension::exclude = nullptr; void PhysicsDirectSpaceState2DExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_body_excluded_from_query", "body"), &PhysicsDirectSpaceState2DExtension::is_body_excluded_from_query); + GDVIRTUAL_BIND(_intersect_ray, "from", "to", "collision_mask", "collide_with_bodies", "collide_with_areas", "hit_from_inside", "result"); GDVIRTUAL_BIND(_intersect_point, "position", "canvas_instance_id", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results"); GDVIRTUAL_BIND(_intersect_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "result", "max_results"); @@ -203,6 +205,9 @@ void PhysicsServer2DExtension::_bind_methods() { /* BODY API */ + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_body", "body"), &PhysicsServer2DExtension::body_test_motion_is_excluding_body); + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_object", "object"), &PhysicsServer2DExtension::body_test_motion_is_excluding_object); + GDVIRTUAL_BIND(_body_create); GDVIRTUAL_BIND(_body_set_space, "body", "space"); diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp index 788ece721b..0d8476fd68 100644 --- a/servers/extensions/physics_server_3d_extension.cpp +++ b/servers/extensions/physics_server_3d_extension.cpp @@ -37,6 +37,8 @@ bool PhysicsDirectSpaceState3DExtension::is_body_excluded_from_query(const RID & thread_local const HashSet<RID> *PhysicsDirectSpaceState3DExtension::exclude = nullptr; void PhysicsDirectSpaceState3DExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_body_excluded_from_query", "body"), &PhysicsDirectSpaceState3DExtension::is_body_excluded_from_query); + GDVIRTUAL_BIND(_intersect_ray, "from", "to", "collision_mask", "collide_with_bodies", "collide_with_areas", "hit_from_inside", "hit_back_faces", "result"); GDVIRTUAL_BIND(_intersect_point, "position", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results"); GDVIRTUAL_BIND(_intersect_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "result_count", "max_results"); @@ -206,6 +208,9 @@ void PhysicsServer3DExtension::_bind_methods() { /* BODY API */ + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_body", "body"), &PhysicsServer3DExtension::body_test_motion_is_excluding_body); + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_object", "object"), &PhysicsServer3DExtension::body_test_motion_is_excluding_object); + GDVIRTUAL_BIND(_body_create); GDVIRTUAL_BIND(_body_set_space, "body", "space"); diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 97c0ae0d54..253b28a623 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -123,6 +123,18 @@ void NavigationServer3D::_bind_methods() { ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map"))); ADD_SIGNAL(MethodInfo("navigation_debug_changed")); + + ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &NavigationServer3D::get_process_info); + + BIND_ENUM_CONSTANT(INFO_ACTIVE_MAPS); + BIND_ENUM_CONSTANT(INFO_REGION_COUNT); + BIND_ENUM_CONSTANT(INFO_AGENT_COUNT); + BIND_ENUM_CONSTANT(INFO_LINK_COUNT); + BIND_ENUM_CONSTANT(INFO_POLYGON_COUNT); + BIND_ENUM_CONSTANT(INFO_EDGE_COUNT); + BIND_ENUM_CONSTANT(INFO_EDGE_MERGE_COUNT); + BIND_ENUM_CONSTANT(INFO_EDGE_CONNECTION_COUNT); + BIND_ENUM_CONSTANT(INFO_EDGE_FREE_COUNT); } NavigationServer3D *NavigationServer3D::get_singleton() { diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index afd7216a43..6c4bd2e151 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -260,6 +260,20 @@ public: NavigationServer3D(); virtual ~NavigationServer3D(); + enum ProcessInfo { + INFO_ACTIVE_MAPS, + INFO_REGION_COUNT, + INFO_AGENT_COUNT, + INFO_LINK_COUNT, + INFO_POLYGON_COUNT, + INFO_EDGE_COUNT, + INFO_EDGE_MERGE_COUNT, + INFO_EDGE_CONNECTION_COUNT, + INFO_EDGE_FREE_COUNT, + }; + + virtual int get_process_info(ProcessInfo p_info) const = 0; + #ifdef DEBUG_ENABLED private: bool debug_enabled = false; @@ -357,4 +371,6 @@ public: static NavigationServer3D *new_default_server(); }; +VARIANT_ENUM_CAST(NavigationServer3D::ProcessInfo); + #endif // NAVIGATION_SERVER_3D_H diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index 36c47a07b9..d13f4ee801 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -758,24 +758,72 @@ public: typedef void (*CollisionFunc)(const GodotShape3D *, const Transform3D &, const GodotShape3D *, const Transform3D &, _CollectorCallback *p_callback, real_t, real_t); +// Perform analytic sphere-sphere collision and report results to collector template <bool withMargin> -static void _collision_sphere_sphere(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); - const GodotSphereShape3D *sphere_B = static_cast<const GodotSphereShape3D *>(p_b); +static void analytic_sphere_collision(const Vector3 &p_origin_a, real_t p_radius_a, const Vector3 &p_origin_b, real_t p_radius_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + // Expand the spheres by the margins if enabled + if (withMargin) { + p_radius_a += p_margin_a; + p_radius_b += p_margin_b; + } - SeparatorAxisTest<GodotSphereShape3D, GodotSphereShape3D, withMargin> separator(sphere_A, p_transform_a, sphere_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + // Get the vector from sphere B to A + Vector3 b_to_a = p_origin_a - p_origin_b; - // previous axis + // Get the length from B to A + real_t b_to_a_len = b_to_a.length(); - if (!separator.test_previous_axis()) { + // Calculate the sphere overlap, and bail if not overlapping + real_t overlap = p_radius_a + p_radius_b - b_to_a_len; + if (overlap < 0) return; - } - if (!separator.test_axis((p_transform_a.origin - p_transform_b.origin).normalized())) { + // Report collision + p_collector->collided = true; + + // Bail if there is no callback to receive the A and B collision points. + if (!p_collector->callback) { return; } - separator.generate_contacts(); + // Normalize the B to A vector + if (b_to_a_len < CMP_EPSILON) { + b_to_a = Vector3(0, 1, 0); // Spheres coincident, use arbitrary direction + } else { + b_to_a /= b_to_a_len; + } + + // Report collision points. The operations below are intended to minimize + // floating-point precision errors. This is done by calculating the first + // collision point from the smaller sphere, and then jumping across to + // the larger spheres collision point using the overlap distance. This + // jump is usually small even if the large sphere is massive, and so the + // second point will not suffer from precision errors. + if (p_radius_a < p_radius_b) { + Vector3 point_a = p_origin_a - b_to_a * p_radius_a; + Vector3 point_b = point_a + b_to_a * overlap; + p_collector->call(point_a, point_b); // Consider adding b_to_a vector + } else { + Vector3 point_b = p_origin_b + b_to_a * p_radius_b; + Vector3 point_a = point_b - b_to_a * overlap; + p_collector->call(point_a, point_b); // Consider adding b_to_a vector + } +} + +template <bool withMargin> +static void _collision_sphere_sphere(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotSphereShape3D *sphere_B = static_cast<const GodotSphereShape3D *>(p_b); + + // Perform an analytic sphere collision between the two spheres + analytic_sphere_collision<withMargin>( + p_transform_a.origin, + sphere_A->get_radius(), + p_transform_b.origin, + sphere_B->get_radius(), + p_collector, + p_margin_a, + p_margin_b); } template <bool withMargin> @@ -783,50 +831,36 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); const GodotBoxShape3D *box_B = static_cast<const GodotBoxShape3D *>(p_b); - SeparatorAxisTest<GodotSphereShape3D, GodotBoxShape3D, withMargin> separator(sphere_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + // Find the point on the box nearest to the center of the sphere. - if (!separator.test_previous_axis()) { - return; - } + Vector3 center = p_transform_b.xform_inv(p_transform_a.origin); + Vector3 extents = box_B->get_half_extents(); + Vector3 nearest(MIN(MAX(center.x, -extents.x), extents.x), + MIN(MAX(center.y, -extents.y), extents.y), + MIN(MAX(center.z, -extents.z), extents.z)); + nearest = p_transform_b.xform(nearest); - // test faces + // See if it is inside the sphere. - for (int i = 0; i < 3; i++) { - Vector3 axis = p_transform_b.basis.get_column(i).normalized(); - - if (!separator.test_axis(axis)) { - return; - } + Vector3 delta = nearest - p_transform_a.origin; + real_t length = delta.length(); + if (length > sphere_A->get_radius() + p_margin_a + p_margin_b) { + return; } - - // calculate closest point to sphere - - Vector3 cnormal = p_transform_b.xform_inv(p_transform_a.origin); - - Vector3 cpoint = p_transform_b.xform(Vector3( - - (cnormal.x < 0) ? -box_B->get_half_extents().x : box_B->get_half_extents().x, - (cnormal.y < 0) ? -box_B->get_half_extents().y : box_B->get_half_extents().y, - (cnormal.z < 0) ? -box_B->get_half_extents().z : box_B->get_half_extents().z)); - - // use point to test axis - Vector3 point_axis = (p_transform_a.origin - cpoint).normalized(); - - if (!separator.test_axis(point_axis)) { + p_collector->collided = true; + if (!p_collector->callback) { return; } - - // test edges - - for (int i = 0; i < 3; i++) { - Vector3 axis = point_axis.cross(p_transform_b.basis.get_column(i)).cross(p_transform_b.basis.get_column(i)).normalized(); - - if (!separator.test_axis(axis)) { - return; - } + Vector3 axis; + if (length == 0) { + // The box passes through the sphere center. Select an axis based on the box's center. + axis = (p_transform_b.origin - nearest).normalized(); + } else { + axis = delta / length; } - - separator.generate_contacts(); + Vector3 point_a = p_transform_a.origin + (sphere_A->get_radius() + p_margin_a) * axis; + Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest); + p_collector->call(point_a, point_b); } template <bool withMargin> @@ -834,41 +868,66 @@ static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - SeparatorAxisTest<GodotSphereShape3D, GodotCapsuleShape3D, withMargin> separator(sphere_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); - - if (!separator.test_previous_axis()) { - return; - } - - //capsule sphere 1, sphere - - Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); - - Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis; + real_t capsule_B_radius = capsule_B->get_radius(); + + // Construct the capsule segment (ball-center to ball-center) + Vector3 capsule_segment[2]; + Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B_radius); + capsule_segment[0] = p_transform_b.origin + capsule_axis; + capsule_segment[1] = p_transform_b.origin - capsule_axis; + + // Get the capsules closest segment-point to the sphere + Vector3 capsule_closest = Geometry3D::get_closest_point_to_segment(p_transform_a.origin, capsule_segment); + + // Perform an analytic sphere collision between the sphere and the sphere-collider in the capsule + analytic_sphere_collision<withMargin>( + p_transform_a.origin, + sphere_A->get_radius(), + capsule_closest, + capsule_B_radius, + p_collector, + p_margin_a, + p_margin_b); +} - if (!separator.test_axis((capsule_ball_1 - p_transform_a.origin).normalized())) { +template <bool withMargin> +static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radius_b, real_t p_height_b, const Transform3D &p_transform_a, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + // Find the point on the cylinder nearest to the center of the sphere. + + Vector3 center = p_transform_b.xform_inv(p_transform_a.origin); + Vector3 nearest = center; + real_t radius = p_radius_b; + real_t r = Math::sqrt(center.x * center.x + center.z * center.z); + if (r > radius) { + real_t scale = radius / r; + nearest.x *= scale; + nearest.z *= scale; + } + real_t half_height = p_height_b / 2; + nearest.y = MIN(MAX(center.y, -half_height), half_height); + nearest = p_transform_b.xform(nearest); + + // See if it is inside the sphere. + + Vector3 delta = nearest - p_transform_a.origin; + real_t length = delta.length(); + if (length > p_radius_a + p_margin_a + p_margin_b) { return; } - - //capsule sphere 2, sphere - - Vector3 capsule_ball_2 = p_transform_b.origin - capsule_axis; - - if (!separator.test_axis((capsule_ball_2 - p_transform_a.origin).normalized())) { + p_collector->collided = true; + if (!p_collector->callback) { return; } - - //capsule edge, sphere - - Vector3 b2a = p_transform_a.origin - p_transform_b.origin; - - Vector3 axis = b2a.cross(capsule_axis).cross(capsule_axis).normalized(); - - if (!separator.test_axis(axis)) { - return; + Vector3 axis; + if (length == 0) { + // The cylinder passes through the sphere center. Select an axis based on the cylinder's center. + axis = (p_transform_b.origin - nearest).normalized(); + } else { + axis = delta / length; } - - separator.generate_contacts(); + Vector3 point_a = p_transform_a.origin + (p_radius_a + p_margin_a) * axis; + Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest); + p_collector->call(point_a, point_b); } template <bool withMargin> @@ -876,58 +935,7 @@ static void _collision_sphere_cylinder(const GodotShape3D *p_a, const Transform3 const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); const GodotCylinderShape3D *cylinder_B = static_cast<const GodotCylinderShape3D *>(p_b); - SeparatorAxisTest<GodotSphereShape3D, GodotCylinderShape3D, withMargin> separator(sphere_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); - - if (!separator.test_previous_axis()) { - return; - } - - // Cylinder B end caps. - Vector3 cylinder_B_axis = p_transform_b.basis.get_column(1).normalized(); - if (!separator.test_axis(cylinder_B_axis)) { - return; - } - - Vector3 cylinder_diff = p_transform_b.origin - p_transform_a.origin; - - // Cylinder B lateral surface. - if (!separator.test_axis(cylinder_B_axis.cross(cylinder_diff).cross(cylinder_B_axis).normalized())) { - return; - } - - // Closest point to cylinder caps. - const Vector3 &sphere_center = p_transform_a.origin; - Vector3 cyl_axis = p_transform_b.basis.get_column(1); - Vector3 cap_axis = p_transform_b.basis.get_column(0); - real_t height_scale = cyl_axis.length(); - real_t cap_dist = cylinder_B->get_height() * 0.5 * height_scale; - cyl_axis /= height_scale; - real_t radius_scale = cap_axis.length(); - real_t cap_radius = cylinder_B->get_radius() * radius_scale; - - for (int i = 0; i < 2; i++) { - Vector3 cap_dir = ((i == 0) ? cyl_axis : -cyl_axis); - Vector3 cap_pos = p_transform_b.origin + cap_dir * cap_dist; - - Vector3 closest_point; - - Vector3 diff = sphere_center - cap_pos; - Vector3 proj = diff - cap_dir.dot(diff) * cap_dir; - - real_t proj_len = proj.length(); - if (Math::is_zero_approx(proj_len)) { - // Point is equidistant to all circle points. - continue; - } - - closest_point = cap_pos + (cap_radius / proj_len) * proj; - - if (!separator.test_axis((closest_point - sphere_center).normalized())) { - return; - } - } - - separator.generate_contacts(); + analytic_sphere_cylinder_collision<withMargin>(sphere_A->get_radius(), cylinder_B->get_radius(), cylinder_B->get_height(), p_transform_a, p_transform_b, p_collector, p_margin_a, p_margin_b); } template <bool withMargin> @@ -1615,63 +1623,31 @@ static void _collision_capsule_capsule(const GodotShape3D *p_a, const Transform3 const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - SeparatorAxisTest<GodotCapsuleShape3D, GodotCapsuleShape3D, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); - - if (!separator.test_previous_axis()) { - return; - } - - // some values - - Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius()); - Vector3 capsule_B_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); - - Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis; - Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis; - Vector3 capsule_B_ball_1 = p_transform_b.origin + capsule_B_axis; - Vector3 capsule_B_ball_2 = p_transform_b.origin - capsule_B_axis; - - //balls-balls - - if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_1).normalized())) { - return; - } - if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_2).normalized())) { - return; - } - - if (!separator.test_axis((capsule_A_ball_2 - capsule_B_ball_1).normalized())) { - return; - } - if (!separator.test_axis((capsule_A_ball_2 - capsule_B_ball_2).normalized())) { - return; - } - - // edges-balls - - if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_1).cross(capsule_A_axis).cross(capsule_A_axis).normalized())) { - return; - } - - if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_2).cross(capsule_A_axis).cross(capsule_A_axis).normalized())) { - return; - } - - if (!separator.test_axis((capsule_B_ball_1 - capsule_A_ball_1).cross(capsule_B_axis).cross(capsule_B_axis).normalized())) { - return; - } - - if (!separator.test_axis((capsule_B_ball_1 - capsule_A_ball_2).cross(capsule_B_axis).cross(capsule_B_axis).normalized())) { - return; - } - - // edges - - if (!separator.test_axis(capsule_A_axis.cross(capsule_B_axis).normalized())) { - return; - } - - separator.generate_contacts(); + real_t capsule_A_radius = capsule_A->get_radius(); + real_t capsule_B_radius = capsule_B->get_radius(); + + // Get the closest points between the capsule segments + Vector3 capsule_A_closest; + Vector3 capsule_B_closest; + Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A_radius); + Vector3 capsule_B_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B_radius); + Geometry3D::get_closest_points_between_segments( + p_transform_a.origin + capsule_A_axis, + p_transform_a.origin - capsule_A_axis, + p_transform_b.origin + capsule_B_axis, + p_transform_b.origin - capsule_B_axis, + capsule_A_closest, + capsule_B_closest); + + // Perform the analytic collision between the two closest capsule spheres + analytic_sphere_collision<withMargin>( + capsule_A_closest, + capsule_A_radius, + capsule_B_closest, + capsule_B_radius, + p_collector, + p_margin_a, + p_margin_b); } template <bool withMargin> @@ -1679,61 +1655,24 @@ static void _collision_capsule_cylinder(const GodotShape3D *p_a, const Transform const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); const GodotCylinderShape3D *cylinder_B = static_cast<const GodotCylinderShape3D *>(p_b); - SeparatorAxisTest<GodotCapsuleShape3D, GodotCylinderShape3D, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); - - if (!separator.test_previous_axis()) { - return; - } - - // Cylinder B end caps. - Vector3 cylinder_B_axis = p_transform_b.basis.get_column(1).normalized(); - if (!separator.test_axis(cylinder_B_axis)) { - return; - } - - // Cylinder edge against capsule balls. - - Vector3 capsule_A_axis = p_transform_a.basis.get_column(1); - - Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis * (capsule_A->get_height() * 0.5 - capsule_A->get_radius()); - Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis * (capsule_A->get_height() * 0.5 - capsule_A->get_radius()); - - if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_1).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) { - return; - } - - if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_2).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) { - return; - } - - // Cylinder edge against capsule edge. + // Find the closest points between the axes of the two objects. - Vector3 center_diff = p_transform_b.origin - p_transform_a.origin; - - if (!separator.test_axis(capsule_A_axis.cross(center_diff).cross(capsule_A_axis).normalized())) { - return; - } - - if (!separator.test_axis(cylinder_B_axis.cross(center_diff).cross(cylinder_B_axis).normalized())) { - return; - } - - real_t proj = capsule_A_axis.cross(cylinder_B_axis).cross(cylinder_B_axis).dot(capsule_A_axis); - if (Math::is_zero_approx(proj)) { - // Parallel capsule and cylinder axes, handle with specific axes only. - // Note: GJKEPA with no margin can lead to degenerate cases in this situation. - separator.generate_contacts(); - return; - } - - GodotCollisionSolver3D::CallbackResult callback = SeparatorAxisTest<GodotCapsuleShape3D, GodotCylinderShape3D, withMargin>::test_contact_points; - - // Fallback to generic algorithm to find the best separating axis. - if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) { - return; - } - - separator.generate_contacts(); + Vector3 capsule_A_closest; + Vector3 cylinder_B_closest; + Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius()); + Vector3 cylinder_B_axis = p_transform_b.basis.get_column(1) * (cylinder_B->get_height() * 0.5); + Geometry3D::get_closest_points_between_segments( + p_transform_a.origin + capsule_A_axis, + p_transform_a.origin - capsule_A_axis, + p_transform_b.origin + cylinder_B_axis, + p_transform_b.origin - cylinder_B_axis, + capsule_A_closest, + cylinder_B_closest); + + // Perform the collision test between the cylinder and the nearest sphere on the capsule axis. + + Transform3D sphere_transform(p_transform_a.basis, capsule_A_closest); + analytic_sphere_cylinder_collision<withMargin>(capsule_A->get_radius(), cylinder_B->get_radius(), cylinder_B->get_height(), sphere_transform, p_transform_b, p_collector, p_margin_a, p_margin_b); } template <bool withMargin> diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 85b5ef5e09..bd34d83ea3 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1668,39 +1668,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co using_voxelgi = true; } - if (p_render_data->environment.is_null() && using_voxelgi) { - depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI; - } else if (p_render_data->environment.is_valid() && (environment_get_ssr_enabled(p_render_data->environment) || environment_get_sdfgi_enabled(p_render_data->environment) || using_voxelgi)) { + if (p_render_data->environment.is_valid()) { if (environment_get_sdfgi_enabled(p_render_data->environment)) { - depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also voxelgi using_sdfgi = true; - } else { - depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } if (environment_get_ssr_enabled(p_render_data->environment)) { using_separate_specular = true; using_ssr = true; color_pass_flags |= COLOR_PASS_FLAG_SEPARATE_SPECULAR; } - } else if (p_render_data->environment.is_valid() && (environment_get_ssao_enabled(p_render_data->environment) || using_ssil || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { - depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; - } - - switch (depth_pass_mode) { - case PASS_MODE_DEPTH: { - depth_framebuffer = rb_data->get_depth_fb(); - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { - depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS); - depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: { - depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS_VOXELGI); - depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); - depth_pass_clear.push_back(Color(0, 0, 0, 0)); - } break; - default: { - }; } if (p_render_data->scene_data->view_count > 1) { @@ -1731,6 +1707,38 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); + if (rb.is_valid()) { + if (using_voxelgi) { + depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI; + } else if (p_render_data->environment.is_valid()) { + if (environment_get_ssr_enabled(p_render_data->environment) || + environment_get_sdfgi_enabled(p_render_data->environment) || + environment_get_ssao_enabled(p_render_data->environment) || + using_ssil || + get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER || + scene_state.used_normal_texture) { + depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; + } + } + + switch (depth_pass_mode) { + case PASS_MODE_DEPTH: { + depth_framebuffer = rb_data->get_depth_fb(); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS); + depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: { + depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS_VOXELGI); + depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); + depth_pass_clear.push_back(Color(0, 0, 0, 0)); + } break; + default: { + }; + } + } + bool using_sss = rb_data.is_valid() && scene_state.used_sss && ss_effects->sss_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; if (using_sss && !using_separate_specular) { @@ -1914,7 +1922,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true); bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; - bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; + bool can_continue_depth = !(scene_state.used_depth_texture || scene_state.used_normal_texture) && !using_ssr && !using_sss; { bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes); @@ -3436,7 +3444,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; - bool has_base_alpha = (p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha; + bool has_base_alpha = (p_material->shader_data->uses_alpha && (!p_material->shader_data->uses_alpha_clip || p_material->shader_data->uses_alpha_antialiasing)) || has_read_screen_alpha; bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; bool has_alpha = has_base_alpha || has_blend_alpha; @@ -3465,7 +3473,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED) { //material is only meant for alpha pass flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) { + if ((p_material->shader_data->uses_depth_prepass_alpha || p_material->shader_data->uses_alpha_antialiasing) && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) { flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; } @@ -3481,7 +3489,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet SceneShaderForwardClustered::MaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D)); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 9117320eab..7eabce2f79 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -60,6 +60,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uses_point_size = false; uses_alpha = false; uses_alpha_clip = false; + uses_alpha_antialiasing = false; uses_blend_alpha = false; uses_depth_prepass_alpha = false; uses_discard = false; @@ -111,9 +112,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["ALPHA"] = &uses_alpha; actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip; - // Use alpha clip pipeline for alpha hash/dither. - // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows. actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip; + actions.usage_flag_pointers["ALPHA_ANTIALIASING_EDGE"] = &uses_alpha_antialiasing; + actions.usage_flag_pointers["ALPHA_TEXTURE_COORDINATE"] = &uses_alpha_antialiasing; actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha; actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; @@ -121,7 +122,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; + actions.usage_flag_pointers["NORMAL_ROUGHNESS_TEXTURE"] = &uses_normal_texture; actions.usage_flag_pointers["DISCARD"] = &uses_discard; actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; @@ -309,14 +310,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { } RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; - if (depth_pre_pass_enabled && casts_shadows() && !uses_depth_prepass_alpha) { - // We already have a depth from the depth pre-pass, there is no need to write it again. - // In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL. - // This way we can use the early depth test to discard transparent fragments before the fragment shader even starts. - // This cannot be used with depth_prepass_alpha as it uses a different threshold during the depth-prepass and regular drawing. - depth_stencil.depth_compare_operator = RD::COMPARE_OP_EQUAL; - depth_stencil.enable_depth_write = false; - } RD::PipelineColorBlendState blend_state; RD::PipelineMultisampleState multisample_state; @@ -338,6 +331,14 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { } else { blend_state = blend_state_color_opaque; + if (depth_pre_pass_enabled) { + // We already have a depth from the depth pre-pass, there is no need to write it again. + // In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL. + // This way we can use the early depth test to discard transparent fragments before the fragment shader even starts. + depth_stencil.depth_compare_operator = RD::COMPARE_OP_EQUAL; + depth_stencil.enable_depth_write = false; + } + if (l & PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR) { shader_flags |= SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR; } @@ -392,7 +393,7 @@ bool SceneShaderForwardClustered::ShaderData::is_animated() const { bool SceneShaderForwardClustered::ShaderData::casts_shadows() const { bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture; - bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha; + bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha; bool has_alpha = has_base_alpha || uses_blend_alpha; return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 1169ae784c..ffaf091b36 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -153,6 +153,7 @@ public: bool uses_alpha = false; bool uses_blend_alpha = false; bool uses_alpha_clip = false; + bool uses_alpha_antialiasing = false; bool uses_depth_prepass_alpha = false; bool uses_discard = false; bool uses_roughness = false; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 72857cdea7..78d29e2a41 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2349,9 +2349,9 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; - bool has_base_alpha = ((p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha); + bool has_base_alpha = p_material->shader_data->uses_alpha && (!p_material->shader_data->uses_alpha_clip || p_material->shader_data->uses_alpha_antialiasing); bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; - bool has_alpha = has_base_alpha || has_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha || has_read_screen_alpha; uint32_t flags = 0; @@ -2375,10 +2375,10 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; } - if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) { + if (has_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) { //material is only meant for alpha pass flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) { + if ((p_material->shader_data->uses_depth_prepass_alpha || p_material->shader_data->uses_alpha_antialiasing) && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) { flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; } @@ -2394,7 +2394,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI SceneShaderForwardMobile::MaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D)); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 2e9a33a636..ee4c8001eb 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -62,6 +62,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uses_point_size = false; uses_alpha = false; uses_alpha_clip = false; + uses_alpha_antialiasing = false; uses_blend_alpha = false; uses_depth_prepass_alpha = false; uses_discard = false; @@ -112,9 +113,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["ALPHA"] = &uses_alpha; actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip; - // Use alpha clip pipeline for alpha hash/dither. - // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows. actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip; + actions.usage_flag_pointers["ALPHA_ANTIALIASING_EDGE"] = &uses_alpha_antialiasing; + actions.usage_flag_pointers["ALPHA_TEXTURE_COORDINATE"] = &uses_alpha_antialiasing; actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha; // actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; @@ -122,7 +123,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; + actions.usage_flag_pointers["NORMAL_ROUGHNESS_TEXTURE"] = &uses_normal_texture; actions.usage_flag_pointers["DISCARD"] = &uses_discard; actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; @@ -338,7 +339,7 @@ bool SceneShaderForwardMobile::ShaderData::is_animated() const { bool SceneShaderForwardMobile::ShaderData::casts_shadows() const { bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture; - bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha; + bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha; bool has_alpha = has_base_alpha || uses_blend_alpha; return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED)); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 99f252b9ca..1f92697ecc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -114,6 +114,7 @@ public: bool uses_alpha = false; bool uses_blend_alpha = false; bool uses_alpha_clip = false; + bool uses_alpha_antialiasing = false; bool uses_depth_prepass_alpha = false; bool uses_discard = false; bool uses_roughness = false; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index be53a7ae49..d32e6d717f 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -118,9 +118,15 @@ layout(location = 10) out flat uint instance_index_interp; // !BAS! This needs to become an input once we implement our fallback! #define ViewIndex 0 #endif // has_VK_KHR_multiview +vec3 normal_roughness_uv(vec2 uv) { + return vec3(uv, ViewIndex); +} #else // USE_MULTIVIEW // Set to zero, not supported in non stereo #define ViewIndex 0 +vec2 normal_roughness_uv(vec2 uv) { + return uv; +} #endif //USE_MULTIVIEW invariant gl_Position; @@ -544,9 +550,15 @@ layout(location = 10) in flat uint instance_index_interp; // !BAS! This needs to become an input once we implement our fallback! #define ViewIndex 0 #endif // has_VK_KHR_multiview +vec3 normal_roughness_uv(vec2 uv) { + return vec3(uv, ViewIndex); +} #else // USE_MULTIVIEW // Set to zero, not supported in non stereo #define ViewIndex 0 +vec2 normal_roughness_uv(vec2 uv) { + return uv; +} #endif //USE_MULTIVIEW //defines to keep compatibility with vertex diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index 3a45ab0059..1f524313f2 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -268,6 +268,7 @@ layout(r32ui, set = 1, binding = 13) uniform restrict uimage3D geom_facing_grid; #define color_buffer shadow_atlas #define normal_roughness_buffer shadow_atlas +#define multiviewSampler sampler2D #else layout(set = 1, binding = 10) uniform texture2D depth_buffer; @@ -277,10 +278,12 @@ layout(set = 1, binding = 11) uniform texture2D color_buffer; layout(set = 1, binding = 12) uniform texture2DArray normal_roughness_buffer; layout(set = 1, binding = 14) uniform texture2DArray ambient_buffer; layout(set = 1, binding = 15) uniform texture2DArray reflection_buffer; +#define multiviewSampler sampler2DArray #else // USE_MULTIVIEW layout(set = 1, binding = 12) uniform texture2D normal_roughness_buffer; layout(set = 1, binding = 14) uniform texture2D ambient_buffer; layout(set = 1, binding = 15) uniform texture2D reflection_buffer; +#define multiviewSampler sampler2D #endif layout(set = 1, binding = 13) uniform texture2D ao_buffer; layout(set = 1, binding = 16) uniform texture2DArray sdfgi_lightprobe_texture; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 4c4b3d13f9..6017eff55e 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -291,6 +291,10 @@ void RenderingServerDefault::set_boot_image(const Ref<Image> &p_image, const Col RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter); } +Color RenderingServerDefault::get_default_clear_color() { + return RSG::texture_storage->get_default_clear_color(); +} + void RenderingServerDefault::set_default_clear_color(const Color &p_color) { RSG::viewport->set_default_clear_color(p_color); } diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index f2fadd5e1f..d053c60b85 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -986,6 +986,7 @@ public: virtual double get_frame_setup_time_cpu() const override; virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override; + virtual Color get_default_clear_color() override; virtual void set_default_clear_color(const Color &p_color) override; virtual bool has_feature(Features p_feature) const override; diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 57215d9d63..626da90168 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -1183,6 +1183,10 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene code += "("; + // if normal roughness texture is used, we will add logic to automatically switch between + // sampler2D and sampler2D array and vec2 UV and vec3 UV. + bool normal_roughness_texture_used = false; + for (int i = 1; i < onode->arguments.size(); i++) { if (i > 1) { code += ", "; @@ -1282,11 +1286,24 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene } } - code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")"; + String data_type_name = ""; + if (texture_uniform == "NORMAL_ROUGHNESS_TEXTURE") { + data_type_name = "multiviewSampler"; + normal_roughness_texture_used = true; + } else { + data_type_name = ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()); + } + + code += data_type_name + "(" + node_code + ", " + sampler_name + ")"; } else { code += node_code; } } else { + if (normal_roughness_texture_used && i == 2) { + // UV coordinate after using normal roughness texture. + node_code = "normal_roughness_uv(" + node_code + ".xy)"; + } + code += node_code; } } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 658d683398..14d8d035e2 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2763,6 +2763,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_white_texture"), &RenderingServer::get_white_texture); ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "use_filter"), &RenderingServer::set_boot_image, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("get_default_clear_color"), &RenderingServer::get_default_clear_color); ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color); ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 88144cfeeb..6efe28a847 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1560,6 +1560,7 @@ public: virtual void mesh_add_surface_from_planes(RID p_mesh, const Vector<Plane> &p_planes); virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; + virtual Color get_default_clear_color() = 0; virtual void set_default_clear_color(const Color &p_color) = 0; enum Features { |