diff options
Diffstat (limited to 'servers')
39 files changed, 1090 insertions, 384 deletions
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index 45b9e6414d..30a99d3d74 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -1114,12 +1114,12 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) { PhysicsServer2D::ShapeType type_A = p_shape_A->get_type(); - ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_LINE, false); + ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN, false); ERR_FAIL_COND_V(p_shape_A->is_concave(), false); PhysicsServer2D::ShapeType type_B = p_shape_B->get_type(); - ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_LINE, false); + ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); static const CollisionFunc collision_table[5][5] = { diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp index ed398a24e5..8f8a4a862c 100644 --- a/servers/physics_2d/collision_solver_2d_sw.cpp +++ b/servers/physics_2d/collision_solver_2d_sw.cpp @@ -34,14 +34,14 @@ #define collision_solver sat_2d_calculate_penetration //#define collision_solver gjk_epa_calculate_penetration -bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { - const LineShape2DSW *line = static_cast<const LineShape2DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_LINE) { +bool CollisionSolver2DSW::solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { + const WorldMarginShape2DSW *world_margin = static_cast<const WorldMarginShape2DSW *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_MARGIN) { return false; } - Vector2 n = p_transform_A.basis_xform(line->get_normal()).normalized(); - Vector2 p = p_transform_A.xform(line->get_normal() * line->get_d()); + Vector2 n = p_transform_A.basis_xform(world_margin->get_normal()).normalized(); + Vector2 p = p_transform_A.xform(world_margin->get_normal() * world_margin->get_d()); real_t d = n.dot(p); Vector2 supports[2]; @@ -166,15 +166,15 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p swap = true; } - if (type_A == PhysicsServer2D::SHAPE_LINE) { - if (type_B == PhysicsServer2D::SHAPE_LINE) { + if (type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN) { + if (type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN) { return false; } if (swap) { - return solve_static_line(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); + return solve_static_world_margin(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); } else { - return solve_static_line(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); + return solve_static_world_margin(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); } } else if (concave_B) { diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h index 4f12ca9e88..17c0c2fe70 100644 --- a/servers/physics_2d/collision_solver_2d_sw.h +++ b/servers/physics_2d/collision_solver_2d_sw.h @@ -38,7 +38,7 @@ public: typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata); private: - static bool solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); static void concave_callback(void *p_userdata, Shape2DSW *p_convex); static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); static bool solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr); diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index 4dcc4a9cfd..88c097453e 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -42,8 +42,8 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) { Shape2DSW *shape = nullptr; switch (p_shape) { - case SHAPE_LINE: { - shape = memnew(LineShape2DSW); + case SHAPE_WORLD_MARGIN: { + shape = memnew(WorldMarginShape2DSW); } break; case SHAPE_SEGMENT: { shape = memnew(SegmentShape2DSW); @@ -75,8 +75,8 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) { return id; } -RID PhysicsServer2DSW::line_shape_create() { - return _shape_create(SHAPE_LINE); +RID PhysicsServer2DSW::world_margin_shape_create() { + return _shape_create(SHAPE_WORLD_MARGIN); } RID PhysicsServer2DSW::segment_shape_create() { diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index e1ad6a56ee..3610f43f93 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -87,7 +87,7 @@ public: Vector2 *ptr; }; - virtual RID line_shape_create() override; + virtual RID world_margin_shape_create() override; virtual RID segment_shape_create() override; virtual RID circle_shape_create() override; virtual RID rectangle_shape_create() override; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index 7bc1096f93..b93178919d 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -79,7 +79,7 @@ public: #include "servers/server_wrap_mt_common.h" //FUNC1RID(shape,ShapeType); todo fix - FUNCRID(line_shape) + FUNCRID(world_margin_shape) FUNCRID(segment_shape) FUNCRID(circle_shape) FUNCRID(rectangle_shape) diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index b16efbfe64..b3e4ca84c3 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -88,15 +88,15 @@ Shape2DSW::~Shape2DSW() { /*********************************************************/ /*********************************************************/ -void LineShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void WorldMarginShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { r_amount = 0; } -bool LineShape2DSW::contains_point(const Vector2 &p_point) const { +bool WorldMarginShape2DSW::contains_point(const Vector2 &p_point) const { return normal.dot(p_point) < d; } -bool LineShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool WorldMarginShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { Vector2 segment = p_begin - p_end; real_t den = normal.dot(segment); @@ -118,11 +118,11 @@ bool LineShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_e return true; } -real_t LineShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t WorldMarginShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return 0; } -void LineShape2DSW::set_data(const Variant &p_data) { +void WorldMarginShape2DSW::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY); Array arr = p_data; ERR_FAIL_COND(arr.size() != 2); @@ -131,7 +131,7 @@ void LineShape2DSW::set_data(const Variant &p_data) { configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2))); } -Variant LineShape2DSW::get_data() const { +Variant WorldMarginShape2DSW::get_data() const { Array arr; arr.resize(2); arr[0] = normal; diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index 3e4271b156..2de0f3cb9f 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -36,7 +36,7 @@ /* -SHAPE_LINE, ///< plane:"plane" +SHAPE_WORLD_MARGIN, ///< plane:"plane" SHAPE_SEGMENT, ///< real_t:"length" SHAPE_CIRCLE, ///< real_t:"radius" SHAPE_RECTANGLE, ///< vec3:"extents" @@ -152,7 +152,7 @@ public: r_max = MAX(maxa, maxb); \ } -class LineShape2DSW : public Shape2DSW { +class WorldMarginShape2DSW : public Shape2DSW { Vector2 normal; real_t d; @@ -160,7 +160,7 @@ public: _FORCE_INLINE_ Vector2 get_normal() const { return normal; } _FORCE_INLINE_ real_t get_d() const { return d; } - virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_LINE; } + virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_WORLD_MARGIN; } virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); } virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const; diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 65dc198592..f04f3ab583 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -560,7 +560,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (!shapes_found) { if (r_result) { *r_result = PhysicsServer2D::MotionResult(); - r_result->motion = p_motion; + r_result->travel = p_motion; } return false; } @@ -954,9 +954,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co Vector2 rel_vec = r_result->collision_point - body->get_transform().get_origin(); r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); - r_result->motion = safe * p_motion; + r_result->travel = safe * p_motion; r_result->remainder = p_motion - safe * p_motion; - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel += (body_transform.get_origin() - p_from.get_origin()); } collided = true; @@ -964,9 +964,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } if (!collided && r_result) { - r_result->motion = p_motion; + r_result->travel = p_motion; r_result->remainder = Vector2(); - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel += (body_transform.get_origin() - p_from.get_origin()); } return collided; diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp index a9f5c4aec3..364f63e4ad 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/area_3d_sw.cpp @@ -30,8 +30,16 @@ #include "area_3d_sw.h" #include "body_3d_sw.h" +#include "soft_body_3d_sw.h" #include "space_3d_sw.h" +Area3DSW::BodyKey::BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { + rid = p_body->get_self(); + instance_id = p_body->get_instance_id(); + body_shape = p_body_shape; + area_shape = p_area_shape; +} + Area3DSW::BodyKey::BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h index 12f7545c08..5959ee1e95 100644 --- a/servers/physics_3d/area_3d_sw.h +++ b/servers/physics_3d/area_3d_sw.h @@ -38,6 +38,7 @@ class Space3DSW; class Body3DSW; +class SoftBody3DSW; class Constraint3DSW; class Area3DSW : public CollisionObject3DSW { @@ -80,6 +81,7 @@ class Area3DSW : public CollisionObject3DSW { } _FORCE_INLINE_ BodyKey() {} + BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); }; @@ -91,6 +93,7 @@ class Area3DSW : public CollisionObject3DSW { _FORCE_INLINE_ BodyState() { state = 0; } }; + Map<BodyKey, BodyState> monitored_soft_bodies; Map<BodyKey, BodyState> monitored_bodies; Map<BodyKey, BodyState> monitored_areas; @@ -115,6 +118,9 @@ public: _FORCE_INLINE_ void add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); _FORCE_INLINE_ void remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); _FORCE_INLINE_ void remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); @@ -166,6 +172,22 @@ public: ~Area3DSW(); }; +void Area3DSW::add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { + BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape); + monitored_soft_bodies[bk].inc(); + if (!monitor_query_list.in_list()) { + _queue_monitor_update(); + } +} + +void Area3DSW::remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { + BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape); + monitored_soft_bodies[bk].dec(); + if (!monitor_query_list.in_list()) { + _queue_monitor_update(); + } +} + void Area3DSW::add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { BodyKey bk(p_body, p_body_shape, p_area_shape); monitored_bodies[bk].inc(); @@ -198,4 +220,16 @@ void Area3DSW::remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, u } } +struct AreaCMP { + Area3DSW *area; + int refCount; + _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); } + _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); } + _FORCE_INLINE_ AreaCMP() {} + _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) { + area = p_area; + refCount = 1; + } +}; + #endif // AREA__SW_H diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index f43c2c965e..e740565da6 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -181,3 +181,85 @@ Area2Pair3DSW::~Area2Pair3DSW() { area_a->remove_constraint(this); area_b->remove_constraint(this); } + +//////////////////////////////////////////////////// + +bool AreaSoftBodyPair3DSW::setup(real_t p_step) { + bool result = false; + if ( + area->interacts_with(soft_body) && + CollisionSolver3DSW::solve_static( + soft_body->get_shape(soft_body_shape), + soft_body->get_transform() * soft_body->get_shape_transform(soft_body_shape), + area->get_shape(area_shape), + area->get_transform() * area->get_shape_transform(area_shape), + nullptr, + this)) { + result = true; + } + + process_collision = false; + if (result != colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + process_collision = true; + } else if (area->has_monitor_callback()) { + process_collision = true; + } + + colliding = result; + } + + return process_collision; +} + +bool AreaSoftBodyPair3DSW::pre_solve(real_t p_step) { + if (!process_collision) { + return false; + } + + if (colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + soft_body->add_area(area); + } + + if (area->has_monitor_callback()) { + area->add_soft_body_to_query(soft_body, soft_body_shape, area_shape); + } + } else { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + soft_body->remove_area(area); + } + + if (area->has_monitor_callback()) { + area->remove_soft_body_from_query(soft_body, soft_body_shape, area_shape); + } + } + + return false; // Never do any post solving. +} + +void AreaSoftBodyPair3DSW::solve(real_t p_step) { + // Nothing to do. +} + +AreaSoftBodyPair3DSW::AreaSoftBodyPair3DSW(SoftBody3DSW *p_soft_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape) { + soft_body = p_soft_body; + area = p_area; + soft_body_shape = p_soft_body_shape; + area_shape = p_area_shape; + soft_body->add_constraint(this); + area->add_constraint(this); +} + +AreaSoftBodyPair3DSW::~AreaSoftBodyPair3DSW() { + if (colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + soft_body->remove_area(area); + } + if (area->has_monitor_callback()) { + area->remove_soft_body_from_query(soft_body, soft_body_shape, area_shape); + } + } + soft_body->remove_constraint(this); + area->remove_constraint(this); +} diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h index 596d893082..8cc9e9ad63 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/area_pair_3d_sw.h @@ -34,6 +34,7 @@ #include "area_3d_sw.h" #include "body_3d_sw.h" #include "constraint_3d_sw.h" +#include "soft_body_3d_sw.h" class AreaPair3DSW : public Constraint3DSW { Body3DSW *body; @@ -69,4 +70,21 @@ public: ~Area2Pair3DSW(); }; +class AreaSoftBodyPair3DSW : public Constraint3DSW { + SoftBody3DSW *soft_body; + Area3DSW *area; + int soft_body_shape; + int area_shape; + bool colliding = false; + bool process_collision = false; + +public: + virtual bool setup(real_t p_step) override; + virtual bool pre_solve(real_t p_step) override; + virtual void solve(real_t p_step) override; + + AreaSoftBodyPair3DSW(SoftBody3DSW *p_sof_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape); + ~AreaSoftBodyPair3DSW(); +}; + #endif // AREA_PAIR__SW_H diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index bdc615ab6c..efb114a325 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -96,18 +96,6 @@ class Body3DSW : public CollisionObject3DSW { Map<Constraint3DSW *, int> constraint_map; - struct AreaCMP { - Area3DSW *area; - int refCount; - _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); } - _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); } - _FORCE_INLINE_ AreaCMP() {} - _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) { - area = p_area; - refCount = 1; - } - }; - Vector<AreaCMP> areas; struct Contact { diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index 161e7e101b..dcecac1c73 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -102,6 +102,10 @@ void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, i ++cinfo.contact_count; + if (!cinfo.result_callback) { + return; + } + if (cinfo.swap_result) { cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata); } else { diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp index 724125bea8..73b81444e1 100644 --- a/servers/physics_3d/soft_body_3d_sw.cpp +++ b/servers/physics_3d/soft_body_3d_sw.cpp @@ -928,6 +928,19 @@ void SoftBody3DSW::apply_forces() { } } +void SoftBody3DSW::_compute_area_gravity(const Area3DSW *p_area) { + if (p_area->is_gravity_point()) { + if (p_area->get_gravity_distance_scale() > 0) { + Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin(); + gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2)); + } else { + gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity(); + } + } else { + gravity += p_area->get_gravity_vector() * p_area->get_gravity(); + } +} + void SoftBody3DSW::predict_motion(real_t p_delta) { const real_t inv_delta = 1.0 / p_delta; @@ -935,9 +948,35 @@ void SoftBody3DSW::predict_motion(real_t p_delta) { Area3DSW *def_area = get_space()->get_default_area(); ERR_FAIL_COND(!def_area); + gravity = def_area->get_gravity_vector() * def_area->get_gravity(); + + int ac = areas.size(); + bool stopped = false; + + if (ac) { + areas.sort(); + const AreaCMP *aa = &areas[0]; + for (int i = ac - 1; i >= 0 && !stopped; i--) { + PhysicsServer3D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode(); + switch (mode) { + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + _compute_area_gravity(aa[i].area); + stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + gravity = Vector3(0, 0, 0); + _compute_area_gravity(aa[i].area); + stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } + } + } // Apply forces. - Vector3 gravity = def_area->get_gravity_vector() * def_area->get_gravity(); add_velocity(gravity * p_delta); apply_forces(); diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h index ac8bcbf0b9..be0620c506 100644 --- a/servers/physics_3d/soft_body_3d_sw.h +++ b/servers/physics_3d/soft_body_3d_sw.h @@ -31,6 +31,7 @@ #ifndef SOFT_BODY_3D_SW_H #define SOFT_BODY_3D_SW_H +#include "area_3d_sw.h" #include "collision_object_3d_sw.h" #include "core/math/aabb.h" @@ -100,14 +101,20 @@ class SoftBody3DSW : public CollisionObject3DSW { real_t drag_coefficient = 0.0; // [0,1] LocalVector<int> pinned_vertices; + Vector3 gravity; + SelfList<SoftBody3DSW> active_list; Set<Constraint3DSW *> constraints; + Vector<AreaCMP> areas; + VSet<RID> exceptions; uint64_t island_step = 0; + _FORCE_INLINE_ void _compute_area_gravity(const Area3DSW *p_area); + public: SoftBody3DSW(); @@ -129,6 +136,25 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } + _FORCE_INLINE_ void add_area(Area3DSW *p_area) { + int index = areas.find(AreaCMP(p_area)); + if (index > -1) { + areas.write[index].refCount += 1; + } else { + areas.ordered_insert(AreaCMP(p_area)); + } + } + + _FORCE_INLINE_ void remove_area(Area3DSW *p_area) { + int index = areas.find(AreaCMP(p_area)); + if (index > -1) { + areas.write[index].refCount -= 1; + if (areas[index].refCount < 1) { + areas.remove(index); + } + } + } + virtual void set_space(Space3DSW *p_space); void set_mesh(const Ref<Mesh> &p_mesh); diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index 730460d66a..f9e55ad525 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -600,7 +600,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co if (!shapes_found) { if (r_result) { *r_result = PhysicsServer3D::MotionResult(); - r_result->motion = p_motion; + r_result->travel = p_motion; } return false; @@ -879,9 +879,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass()); r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); - r_result->motion = safe * p_motion; + r_result->travel = safe * p_motion; r_result->remainder = p_motion - safe * p_motion; - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel += (body_transform.get_origin() - p_from.get_origin()); } collided = true; @@ -889,9 +889,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co } if (!collided && r_result) { - r_result->motion = p_motion; + r_result->travel = p_motion; r_result->remainder = Vector3(); - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel += (body_transform.get_origin() - p_from.get_origin()); } return collided; @@ -921,7 +921,9 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A)); return area2_pair; } else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) { - // Area/Soft Body, not supported. + SoftBody3DSW *softbody = static_cast<SoftBody3DSW *>(B); + AreaSoftBodyPair3DSW *soft_area_pair = memnew(AreaSoftBodyPair3DSW(softbody, p_subindex_B, area, p_subindex_A)); + return soft_area_pair; } else { Body3DSW *body = static_cast<Body3DSW *>(B); AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A)); diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index c2dedde0be..c96f85446c 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -422,11 +422,11 @@ void PhysicsDirectSpaceState2D::_bind_methods() { /////////////////////////////// -Vector2 PhysicsTestMotionResult2D::get_motion() const { - return result.motion; +Vector2 PhysicsTestMotionResult2D::get_travel() const { + return result.travel; } -Vector2 PhysicsTestMotionResult2D::get_motion_remainder() const { +Vector2 PhysicsTestMotionResult2D::get_remainder() const { return result.remainder; } @@ -471,8 +471,8 @@ real_t PhysicsTestMotionResult2D::get_collision_unsafe_fraction() const { } void PhysicsTestMotionResult2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult2D::get_motion); - ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult2D::get_motion_remainder); + ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult2D::get_travel); + ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult2D::get_remainder); ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult2D::get_collision_point); ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult2D::get_collision_normal); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult2D::get_collider_velocity); @@ -484,8 +484,8 @@ void PhysicsTestMotionResult2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult2D::get_collision_safe_fraction); ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult2D::get_collision_unsafe_fraction); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "", "get_motion"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_remainder"), "", "get_motion_remainder"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "travel"), "", "get_travel"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "remainder"), "", "get_remainder"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_point"), "", "get_collision_point"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity"); @@ -513,7 +513,7 @@ bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, c } void PhysicsServer2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("line_shape_create"), &PhysicsServer2D::line_shape_create); + ClassDB::bind_method(D_METHOD("world_margin_shape_create"), &PhysicsServer2D::world_margin_shape_create); ClassDB::bind_method(D_METHOD("segment_shape_create"), &PhysicsServer2D::segment_shape_create); ClassDB::bind_method(D_METHOD("circle_shape_create"), &PhysicsServer2D::circle_shape_create); ClassDB::bind_method(D_METHOD("rectangle_shape_create"), &PhysicsServer2D::rectangle_shape_create); @@ -674,7 +674,7 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); - BIND_ENUM_CONSTANT(SHAPE_LINE); + BIND_ENUM_CONSTANT(SHAPE_WORLD_MARGIN); BIND_ENUM_CONSTANT(SHAPE_SEGMENT); BIND_ENUM_CONSTANT(SHAPE_CIRCLE); BIND_ENUM_CONSTANT(SHAPE_RECTANGLE); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index dbbc128793..4c559dd7bd 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -219,7 +219,7 @@ public: static PhysicsServer2D *get_singleton(); enum ShapeType { - SHAPE_LINE, ///< plane:"plane" + SHAPE_WORLD_MARGIN, ///< plane:"plane" SHAPE_SEGMENT, ///< float:"length" SHAPE_CIRCLE, ///< float:"radius" SHAPE_RECTANGLE, ///< vec3:"extents" @@ -229,7 +229,7 @@ public: SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error }; - virtual RID line_shape_create() = 0; + virtual RID world_margin_shape_create() = 0; virtual RID segment_shape_create() = 0; virtual RID circle_shape_create() = 0; virtual RID rectangle_shape_create() = 0; @@ -465,7 +465,7 @@ public: virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) = 0; struct MotionResult { - Vector2 motion; + Vector2 travel; Vector2 remainder; Vector2 collision_point; @@ -479,6 +479,10 @@ public: RID collider; int collider_shape = 0; Variant collider_metadata; + + real_t get_angle(Vector2 p_up_direction) const { + return Math::acos(collision_normal.dot(p_up_direction)); + } }; virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) = 0; @@ -588,8 +592,8 @@ protected: public: PhysicsServer2D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer2D::MotionResult *>(&result); } - Vector2 get_motion() const; - Vector2 get_motion_remainder() const; + Vector2 get_travel() const; + Vector2 get_remainder() const; Vector2 get_collision_point() const; Vector2 get_collision_normal() const; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 89987b5fe9..53863cea72 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -369,11 +369,11 @@ void PhysicsDirectSpaceState3D::_bind_methods() { /////////////////////////////// -Vector3 PhysicsTestMotionResult3D::get_motion() const { - return result.motion; +Vector3 PhysicsTestMotionResult3D::get_travel() const { + return result.travel; } -Vector3 PhysicsTestMotionResult3D::get_motion_remainder() const { +Vector3 PhysicsTestMotionResult3D::get_remainder() const { return result.remainder; } @@ -418,8 +418,8 @@ real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const { } void PhysicsTestMotionResult3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult3D::get_motion); - ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult3D::get_motion_remainder); + ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult3D::get_travel); + ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult3D::get_remainder); ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult3D::get_collision_point); ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult3D::get_collision_normal); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult3D::get_collider_velocity); @@ -431,8 +431,8 @@ void PhysicsTestMotionResult3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult3D::get_collision_safe_fraction); ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult3D::get_collision_unsafe_fraction); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "", "get_motion"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_remainder"), "", "get_motion_remainder"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_point"), "", "get_collision_point"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_normal"), "", "get_collision_normal"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity"); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 31ae352d9e..f806fd55be 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -473,7 +473,7 @@ public: virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0; struct MotionResult { - Vector3 motion; + Vector3 travel; Vector3 remainder; Vector3 collision_point; @@ -487,6 +487,10 @@ public: RID collider; int collider_shape = 0; Variant collider_metadata; + + real_t get_angle(Vector3 p_up_direction) const { + return Math::acos(collision_normal.dot(p_up_direction)); + } }; virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) = 0; @@ -752,8 +756,8 @@ protected: public: PhysicsServer3D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer3D::MotionResult *>(&result); } - Vector3 get_motion() const; - Vector3 get_motion_remainder() const; + Vector3 get_travel() const; + Vector3 get_remainder() const; Vector3 get_collision_point() const; Vector3 get_collision_normal() const; diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index c609f25e31..f5b6be4795 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -739,6 +739,26 @@ void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const S RD::get_singleton()->compute_list_end(); } +void EffectsRD::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of mipmap with the clustered renderer."); + + memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); + + BlurRasterMode mode = BLUR_MIPMAP; + + blur_raster.push_constant.pixel_size[0] = 1.0 / float(p_size.x); + blur_raster.push_constant.pixel_size[1] = 1.0 / float(p_size.y); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip) { CopyToDPPushConstant push_constant; push_constant.screen_rect[0] = p_rect.position.x; @@ -928,7 +948,7 @@ void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_ } } -void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { +void EffectsRD::bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of BOKEH DOF with the mobile renderer."); bokeh.push_constant.blur_far_active = p_dof_far; @@ -957,22 +977,22 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i // The alpha channel of the source color texture is filled with the expected circle size // If used for DOF far, the size is positive, if used for near, its negative. - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BLUR_SIZE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.depth_texture), 1); - bokeh.push_constant.size[0] = p_base_texture_size.x; - bokeh.push_constant.size[1] = p_base_texture_size.y; + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y; RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) { //second pass - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]); static const int quality_samples[4] = { 6, 12, 12, 24 }; @@ -981,18 +1001,18 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) { //box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes) - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1); - bokeh.push_constant.size[0] = p_base_texture_size.x >> 1; - bokeh.push_constant.size[1] = p_base_texture_size.y >> 1; + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1; bokeh.push_constant.half_size = true; bokeh.push_constant.blur_size *= 0.5; } else { //medium and high quality use full size - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.secondary_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1); } RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); @@ -1004,11 +1024,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i bokeh.push_constant.second_pass = true; if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture2), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[1]), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1); } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.secondary_texture), 1); } RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); @@ -1019,25 +1039,25 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) { //forth pass, upscale for low quality - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[1]), 1); - bokeh.push_constant.size[0] = p_base_texture_size.x; - bokeh.push_constant.size[1] = p_base_texture_size.y; + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y; bokeh.push_constant.half_size = false; bokeh.push_constant.second_pass = false; RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1); } } else { //circle //second pass - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR]); static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 }; @@ -1046,11 +1066,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i //circle always runs in half size, otherwise too expensive - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1); - bokeh.push_constant.size[0] = p_base_texture_size.x >> 1; - bokeh.push_constant.size[1] = p_base_texture_size.y >> 1; + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1; bokeh.push_constant.half_size = true; RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); @@ -1062,93 +1082,195 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i // upscale - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1); - bokeh.push_constant.size[0] = p_base_texture_size.x; - bokeh.push_constant.size[1] = p_base_texture_size.y; + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y; bokeh.push_constant.half_size = false; bokeh.push_constant.second_pass = false; RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1); } RD::get_singleton()->compute_list_end(); } -void EffectsRD::blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { +void EffectsRD::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use blur DOF with the clustered renderer."); - memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); + memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant)); - BlurRasterMode blur_mode; - int qsteps[4] = { 4, 4, 10, 20 }; - uint32_t base_flags = p_cam_orthogonal ? BLUR_FLAG_USE_ORTHOGONAL_PROJECTION : 0; - - Vector2 pixel_size = Vector2(1.0 / p_base_texture_size.width, 1.0 / p_base_texture_size.height); + bokeh.push_constant.orthogonal = p_cam_orthogonal; + bokeh.push_constant.size[0] = p_buffers.base_texture_size.width; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.height; + bokeh.push_constant.z_far = p_cam_zfar; + bokeh.push_constant.z_near = p_cam_znear; - blur_raster.push_constant.dof_radius = (p_dof_blur_amount * p_dof_blur_amount) / qsteps[p_quality]; - blur_raster.push_constant.pixel_size[0] = pixel_size.x; - blur_raster.push_constant.pixel_size[1] = pixel_size.y; - blur_raster.push_constant.camera_z_far = p_cam_zfar; - blur_raster.push_constant.camera_z_near = p_cam_znear; + bokeh.push_constant.second_pass = false; + bokeh.push_constant.half_size = false; + bokeh.push_constant.blur_size = p_dof_blur_amount; if (p_dof_far || p_dof_near) { - if (p_quality == RS::DOF_BLUR_QUALITY_HIGH) { - blur_mode = BLUR_MODE_DOF_HIGH; - } else if (p_quality == RS::DOF_BLUR_QUALITY_MEDIUM) { - blur_mode = BLUR_MODE_DOF_MEDIUM; - } else { // for LOW or VERYLOW we use LOW - blur_mode = BLUR_MODE_DOF_LOW; - } - if (p_dof_far) { - base_flags |= BLUR_FLAG_DOF_FAR; - blur_raster.push_constant.dof_far_begin = p_dof_far_begin; - blur_raster.push_constant.dof_far_end = p_dof_far_begin + p_dof_far_size; + bokeh.push_constant.blur_far_active = true; + bokeh.push_constant.blur_far_begin = p_dof_far_begin; + bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size; } if (p_dof_near) { - base_flags |= BLUR_FLAG_DOF_NEAR; - blur_raster.push_constant.dof_near_begin = p_dof_near_begin; - blur_raster.push_constant.dof_near_end = p_dof_near_begin - p_dof_near_size; + bokeh.push_constant.blur_near_active = true; + bokeh.push_constant.blur_near_begin = p_dof_near_begin; + bokeh.push_constant.blur_near_end = p_dof_near_begin - p_dof_near_size; } - //HORIZONTAL - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_secondary_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_secondary_fb))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base_texture), 0); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + { + // generate our depth data + RID framebuffer = p_buffers.base_weight_fb; + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.depth_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL; - blur_raster.push_constant.dof_dir[0] = 1.0; - blur_raster.push_constant.dof_dir[1] = 0.0; + RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant)); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + } - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) { + // double pass approach + BokehMode mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL; - //VERTICAL - draw_list = RD::get_singleton()->draw_list_begin(p_base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_base_fb))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary_texture), 0); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) { + //box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes) + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1; + bokeh.push_constant.half_size = true; + bokeh.push_constant.blur_size *= 0.5; + } - blur_raster.push_constant.flags = base_flags; - blur_raster.push_constant.dof_dir[0] = 0.0; - blur_raster.push_constant.dof_dir[1] = 1.0; + static const int quality_samples[4] = { 6, 12, 12, 24 }; + bokeh.push_constant.blur_scale = 0.5; + bokeh.push_constant.steps = quality_samples[p_quality]; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb; - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + // Pass 1 + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + + // Pass 2 + if (!bokeh.push_constant.half_size) { + // do not output weight, we're writing back into our base buffer + mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT; + } + bokeh.push_constant.second_pass = true; + + framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[1] : p_buffers.base_fb; + RID texture = bokeh.push_constant.half_size ? p_buffers.half_texture[0] : p_buffers.secondary_texture; + RID weight = bokeh.push_constant.half_size ? p_buffers.weight_texture[2] : p_buffers.weight_texture[1]; + + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(texture), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(weight), 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + + if (bokeh.push_constant.half_size) { + // Compose pass + mode = BOKEH_COMPOSITE; + framebuffer = p_buffers.base_fb; + + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[1]), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[3]), 1); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + } + + } else { + // circular is a single pass approach + BokehMode mode = BOKEH_GEN_BOKEH_CIRCULAR; + + { + // circle always runs in half size, otherwise too expensive (though the code below does support making this optional) + bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1; + bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1; + bokeh.push_constant.half_size = true; + // bokeh.push_constant.blur_size *= 0.5; + } + + static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 }; + bokeh.push_constant.blur_scale = quality_scale[p_quality]; + bokeh.push_constant.steps = 0.0; + + RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb; + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + + if (bokeh.push_constant.half_size) { + // Compose + mode = BOKEH_COMPOSITE; + framebuffer = p_buffers.base_fb; + + draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[0]), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[2]), 1); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + } else { + // Just copy it back (we use our blur raster shader here).. + draw_list = RD::get_singleton()->draw_list_begin(p_buffers.base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[BLUR_MODE_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_buffers.base_fb))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.secondary_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + } + } } } @@ -1771,12 +1893,11 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { // init blur shader (on compute use copy shader) Vector<String> blur_modes; + blur_modes.push_back("\n#define MODE_MIPMAP\n"); // BLUR_MIPMAP blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE - blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_LOW\n"); // BLUR_MODE_DOF_LOW - blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_MEDIUM\n"); // BLUR_MODE_DOF_MEDIUM - blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_HIGH\n"); // BLUR_MODE_DOF_HIGH + blur_modes.push_back("\n#define MODE_COPY\n"); // BLUR_MODE_COPY blur_raster.shader.initialize(blur_modes); memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); @@ -1956,23 +2077,39 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0); } + // Initialize bokeh + Vector<String> bokeh_modes; + bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n"); + bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n#define OUTPUT_WEIGHT\n"); + bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n"); + bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n#define OUTPUT_WEIGHT\n"); + bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n"); + bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n#define OUTPUT_WEIGHT\n"); + bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n"); if (prefer_raster_effects) { - // not supported - } else { - // Initialize bokeh - Vector<String> bokeh_modes; - bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n"); - bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n"); - bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n"); - bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n"); - bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n"); + bokeh.raster_shader.initialize(bokeh_modes); + + bokeh.shader_version = bokeh.raster_shader.version_create(); - bokeh.shader.initialize(bokeh_modes); + const int att_count[BOKEH_MAX] = { 1, 2, 1, 2, 1, 2, 1 }; + for (int i = 0; i < BOKEH_MAX; i++) { + RD::PipelineColorBlendState blend_state = (i == BOKEH_COMPOSITE) ? RD::PipelineColorBlendState::create_blend(att_count[i]) : RD::PipelineColorBlendState::create_disabled(att_count[i]); + bokeh.raster_pipelines[i].setup(bokeh.raster_shader.version_get_shader(bokeh.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + } + } else { + bokeh.compute_shader.initialize(bokeh_modes); + bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_BOX_NOWEIGHT, false); + bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT, false); + bokeh.shader_version = bokeh.compute_shader.version_create(); - bokeh.shader_version = bokeh.shader.version_create(); + for (int i = 0; i < BOKEH_MAX; i++) { + if (bokeh.compute_shader.is_variant_enabled(i)) { + bokeh.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i)); + } + } for (int i = 0; i < BOKEH_MAX; i++) { - bokeh.pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.shader.version_get_shader(bokeh.shader_version, i)); + bokeh.raster_pipelines[i].clear(); } } @@ -2173,12 +2310,13 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { if (prefer_raster_effects) { filter.raster_shader.initialize(cubemap_filter_modes); - filter.shader_version = filter.raster_shader.version_create(); // array variants are not supported in raster filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false); filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false); + filter.shader_version = filter.raster_shader.version_create(); + for (int i = 0; i < FILTER_MODE_MAX; i++) { if (filter.raster_shader.is_variant_enabled(i)) { filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); @@ -2390,12 +2528,13 @@ EffectsRD::~EffectsRD() { if (prefer_raster_effects) { blur_raster.shader.version_free(blur_raster.shader_version); + bokeh.raster_shader.version_free(blur_raster.shader_version); luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version); roughness.raster_shader.version_free(roughness.shader_version); cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version); filter.raster_shader.version_free(filter.shader_version); } else { - bokeh.shader.version_free(bokeh.shader_version); + bokeh.compute_shader.version_free(bokeh.shader_version); luminance_reduce.shader.version_free(luminance_reduce.shader_version); roughness.compute_shader.version_free(roughness.shader_version); cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 79d9a8b738..0c9b2efb7f 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -35,6 +35,7 @@ #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" #include "servers/rendering/renderer_rd/shaders/blur_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h" @@ -69,13 +70,12 @@ private: bool prefer_raster_effects; enum BlurRasterMode { + BLUR_MIPMAP, + BLUR_MODE_GAUSSIAN_BLUR, BLUR_MODE_GAUSSIAN_GLOW, BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, - - BLUR_MODE_DOF_LOW, - BLUR_MODE_DOF_MEDIUM, - BLUR_MODE_DOF_HIGH, + BLUR_MODE_COPY, BLUR_MODE_MAX }; @@ -84,8 +84,6 @@ private: BLUR_FLAG_HORIZONTAL = (1 << 0), BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1), BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2), - BLUR_FLAG_DOF_FAR = (1 << 3), - BLUR_FLAG_DOF_NEAR = (1 << 4), }; struct BlurRasterPushConstant { @@ -103,19 +101,6 @@ private: float glow_white; float glow_luminance_cap; float glow_auto_exposure_grey; - - //dof - float dof_far_begin; - float dof_far_end; - float dof_near_begin; - float dof_near_end; - - float dof_radius; - float dof_pad[3]; - - float dof_dir[2]; - float camera_z_far; - float camera_z_near; }; struct BlurRaster { @@ -252,29 +237,29 @@ private: }; struct TonemapPushConstant { - float bcs[3]; - uint32_t use_bcs; + float bcs[3]; // 12 - 12 + uint32_t use_bcs; // 4 - 16 - uint32_t use_glow; - uint32_t use_auto_exposure; - uint32_t use_color_correction; - uint32_t tonemapper; + uint32_t use_glow; // 4 - 20 + uint32_t use_auto_exposure; // 4 - 24 + uint32_t use_color_correction; // 4 - 28 + uint32_t tonemapper; // 4 - 32 - uint32_t glow_texture_size[2]; - float glow_intensity; - uint32_t pad3; + uint32_t glow_texture_size[2]; // 8 - 40 + float glow_intensity; // 4 - 44 + uint32_t pad3; // 4 - 48 - uint32_t glow_mode; - float glow_levels[7]; + uint32_t glow_mode; // 4 - 52 + float glow_levels[7]; // 28 - 80 - float exposure; - float white; - float auto_exposure_grey; - uint32_t pad2; + float exposure; // 4 - 84 + float white; // 4 - 88 + float auto_exposure_grey; // 4 - 92 + uint32_t pad2; // 4 - 96 - float pixel_size[2]; - uint32_t use_fxaa; - uint32_t use_debanding; + float pixel_size[2]; // 8 - 104 + uint32_t use_fxaa; // 4 - 108 + uint32_t use_debanding; // 4 - 112 }; /* tonemap actually writes to a framebuffer, which is @@ -375,7 +360,9 @@ private: enum BokehMode { BOKEH_GEN_BLUR_SIZE, BOKEH_GEN_BOKEH_BOX, + BOKEH_GEN_BOKEH_BOX_NOWEIGHT, BOKEH_GEN_BOKEH_HEXAGONAL, + BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT, BOKEH_GEN_BOKEH_CIRCULAR, BOKEH_COMPOSITE, BOKEH_MAX @@ -383,9 +370,11 @@ private: struct Bokeh { BokehPushConstant push_constant; - BokehDofShaderRD shader; + BokehDofShaderRD compute_shader; + BokehDofRasterShaderRD raster_shader; RID shader_version; - RID pipelines[BOKEH_MAX]; + RID compute_pipelines[BOKEH_MAX]; + PipelineCacheRD raster_pipelines[BOKEH_MAX]; } bokeh; enum SSAOMode { @@ -780,12 +769,31 @@ public: void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); + void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size); void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); - void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); - void blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); + struct BokehBuffers { + // bokeh buffers + + // textures + Size2i base_texture_size; + RID base_texture; + RID depth_texture; + RID secondary_texture; + RID half_texture[2]; + + // raster only + RID base_fb; + RID secondary_fb; // with weights + RID half_fb[2]; // with weights + RID base_weight_fb; + RID weight_texture[4]; + }; + + void bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); + void bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); struct TonemapSettings { bool use_glow = false; 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 0d304556c2..5a0ad97c7c 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1533,6 +1533,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + if (scene_state.used_screen_texture) { + // Copy screen texture to backbuffer so we can read from it + _render_buffers_copy_screen_texture(p_render_data); + } + + if (scene_state.used_depth_texture) { + // Copy depth texture to backbuffer so we can read from it + _render_buffers_copy_depth_texture(p_render_data); + } + RENDER_TIMESTAMP("Render Transparent Pass"); RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); @@ -2219,7 +2229,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID(); + RID texture = (dbt.is_valid()) ? dbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); u.ids.push_back(texture); uniforms.push_back(u); } 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 89d14e871a..be18a73989 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 @@ -131,9 +131,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); - if (err != OK) { - return; - } + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { version = shader_singleton->shader.version_create(); 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 ab052885c6..96b3cdadd4 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -414,7 +414,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ RD::Uniform u; u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID(); + RID texture = (dbt.is_valid()) ? dbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); u.ids.push_back(texture); uniforms.push_back(u); } @@ -769,6 +770,16 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass } + if (scene_state.used_screen_texture) { + // Copy screen texture to backbuffer so we can read from it + _render_buffers_copy_screen_texture(p_render_data); + } + + if (scene_state.used_depth_texture) { + // Copy depth texture to backbuffer so we can read from it + _render_buffers_copy_depth_texture(p_render_data); + } + // transparent pass RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass"); 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 bcdcb05653..735014a2ec 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 @@ -135,8 +135,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); - - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { version = shader_singleton->shader.version_create(); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 14b2768c29..f8aefdb29c 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1970,8 +1970,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code); - - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { version = canvas_singleton->shader.canvas_shader.version_create(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 057d108578..5016c99a1e 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1464,6 +1464,85 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { base_width = MAX(1, base_width >> 1); base_height = MAX(1, base_height >> 1); } + + if (!_render_buffers_can_be_storage()) { + // create 4 weight textures, 2 full size, 2 half size + + tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP + tf.width = rb->width; + tf.height = rb->height; + tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D; + tf.array_layers = rb->view_count; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.mipmaps = 1; + for (uint32_t i = 0; i < 4; i++) { + // associated blur texture + RID texture; + if (i == 0) { + texture = rb->texture; + } else if (i == 1) { + texture = rb->blur[0].mipmaps[0].texture; + } else if (i == 2) { + texture = rb->blur[1].mipmaps[0].texture; + } else if (i == 3) { + texture = rb->blur[0].mipmaps[1].texture; + } + + // create weight texture + rb->weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + // create frame buffer + Vector<RID> fb; + fb.push_back(texture); + fb.push_back(rb->weight_buffers[i].weight); + rb->weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb); + + if (i == 1) { + // next 2 are half size + tf.width = MAX(1, tf.width >> 1); + tf.height = MAX(1, tf.height >> 1); + } + } + + { + // and finally an FB for just our base weights + Vector<RID> fb; + fb.push_back(rb->weight_buffers[0].weight); + rb->base_weight_fb = RD::get_singleton()->framebuffer_create(fb); + } + } +} + +void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *rb) { + ERR_FAIL_COND(!rb->depth_back_texture.is_null()); + + { + RD::TextureFormat tf; + if (rb->view_count > 1) { + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + } + // We're not using this as a depth stencil, just copying our data into this. May need to look into using a different format on mobile, maybe R16? + tf.format = RD::DATA_FORMAT_R32_SFLOAT; + + tf.width = rb->width; + tf.height = rb->height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.array_layers = rb->view_count; // create a layer for every view + + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // set this as color attachment because we're copying data into it, it's not actually used as a depth buffer + + rb->depth_back_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + if (!_render_buffers_can_be_storage()) { + // create framebuffer so we can write into this... + + Vector<RID> fb; + fb.push_back(rb->depth_back_texture); + + rb->depth_back_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count); + } } void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) { @@ -1532,6 +1611,16 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->depth_texture = RID(); } + if (rb->depth_back_fb.is_valid()) { + RD::get_singleton()->free(rb->depth_back_fb); + rb->depth_back_fb = RID(); + } + + if (rb->depth_back_texture.is_valid()) { + RD::get_singleton()->free(rb->depth_back_texture); + rb->depth_back_texture = RID(); + } + for (int i = 0; i < 2; i++) { for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) { // do we free the texture slice here? or is it enough to free the main texture? @@ -1832,6 +1921,58 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set); } +void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + ERR_FAIL_COND(!rb); + + RD::get_singleton()->draw_command_begin_label("Copy screen texture"); + + if (rb->blur[0].texture.is_null()) { + _allocate_blur_textures(rb); + } + + // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye + + bool can_use_storage = _render_buffers_can_be_storage(); + + if (can_use_storage) { + storage->get_effects()->copy_to_rect(rb->texture, rb->blur[0].mipmaps[0].texture, Rect2i(0, 0, rb->width, rb->height)); + for (int i = 1; i < rb->blur[0].mipmaps.size(); i++) { + storage->get_effects()->make_mipmap(rb->blur[0].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i].texture, Size2i(rb->blur[0].mipmaps[i].width, rb->blur[0].mipmaps[i].height)); + } + } else { + storage->get_effects()->copy_to_fb_rect(rb->texture, rb->blur[0].mipmaps[0].fb, Rect2i(0, 0, rb->width, rb->height)); + for (int i = 1; i < rb->blur[0].mipmaps.size(); i++) { + storage->get_effects()->make_mipmap_raster(rb->blur[0].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i].fb, Size2i(rb->blur[0].mipmaps[i].width, rb->blur[0].mipmaps[i].height)); + } + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + ERR_FAIL_COND(!rb); + + RD::get_singleton()->draw_command_begin_label("Copy depth texture"); + + if (rb->depth_back_texture.is_null()) { + _allocate_depth_backbuffer_textures(rb); + } + + // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye + + bool can_use_storage = _render_buffers_can_be_storage(); + + if (can_use_storage) { + storage->get_effects()->copy_to_rect(rb->depth_texture, rb->depth_back_texture, Rect2i(0, 0, rb->width, rb->height)); + } else { + storage->get_effects()->copy_to_fb_rect(rb->depth_texture, rb->depth_back_fb, Rect2i(0, 0, rb->width, rb->height)); + } + + RD::get_singleton()->draw_command_end_label(); +} + void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); ERR_FAIL_COND(!rb); @@ -1851,11 +1992,34 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende _allocate_blur_textures(rb); } + EffectsRD::BokehBuffers buffers; + + // textures we use + buffers.base_texture_size = Size2i(rb->width, rb->height); + buffers.base_texture = rb->texture; + buffers.depth_texture = rb->depth_texture; + buffers.secondary_texture = rb->blur[0].mipmaps[0].texture; + buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture; + buffers.half_texture[1] = rb->blur[0].mipmaps[1].texture; + + float bokeh_size = camfx->dof_blur_amount * 64.0; if (can_use_storage) { - float bokeh_size = camfx->dof_blur_amount * 64.0; - storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); + storage->get_effects()->bokeh_dof(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); } else { - storage->get_effects()->blur_dof_raster(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->texture_fb, rb->blur[0].mipmaps[0].texture, rb->blur[0].mipmaps[0].fb, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, camfx->dof_blur_amount, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); + // set framebuffers + buffers.base_fb = rb->texture_fb; + buffers.secondary_fb = rb->weight_buffers[1].fb; + buffers.half_fb[0] = rb->weight_buffers[2].fb; + buffers.half_fb[1] = rb->weight_buffers[3].fb; + buffers.weight_texture[0] = rb->weight_buffers[0].weight; + buffers.weight_texture[1] = rb->weight_buffers[1].weight; + buffers.weight_texture[2] = rb->weight_buffers[2].weight; + buffers.weight_texture[3] = rb->weight_buffers[3].weight; + + // set weight buffers + buffers.base_weight_fb = rb->base_weight_fb; + + storage->get_effects()->bokeh_dof_raster(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); } RD::get_singleton()->draw_command_end_label(); } @@ -2157,6 +2321,15 @@ RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_b return rb->blur[0].texture; } +RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + if (!rb->depth_back_texture.is_valid()) { + return RID(); //not valid at the moment + } + return rb->depth_back_texture; +} + RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 336dd6e1a7..5306df36f0 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -134,6 +134,8 @@ protected: void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); + void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); + void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data); void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data); void _disable_clear_request(const RenderDataRD *p_render_data); @@ -483,6 +485,18 @@ private: Blur blur[2]; //the second one starts from the first mipmap + struct WeightBuffers { + RID weight; + RID fb; // FB with both texture and weight + }; + + // 2 full size, 2 half size + WeightBuffers weight_buffers[4]; // Only used in raster + RID base_weight_fb; // base buffer for weight + + RID depth_back_texture; + RID depth_back_fb; // only used on mobile + struct Luminance { Vector<RID> reduce; RID current; @@ -526,6 +540,7 @@ private: void _free_render_buffer_data(RenderBuffers *rb); void _allocate_blur_textures(RenderBuffers *rb); + void _allocate_depth_backbuffer_textures(RenderBuffers *rb); void _allocate_luminance_textures(RenderBuffers *rb); void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer); @@ -1174,6 +1189,7 @@ public: RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); + RID render_buffers_get_back_depth_texture(RID p_render_buffers); RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers); RID render_buffers_get_default_voxel_gi_buffer(); RID render_buffers_get_gi_ambient_texture(RID p_render_buffers); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 9331cab090..9e85608f1e 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -92,8 +92,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); - - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { version = scene_singleton->sky.sky_shader.shader.version_create(); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 096d5563e6..7d438345f1 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -5268,8 +5268,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code); - - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { version = base_singleton->particles_shader.shader.version_create(); diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 44705b2bd6..529328f0ed 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -142,9 +142,7 @@ public: ERR_FAIL_COND_V(!variants_enabled[p_variant], RID()); Version *version = version_owner.getornull(p_version); - if (!version) { - return RID(); - } + ERR_FAIL_COND_V(!version, RID()); if (version->dirty) { _compile_version(version); diff --git a/servers/rendering/renderer_rd/shaders/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/blur_raster.glsl index b1d1c2365e..0789a4b396 100644 --- a/servers/rendering/renderer_rd/shaders/blur_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl @@ -37,32 +37,6 @@ layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(location = 0) out vec4 frag_color; -//DOF -#ifdef MODE_DOF_BLUR - -layout(set = 1, binding = 0) uniform sampler2D dof_source_depth; - -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); -#endif - -#ifdef DOF_QUALITY_MEDIUM -const int dof_kernel_size = 11; -const int dof_kernel_from = 5; -const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); - -#endif - -#ifdef DOF_QUALITY_HIGH -const int dof_kernel_size = 21; -const int dof_kernel_from = 10; -const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); -#endif - -#endif - void main() { #ifdef MODE_MIPMAP @@ -155,74 +129,8 @@ void main() { #endif -#ifdef MODE_DOF_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = texture(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); - } - - // mix near and far blur amount - float amount = 1.0; - if (bool(blur.flags & FLAG_DOF_FAR)) { - amount *= 1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, depth); - } - if (bool(blur.flags & FLAG_DOF_NEAR)) { - amount *= smoothstep(blur.dof_near_end, blur.dof_near_begin, depth); - } - amount = 1.0 - amount; - - if (amount > 0.0) { - float k_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - - // mix near and far blur amount - float tap_amount = 1.0; - if (bool(blur.flags & FLAG_DOF_FAR)) { - tap_amount *= mix(1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, tap_depth), 0.0, int_ofs == 0); - } - if (bool(blur.flags & FLAG_DOF_NEAR)) { - tap_amount *= mix(smoothstep(blur.dof_near_end, blur.dof_near_begin, tap_depth), 0.0, int_ofs == 0); - } - tap_amount = 1.0 - tap_amount; - - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k; - - k_accum += tap_k * tap_amount; - color_accum += tap_color * tap_amount; - } - - if (k_accum > 0.0) { - color_accum /= k_accum; - } - - frag_color = color_accum; ///k_accum; - } else { - // we are in focus, don't waste time - frag_color = texture(source_color, uv_interp, 0.0); - } - +#ifdef MODE_COPY + vec4 color = textureLod(source_color, uv_interp, 0.0); + frag_color = color; #endif } diff --git a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl index 6ea968e595..52bf2886b5 100644 --- a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl @@ -1,8 +1,6 @@ #define FLAG_HORIZONTAL (1 << 0) #define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1) #define FLAG_GLOW_FIRST_PASS (1 << 2) -#define FLAG_DOF_FAR (1 << 3) -#define FLAG_DOF_NEAR (1 << 4) layout(push_constant, binding = 1, std430) uniform Blur { vec2 pixel_size; @@ -19,18 +17,5 @@ layout(push_constant, binding = 1, std430) uniform Blur { float glow_white; float glow_luminance_cap; float glow_auto_exposure_grey; - - // DOF. - float dof_far_begin; - float dof_far_end; - float dof_near_begin; - float dof_near_end; - - float dof_radius; - float dof_pad[3]; - - vec2 dof_dir; - float camera_z_far; - float camera_z_near; } blur; diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl index b70e0b6bd5..0438671dd2 100644 --- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl @@ -25,34 +25,7 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh; // based on https://www.shadertoy.com/view/Xd3GDl -layout(push_constant, binding = 1, std430) uniform Params { - ivec2 size; - float z_far; - float z_near; - - bool orthogonal; - float blur_size; - float blur_scale; - int blur_steps; - - bool blur_near_active; - float blur_near_begin; - float blur_near_end; - bool blur_far_active; - - float blur_far_begin; - float blur_far_end; - bool second_pass; - bool half_size; - - bool use_jitter; - float jitter_seed; - uint pad[2]; -} -params; - -//used to work around downsampling filter -#define DEPTH_GAP 0.0 +#include "bokeh_dof_inc.glsl" #ifdef MODE_GEN_BLUR_SIZE @@ -80,15 +53,6 @@ float get_blur_size(float depth) { #endif -const float GOLDEN_ANGLE = 2.39996323; - -//note: uniform pdf rand [0;1[ -float hash12n(vec2 p) { - p = fract(p * vec2(5.3987, 5.4421)); - p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); - return fract(p.x * p.y * 95.4307); -} - #if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL) vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) { diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl new file mode 100644 index 0000000000..fadea1631c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl @@ -0,0 +1,37 @@ +layout(push_constant, binding = 1, std430) uniform Params { + ivec2 size; + float z_far; + float z_near; + + bool orthogonal; + float blur_size; + float blur_scale; + int blur_steps; + + bool blur_near_active; + float blur_near_begin; + float blur_near_end; + bool blur_far_active; + + float blur_far_begin; + float blur_far_end; + bool second_pass; + bool half_size; + + bool use_jitter; + float jitter_seed; + uint pad[2]; +} +params; + +//used to work around downsampling filter +#define DEPTH_GAP 0.0 + +const float GOLDEN_ANGLE = 2.39996323; + +//note: uniform pdf rand [0;1[ +float hash12n(vec2 p) { + p = fract(p * vec2(5.3987, 5.4421)); + p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); + return fract(p.x * p.y * 95.4307); +} diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl new file mode 100644 index 0000000000..43a2a29616 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl @@ -0,0 +1,253 @@ +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "bokeh_dof_inc.glsl" + +layout(location = 0) out vec2 uv_interp; +/* clang-format on */ + +void main() { + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); +} + +/* clang-format off */ +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#include "bokeh_dof_inc.glsl" + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +#ifdef MODE_GEN_BLUR_SIZE +layout(location = 0) out float weight; + +layout(set = 0, binding = 0) uniform sampler2D source_depth; +#else +layout(location = 0) out vec4 frag_color; +#ifdef OUTPUT_WEIGHT +layout(location = 1) out float weight; +#endif + +layout(set = 0, binding = 0) uniform sampler2D source_color; +layout(set = 1, binding = 0) uniform sampler2D source_weight; +#ifdef MODE_COMPOSITE_BOKEH +layout(set = 2, binding = 0) uniform sampler2D original_weight; +#endif +#endif + +//DOF +// Bokeh single pass implementation based on http://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html + +#ifdef MODE_GEN_BLUR_SIZE + +float get_depth_at_pos(vec2 uv) { + float depth = textureLod(source_depth, uv, 0.0).x; + if (params.orthogonal) { + depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + } else { + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + } + return depth; +} + +float get_blur_size(float depth) { + if (params.blur_near_active && depth < params.blur_near_begin) { + return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative + } + + if (params.blur_far_active && depth > params.blur_far_begin) { + return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP; + } + + return 0.0; +} + +#endif + +#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL) + +vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) { + dir *= pixel_size; + vec4 color = texture(source_color, uv); + color.a = texture(source_weight, uv).r; + + vec4 accum = color; + float total = 1.0; + + float blur_scale = params.blur_size / float(params.blur_steps); + + if (params.use_jitter) { + uv += dir * (hash12n(uv + params.jitter_seed) - 0.5); + } + + for (int i = -params.blur_steps; i <= params.blur_steps; i++) { + if (i == 0) { + continue; + } + float radius = float(i) * blur_scale; + vec2 suv = uv + dir * radius; + radius = abs(radius); + + vec4 sample_color = texture(source_color, suv); + sample_color.a = texture(source_weight, suv).r; + float limit; + + if (sample_color.a < color.a) { + limit = abs(sample_color.a); + } else { + limit = abs(color.a); + } + + limit -= DEPTH_GAP; + + float m = smoothstep(radius - 0.5, radius + 0.5, limit); + + accum += mix(color, sample_color, m); + + total += 1.0; + } + + return accum / total; +} + +#endif + +void main() { + vec2 pixel_size = 1.0 / vec2(params.size); + vec2 uv = uv_interp; + +#ifdef MODE_GEN_BLUR_SIZE + uv += pixel_size * 0.5; + float center_depth = get_depth_at_pos(uv); + weight = get_blur_size(center_depth); +#endif + +#ifdef MODE_BOKEH_BOX + //pixel_size*=0.5; //resolution is doubled + if (params.second_pass || !params.half_size) { + uv += pixel_size * 0.5; //half pixel to read centers + } else { + uv += pixel_size * 0.25; //half pixel to read centers from full res + } + + float alpha = texture(source_color, uv).a; // retain this + vec2 dir = (params.second_pass ? vec2(0.0, 1.0) : vec2(1.0, 0.0)); + + vec4 color = weighted_filter_dir(dir, uv, pixel_size); + + frag_color = color; + frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size +#ifdef OUTPUT_WEIGHT + weight = color.a; +#endif + +#endif + +#ifdef MODE_BOKEH_HEXAGONAL + + //pixel_size*=0.5; //resolution is doubled + if (params.second_pass || !params.half_size) { + uv += pixel_size * 0.5; //half pixel to read centers + } else { + uv += pixel_size * 0.25; //half pixel to read centers from full res + } + + float alpha = texture(source_color, uv).a; // retain this + + vec2 dir = (params.second_pass ? normalize(vec2(1.0, 0.577350269189626)) : vec2(0.0, 1.0)); + + vec4 color = weighted_filter_dir(dir, uv, pixel_size); + + if (params.second_pass) { + dir = normalize(vec2(-1.0, 0.577350269189626)); + + vec4 color2 = weighted_filter_dir(dir, uv, pixel_size); + + color.rgb = min(color.rgb, color2.rgb); + color.a = (color.a + color2.a) * 0.5; + } + + frag_color = color; + frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size +#ifdef OUTPUT_WEIGHT + weight = color.a; +#endif + +#endif + +#ifdef MODE_BOKEH_CIRCULAR + if (params.half_size) { + pixel_size *= 0.5; //resolution is doubled + } + + uv += pixel_size * 0.5; //half pixel to read centers + + vec4 color = texture(source_color, uv); + float alpha = color.a; // retain this + color.a = texture(source_weight, uv).r; + + vec4 color_accum = color; + float accum = 1.0; + + float radius = params.blur_scale; + for (float ang = 0.0; radius < params.blur_size; ang += GOLDEN_ANGLE) { + vec2 uv_adj = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius; + + vec4 sample_color = texture(source_color, uv_adj); + sample_color.a = texture(source_weight, uv_adj).r; + + float limit; + + if (sample_color.a < color.a) { + limit = abs(sample_color.a); + } else { + limit = abs(color.a); + } + + limit -= DEPTH_GAP; + + float m = smoothstep(radius - 0.5, radius + 0.5, limit); + color_accum += mix(color_accum / accum, sample_color, m); + accum += 1.0; + + radius += params.blur_scale / radius; + } + + color_accum = color_accum / accum; + + frag_color.rgb = color_accum.rgb; + frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size +#ifdef OUTPUT_WEIGHT + weight = color_accum.a; +#endif + +#endif + +#ifdef MODE_COMPOSITE_BOKEH + frag_color.rgb = texture(source_color, uv).rgb; + + float center_weigth = texture(source_weight, uv).r; + float sample_weight = texture(original_weight, uv).r; + + float mix_amount; + if (sample_weight < center_weigth) { + mix_amount = min(1.0, max(0.0, max(abs(center_weigth), abs(sample_weight)) - DEPTH_GAP)); + } else { + mix_amount = min(1.0, max(0.0, abs(center_weigth) - DEPTH_GAP)); + } + + // let alpha blending take care of mixing + frag_color.a = mix_amount; +#endif +} |