diff options
Diffstat (limited to 'servers')
172 files changed, 12813 insertions, 6694 deletions
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 138cb6e1f8..08c482553b 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -246,6 +246,7 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) { init_channels_and_buffers(); } + ERR_FAIL_COND_MSG(buses.is_empty() && todo, "AudioServer bus count is less than 1."); while (todo) { if (to_mix == 0) { _mix_step(); diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp index b06f32417c..ee4a2e148b 100644 --- a/servers/camera_server.cpp +++ b/servers/camera_server.cpp @@ -99,6 +99,8 @@ Ref<CameraFeed> CameraServer::get_feed_by_id(int p_id) { }; void CameraServer::add_feed(const Ref<CameraFeed> &p_feed) { + ERR_FAIL_COND(p_feed.is_null()); + // add our feed feeds.push_back(p_feed); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 2fa333cc05..7bd1075006 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -253,27 +253,6 @@ bool DisplayServer::get_swap_cancel_ok() { void DisplayServer::enable_for_stealing_focus(OS::ProcessID pid) { } -//plays video natively, in fullscreen, only implemented in mobile for now, likely not possible to implement on linux also. -Error DisplayServer::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen) { - ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Native video not supported by this display server."); -} - -bool DisplayServer::native_video_is_playing() const { - return false; -} - -void DisplayServer::native_video_pause() { - WARN_PRINT("Native video not supported by this display server."); -} - -void DisplayServer::native_video_unpause() { - WARN_PRINT("Native video not supported by this display server."); -} - -void DisplayServer::native_video_stop() { - WARN_PRINT("Native video not supported by this display server."); -} - Error DisplayServer::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); return OK; @@ -477,12 +456,6 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("enable_for_stealing_focus", "process_id"), &DisplayServer::enable_for_stealing_focus); - ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track", "screen"), &DisplayServer::native_video_play); - ClassDB::bind_method(D_METHOD("native_video_is_playing"), &DisplayServer::native_video_is_playing); - ClassDB::bind_method(D_METHOD("native_video_stop"), &DisplayServer::native_video_stop); - ClassDB::bind_method(D_METHOD("native_video_pause"), &DisplayServer::native_video_pause); - ClassDB::bind_method(D_METHOD("native_video_unpause"), &DisplayServer::native_video_unpause); - ClassDB::bind_method(D_METHOD("dialog_show", "title", "description", "buttons", "callback"), &DisplayServer::dialog_show); ClassDB::bind_method(D_METHOD("dialog_input_text", "title", "description", "existing_text", "callback"), &DisplayServer::dialog_input_text); @@ -518,7 +491,6 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_VIRTUAL_KEYBOARD); BIND_ENUM_CONSTANT(FEATURE_CURSOR_SHAPE); BIND_ENUM_CONSTANT(FEATURE_CUSTOM_CURSOR_SHAPE); - BIND_ENUM_CONSTANT(FEATURE_NATIVE_VIDEO); BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG); BIND_ENUM_CONSTANT(FEATURE_CONSOLE_WINDOW); BIND_ENUM_CONSTANT(FEATURE_IME); diff --git a/servers/display_server.h b/servers/display_server.h index 3aab572120..f05aa1f59a 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -97,7 +97,6 @@ public: FEATURE_VIRTUAL_KEYBOARD, FEATURE_CURSOR_SHAPE, FEATURE_CUSTOM_CURSOR_SHAPE, - FEATURE_NATIVE_VIDEO, FEATURE_NATIVE_DIALOG, FEATURE_CONSOLE_WINDOW, FEATURE_IME, @@ -324,13 +323,6 @@ public: virtual void enable_for_stealing_focus(OS::ProcessID pid); - //plays video natively, in fullscreen, only implemented in mobile for now, likely not possible to implement on linux also. - virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen = SCREEN_OF_MAIN_WINDOW); - virtual bool native_video_is_playing() const; - virtual void native_video_pause(); - virtual void native_video_unpause(); - virtual void native_video_stop(); - virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback); virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback); diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp index 6485c8d1e9..532cb259b3 100644 --- a/servers/physics_2d/area_2d_sw.cpp +++ b/servers/physics_2d/area_2d_sw.cpp @@ -215,7 +215,9 @@ void Area2DSW::call_queries() { for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) { if (E->get().state == 0) { // Nothing happened - E = E->next(); + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_bodies.erase(E); + E = next; continue; } @@ -250,7 +252,9 @@ void Area2DSW::call_queries() { for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) { if (E->get().state == 0) { // Nothing happened - E = E->next(); + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_areas.erase(E); + E = next; continue; } diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index 21ad57e344..eb9fc0e800 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -40,31 +40,48 @@ bool AreaPair2DSW::setup(real_t p_step) { result = true; } + process_collision = false; if (result != colliding) { - if (result) { - if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { - body->add_area(area); - } - if (area->has_monitor_callback()) { - area->add_body_to_query(body, body_shape, area_shape); - } - - } else { - if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { - body->remove_area(area); - } - if (area->has_monitor_callback()) { - area->remove_body_from_query(body, body_shape, area_shape); - } + if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + process_collision = true; + } else if (area->has_monitor_callback()) { + process_collision = true; } colliding = result; } - return false; //never do any post solving + return process_collision; +} + +bool AreaPair2DSW::pre_solve(real_t p_step) { + if (!process_collision) { + return false; + } + + if (colliding) { + if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + body->add_area(area); + } + + if (area->has_monitor_callback()) { + area->add_body_to_query(body, body_shape, area_shape); + } + } else { + if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + body->remove_area(area); + } + + if (area->has_monitor_callback()) { + area->remove_body_from_query(body, body_shape, area_shape); + } + } + + return false; // Never do any post solving. } void AreaPair2DSW::solve(real_t p_step) { + // Nothing to do. } AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape) { @@ -72,7 +89,6 @@ AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, area = p_area; body_shape = p_body_shape; area_shape = p_area_shape; - colliding = false; body->add_constraint(this, 0); area->add_constraint(this); if (p_body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { //need to be active to process pair @@ -103,33 +119,48 @@ bool Area2Pair2DSW::setup(real_t p_step) { result = true; } + process_collision = false; if (result != colliding) { - if (result) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { - area_b->add_area_to_query(area_a, shape_a, shape_b); - } - - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { - area_a->add_area_to_query(area_b, shape_b, shape_a); - } - - } else { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { - area_b->remove_area_from_query(area_a, shape_a, shape_b); - } - - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { - area_a->remove_area_from_query(area_b, shape_b, shape_a); - } + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + process_collision = true; + } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + process_collision = true; } colliding = result; } - return false; //never do any post solving + return process_collision; +} + +bool Area2Pair2DSW::pre_solve(real_t p_step) { + if (!process_collision) { + return false; + } + + if (colliding) { + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + area_b->add_area_to_query(area_a, shape_a, shape_b); + } + + if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + area_a->add_area_to_query(area_b, shape_b, shape_a); + } + } else { + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + area_b->remove_area_from_query(area_a, shape_a, shape_b); + } + + if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + area_a->remove_area_from_query(area_b, shape_b, shape_a); + } + } + + return false; // Never do any post solving. } void Area2Pair2DSW::solve(real_t p_step) { + // Nothing to do. } Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b) { @@ -137,7 +168,6 @@ Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area area_b = p_area_b; shape_a = p_shape_a; shape_b = p_shape_b; - colliding = false; area_a->add_constraint(this); area_b->add_constraint(this); } diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h index 4015aad5d1..4632a307d9 100644 --- a/servers/physics_2d/area_pair_2d_sw.h +++ b/servers/physics_2d/area_pair_2d_sw.h @@ -36,30 +36,34 @@ #include "constraint_2d_sw.h" class AreaPair2DSW : public Constraint2DSW { - Body2DSW *body; - Area2DSW *area; - int body_shape; - int area_shape; - bool colliding; + Body2DSW *body = nullptr; + Area2DSW *area = nullptr; + int body_shape = 0; + int area_shape = 0; + bool colliding = false; + bool process_collision = false; public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape); ~AreaPair2DSW(); }; class Area2Pair2DSW : public Constraint2DSW { - Area2DSW *area_a; - Area2DSW *area_b; - int shape_a; - int shape_b; - bool colliding; + Area2DSW *area_a = nullptr; + Area2DSW *area_b = nullptr; + int shape_a = 0; + int shape_b = 0; + bool colliding = false; + bool process_collision = false; public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b); ~Area2Pair2DSW(); diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index d0636047b7..f78a487e27 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -104,31 +104,17 @@ void Body2DSW::set_active(bool p_active) { } active = p_active; - if (!p_active) { - if (get_space()) { - get_space()->body_remove_from_active_list(&active_list); - } - } else { + + if (active) { if (mode == PhysicsServer2D::BODY_MODE_STATIC) { - return; //static bodies can't become active - } - if (get_space()) { + // Static bodies can't be active. + active = false; + } else if (get_space()) { get_space()->body_add_to_active_list(&active_list); } - - //still_time=0; - } - /* - if (!space) - return; - - for(int i=0;i<get_shape_count();i++) { - Shape &s=shapes[i]; - if (s.bpid>0) { - get_space()->get_broadphase()->set_active(s.bpid,active); - } + } else if (get_space()) { + get_space()->body_remove_from_active_list(&active_list); } -*/ } void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) { @@ -370,13 +356,6 @@ void Body2DSW::set_space(Space2DSW *p_space) { if (active) { get_space()->body_add_to_active_list(&active_list); } - /* - _update_queries(); - if (is_active()) { - active=false; - set_active(true); - } - */ } first_integration = false; @@ -591,16 +570,17 @@ void Body2DSW::call_queries() { Variant v = dbs; const Variant *vp[2] = { &v, &fi_callback->callback_udata }; - Object *obj = ObjectDB::get_instance(fi_callback->id); + Object *obj = fi_callback->callable.get_object(); if (!obj) { - set_force_integration_callback(ObjectID(), StringName()); + set_force_integration_callback(Callable()); } else { Callable::CallError ce; + Variant rv; if (fi_callback->callback_udata.get_type() != Variant::NIL) { - obj->call(fi_callback->method, vp, 2, ce); + fi_callback->callable.call(vp, 2, rv, ce); } else { - obj->call(fi_callback->method, vp, 1, ce); + fi_callback->callable.call(vp, 1, rv, ce); } } } @@ -625,16 +605,15 @@ bool Body2DSW::sleep_test(real_t p_step) { } } -void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) { +void Body2DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { if (fi_callback) { memdelete(fi_callback); fi_callback = nullptr; } - if (p_id.is_valid()) { + if (p_callable.get_object()) { fi_callback = memnew(ForceIntegrationCallback); - fi_callback->id = p_id; - fi_callback->method = p_method; + fi_callback->callable = p_callable; fi_callback->callback_udata = p_udata; } } @@ -658,8 +637,6 @@ Body2DSW::Body2DSW() : omit_force_integration = false; applied_torque = 0; island_step = 0; - island_next = nullptr; - island_list_next = nullptr; _set_static(false); first_time_kinematic = false; linear_damp = -1; diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 60d55ab8bd..b4a95651cb 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -117,23 +117,20 @@ class Body2DSW : public CollisionObject2DSW { int contact_count; struct ForceIntegrationCallback { - ObjectID id; - StringName method; + Callable callable; Variant callback_udata; }; ForceIntegrationCallback *fi_callback; uint64_t island_step; - Body2DSW *island_next; - Body2DSW *island_list_next; _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area); friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose public: - void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); + void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant()); _FORCE_INLINE_ void add_area(Area2DSW *p_area) { int index = areas.find(AreaCMP(p_area)); @@ -175,12 +172,6 @@ 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_ Body2DSW *get_island_next() const { return island_next; } - _FORCE_INLINE_ void set_island_next(Body2DSW *p_next) { island_next = p_next; } - - _FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; } - _FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; } - _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); } _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); } const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; } diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index da70ac7d4b..ff31825b83 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -87,10 +87,13 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto int least_deep = -1; real_t min_depth = 1e10; + const Transform2D &transform_A = A->get_transform(); + const Transform2D &transform_B = B->get_transform(); + for (int i = 0; i <= contact_count; i++) { Contact &c = (i == contact_count) ? contact : contacts[i]; - Vector2 global_A = A->get_transform().basis_xform(c.local_A); - Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B; + Vector2 global_A = transform_A.basis_xform(c.local_A); + Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B; Vector2 axis = global_A - global_B; real_t depth = axis.dot(c.normal); @@ -124,6 +127,9 @@ void BodyPair2DSW::_validate_contacts() { real_t max_separation = space->get_contact_max_separation(); real_t max_separation2 = max_separation * max_separation; + const Transform2D &transform_A = A->get_transform(); + const Transform2D &transform_B = B->get_transform(); + for (int i = 0; i < contact_count; i++) { Contact &c = contacts[i]; @@ -134,8 +140,8 @@ void BodyPair2DSW::_validate_contacts() { } else { c.reused = false; - Vector2 global_A = A->get_transform().basis_xform(c.local_A); - Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B; + Vector2 global_A = transform_A.basis_xform(c.local_A); + Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B; Vector2 axis = global_A - global_B; real_t depth = axis.dot(c.normal); @@ -220,14 +226,16 @@ real_t combine_friction(Body2DSW *A, Body2DSW *B) { } bool BodyPair2DSW::setup(real_t p_step) { - //cannot collide + dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) { collided = false; return false; } - bool report_contacts_only = false; - if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) { + report_contacts_only = false; + if (!dynamic_A && !dynamic_B) { if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) { report_contacts_only = true; } else { @@ -246,12 +254,12 @@ bool BodyPair2DSW::setup(real_t p_step) { _validate_contacts(); - Vector2 offset_A = A->get_transform().get_origin(); + const Vector2 &offset_A = A->get_transform().get_origin(); Transform2D xform_Au = A->get_transform().untranslated(); Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A); Transform2D xform_Bu = B->get_transform(); - xform_Bu.elements[2] -= A->get_transform().get_origin(); + xform_Bu.elements[2] -= offset_A; Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B); Shape2DSW *shape_A_ptr = A->get_shape(shape_A); @@ -272,13 +280,13 @@ bool BodyPair2DSW::setup(real_t p_step) { if (!collided) { //test ccd (currently just a raycast) - if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) { + if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && dynamic_A) { if (_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B)) { collided = true; } } - if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) { + if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && dynamic_B) { if (_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A, true)) { collided = true; } @@ -338,9 +346,21 @@ bool BodyPair2DSW::setup(real_t p_step) { } } + return true; +} + +bool BodyPair2DSW::pre_solve(real_t p_step) { + if (!collided || oneway_disabled) { + return false; + } + real_t max_penetration = space->get_contact_max_allowed_penetration(); real_t bias = 0.3; + + Shape2DSW *shape_A_ptr = A->get_shape(shape_A); + Shape2DSW *shape_B_ptr = B->get_shape(shape_B); + if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) { if (shape_A_ptr->get_custom_bias() == 0) { bias = shape_B_ptr->get_custom_bias(); @@ -351,21 +371,23 @@ bool BodyPair2DSW::setup(real_t p_step) { } } - cc = 0; - real_t inv_dt = 1.0 / p_step; bool do_process = false; + const Vector2 &offset_A = A->get_transform().get_origin(); + const Transform2D &transform_A = A->get_transform(); + const Transform2D &transform_B = B->get_transform(); + for (int i = 0; i < contact_count; i++) { Contact &c = contacts[i]; - c.active = false; - Vector2 global_A = xform_Au.xform(c.local_A); - Vector2 global_B = xform_Bu.xform(c.local_B); + Vector2 global_A = transform_A.basis_xform(c.local_A); + Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B; - real_t depth = c.normal.dot(global_A - global_B); + Vector2 axis = global_A - global_B; + real_t depth = axis.dot(c.normal); if (depth <= 0 || !c.reused) { continue; @@ -396,8 +418,6 @@ bool BodyPair2DSW::setup(real_t p_step) { continue; } - c.active = true; - // Precompute normal mass, tangent mass, and bias. real_t rnA = c.rA.dot(c.normal); real_t rnB = c.rB.dot(c.normal); @@ -421,8 +441,12 @@ bool BodyPair2DSW::setup(real_t p_step) { // Apply normal + friction impulse Vector2 P = c.acc_normal_impulse * c.normal + c.acc_tangent_impulse * tangent; - A->apply_impulse(-P, c.rA); - B->apply_impulse(P, c.rB); + if (dynamic_A) { + A->apply_impulse(-P, c.rA); + } + if (dynamic_B) { + B->apply_impulse(P, c.rB); + } } #endif @@ -434,6 +458,7 @@ bool BodyPair2DSW::setup(real_t p_step) { c.bounce = c.bounce * dv.dot(c.normal); } + c.active = true; do_process = true; } @@ -441,13 +466,12 @@ bool BodyPair2DSW::setup(real_t p_step) { } void BodyPair2DSW::solve(real_t p_step) { - if (!collided) { + if (!collided || oneway_disabled) { return; } for (int i = 0; i < contact_count; ++i) { Contact &c = contacts[i]; - cc++; if (!c.active) { continue; @@ -474,8 +498,12 @@ void BodyPair2DSW::solve(real_t p_step) { Vector2 jb = c.normal * (c.acc_bias_impulse - jbnOld); - A->apply_bias_impulse(-jb, c.rA); - B->apply_bias_impulse(jb, c.rB); + if (dynamic_A) { + A->apply_bias_impulse(-jb, c.rA); + } + if (dynamic_B) { + B->apply_bias_impulse(jb, c.rB); + } real_t jn = -(c.bounce + vn) * c.mass_normal; real_t jnOld = c.acc_normal_impulse; @@ -490,8 +518,12 @@ void BodyPair2DSW::solve(real_t p_step) { Vector2 j = c.normal * (c.acc_normal_impulse - jnOld) + tangent * (c.acc_tangent_impulse - jtOld); - A->apply_impulse(-j, c.rA); - B->apply_impulse(j, c.rB); + if (dynamic_A) { + A->apply_impulse(-j, c.rA); + } + if (dynamic_B) { + B->apply_impulse(j, c.rB); + } } } @@ -504,9 +536,6 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh space = A->get_space(); A->add_constraint(this, 0); B->add_constraint(this, 1); - contact_count = 0; - collided = false; - oneway_disabled = false; } BodyPair2DSW::~BodyPair2DSW() { diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h index 31ab9b9017..4b42b44c92 100644 --- a/servers/physics_2d/body_pair_2d_sw.h +++ b/servers/physics_2d/body_pair_2d_sw.h @@ -44,13 +44,16 @@ class BodyPair2DSW : public Constraint2DSW { Body2DSW *B; }; - Body2DSW *_arr[2]; + Body2DSW *_arr[2] = { nullptr, nullptr }; }; - int shape_A; - int shape_B; + int shape_A = 0; + int shape_B = 0; - Space2DSW *space; + bool dynamic_A = false; + bool dynamic_B = false; + + Space2DSW *space = nullptr; struct Contact { Vector2 position; @@ -73,10 +76,10 @@ class BodyPair2DSW : public Constraint2DSW { Vector2 sep_axis; Contact contacts[MAX_CONTACTS]; - int contact_count; - bool collided; - bool oneway_disabled; - int cc; + int contact_count = 0; + bool collided = false; + bool oneway_disabled = false; + bool report_contacts_only = false; bool _test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result = false); void _validate_contacts(); @@ -84,8 +87,9 @@ class BodyPair2DSW : public Constraint2DSW { _FORCE_INLINE_ void _contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B); public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B); ~BodyPair2DSW(); diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp deleted file mode 100644 index 17424629a9..0000000000 --- a/servers/physics_2d/broad_phase_2d_basic.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************/ -/* broad_phase_2d_basic.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "broad_phase_2d_basic.h" - -BroadPhase2DBasic::ID BroadPhase2DBasic::create(CollisionObject2DSW *p_object_, int p_subindex) { - current++; - - Element e; - e.owner = p_object_; - e._static = false; - e.subindex = p_subindex; - - element_map[current] = e; - return current; -} - -void BroadPhase2DBasic::move(ID p_id, const Rect2 &p_aabb) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - E->get().aabb = p_aabb; -} - -void BroadPhase2DBasic::set_static(ID p_id, bool p_static) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - E->get()._static = p_static; -} - -void BroadPhase2DBasic::remove(ID p_id) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - element_map.erase(E); -} - -CollisionObject2DSW *BroadPhase2DBasic::get_object(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, nullptr); - return E->get().owner; -} - -bool BroadPhase2DBasic::is_static(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, false); - return E->get()._static; -} - -int BroadPhase2DBasic::get_subindex(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, -1); - return E->get().subindex; -} - -int BroadPhase2DBasic::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { - int rc = 0; - - for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) { - const Rect2 aabb = E->get().aabb; - if (aabb.intersects_segment(p_from, p_to)) { - p_results[rc] = E->get().owner; - p_result_indices[rc] = E->get().subindex; - rc++; - if (rc >= p_max_results) { - break; - } - } - } - - return rc; -} - -int BroadPhase2DBasic::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { - int rc = 0; - - for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) { - const Rect2 aabb = E->get().aabb; - if (aabb.intersects(p_aabb)) { - p_results[rc] = E->get().owner; - p_result_indices[rc] = E->get().subindex; - rc++; - if (rc >= p_max_results) { - break; - } - } - } - - return rc; -} - -void BroadPhase2DBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { - pair_userdata = p_userdata; - pair_callback = p_pair_callback; -} - -void BroadPhase2DBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { - unpair_userdata = p_userdata; - unpair_callback = p_unpair_callback; -} - -void BroadPhase2DBasic::update() { - // recompute pairs - for (Map<ID, Element>::Element *I = element_map.front(); I; I = I->next()) { - for (Map<ID, Element>::Element *J = I->next(); J; J = J->next()) { - Element *elem_A = &I->get(); - Element *elem_B = &J->get(); - - if (elem_A->owner == elem_B->owner) { - continue; - } - - bool pair_ok = elem_A->aabb.intersects(elem_B->aabb) && (!elem_A->_static || !elem_B->_static); - - PairKey key(I->key(), J->key()); - - Map<PairKey, void *>::Element *E = pair_map.find(key); - - if (!pair_ok && E) { - if (unpair_callback) { - unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, E->get(), unpair_userdata); - } - pair_map.erase(key); - } - - if (pair_ok && !E) { - void *data = nullptr; - if (pair_callback) { - data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, unpair_userdata); - if (data) { - pair_map.insert(key, data); - } - } - } - } - } -} - -BroadPhase2DSW *BroadPhase2DBasic::_create() { - return memnew(BroadPhase2DBasic); -} - -BroadPhase2DBasic::BroadPhase2DBasic() { - current = 1; - unpair_callback = nullptr; - unpair_userdata = nullptr; - pair_callback = nullptr; - pair_userdata = nullptr; -} diff --git a/servers/physics_2d/broad_phase_2d_bvh.cpp b/servers/physics_2d/broad_phase_2d_bvh.cpp new file mode 100644 index 0000000000..5f53f4a012 --- /dev/null +++ b/servers/physics_2d/broad_phase_2d_bvh.cpp @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* broad_phase_2d_bvh.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "broad_phase_2d_bvh.h" +#include "collision_object_2d_sw.h" + +BroadPhase2DSW::ID BroadPhase2DBVH::create(CollisionObject2DSW *p_object, int p_subindex, const Rect2 &p_aabb, bool p_static) { + ID oid = bvh.create(p_object, true, p_aabb, p_subindex, !p_static, 1 << p_object->get_type(), p_static ? 0 : 0xFFFFF); // Pair everything, don't care? + return oid + 1; +} + +void BroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) { + bvh.move(p_id - 1, p_aabb); +} + +void BroadPhase2DBVH::set_static(ID p_id, bool p_static) { + CollisionObject2DSW *it = bvh.get(p_id - 1); + bvh.set_pairable(p_id - 1, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF, false); // Pair everything, don't care? +} + +void BroadPhase2DBVH::remove(ID p_id) { + bvh.erase(p_id - 1); +} + +CollisionObject2DSW *BroadPhase2DBVH::get_object(ID p_id) const { + CollisionObject2DSW *it = bvh.get(p_id - 1); + ERR_FAIL_COND_V(!it, nullptr); + return it; +} + +bool BroadPhase2DBVH::is_static(ID p_id) const { + return !bvh.is_pairable(p_id - 1); +} + +int BroadPhase2DBVH::get_subindex(ID p_id) const { + return bvh.get_subindex(p_id - 1); +} + +int BroadPhase2DBVH::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { + return bvh.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices); +} + +int BroadPhase2DBVH::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { + return bvh.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices); +} + +void *BroadPhase2DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject2DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject2DSW *p_object_B, int subindex_B) { + BroadPhase2DBVH *bpo = (BroadPhase2DBVH *)(self); + if (!bpo->pair_callback) { + return nullptr; + } + + return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata); +} + +void BroadPhase2DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject2DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject2DSW *p_object_B, int subindex_B, void *pairdata) { + BroadPhase2DBVH *bpo = (BroadPhase2DBVH *)(self); + if (!bpo->unpair_callback) { + return; + } + + bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata); +} + +void BroadPhase2DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { + pair_callback = p_pair_callback; + pair_userdata = p_userdata; +} + +void BroadPhase2DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { + unpair_callback = p_unpair_callback; + unpair_userdata = p_userdata; +} + +void BroadPhase2DBVH::update() { + bvh.update(); +} + +BroadPhase2DSW *BroadPhase2DBVH::_create() { + return memnew(BroadPhase2DBVH); +} + +BroadPhase2DBVH::BroadPhase2DBVH() { + bvh.set_pair_callback(_pair_callback, this); + bvh.set_unpair_callback(_unpair_callback, this); + pair_callback = nullptr; + pair_userdata = nullptr; + unpair_userdata = nullptr; +} diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_bvh.h index ca1db360fb..6c11d2561b 100644 --- a/servers/physics_2d/broad_phase_2d_basic.h +++ b/servers/physics_2d/broad_phase_2d_bvh.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_2d_basic.h */ +/* broad_phase_2d_bvh.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,49 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BROAD_PHASE_2D_BASIC_H -#define BROAD_PHASE_2D_BASIC_H +#ifndef BROAD_PHASE_2D_BVH_H +#define BROAD_PHASE_2D_BVH_H -#include "core/templates/map.h" -#include "space_2d_sw.h" -class BroadPhase2DBasic : public BroadPhase2DSW { - struct Element { - CollisionObject2DSW *owner; - bool _static; - Rect2 aabb; - int subindex; - }; +#include "broad_phase_2d_sw.h" +#include "core/math/bvh.h" +#include "core/math/rect2.h" +#include "core/math/vector2.h" - Map<ID, Element> element_map; +class BroadPhase2DBVH : public BroadPhase2DSW { + BVH_Manager<CollisionObject2DSW, true, 128, Rect2, Vector2> bvh; - ID current; - - struct PairKey { - union { - struct { - ID a; - ID b; - }; - uint64_t key; - }; - - _FORCE_INLINE_ bool operator<(const PairKey &p_key) const { - return key < p_key.key; - } - - PairKey() { key = 0; } - PairKey(ID p_a, ID p_b) { - if (p_a > p_b) { - a = p_b; - b = p_a; - } else { - a = p_a; - b = p_b; - } - } - }; - - Map<PairKey, void *> pair_map; + static void *_pair_callback(void *, uint32_t, CollisionObject2DSW *, int, uint32_t, CollisionObject2DSW *, int); + static void _unpair_callback(void *, uint32_t, CollisionObject2DSW *, int, uint32_t, CollisionObject2DSW *, int, void *); PairCallback pair_callback; void *pair_userdata; @@ -79,7 +49,7 @@ class BroadPhase2DBasic : public BroadPhase2DSW { public: // 0 is an invalid ID - virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0); + virtual ID create(CollisionObject2DSW *p_object, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false); virtual void move(ID p_id, const Rect2 &p_aabb); virtual void set_static(ID p_id, bool p_static); virtual void remove(ID p_id); @@ -97,7 +67,7 @@ public: virtual void update(); static BroadPhase2DSW *_create(); - BroadPhase2DBasic(); + BroadPhase2DBVH(); }; -#endif // BROAD_PHASE_2D_BASIC_H +#endif // BROAD_PHASE_2D_BVH_H diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp deleted file mode 100644 index 6cfe6908d1..0000000000 --- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp +++ /dev/null @@ -1,735 +0,0 @@ -/*************************************************************************/ -/* broad_phase_2d_hash_grid.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "broad_phase_2d_hash_grid.h" -#include "collision_object_2d_sw.h" -#include "core/config/project_settings.h" - -#define LARGE_ELEMENT_FI 1.01239812 - -void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) { - Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with); - - ERR_FAIL_COND(p_elem->_static && p_with->_static); - - if (!E) { - PairData *pd = memnew(PairData); - p_elem->paired[p_with] = pd; - p_with->paired[p_elem] = pd; - } else { - E->get()->rc++; - } -} - -void BroadPhase2DHashGrid::_unpair_attempt(Element *p_elem, Element *p_with) { - Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with); - - ERR_FAIL_COND(!E); //this should really be paired.. - - E->get()->rc--; - - if (E->get()->rc == 0) { - if (E->get()->colliding) { - //uncollide - if (unpair_callback) { - unpair_callback(p_elem->owner, p_elem->subindex, p_with->owner, p_with->subindex, E->get()->ud, unpair_userdata); - } - } - - memdelete(E->get()); - p_elem->paired.erase(E); - p_with->paired.erase(p_elem); - } -} - -void BroadPhase2DHashGrid::_check_motion(Element *p_elem) { - for (Map<Element *, PairData *>::Element *E = p_elem->paired.front(); E; E = E->next()) { - bool physical_collision = p_elem->aabb.intersects(E->key()->aabb); - bool logical_collision = p_elem->owner->test_collision_mask(E->key()->owner); - - if (physical_collision) { - if (!E->get()->colliding || (logical_collision && !E->get()->ud && pair_callback)) { - E->get()->ud = pair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, pair_userdata); - } else if (E->get()->colliding && !logical_collision && E->get()->ud && unpair_callback) { - unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata); - E->get()->ud = nullptr; - } - E->get()->colliding = true; - } else { // No physcial_collision - if (E->get()->colliding && unpair_callback) { - unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata); - } - E->get()->colliding = false; - } - } -} - -void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) { - Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI); //use magic number to avoid floating point issues - if (sz.width * sz.height > large_object_min_surface) { - //large object, do not use grid, must check against all elements - for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) { - if (E->key() == p_elem->self) { - continue; // do not pair against itself - } - if (E->get().owner == p_elem->owner) { - continue; - } - if (E->get()._static && p_static) { - continue; - } - - _pair_attempt(p_elem, &E->get()); - } - - large_elements[p_elem].inc(); - return; - } - - Point2i from = (p_rect.position / cell_size).floor(); - Point2i to = ((p_rect.position + p_rect.size) / cell_size).floor(); - - for (int i = from.x; i <= to.x; i++) { - for (int j = from.y; j <= to.y; j++) { - PosKey pk; - pk.x = i; - pk.y = j; - - uint32_t idx = pk.hash() % hash_table_size; - PosBin *pb = hash_table[idx]; - - while (pb) { - if (pb->key == pk) { - break; - } - - pb = pb->next; - } - - bool entered = false; - - if (!pb) { - //does not exist, create! - pb = memnew(PosBin); - pb->key = pk; - pb->next = hash_table[idx]; - hash_table[idx] = pb; - } - - if (p_static) { - if (pb->static_object_set[p_elem].inc() == 1) { - entered = true; - } - } else { - if (pb->object_set[p_elem].inc() == 1) { - entered = true; - } - } - - if (entered) { - for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) { - if (E->key()->owner == p_elem->owner) { - continue; - } - _pair_attempt(p_elem, E->key()); - } - - if (!p_static) { - for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) { - if (E->key()->owner == p_elem->owner) { - continue; - } - _pair_attempt(p_elem, E->key()); - } - } - } - } - } - - //pair separatedly with large elements - - for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) { - if (E->key() == p_elem) { - continue; // do not pair against itself - } - if (E->key()->owner == p_elem->owner) { - continue; - } - if (E->key()->_static && p_static) { - continue; - } - - _pair_attempt(E->key(), p_elem); - } -} - -void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) { - Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI); - if (sz.width * sz.height > large_object_min_surface) { - //unpair all elements, instead of checking all, just check what is already paired, so we at least save from checking static vs static - Map<Element *, PairData *>::Element *E = p_elem->paired.front(); - while (E) { - Map<Element *, PairData *>::Element *next = E->next(); - _unpair_attempt(p_elem, E->key()); - E = next; - } - - if (large_elements[p_elem].dec() == 0) { - large_elements.erase(p_elem); - } - return; - } - - Point2i from = (p_rect.position / cell_size).floor(); - Point2i to = ((p_rect.position + p_rect.size) / cell_size).floor(); - - for (int i = from.x; i <= to.x; i++) { - for (int j = from.y; j <= to.y; j++) { - PosKey pk; - pk.x = i; - pk.y = j; - - uint32_t idx = pk.hash() % hash_table_size; - PosBin *pb = hash_table[idx]; - - while (pb) { - if (pb->key == pk) { - break; - } - - pb = pb->next; - } - - ERR_CONTINUE(!pb); //should exist!! - - bool exited = false; - - if (p_static) { - if (pb->static_object_set[p_elem].dec() == 0) { - pb->static_object_set.erase(p_elem); - exited = true; - } - } else { - if (pb->object_set[p_elem].dec() == 0) { - pb->object_set.erase(p_elem); - exited = true; - } - } - - if (exited) { - for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) { - if (E->key()->owner == p_elem->owner) { - continue; - } - _unpair_attempt(p_elem, E->key()); - } - - if (!p_static) { - for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) { - if (E->key()->owner == p_elem->owner) { - continue; - } - _unpair_attempt(p_elem, E->key()); - } - } - } - - if (pb->object_set.is_empty() && pb->static_object_set.is_empty()) { - if (hash_table[idx] == pb) { - hash_table[idx] = pb->next; - } else { - PosBin *px = hash_table[idx]; - - while (px) { - if (px->next == pb) { - px->next = pb->next; - break; - } - - px = px->next; - } - - ERR_CONTINUE(!px); - } - - memdelete(pb); - } - } - } - - for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) { - if (E->key() == p_elem) { - continue; // do not pair against itself - } - if (E->key()->owner == p_elem->owner) { - continue; - } - if (E->key()->_static && p_static) { - continue; - } - - //unpair from large elements - _unpair_attempt(p_elem, E->key()); - } -} - -BroadPhase2DHashGrid::ID BroadPhase2DHashGrid::create(CollisionObject2DSW *p_object, int p_subindex) { - current++; - - Element e; - e.owner = p_object; - e._static = false; - e.subindex = p_subindex; - e.self = current; - e.pass = 0; - - element_map[current] = e; - return current; -} - -void BroadPhase2DHashGrid::move(ID p_id, const Rect2 &p_aabb) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (p_aabb != e.aabb) { - if (p_aabb != Rect2()) { - _enter_grid(&e, p_aabb, e._static); - } - if (e.aabb != Rect2()) { - _exit_grid(&e, e.aabb, e._static); - } - e.aabb = p_aabb; - } - - _check_motion(&e); -} - -void BroadPhase2DHashGrid::set_static(ID p_id, bool p_static) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (e._static == p_static) { - return; - } - - if (e.aabb != Rect2()) { - _exit_grid(&e, e.aabb, e._static); - } - - e._static = p_static; - - if (e.aabb != Rect2()) { - _enter_grid(&e, e.aabb, e._static); - _check_motion(&e); - } -} - -void BroadPhase2DHashGrid::remove(ID p_id) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (e.aabb != Rect2()) { - _exit_grid(&e, e.aabb, e._static); - } - - element_map.erase(p_id); -} - -CollisionObject2DSW *BroadPhase2DHashGrid::get_object(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, nullptr); - return E->get().owner; -} - -bool BroadPhase2DHashGrid::is_static(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, false); - return E->get()._static; -} - -int BroadPhase2DHashGrid::get_subindex(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, -1); - return E->get().subindex; -} - -template <bool use_aabb, bool use_segment> -void BroadPhase2DHashGrid::_cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index) { - PosKey pk; - pk.x = p_cell.x; - pk.y = p_cell.y; - - uint32_t idx = pk.hash() % hash_table_size; - PosBin *pb = hash_table[idx]; - - while (pb) { - if (pb->key == pk) { - break; - } - - pb = pb->next; - } - - if (!pb) { - return; - } - - for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) { - if (index >= p_max_results) { - break; - } - if (E->key()->pass == pass) { - continue; - } - - E->key()->pass = pass; - - if (use_aabb && !p_aabb.intersects(E->key()->aabb)) { - continue; - } - - if (use_segment && !E->key()->aabb.intersects_segment(p_from, p_to)) { - continue; - } - - p_results[index] = E->key()->owner; - p_result_indices[index] = E->key()->subindex; - index++; - } - - for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) { - if (index >= p_max_results) { - break; - } - if (E->key()->pass == pass) { - continue; - } - - if (use_aabb && !p_aabb.intersects(E->key()->aabb)) { - continue; - } - - if (use_segment && !E->key()->aabb.intersects_segment(p_from, p_to)) { - continue; - } - - E->key()->pass = pass; - p_results[index] = E->key()->owner; - p_result_indices[index] = E->key()->subindex; - index++; - } -} - -int BroadPhase2DHashGrid::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { - pass++; - - Vector2 dir = (p_to - p_from); - if (dir == Vector2()) { - return 0; - } - //avoid divisions by zero - dir.normalize(); - if (dir.x == 0.0) { - dir.x = 0.000001; - } - if (dir.y == 0.0) { - dir.y = 0.000001; - } - Vector2 delta = dir.abs(); - - delta.x = cell_size / delta.x; - delta.y = cell_size / delta.y; - - Point2i pos = (p_from / cell_size).floor(); - Point2i end = (p_to / cell_size).floor(); - - Point2i step = Vector2(SGN(dir.x), SGN(dir.y)); - - Vector2 max; - - if (dir.x < 0) { - max.x = (Math::floor((double)pos.x) * cell_size - p_from.x) / dir.x; - } else { - max.x = (Math::floor((double)pos.x + 1) * cell_size - p_from.x) / dir.x; - } - - if (dir.y < 0) { - max.y = (Math::floor((double)pos.y) * cell_size - p_from.y) / dir.y; - } else { - max.y = (Math::floor((double)pos.y + 1) * cell_size - p_from.y) / dir.y; - } - - int cullcount = 0; - _cull<false, true>(pos, Rect2(), p_from, p_to, p_results, p_max_results, p_result_indices, cullcount); - - bool reached_x = false; - bool reached_y = false; - - while (true) { - if (max.x < max.y) { - max.x += delta.x; - pos.x += step.x; - } else { - max.y += delta.y; - pos.y += step.y; - } - - if (step.x > 0) { - if (pos.x >= end.x) { - reached_x = true; - } - } else if (pos.x <= end.x) { - reached_x = true; - } - - if (step.y > 0) { - if (pos.y >= end.y) { - reached_y = true; - } - } else if (pos.y <= end.y) { - reached_y = true; - } - - _cull<false, true>(pos, Rect2(), p_from, p_to, p_results, p_max_results, p_result_indices, cullcount); - - if (reached_x && reached_y) { - break; - } - } - - for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) { - if (cullcount >= p_max_results) { - break; - } - if (E->key()->pass == pass) { - continue; - } - - E->key()->pass = pass; - - /* - if (use_aabb && !p_aabb.intersects(E->key()->aabb)) - continue; - */ - - if (!E->key()->aabb.intersects_segment(p_from, p_to)) { - continue; - } - - p_results[cullcount] = E->key()->owner; - p_result_indices[cullcount] = E->key()->subindex; - cullcount++; - } - - return cullcount; -} - -int BroadPhase2DHashGrid::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { - pass++; - - Point2i from = (p_aabb.position / cell_size).floor(); - Point2i to = ((p_aabb.position + p_aabb.size) / cell_size).floor(); - int cullcount = 0; - - for (int i = from.x; i <= to.x; i++) { - for (int j = from.y; j <= to.y; j++) { - _cull<true, false>(Point2i(i, j), p_aabb, Point2(), Point2(), p_results, p_max_results, p_result_indices, cullcount); - } - } - - for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) { - if (cullcount >= p_max_results) { - break; - } - if (E->key()->pass == pass) { - continue; - } - - E->key()->pass = pass; - - if (!p_aabb.intersects(E->key()->aabb)) { - continue; - } - - /* - if (!E->key()->aabb.intersects_segment(p_from,p_to)) - continue; - */ - - p_results[cullcount] = E->key()->owner; - p_result_indices[cullcount] = E->key()->subindex; - cullcount++; - } - return cullcount; -} - -void BroadPhase2DHashGrid::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { - pair_callback = p_pair_callback; - pair_userdata = p_userdata; -} - -void BroadPhase2DHashGrid::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { - unpair_callback = p_unpair_callback; - unpair_userdata = p_userdata; -} - -void BroadPhase2DHashGrid::update() { -} - -BroadPhase2DSW *BroadPhase2DHashGrid::_create() { - return memnew(BroadPhase2DHashGrid); -} - -BroadPhase2DHashGrid::BroadPhase2DHashGrid() { - hash_table_size = GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096); - ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bp_hash_table_size", PropertyInfo(Variant::INT, "physics/2d/bp_hash_table_size", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); - hash_table_size = Math::larger_prime(hash_table_size); - hash_table = memnew_arr(PosBin *, hash_table_size); - - cell_size = GLOBAL_DEF("physics/2d/cell_size", 128); - ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/cell_size", PropertyInfo(Variant::INT, "physics/2d/cell_size", PROPERTY_HINT_RANGE, "0,512,1,or_greater")); - - large_object_min_surface = GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512); - ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/large_object_surface_threshold_in_cells", PropertyInfo(Variant::INT, "physics/2d/large_object_surface_threshold_in_cells", PROPERTY_HINT_RANGE, "0,1024,1,or_greater")); - - for (uint32_t i = 0; i < hash_table_size; i++) { - hash_table[i] = nullptr; - } - pass = 1; - - current = 0; -} - -BroadPhase2DHashGrid::~BroadPhase2DHashGrid() { - for (uint32_t i = 0; i < hash_table_size; i++) { - while (hash_table[i]) { - PosBin *pb = hash_table[i]; - hash_table[i] = pb->next; - memdelete(pb); - } - } - - memdelete_arr(hash_table); -} - -/* 3D version of voxel traversal: - -public IEnumerable<Point3D> GetCellsOnRay(Ray ray, int maxDepth) -{ - // Implementation is based on: - // "A Fast Voxel Traversal Algorithm for Ray Tracing" - // John Amanatides, Andrew Woo - // http://www.cse.yorku.ca/~amana/research/grid.pdf - // https://web.archive.org/web/20100616193049/http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf - - // NOTES: - // * This code assumes that the ray's position and direction are in 'cell coordinates', which means - // that one unit equals one cell in all directions. - // * When the ray doesn't start within the voxel grid, calculate the first position at which the - // ray could enter the grid. If it never enters the grid, there is nothing more to do here. - // * Also, it is important to test when the ray exits the voxel grid when the grid isn't infinite. - // * The Point3D structure is a simple structure having three integer fields (X, Y and Z). - - // The cell in which the ray starts. - Point3D start = GetCellAt(ray.Position); // Rounds the position's X, Y and Z down to the nearest integer values. - int x = start.X; - int y = start.Y; - int z = start.Z; - - // Determine which way we go. - int stepX = Math.Sign(ray.Direction.X); - int stepY = Math.Sign(ray.Direction.Y); - int stepZ = Math.Sign(ray.Direction.Z); - - // Calculate cell boundaries. When the step (i.e. direction sign) is positive, - // the next boundary is AFTER our current position, meaning that we have to add 1. - // Otherwise, it is BEFORE our current position, in which case we add nothing. - Point3D cellBoundary = new Point3D( - x + (stepX > 0 ? 1 : 0), - y + (stepY > 0 ? 1 : 0), - z + (stepZ > 0 ? 1 : 0)); - - // NOTE: For the following calculations, the result will be Single.PositiveInfinity - // when ray.Direction.X, Y or Z equals zero, which is OK. However, when the left-hand - // value of the division also equals zero, the result is Single.NaN, which is not OK. - - // Determine how far we can travel along the ray before we hit a voxel boundary. - Vector3 tMax = new Vector3( - (cellBoundary.X - ray.Position.X) / ray.Direction.X, // Boundary is a plane on the YZ axis. - (cellBoundary.Y - ray.Position.Y) / ray.Direction.Y, // Boundary is a plane on the XZ axis. - (cellBoundary.Z - ray.Position.Z) / ray.Direction.Z); // Boundary is a plane on the XY axis. - if (Single.IsNaN(tMax.X)) tMax.X = Single.PositiveInfinity; - if (Single.IsNaN(tMax.Y)) tMax.Y = Single.PositiveInfinity; - if (Single.IsNaN(tMax.Z)) tMax.Z = Single.PositiveInfinity; - - // Determine how far we must travel along the ray before we have crossed a gridcell. - Vector3 tDelta = new Vector3( - stepX / ray.Direction.X, // Crossing the width of a cell. - stepY / ray.Direction.Y, // Crossing the height of a cell. - stepZ / ray.Direction.Z); // Crossing the depth of a cell. - if (Single.IsNaN(tDelta.X)) tDelta.X = Single.PositiveInfinity; - if (Single.IsNaN(tDelta.Y)) tDelta.Y = Single.PositiveInfinity; - if (Single.IsNaN(tDelta.Z)) tDelta.Z = Single.PositiveInfinity; - - // For each step, determine which distance to the next voxel boundary is lowest (i.e. - // which voxel boundary is nearest) and walk that way. - for (int i = 0; i < maxDepth; i++) - { - // Return it. - yield return new Point3D(x, y, z); - - // Do the next step. - if (tMax.X < tMax.Y && tMax.X < tMax.Z) - { - // tMax.X is the lowest, an YZ cell boundary plane is nearest. - x += stepX; - tMax.X += tDelta.X; - } - else if (tMax.Y < tMax.Z) - { - // tMax.Y is the lowest, an XZ cell boundary plane is nearest. - y += stepY; - tMax.Y += tDelta.Y; - } - else - { - // tMax.Z is the lowest, an XY cell boundary plane is nearest. - z += stepZ; - tMax.Z += tDelta.Z; - } - } - - */ diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h deleted file mode 100644 index eb7c8879ac..0000000000 --- a/servers/physics_2d/broad_phase_2d_hash_grid.h +++ /dev/null @@ -1,187 +0,0 @@ -/*************************************************************************/ -/* broad_phase_2d_hash_grid.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef BROAD_PHASE_2D_HASH_GRID_H -#define BROAD_PHASE_2D_HASH_GRID_H - -#include "broad_phase_2d_sw.h" -#include "core/templates/map.h" - -class BroadPhase2DHashGrid : public BroadPhase2DSW { - struct PairData { - bool colliding; - int rc; - void *ud; - PairData() { - colliding = false; - rc = 1; - ud = nullptr; - } - }; - - struct Element { - ID self; - CollisionObject2DSW *owner; - bool _static; - Rect2 aabb; - int subindex; - uint64_t pass; - Map<Element *, PairData *> paired; - }; - - struct RC { - int ref; - - _FORCE_INLINE_ int inc() { - ref++; - return ref; - } - _FORCE_INLINE_ int dec() { - ref--; - return ref; - } - - _FORCE_INLINE_ RC() { - ref = 0; - } - }; - - Map<ID, Element> element_map; - Map<Element *, RC> large_elements; - - ID current; - - uint64_t pass; - - struct PairKey { - union { - struct { - ID a; - ID b; - }; - uint64_t key; - }; - - _FORCE_INLINE_ bool operator<(const PairKey &p_key) const { - return key < p_key.key; - } - - PairKey() { key = 0; } - PairKey(ID p_a, ID p_b) { - if (p_a > p_b) { - a = p_b; - b = p_a; - } else { - a = p_a; - b = p_b; - } - } - }; - - Map<PairKey, PairData> pair_map; - - int cell_size; - int large_object_min_surface; - - PairCallback pair_callback; - void *pair_userdata; - UnpairCallback unpair_callback; - void *unpair_userdata; - - void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static); - void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static); - template <bool use_aabb, bool use_segment> - _FORCE_INLINE_ void _cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index); - - struct PosKey { - union { - struct { - int32_t x; - int32_t y; - }; - uint64_t key; - }; - - _FORCE_INLINE_ uint32_t hash() const { - uint64_t k = key; - k = (~k) + (k << 18); // k = (k << 18) - k - 1; - k = k ^ (k >> 31); - k = k * 21; // k = (k + (k << 2)) + (k << 4); - k = k ^ (k >> 11); - k = k + (k << 6); - k = k ^ (k >> 22); - return k; - } - - bool operator==(const PosKey &p_key) const { return key == p_key.key; } - _FORCE_INLINE_ bool operator<(const PosKey &p_key) const { - return key < p_key.key; - } - }; - - struct PosBin { - PosKey key; - Map<Element *, RC> object_set; - Map<Element *, RC> static_object_set; - PosBin *next; - }; - - uint32_t hash_table_size; - PosBin **hash_table; - - void _pair_attempt(Element *p_elem, Element *p_with); - void _unpair_attempt(Element *p_elem, Element *p_with); - void _check_motion(Element *p_elem); - -public: - virtual ID create(CollisionObject2DSW *p_object, int p_subindex = 0); - virtual void move(ID p_id, const Rect2 &p_aabb); - virtual void set_static(ID p_id, bool p_static); - virtual void remove(ID p_id); - - virtual CollisionObject2DSW *get_object(ID p_id) const; - virtual bool is_static(ID p_id) const; - virtual int get_subindex(ID p_id) const; - - virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - - virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata); - virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata); - - virtual void update(); - - static BroadPhase2DSW *_create(); - - BroadPhase2DHashGrid(); - ~BroadPhase2DHashGrid(); -}; - -#endif // BROAD_PHASE_2D_HASH_GRID_H diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h index d17ee6e2d6..0f82f06b9c 100644 --- a/servers/physics_2d/broad_phase_2d_sw.h +++ b/servers/physics_2d/broad_phase_2d_sw.h @@ -48,7 +48,7 @@ public: typedef void (*UnpairCallback)(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_userdata); // 0 is an invalid ID - virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0) = 0; + virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false) = 0; virtual void move(ID p_id, const Rect2 &p_aabb) = 0; virtual void set_static(ID p_id, bool p_static) = 0; virtual void remove(ID p_id) = 0; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 7a2f312263..fa87dc1f3f 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -182,19 +182,19 @@ void CollisionObject2DSW::_update_shapes() { continue; } - if (s.bpid == 0) { - s.bpid = space->get_broadphase()->create(this, i); - space->get_broadphase()->set_static(s.bpid, _static); - } - //not quite correct, should compute the next matrix.. Rect2 shape_aabb = s.shape->get_aabb(); Transform2D xform = transform * s.xform; shape_aabb = xform.xform(shape_aabb); + shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05); s.aabb_cache = shape_aabb; - s.aabb_cache = s.aabb_cache.grow((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05); - space->get_broadphase()->move(s.bpid, s.aabb_cache); + if (s.bpid == 0) { + s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static); + space->get_broadphase()->set_static(s.bpid, _static); + } + + space->get_broadphase()->move(s.bpid, shape_aabb); } } @@ -209,11 +209,6 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) { continue; } - if (s.bpid == 0) { - s.bpid = space->get_broadphase()->create(this, i); - space->get_broadphase()->set_static(s.bpid, _static); - } - //not quite correct, should compute the next matrix.. Rect2 shape_aabb = s.shape->get_aabb(); Transform2D xform = transform * s.xform; @@ -221,6 +216,11 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) { shape_aabb = shape_aabb.merge(Rect2(shape_aabb.position + p_motion, shape_aabb.size)); //use motion s.aabb_cache = shape_aabb; + if (s.bpid == 0) { + s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static); + space->get_broadphase()->set_static(s.bpid, _static); + } + space->get_broadphase()->move(s.bpid, shape_aabb); } } diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 2db3961f41..c395e59694 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -143,8 +143,8 @@ public: return shapes[p_index].metadata; } - _FORCE_INLINE_ Transform2D get_transform() const { return transform; } - _FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; } + _FORCE_INLINE_ const Transform2D &get_transform() const { return transform; } + _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; } _FORCE_INLINE_ Space2DSW *get_space() const { return space; } void set_shape_as_disabled(int p_idx, bool p_disabled); diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h index 49ae4dd848..5e8dfbe570 100644 --- a/servers/physics_2d/constraint_2d_sw.h +++ b/servers/physics_2d/constraint_2d_sw.h @@ -37,8 +37,6 @@ class Constraint2DSW { Body2DSW **_body_ptr; int _body_count; uint64_t island_step; - Constraint2DSW *island_next; - Constraint2DSW *island_list_next; bool disabled_collisions_between_bodies; RID self; @@ -58,12 +56,6 @@ 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_ Constraint2DSW *get_island_next() const { return island_next; } - _FORCE_INLINE_ void set_island_next(Constraint2DSW *p_next) { island_next = p_next; } - - _FORCE_INLINE_ Constraint2DSW *get_island_list_next() const { return island_list_next; } - _FORCE_INLINE_ void set_island_list_next(Constraint2DSW *p_next) { island_list_next = p_next; } - _FORCE_INLINE_ Body2DSW **get_body_ptr() const { return _body_ptr; } _FORCE_INLINE_ int get_body_count() const { return _body_count; } @@ -71,6 +63,7 @@ public: _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } virtual bool setup(real_t p_step) = 0; + virtual bool pre_solve(real_t p_step) = 0; virtual void solve(real_t p_step) = 0; virtual ~Constraint2DSW() {} diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index c7b556deba..eaec582f9b 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -97,8 +97,16 @@ normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vecto } bool PinJoint2DSW::setup(real_t p_step) { + dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + Space2DSW *space = A->get_space(); ERR_FAIL_COND_V(!space, false); + rA = A->get_transform().basis_xform(anchor_A); rB = B ? B->get_transform().basis_xform(anchor_B) : anchor_B; @@ -143,12 +151,6 @@ bool PinJoint2DSW::setup(real_t p_step) { bias = delta * -(get_bias() == 0 ? space->get_constraint_bias() : get_bias()) * (1.0 / p_step); - // apply accumulated impulse - A->apply_impulse(-P, rA); - if (B) { - B->apply_impulse(P, rB); - } - return true; } @@ -156,6 +158,18 @@ inline Vector2 custom_cross(const Vector2 &p_vec, real_t p_other) { return Vector2(p_other * p_vec.y, -p_other * p_vec.x); } +bool PinJoint2DSW::pre_solve(real_t p_step) { + // Apply accumulated impulse. + if (dynamic_A) { + A->apply_impulse(-P, rA); + } + if (B && dynamic_B) { + B->apply_impulse(P, rB); + } + + return true; +} + void PinJoint2DSW::solve(real_t p_step) { // compute relative velocity Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity()); @@ -169,8 +183,10 @@ void PinJoint2DSW::solve(real_t p_step) { Vector2 impulse = M.basis_xform(bias - rel_vel - Vector2(softness, softness) * P); - A->apply_impulse(-impulse, rA); - if (B) { + if (dynamic_A) { + A->apply_impulse(-impulse, rA); + } + if (B && dynamic_B) { B->apply_impulse(impulse, rB); } @@ -257,10 +273,19 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) { } bool GrooveJoint2DSW::setup(real_t p_step) { + dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + + Space2DSW *space = A->get_space(); + ERR_FAIL_COND_V(!space, false); + // calculate endpoints in worldspace Vector2 ta = A->get_transform().xform(A_groove_1); Vector2 tb = A->get_transform().xform(A_groove_2); - Space2DSW *space = A->get_space(); // calculate axis Vector2 n = -(tb - ta).orthogonal().normalized(); @@ -299,14 +324,22 @@ bool GrooveJoint2DSW::setup(real_t p_step) { real_t _b = get_bias(); gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).clamped(get_max_bias()); - // apply accumulated impulse - A->apply_impulse(-jn_acc, rA); - B->apply_impulse(jn_acc, rB); - correct = true; return true; } +bool GrooveJoint2DSW::pre_solve(real_t p_step) { + // Apply accumulated impulse. + if (dynamic_A) { + A->apply_impulse(-jn_acc, rA); + } + if (dynamic_B) { + B->apply_impulse(jn_acc, rB); + } + + return true; +} + void GrooveJoint2DSW::solve(real_t p_step) { // compute impulse Vector2 vr = relative_velocity(A, B, rA, rB); @@ -319,8 +352,12 @@ void GrooveJoint2DSW::solve(real_t p_step) { j = jn_acc - jOld; - A->apply_impulse(-j, rA); - B->apply_impulse(j, rB); + if (dynamic_A) { + A->apply_impulse(-j, rA); + } + if (dynamic_B) { + B->apply_impulse(j, rB); + } } GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b) : @@ -342,6 +379,13 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_ ////////////////////////////////////////////// bool DampedSpringJoint2DSW::setup(real_t p_step) { + dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + rA = A->get_transform().basis_xform(anchor_A); rB = B->get_transform().basis_xform(anchor_B); @@ -360,12 +404,21 @@ bool DampedSpringJoint2DSW::setup(real_t p_step) { target_vrn = 0.0f; v_coef = 1.0f - Math::exp(-damping * (p_step)*k); - // apply spring force + // Calculate spring force. real_t f_spring = (rest_length - dist) * stiffness; - Vector2 j = n * f_spring * (p_step); + j = n * f_spring * (p_step); + + return true; +} - A->apply_impulse(-j, rA); - B->apply_impulse(j, rB); +bool DampedSpringJoint2DSW::pre_solve(real_t p_step) { + // Apply spring force. + if (dynamic_A) { + A->apply_impulse(-j, rA); + } + if (dynamic_B) { + B->apply_impulse(j, rB); + } return true; } @@ -380,8 +433,12 @@ void DampedSpringJoint2DSW::solve(real_t p_step) { target_vrn = vrn + v_damp; Vector2 j = n * v_damp * n_mass; - A->apply_impulse(-j, rA); - B->apply_impulse(j, rB); + if (dynamic_A) { + A->apply_impulse(-j, rA); + } + if (dynamic_B) { + B->apply_impulse(j, rB); + } } void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) { diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h index 628de972ae..ccc5c585a0 100644 --- a/servers/physics_2d/joints_2d_sw.h +++ b/servers/physics_2d/joints_2d_sw.h @@ -39,6 +39,10 @@ class Joint2DSW : public Constraint2DSW { real_t bias; real_t max_bias; +protected: + bool dynamic_A = false; + bool dynamic_B = false; + public: _FORCE_INLINE_ void set_max_force(real_t p_force) { max_force = p_force; } _FORCE_INLINE_ real_t get_max_force() const { return max_force; } @@ -49,8 +53,9 @@ public: _FORCE_INLINE_ void set_max_bias(real_t p_bias) { max_bias = p_bias; } _FORCE_INLINE_ real_t get_max_bias() const { return max_bias; } - virtual bool setup(real_t p_step) { return false; } - virtual void solve(real_t p_step) {} + virtual bool setup(real_t p_step) override { return false; } + virtual bool pre_solve(real_t p_step) override { return false; } + virtual void solve(real_t p_step) override {} void copy_settings_from(Joint2DSW *p_joint); @@ -90,10 +95,11 @@ class PinJoint2DSW : public Joint2DSW { real_t softness; public: - virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_PIN; } + virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_PIN; } - virtual bool setup(real_t p_step); - virtual void solve(real_t p_step); + 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; void set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value); real_t get_param(PhysicsServer2D::PinJointParam p_param) const; @@ -126,10 +132,11 @@ class GrooveJoint2DSW : public Joint2DSW { bool correct; public: - virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_GROOVE; } + virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_GROOVE; } - virtual bool setup(real_t p_step); - virtual void solve(real_t p_step); + 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; GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b); }; @@ -153,15 +160,17 @@ class DampedSpringJoint2DSW : public Joint2DSW { Vector2 rA, rB; Vector2 n; + Vector2 j; real_t n_mass; real_t target_vrn; real_t v_coef; public: - virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; } + virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; } - virtual bool setup(real_t p_step); - virtual void solve(real_t p_step); + 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; void set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value); real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const; diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index 1040437ca7..425546e5ca 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -30,8 +30,7 @@ #include "physics_server_2d_sw.h" -#include "broad_phase_2d_basic.h" -#include "broad_phase_2d_hash_grid.h" +#include "broad_phase_2d_bvh.h" #include "collision_solver_2d_sw.h" #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" @@ -927,10 +926,10 @@ int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const { return body->get_max_contacts_reported(); } -void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { +void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { Body2DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); - body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata); + body->set_force_integration_callback(p_callable, p_udata); } bool PhysicsServer2DSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) { @@ -1356,8 +1355,7 @@ PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr; PhysicsServer2DSW::PhysicsServer2DSW(bool p_using_threads) { singletonsw = this; - BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create; - //BroadPhase2DSW::create_func=BroadPhase2DBasic::_create; + BroadPhase2DSW::create_func = BroadPhase2DBVH::_create; active = true; island_count = 0; diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index 65c5df0fce..efa0784245 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -242,7 +242,7 @@ public: virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override; virtual int body_get_max_contacts_reported(RID p_body) const override; - virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override; + virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override; virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override; virtual void body_set_pickable(RID p_body, bool p_pickable) override; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index 3577f706de..88ac742e40 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -245,7 +245,7 @@ public: FUNC2(body_set_omit_force_integration, RID, bool); FUNC1RC(bool, body_is_omitting_force_integration, RID); - FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &); + FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &); bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override { return physics_2d_server->body_collide_shape(p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count); diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 6e7e802a8b..6cc086b9b7 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -502,6 +502,7 @@ Variant CapsuleShape2DSW::get_data() const { void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { int support_idx = -1; real_t d = -1e10; + r_amount = 0; for (int i = 0; i < point_count; i++) { //test point @@ -520,7 +521,7 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_su } } - ERR_FAIL_COND(support_idx == -1); + ERR_FAIL_COND_MSG(support_idx == -1, "Convex polygon shape support not found."); r_amount = 1; r_supports[0] = points[support_idx].pos; @@ -580,6 +581,7 @@ bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vec } real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { + ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points."); Rect2 aabb; aabb.position = points[0].pos * p_scale; for (int i = 0; i < point_count; i++) { @@ -691,6 +693,10 @@ bool ConcavePolygonShape2DSW::contains_point(const Vector2 &p_point) const { } bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { + if (segments.size() == 0 || points.size() == 0) { + return false; + } + uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth); enum { diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp index 6613d19729..b8cb4cddc5 100644 --- a/servers/physics_2d/step_2d_sw.cpp +++ b/servers/physics_2d/step_2d_sw.cpp @@ -29,102 +29,98 @@ /*************************************************************************/ #include "step_2d_sw.h" + #include "core/os/os.h" -void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island) { +#define BODY_ISLAND_COUNT_RESERVE 128 +#define BODY_ISLAND_SIZE_RESERVE 512 +#define ISLAND_COUNT_RESERVE 128 +#define ISLAND_SIZE_RESERVE 512 +#define CONSTRAINT_COUNT_RESERVE 1024 + +void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island) { p_body->set_island_step(_step); - p_body->set_island_next(*p_island); - *p_island = p_body; + + if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) { + // Only dynamic bodies are tested for activation. + p_body_island.push_back(p_body); + } for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) { - Constraint2DSW *c = (Constraint2DSW *)E->get().first; - if (c->get_island_step() == _step) { - continue; //already processed + Constraint2DSW *constraint = (Constraint2DSW *)E->get().first; + if (constraint->get_island_step() == _step) { + continue; // Already processed. } - c->set_island_step(_step); - c->set_island_next(*p_constraint_island); - *p_constraint_island = c; + constraint->set_island_step(_step); + p_constraint_island.push_back(constraint); + all_constraints.push_back(constraint); - for (int i = 0; i < c->get_body_count(); i++) { + for (int i = 0; i < constraint->get_body_count(); i++) { if (i == E->get().second) { continue; } - Body2DSW *b = c->get_body_ptr()[i]; - if (b->get_island_step() == _step || b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { - continue; //no go + Body2DSW *other_body = constraint->get_body_ptr()[i]; + if (other_body->get_island_step() == _step) { + continue; // Already processed. } - _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island); + if (other_body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC) { + continue; // Static bodies don't connect islands. + } + _populate_island(other_body, p_body_island, p_constraint_island); } } } -bool Step2DSW::_setup_island(Constraint2DSW *p_island, real_t p_delta) { - Constraint2DSW *ci = p_island; - Constraint2DSW *prev_ci = nullptr; - bool removed_root = false; - while (ci) { - bool process = ci->setup(p_delta); - - if (!process) { - //remove from island if process fails - if (prev_ci) { - prev_ci->set_island_next(ci->get_island_next()); - } else { - removed_root = true; - prev_ci = ci; - } - } else { - prev_ci = ci; +void Step2DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) { + Constraint2DSW *constraint = all_constraints[p_constraint_index]; + constraint->setup(delta); +} + +void Step2DSW::_pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const { + uint32_t constraint_count = p_constraint_island.size(); + uint32_t valid_constraint_count = 0; + for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { + Constraint2DSW *constraint = p_constraint_island[constraint_index]; + if (p_constraint_island[constraint_index]->pre_solve(delta)) { + // Keep this constraint for solving. + p_constraint_island[valid_constraint_count++] = constraint; } - ci = ci->get_island_next(); } - - return removed_root; + p_constraint_island.resize(valid_constraint_count); } -void Step2DSW::_solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta) { - for (int i = 0; i < p_iterations; i++) { - Constraint2DSW *ci = p_island; - while (ci) { - ci->solve(p_delta); - ci = ci->get_island_next(); +void Step2DSW::_solve_island(uint32_t p_island_index, void *p_userdata) const { + const LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[p_island_index]; + + for (int i = 0; i < iterations; i++) { + uint32_t constraint_count = constraint_island.size(); + for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { + constraint_island[constraint_index]->solve(delta); } } } -void Step2DSW::_check_suspend(Body2DSW *p_island, real_t p_delta) { +void Step2DSW::_check_suspend(LocalVector<Body2DSW *> &p_body_island) const { bool can_sleep = true; - Body2DSW *b = p_island; - while (b) { - if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { - b = b->get_island_next(); - continue; //ignore for static - } + uint32_t body_count = p_body_island.size(); + for (uint32_t body_index = 0; body_index < body_count; ++body_index) { + Body2DSW *body = p_body_island[body_index]; - if (!b->sleep_test(p_delta)) { + if (!body->sleep_test(delta)) { can_sleep = false; } - - b = b->get_island_next(); } - //put all to sleep or wake up everyoen - - b = p_island; - while (b) { - if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { - b = b->get_island_next(); - continue; //ignore for static - } + // Put all to sleep or wake up everyone. + for (uint32_t body_index = 0; body_index < body_count; ++body_index) { + Body2DSW *body = p_body_island[body_index]; - bool active = b->is_active(); + bool active = body->is_active(); if (active == can_sleep) { - b->set_active(!can_sleep); + body->set_active(!can_sleep); } - - b = b->get_island_next(); } } @@ -133,6 +129,9 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { p_space->setup(); //update inertias, etc + iterations = p_iterations; + delta = p_delta; + const SelfList<Body2DSW>::List *body_list = &p_space->get_active_body_list(); /* INTEGRATE FORCES */ @@ -157,94 +156,85 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { profile_begtime = profile_endtime; } - /* GENERATE CONSTRAINT ISLANDS */ + /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */ + + uint32_t island_count = 0; + + const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list(); + + while (aml.first()) { + for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { + Constraint2DSW *constraint = E->get(); + if (constraint->get_island_step() == _step) { + continue; + } + constraint->set_island_step(_step); + + // Each constraint can be on a separate island for areas as there's no solving phase. + ++island_count; + if (constraint_islands.size() < island_count) { + constraint_islands.resize(island_count); + } + LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1]; + constraint_island.clear(); + + all_constraints.push_back(constraint); + constraint_island.push_back(constraint); + } + p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here + } + + /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */ - Body2DSW *island_list = nullptr; - Constraint2DSW *constraint_island_list = nullptr; b = body_list->first(); - int island_count = 0; + uint32_t body_island_count = 0; while (b) { Body2DSW *body = b->self(); if (body->get_island_step() != _step) { - Body2DSW *island = nullptr; - Constraint2DSW *constraint_island = nullptr; - _populate_island(body, &island, &constraint_island); - - island->set_island_list_next(island_list); - island_list = island; + ++body_island_count; + if (body_islands.size() < body_island_count) { + body_islands.resize(body_island_count); + } + LocalVector<Body2DSW *> &body_island = body_islands[body_island_count - 1]; + body_island.clear(); + body_island.reserve(BODY_ISLAND_SIZE_RESERVE); - if (constraint_island) { - constraint_island->set_island_list_next(constraint_island_list); - constraint_island_list = constraint_island; - island_count++; + ++island_count; + if (constraint_islands.size() < island_count) { + constraint_islands.resize(island_count); } - } - b = b->next(); - } + LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1]; + constraint_island.clear(); + constraint_island.reserve(ISLAND_SIZE_RESERVE); - p_space->set_island_count(island_count); + _populate_island(body, body_island, constraint_island); - const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list(); + if (body_island.is_empty()) { + --body_island_count; + } - while (aml.first()) { - for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { - Constraint2DSW *c = E->get(); - if (c->get_island_step() == _step) { - continue; + if (constraint_island.is_empty()) { + --island_count; } - c->set_island_step(_step); - c->set_island_next(nullptr); - c->set_island_list_next(constraint_island_list); - constraint_island_list = c; } - p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here + b = b->next(); } + p_space->set_island_count((int)island_count); + { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } - /* SETUP CONSTRAINT ISLANDS */ - - { - Constraint2DSW *ci = constraint_island_list; - Constraint2DSW *prev_ci = nullptr; - while (ci) { - if (_setup_island(ci, p_delta)) { - //removed the root from the island graph because it is not to be processed - - Constraint2DSW *next = ci->get_island_next(); - - if (next) { - //root from list being deleted no longer exists, replace by next - next->set_island_list_next(ci->get_island_list_next()); - if (prev_ci) { - prev_ci->set_island_list_next(next); - } else { - constraint_island_list = next; - } - prev_ci = next; - } else { - //list is empty, just skip - if (prev_ci) { - prev_ci->set_island_list_next(ci->get_island_list_next()); - - } else { - constraint_island_list = ci->get_island_list_next(); - } - } - } else { - prev_ci = ci; - } + /* SETUP CONSTRAINTS / PROCESS COLLISIONS */ - ci = ci->get_island_list_next(); - } - } + uint32_t total_contraint_count = all_constraints.size(); + work_pool.do_work(total_contraint_count, this, &Step2DSW::_setup_contraint, nullptr); { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); @@ -252,15 +242,21 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { profile_begtime = profile_endtime; } + /* PRE-SOLVE CONSTRAINT ISLANDS */ + + // Warning: This doesn't run on threads, because it involves thread-unsafe processing. + for (uint32_t island_index = 0; island_index < island_count; ++island_index) { + _pre_solve_island(constraint_islands[island_index]); + } + /* SOLVE CONSTRAINT ISLANDS */ - { - Constraint2DSW *ci = constraint_island_list; - while (ci) { - //iterating each island separatedly improves cache efficiency - _solve_island(ci, p_iterations, p_delta); - ci = ci->get_island_list_next(); - } + // Warning: _solve_island modifies the constraint islands for optimization purpose, + // their content is not reliable after these calls and shouldn't be used anymore. + if (island_count > 1) { + work_pool.do_work(island_count, this, &Step2DSW::_solve_island, nullptr); + } else if (island_count > 0) { + _solve_island(0); } { //profile @@ -280,12 +276,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { /* SLEEP / WAKE UP ISLANDS */ - { - Body2DSW *bi = island_list; - while (bi) { - _check_suspend(bi, p_delta); - bi = bi->get_island_list_next(); - } + for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) { + _check_suspend(body_islands[island_index]); } { //profile @@ -294,6 +286,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { //profile_begtime=profile_endtime; } + all_constraints.clear(); + p_space->update(); p_space->unlock(); _step++; @@ -301,4 +295,14 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { Step2DSW::Step2DSW() { _step = 1; + + body_islands.reserve(BODY_ISLAND_COUNT_RESERVE); + constraint_islands.reserve(ISLAND_COUNT_RESERVE); + all_constraints.reserve(CONSTRAINT_COUNT_RESERVE); + + work_pool.init(); +} + +Step2DSW::~Step2DSW() { + work_pool.finish(); } diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h index 83b9130608..c51fd73a79 100644 --- a/servers/physics_2d/step_2d_sw.h +++ b/servers/physics_2d/step_2d_sw.h @@ -33,17 +33,31 @@ #include "space_2d_sw.h" +#include "core/templates/local_vector.h" +#include "core/templates/thread_work_pool.h" + class Step2DSW { uint64_t _step; - void _populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island); - bool _setup_island(Constraint2DSW *p_island, real_t p_delta); - void _solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta); - void _check_suspend(Body2DSW *p_island, real_t p_delta); + int iterations = 0; + real_t delta = 0.0; + + ThreadWorkPool work_pool; + + LocalVector<LocalVector<Body2DSW *>> body_islands; + LocalVector<LocalVector<Constraint2DSW *>> constraint_islands; + LocalVector<Constraint2DSW *> all_constraints; + + void _populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island); + void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr); + void _pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const; + void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr) const; + void _check_suspend(LocalVector<Body2DSW *> &p_body_island) const; public: void step(Space2DSW *p_space, real_t p_delta, int p_iterations); Step2DSW(); + ~Step2DSW(); }; #endif // STEP_2D_SW_H diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp index b6c5b3003c..bb4e0ed752 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/area_3d_sw.cpp @@ -215,7 +215,9 @@ void Area3DSW::call_queries() { for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) { if (E->get().state == 0) { // Nothing happened - E = E->next(); + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_bodies.erase(E); + E = next; continue; } @@ -250,7 +252,9 @@ void Area3DSW::call_queries() { for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) { if (E->get().state == 0) { // Nothing happened - E = E->next(); + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_areas.erase(E); + E = next; continue; } diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index 4de5f1ba47..2073df7dee 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -40,31 +40,48 @@ bool AreaPair3DSW::setup(real_t p_step) { result = true; } + process_collision = false; if (result != colliding) { - if (result) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { - body->add_area(area); - } - if (area->has_monitor_callback()) { - area->add_body_to_query(body, body_shape, area_shape); - } - - } else { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { - body->remove_area(area); - } - if (area->has_monitor_callback()) { - area->remove_body_from_query(body, body_shape, area_shape); - } + 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 false; //never do any post solving + return process_collision; +} + +bool AreaPair3DSW::pre_solve(real_t p_step) { + if (!process_collision) { + return false; + } + + if (colliding) { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + body->add_area(area); + } + + if (area->has_monitor_callback()) { + area->add_body_to_query(body, body_shape, area_shape); + } + } else { + if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + body->remove_area(area); + } + + if (area->has_monitor_callback()) { + area->remove_body_from_query(body, body_shape, area_shape); + } + } + + return false; // Never do any post solving. } void AreaPair3DSW::solve(real_t p_step) { + // Nothing to do. } AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape) { @@ -72,7 +89,6 @@ AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, area = p_area; body_shape = p_body_shape; area_shape = p_area_shape; - colliding = false; body->add_constraint(this, 0); area->add_constraint(this); if (p_body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) { @@ -103,33 +119,48 @@ bool Area2Pair3DSW::setup(real_t p_step) { result = true; } + process_collision = false; if (result != colliding) { - if (result) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { - area_b->add_area_to_query(area_a, shape_a, shape_b); - } - - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { - area_a->add_area_to_query(area_b, shape_b, shape_a); - } - - } else { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { - area_b->remove_area_from_query(area_a, shape_a, shape_b); - } - - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { - area_a->remove_area_from_query(area_b, shape_b, shape_a); - } + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + process_collision = true; + } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + process_collision = true; } colliding = result; } - return false; //never do any post solving + return process_collision; +} + +bool Area2Pair3DSW::pre_solve(real_t p_step) { + if (!process_collision) { + return false; + } + + if (colliding) { + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + area_b->add_area_to_query(area_a, shape_a, shape_b); + } + + if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + area_a->add_area_to_query(area_b, shape_b, shape_a); + } + } else { + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + area_b->remove_area_from_query(area_a, shape_a, shape_b); + } + + if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + area_a->remove_area_from_query(area_b, shape_b, shape_a); + } + } + + return false; // Never do any post solving. } void Area2Pair3DSW::solve(real_t p_step) { + // Nothing to do. } Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b) { @@ -137,7 +168,6 @@ Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area area_b = p_area_b; shape_a = p_shape_a; shape_b = p_shape_b; - colliding = false; area_a->add_constraint(this); area_b->add_constraint(this); } diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h index fbdaa25cbb..596d893082 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/area_pair_3d_sw.h @@ -40,11 +40,13 @@ class AreaPair3DSW : public Constraint3DSW { Area3DSW *area; int body_shape; int area_shape; - bool colliding; + bool colliding = false; + bool process_collision = false; public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape); ~AreaPair3DSW(); @@ -55,11 +57,13 @@ class Area2Pair3DSW : public Constraint3DSW { Area3DSW *area_b; int shape_a; int shape_b; - bool colliding; + bool colliding = false; + bool process_collision = false; public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b); ~Area2Pair3DSW(); diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp index 64ba0cb09d..4357c474e4 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/body_3d_sw.cpp @@ -145,31 +145,17 @@ void Body3DSW::set_active(bool p_active) { } active = p_active; - if (!p_active) { - if (get_space()) { - get_space()->body_remove_from_active_list(&active_list); - } - } else { + + if (active) { if (mode == PhysicsServer3D::BODY_MODE_STATIC) { - return; //static bodies can't become active - } - if (get_space()) { + // Static bodies can't be active. + active = false; + } else if (get_space()) { get_space()->body_add_to_active_list(&active_list); } - - //still_time=0; + } else if (get_space()) { + get_space()->body_remove_from_active_list(&active_list); } - /* - if (!space) - return; - - for(int i=0;i<get_shape_count();i++) { - Shape &s=shapes[i]; - if (s.bpid>0) { - get_space()->get_broadphase()->set_active(s.bpid,active); - } - } -*/ } void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) { @@ -392,13 +378,6 @@ void Body3DSW::set_space(Space3DSW *p_space) { if (active) { get_space()->body_add_to_active_list(&active_list); } - /* - _update_queries(); - if (is_active()) { - active=false; - set_active(true); - } - */ } first_integration = true; @@ -693,15 +672,16 @@ void Body3DSW::call_queries() { Variant v = dbs; - Object *obj = ObjectDB::get_instance(fi_callback->id); + Object *obj = fi_callback->callable.get_object(); if (!obj) { - set_force_integration_callback(ObjectID(), StringName()); + set_force_integration_callback(Callable()); } else { const Variant *vp[2] = { &v, &fi_callback->udata }; Callable::CallError ce; int argc = (fi_callback->udata.get_type() == Variant::NIL) ? 1 : 2; - obj->call(fi_callback->method, vp, argc, ce); + Variant rv; + fi_callback->callable.call(vp, argc, rv, ce); } } } @@ -725,16 +705,15 @@ bool Body3DSW::sleep_test(real_t p_step) { } } -void Body3DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) { +void Body3DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { if (fi_callback) { memdelete(fi_callback); fi_callback = nullptr; } - if (p_id.is_valid()) { + if (p_callable.get_object()) { fi_callback = memnew(ForceIntegrationCallback); - fi_callback->id = p_id; - fi_callback->method = p_method; + fi_callback->callable = p_callable; fi_callback->udata = p_udata; } } @@ -761,8 +740,6 @@ Body3DSW::Body3DSW() : omit_force_integration = false; //applied_torque=0; island_step = 0; - island_next = nullptr; - island_list_next = nullptr; first_time_kinematic = false; first_integration = false; _set_static(false); diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index e87ff2364b..9afb8cd56f 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -127,16 +127,13 @@ class Body3DSW : public CollisionObject3DSW { int contact_count; struct ForceIntegrationCallback { - ObjectID id; - StringName method; + Callable callable; Variant udata; }; ForceIntegrationCallback *fi_callback; uint64_t island_step; - Body3DSW *island_next; - Body3DSW *island_list_next; _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area3DSW *p_area); @@ -145,7 +142,7 @@ class Body3DSW : public CollisionObject3DSW { friend class PhysicsDirectBodyState3DSW; // i give up, too many functions to expose public: - void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant()); + void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant()); void set_kinematic_margin(real_t p_margin); _FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; } @@ -189,12 +186,6 @@ 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_ Body3DSW *get_island_next() const { return island_next; } - _FORCE_INLINE_ void set_island_next(Body3DSW *p_next) { island_next = p_next; } - - _FORCE_INLINE_ Body3DSW *get_island_list_next() const { return island_list_next; } - _FORCE_INLINE_ void set_island_list_next(Body3DSW *p_next) { island_list_next = p_next; } - _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; } _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraint_map.erase(p_constraint); } const Map<Constraint3DSW *, int> &get_constraint_map() const { return constraint_map; } diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp index 36114c0c91..cdb3da665e 100644 --- a/servers/physics_3d/body_pair_3d_sw.cpp +++ b/servers/physics_3d/body_pair_3d_sw.cpp @@ -212,14 +212,16 @@ real_t combine_friction(Body3DSW *A, Body3DSW *B) { } bool BodyPair3DSW::setup(real_t p_step) { - //cannot collide + dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) { collided = false; return false; } - bool report_contacts_only = false; - if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) { + report_contacts_only = false; + if (!dynamic_A && !dynamic_B) { if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) { report_contacts_only = true; } else { @@ -237,7 +239,7 @@ bool BodyPair3DSW::setup(real_t p_step) { validate_contacts(); - Vector3 offset_A = A->get_transform().get_origin(); + const Vector3 &offset_A = A->get_transform().get_origin(); Transform xform_Au = Transform(A->get_transform().basis, Vector3()); Transform xform_A = xform_Au * A->get_shape_transform(shape_A); @@ -248,27 +250,37 @@ bool BodyPair3DSW::setup(real_t p_step) { Shape3DSW *shape_A_ptr = A->get_shape(shape_A); Shape3DSW *shape_B_ptr = B->get_shape(shape_B); - bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); - this->collided = collided; + collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); if (!collided) { //test ccd (currently just a raycast) - if (A->is_continuous_collision_detection_enabled() && A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) { + if (A->is_continuous_collision_detection_enabled() && dynamic_A && !dynamic_B) { _test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B); } - if (B->is_continuous_collision_detection_enabled() && B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC && A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) { + if (B->is_continuous_collision_detection_enabled() && dynamic_B && !dynamic_A) { _test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A); } return false; } + return true; +} + +bool BodyPair3DSW::pre_solve(real_t p_step) { + if (!collided) { + return false; + } + real_t max_penetration = space->get_contact_max_allowed_penetration(); real_t bias = (real_t)0.3; + Shape3DSW *shape_A_ptr = A->get_shape(shape_A); + Shape3DSW *shape_B_ptr = B->get_shape(shape_B); + if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) { if (shape_A_ptr->get_custom_bias() == 0) { bias = shape_B_ptr->get_custom_bias(); @@ -281,22 +293,28 @@ bool BodyPair3DSW::setup(real_t p_step) { real_t inv_dt = 1.0 / p_step; + bool do_process = false; + + const Basis &basis_A = A->get_transform().basis; + const Basis &basis_B = B->get_transform().basis; + for (int i = 0; i < contact_count; i++) { Contact &c = contacts[i]; c.active = false; - Vector3 global_A = xform_Au.xform(c.local_A); - Vector3 global_B = xform_Bu.xform(c.local_B); + Vector3 global_A = basis_A.xform(c.local_A); + Vector3 global_B = basis_B.xform(c.local_B) + offset_B; - real_t depth = c.normal.dot(global_A - global_B); + Vector3 axis = global_A - global_B; + real_t depth = axis.dot(c.normal); if (depth <= 0) { continue; } #ifdef DEBUG_ENABLED - if (space->is_debugging_contacts()) { + const Vector3 &offset_A = A->get_transform().get_origin(); space->add_debug_contact(global_A + offset_A); space->add_debug_contact(global_B + offset_A); } @@ -323,6 +341,7 @@ bool BodyPair3DSW::setup(real_t p_step) { } c.active = true; + do_process = true; // Precompute normal mass, tangent mass, and bias. Vector3 inertia_A = A->get_inv_inertia_tensor().xform(c.rA.cross(c.normal)); @@ -335,8 +354,12 @@ bool BodyPair3DSW::setup(real_t p_step) { c.depth = depth; Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse; - A->apply_impulse(-j_vec, c.rA + A->get_center_of_mass()); - B->apply_impulse(j_vec, c.rB + B->get_center_of_mass()); + if (dynamic_A) { + A->apply_impulse(-j_vec, c.rA + A->get_center_of_mass()); + } + if (dynamic_B) { + B->apply_impulse(j_vec, c.rB + B->get_center_of_mass()); + } c.acc_bias_impulse = 0; c.acc_bias_impulse_center_of_mass = 0; @@ -350,7 +373,7 @@ bool BodyPair3DSW::setup(real_t p_step) { } } - return true; + return do_process; } void BodyPair3DSW::solve(real_t p_step) { @@ -358,6 +381,8 @@ void BodyPair3DSW::solve(real_t p_step) { return; } + const real_t max_bias_av = MAX_BIAS_ROTATION / p_step; + for (int i = 0; i < contact_count; i++) { Contact &c = contacts[i]; if (!c.active) { @@ -381,8 +406,12 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld); - A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), MAX_BIAS_ROTATION / p_step); - B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), MAX_BIAS_ROTATION / p_step); + if (dynamic_A) { + A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), max_bias_av); + } + if (dynamic_B) { + B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), max_bias_av); + } crbA = A->get_biased_angular_velocity().cross(c.rA); crbB = B->get_biased_angular_velocity().cross(c.rB); @@ -397,8 +426,12 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com); - A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f); - B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f); + if (dynamic_A) { + A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f); + } + if (dynamic_B) { + B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f); + } } c.active = true; @@ -418,8 +451,12 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 j = c.normal * (c.acc_normal_impulse - jnOld); - A->apply_impulse(-j, c.rA + A->get_center_of_mass()); - B->apply_impulse(j, c.rB + B->get_center_of_mass()); + if (dynamic_A) { + A->apply_impulse(-j, c.rA + A->get_center_of_mass()); + } + if (dynamic_B) { + B->apply_impulse(j, c.rB + B->get_center_of_mass()); + } c.active = true; } @@ -461,8 +498,12 @@ void BodyPair3DSW::solve(real_t p_step) { jt = c.acc_tangent_impulse - jtOld; - A->apply_impulse(-jt, c.rA + A->get_center_of_mass()); - B->apply_impulse(jt, c.rB + B->get_center_of_mass()); + if (dynamic_A) { + A->apply_impulse(-jt, c.rA + A->get_center_of_mass()); + } + if (dynamic_B) { + B->apply_impulse(jt, c.rB + B->get_center_of_mass()); + } c.active = true; } @@ -478,8 +519,6 @@ BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_sh space = A->get_space(); A->add_constraint(this, 0); B->add_constraint(this, 1); - contact_count = 0; - collided = false; } BodyPair3DSW::~BodyPair3DSW() { @@ -561,6 +600,8 @@ void BodySoftBodyPair3DSW::validate_contacts() { } bool BodySoftBodyPair3DSW::setup(real_t p_step) { + body_dynamic = (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + if (!body->test_collision_mask(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) { collided = false; return false; @@ -582,18 +623,32 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { Shape3DSW *shape_A_ptr = body->get_shape(body_shape); Shape3DSW *shape_B_ptr = soft_body->get_shape(0); - bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); - this->collided = collided; + collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); + + return collided; +} + +bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) { + if (!collided) { + return false; + } real_t max_penetration = space->get_contact_max_allowed_penetration(); real_t bias = (real_t)0.3; + + Shape3DSW *shape_A_ptr = body->get_shape(body_shape); + if (shape_A_ptr->get_custom_bias()) { bias = shape_A_ptr->get_custom_bias(); } real_t inv_dt = 1.0 / p_step; + bool do_process = false; + + const Transform &transform_A = body->get_transform(); + uint32_t contact_count = contacts.size(); for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) { Contact &c = contacts[contact_index]; @@ -604,16 +659,17 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { continue; } - Vector3 global_A = xform_Au.xform(c.local_A); + Vector3 global_A = transform_A.xform(c.local_A); Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B; - - real_t depth = c.normal.dot(global_A - global_B); + Vector3 axis = global_A - global_B; + real_t depth = axis.dot(c.normal); if (depth <= 0) { continue; } c.active = true; + do_process = true; #ifdef DEBUG_ENABLED @@ -623,7 +679,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { } #endif - c.rA = global_A - xform_Au.origin - body->get_center_of_mass(); + c.rA = global_A - transform_A.origin - body->get_center_of_mass(); c.rB = global_B; if (body->can_report_contacts()) { @@ -631,7 +687,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { body->add_contact(global_A, -c.normal, depth, body_shape, global_B, 0, soft_body->get_instance_id(), soft_body->get_self(), crA); } - if (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) { + if (body_dynamic) { body->set_active(true); } @@ -645,7 +701,9 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { c.depth = depth; Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse; - body->apply_impulse(c.rA + body->get_center_of_mass(), -j_vec); + if (body_dynamic) { + body->apply_impulse(-j_vec, c.rA + body->get_center_of_mass()); + } soft_body->apply_node_impulse(c.index_B, j_vec); c.acc_bias_impulse = 0; c.acc_bias_impulse_center_of_mass = 0; @@ -661,7 +719,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { } } - return true; + return do_process; } void BodySoftBodyPair3DSW::solve(real_t p_step) { @@ -669,6 +727,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { return; } + const real_t max_bias_av = MAX_BIAS_ROTATION / p_step; + uint32_t contact_count = contacts.size(); for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) { Contact &c = contacts[contact_index]; @@ -691,7 +751,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld); - body->apply_bias_impulse(c.rA + body->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step); + if (body_dynamic) { + body->apply_bias_impulse(-jb, c.rA + body->get_center_of_mass(), max_bias_av); + } soft_body->apply_node_bias_impulse(c.index_B, jb); crbA = body->get_biased_angular_velocity().cross(c.rA); @@ -706,8 +768,10 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com); - body->apply_bias_impulse(body->get_center_of_mass(), -jb_com, 0.0f); - soft_body->apply_node_bias_impulse(c.index_B, -jb_com); + if (body_dynamic) { + body->apply_bias_impulse(-jb_com, body->get_center_of_mass(), 0.0f); + } + soft_body->apply_node_bias_impulse(c.index_B, jb_com); } c.active = true; @@ -726,7 +790,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { Vector3 j = c.normal * (c.acc_normal_impulse - jnOld); - body->apply_impulse(c.rA + body->get_center_of_mass(), -j); + if (body_dynamic) { + body->apply_impulse(-j, c.rA + body->get_center_of_mass()); + } soft_body->apply_node_impulse(c.index_B, j); c.active = true; @@ -767,7 +833,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { jt = c.acc_tangent_impulse - jtOld; - body->apply_impulse(c.rA + body->get_center_of_mass(), -jt); + if (body_dynamic) { + body->apply_impulse(-jt, c.rA + body->get_center_of_mass()); + } soft_body->apply_node_impulse(c.index_B, jt); c.active = true; @@ -775,7 +843,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { } } -BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) { +BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) : + BodyContact3DSW(&body, 1) { body = p_A; soft_body = p_B; body_shape = p_shape_A; diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h index 74dddfa6aa..3f425ba2d7 100644 --- a/servers/physics_3d/body_pair_3d_sw.h +++ b/servers/physics_3d/body_pair_3d_sw.h @@ -57,9 +57,9 @@ protected: }; Vector3 sep_axis; - bool collided; + bool collided = false; - Space3DSW *space; + Space3DSW *space = nullptr; BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) : Constraint3DSW(p_body_ptr, p_body_count) { @@ -77,16 +77,21 @@ class BodyPair3DSW : public BodyContact3DSW { Body3DSW *B; }; - Body3DSW *_arr[2]; + Body3DSW *_arr[2] = { nullptr, nullptr }; }; - int shape_A; - int shape_B; + int shape_A = 0; + int shape_B = 0; + + bool dynamic_A = false; + bool dynamic_B = false; + + bool report_contacts_only = false; Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection Contact contacts[MAX_CONTACTS]; - int contact_count; + int contact_count = 0; static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); @@ -96,18 +101,21 @@ class BodyPair3DSW : public BodyContact3DSW { bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B); public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B); ~BodyPair3DSW(); }; class BodySoftBodyPair3DSW : public BodyContact3DSW { - Body3DSW *body; - SoftBody3DSW *soft_body; + Body3DSW *body = nullptr; + SoftBody3DSW *soft_body = nullptr; - int body_shape; + int body_shape = 0; + + bool body_dynamic = false; LocalVector<Contact> contacts; @@ -118,8 +126,12 @@ class BodySoftBodyPair3DSW : public BodyContact3DSW { void validate_contacts(); public: - bool setup(real_t p_step); - void solve(real_t p_step); + 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; + + virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const override { return soft_body; } + virtual int get_soft_body_count() const override { return 1; } BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B); ~BodySoftBodyPair3DSW(); diff --git a/servers/physics_3d/broad_phase_3d_basic.cpp b/servers/physics_3d/broad_phase_3d_basic.cpp deleted file mode 100644 index b41c2530da..0000000000 --- a/servers/physics_3d/broad_phase_3d_basic.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/*************************************************************************/ -/* broad_phase_3d_basic.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "broad_phase_3d_basic.h" -#include "core/string/print_string.h" -#include "core/templates/list.h" - -BroadPhase3DSW::ID BroadPhase3DBasic::create(CollisionObject3DSW *p_object, int p_subindex) { - ERR_FAIL_COND_V(p_object == nullptr, 0); - - current++; - - Element e; - e.owner = p_object; - e._static = false; - e.subindex = p_subindex; - - element_map[current] = e; - return current; -} - -void BroadPhase3DBasic::move(ID p_id, const AABB &p_aabb) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - E->get().aabb = p_aabb; -} - -void BroadPhase3DBasic::set_static(ID p_id, bool p_static) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - E->get()._static = p_static; -} - -void BroadPhase3DBasic::remove(ID p_id) { - Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - List<PairKey> to_erase; - //unpair must be done immediately on removal to avoid potential invalid pointers - for (Map<PairKey, void *>::Element *F = pair_map.front(); F; F = F->next()) { - if (F->key().a == p_id || F->key().b == p_id) { - if (unpair_callback) { - Element *elem_A = &element_map[F->key().a]; - Element *elem_B = &element_map[F->key().b]; - unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, F->get(), unpair_userdata); - } - to_erase.push_back(F->key()); - } - } - while (to_erase.size()) { - pair_map.erase(to_erase.front()->get()); - to_erase.pop_front(); - } - element_map.erase(E); -} - -CollisionObject3DSW *BroadPhase3DBasic::get_object(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, nullptr); - return E->get().owner; -} - -bool BroadPhase3DBasic::is_static(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, false); - return E->get()._static; -} - -int BroadPhase3DBasic::get_subindex(ID p_id) const { - const Map<ID, Element>::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, -1); - return E->get().subindex; -} - -int BroadPhase3DBasic::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { - int rc = 0; - - for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) { - const AABB aabb = E->get().aabb; - if (aabb.has_point(p_point)) { - p_results[rc] = E->get().owner; - p_result_indices[rc] = E->get().subindex; - rc++; - if (rc >= p_max_results) { - break; - } - } - } - - return rc; -} - -int BroadPhase3DBasic::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { - int rc = 0; - - for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) { - const AABB aabb = E->get().aabb; - if (aabb.intersects_segment(p_from, p_to)) { - p_results[rc] = E->get().owner; - p_result_indices[rc] = E->get().subindex; - rc++; - if (rc >= p_max_results) { - break; - } - } - } - - return rc; -} - -int BroadPhase3DBasic::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { - int rc = 0; - - for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) { - const AABB aabb = E->get().aabb; - if (aabb.intersects(p_aabb)) { - p_results[rc] = E->get().owner; - p_result_indices[rc] = E->get().subindex; - rc++; - if (rc >= p_max_results) { - break; - } - } - } - - return rc; -} - -void BroadPhase3DBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { - pair_userdata = p_userdata; - pair_callback = p_pair_callback; -} - -void BroadPhase3DBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { - unpair_userdata = p_userdata; - unpair_callback = p_unpair_callback; -} - -void BroadPhase3DBasic::update() { - // recompute pairs - for (Map<ID, Element>::Element *I = element_map.front(); I; I = I->next()) { - for (Map<ID, Element>::Element *J = I->next(); J; J = J->next()) { - Element *elem_A = &I->get(); - Element *elem_B = &J->get(); - - if (elem_A->owner == elem_B->owner) { - continue; - } - - bool pair_ok = elem_A->aabb.intersects(elem_B->aabb) && (!elem_A->_static || !elem_B->_static); - - PairKey key(I->key(), J->key()); - - Map<PairKey, void *>::Element *E = pair_map.find(key); - - if (!pair_ok && E) { - if (unpair_callback) { - unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, E->get(), unpair_userdata); - } - pair_map.erase(key); - } - - if (pair_ok && !E) { - void *data = nullptr; - if (pair_callback) { - data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, unpair_userdata); - if (data) { - pair_map.insert(key, data); - } - } - } - } - } -} - -BroadPhase3DSW *BroadPhase3DBasic::_create() { - return memnew(BroadPhase3DBasic); -} - -BroadPhase3DBasic::BroadPhase3DBasic() { - current = 1; - unpair_callback = nullptr; - unpair_userdata = nullptr; - pair_callback = nullptr; - pair_userdata = nullptr; -} diff --git a/servers/physics_3d/broad_phase_3d_basic.h b/servers/physics_3d/broad_phase_3d_basic.h deleted file mode 100644 index 54d34e005f..0000000000 --- a/servers/physics_3d/broad_phase_3d_basic.h +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************/ -/* broad_phase_3d_basic.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef BROAD_PHASE_BASIC_H -#define BROAD_PHASE_BASIC_H - -#include "broad_phase_3d_sw.h" -#include "core/templates/map.h" - -class BroadPhase3DBasic : public BroadPhase3DSW { - struct Element { - CollisionObject3DSW *owner; - bool _static; - AABB aabb; - int subindex; - }; - - Map<ID, Element> element_map; - - ID current; - - struct PairKey { - union { - struct { - ID a; - ID b; - }; - uint64_t key; - }; - - _FORCE_INLINE_ bool operator<(const PairKey &p_key) const { - return key < p_key.key; - } - - PairKey() { key = 0; } - PairKey(ID p_a, ID p_b) { - if (p_a > p_b) { - a = p_b; - b = p_a; - } else { - a = p_a; - b = p_b; - } - } - }; - - Map<PairKey, void *> pair_map; - - PairCallback pair_callback; - void *pair_userdata; - UnpairCallback unpair_callback; - void *unpair_userdata; - -public: - // 0 is an invalid ID - virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0); - virtual void move(ID p_id, const AABB &p_aabb); - virtual void set_static(ID p_id, bool p_static); - virtual void remove(ID p_id); - - virtual CollisionObject3DSW *get_object(ID p_id) const; - virtual bool is_static(ID p_id) const; - virtual int get_subindex(ID p_id) const; - - virtual int cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - virtual int cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - - virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata); - virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata); - - virtual void update(); - - static BroadPhase3DSW *_create(); - BroadPhase3DBasic(); -}; - -#endif // BROAD_PHASE_BASIC_H diff --git a/servers/physics_3d/broad_phase_octree.cpp b/servers/physics_3d/broad_phase_3d_bvh.cpp index 11324fa4e4..f9f64f786d 100644 --- a/servers/physics_3d/broad_phase_octree.cpp +++ b/servers/physics_3d/broad_phase_3d_bvh.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_octree.cpp */ +/* broad_phase_3d_bvh.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,55 +28,55 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "broad_phase_octree.h" +#include "broad_phase_3d_bvh.h" #include "collision_object_3d_sw.h" -BroadPhase3DSW::ID BroadPhaseOctree::create(CollisionObject3DSW *p_object, int p_subindex) { - ID oid = octree.create(p_object, AABB(), p_subindex, false, 1 << p_object->get_type(), 0); - return oid; +BroadPhase3DBVH::ID BroadPhase3DBVH::create(CollisionObject3DSW *p_object, int p_subindex, const AABB &p_aabb, bool p_static) { + ID oid = bvh.create(p_object, true, p_aabb, p_subindex, !p_static, 1 << p_object->get_type(), p_static ? 0 : 0xFFFFF); // Pair everything, don't care? + return oid + 1; } -void BroadPhaseOctree::move(ID p_id, const AABB &p_aabb) { - octree.move(p_id, p_aabb); +void BroadPhase3DBVH::move(ID p_id, const AABB &p_aabb) { + bvh.move(p_id - 1, p_aabb); } -void BroadPhaseOctree::set_static(ID p_id, bool p_static) { - CollisionObject3DSW *it = octree.get(p_id); - octree.set_pairable(p_id, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF); //pair everything, don't care 1? +void BroadPhase3DBVH::set_static(ID p_id, bool p_static) { + CollisionObject3DSW *it = bvh.get(p_id - 1); + bvh.set_pairable(p_id - 1, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF, false); // Pair everything, don't care? } -void BroadPhaseOctree::remove(ID p_id) { - octree.erase(p_id); +void BroadPhase3DBVH::remove(ID p_id) { + bvh.erase(p_id - 1); } -CollisionObject3DSW *BroadPhaseOctree::get_object(ID p_id) const { - CollisionObject3DSW *it = octree.get(p_id); +CollisionObject3DSW *BroadPhase3DBVH::get_object(ID p_id) const { + CollisionObject3DSW *it = bvh.get(p_id - 1); ERR_FAIL_COND_V(!it, nullptr); return it; } -bool BroadPhaseOctree::is_static(ID p_id) const { - return !octree.is_pairable(p_id); +bool BroadPhase3DBVH::is_static(ID p_id) const { + return !bvh.is_pairable(p_id - 1); } -int BroadPhaseOctree::get_subindex(ID p_id) const { - return octree.get_subindex(p_id); +int BroadPhase3DBVH::get_subindex(ID p_id) const { + return bvh.get_subindex(p_id - 1); } -int BroadPhaseOctree::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { - return octree.cull_point(p_point, p_results, p_max_results, p_result_indices); +int BroadPhase3DBVH::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { + return bvh.cull_point(p_point, p_results, p_max_results, p_result_indices); } -int BroadPhaseOctree::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { - return octree.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices); +int BroadPhase3DBVH::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { + return bvh.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices); } -int BroadPhaseOctree::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { - return octree.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices); +int BroadPhase3DBVH::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { + return bvh.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices); } -void *BroadPhaseOctree::_pair_callback(void *self, OctreeElementID p_A, CollisionObject3DSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObject3DSW *p_object_B, int subindex_B) { - BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self); +void *BroadPhase3DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject3DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject3DSW *p_object_B, int subindex_B) { + BroadPhase3DBVH *bpo = (BroadPhase3DBVH *)(self); if (!bpo->pair_callback) { return nullptr; } @@ -84,8 +84,8 @@ void *BroadPhaseOctree::_pair_callback(void *self, OctreeElementID p_A, Collisio return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata); } -void BroadPhaseOctree::_unpair_callback(void *self, OctreeElementID p_A, CollisionObject3DSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObject3DSW *p_object_B, int subindex_B, void *pairdata) { - BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self); +void BroadPhase3DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject3DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject3DSW *p_object_B, int subindex_B, void *pairdata) { + BroadPhase3DBVH *bpo = (BroadPhase3DBVH *)(self); if (!bpo->unpair_callback) { return; } @@ -93,27 +93,27 @@ void BroadPhaseOctree::_unpair_callback(void *self, OctreeElementID p_A, Collisi bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata); } -void BroadPhaseOctree::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { +void BroadPhase3DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { pair_callback = p_pair_callback; pair_userdata = p_userdata; } -void BroadPhaseOctree::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { +void BroadPhase3DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { unpair_callback = p_unpair_callback; unpair_userdata = p_userdata; } -void BroadPhaseOctree::update() { - // does.. not? +void BroadPhase3DBVH::update() { + bvh.update(); } -BroadPhase3DSW *BroadPhaseOctree::_create() { - return memnew(BroadPhaseOctree); +BroadPhase3DSW *BroadPhase3DBVH::_create() { + return memnew(BroadPhase3DBVH); } -BroadPhaseOctree::BroadPhaseOctree() { - octree.set_pair_callback(_pair_callback, this); - octree.set_unpair_callback(_unpair_callback, this); +BroadPhase3DBVH::BroadPhase3DBVH() { + bvh.set_pair_callback(_pair_callback, this); + bvh.set_unpair_callback(_unpair_callback, this); pair_callback = nullptr; pair_userdata = nullptr; unpair_userdata = nullptr; diff --git a/servers/physics_3d/broad_phase_octree.h b/servers/physics_3d/broad_phase_3d_bvh.h index ee681dda96..30b8b7f2aa 100644 --- a/servers/physics_3d/broad_phase_octree.h +++ b/servers/physics_3d/broad_phase_3d_bvh.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_octree.h */ +/* broad_phase_3d_bvh.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,17 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BROAD_PHASE_OCTREE_H -#define BROAD_PHASE_OCTREE_H +#ifndef BROAD_PHASE_3D_BVH_H +#define BROAD_PHASE_3D_BVH_H #include "broad_phase_3d_sw.h" -#include "core/math/octree.h" +#include "core/math/bvh.h" -class BroadPhaseOctree : public BroadPhase3DSW { - Octree<CollisionObject3DSW, true> octree; +class BroadPhase3DBVH : public BroadPhase3DSW { + BVH_Manager<CollisionObject3DSW, true, 128> bvh; - static void *_pair_callback(void *, OctreeElementID, CollisionObject3DSW *, int, OctreeElementID, CollisionObject3DSW *, int); - static void _unpair_callback(void *, OctreeElementID, CollisionObject3DSW *, int, OctreeElementID, CollisionObject3DSW *, int, void *); + static void *_pair_callback(void *, uint32_t, CollisionObject3DSW *, int, uint32_t, CollisionObject3DSW *, int); + static void _unpair_callback(void *, uint32_t, CollisionObject3DSW *, int, uint32_t, CollisionObject3DSW *, int, void *); PairCallback pair_callback; void *pair_userdata; @@ -47,7 +47,7 @@ class BroadPhaseOctree : public BroadPhase3DSW { public: // 0 is an invalid ID - virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0); + virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false); virtual void move(ID p_id, const AABB &p_aabb); virtual void set_static(ID p_id, bool p_static); virtual void remove(ID p_id); @@ -66,7 +66,7 @@ public: virtual void update(); static BroadPhase3DSW *_create(); - BroadPhaseOctree(); + BroadPhase3DBVH(); }; -#endif // BROAD_PHASE_OCTREE_H +#endif // BROAD_PHASE_3D_BVH_H diff --git a/servers/physics_3d/broad_phase_3d_sw.h b/servers/physics_3d/broad_phase_3d_sw.h index 283c087b96..98313cb216 100644 --- a/servers/physics_3d/broad_phase_3d_sw.h +++ b/servers/physics_3d/broad_phase_3d_sw.h @@ -48,7 +48,7 @@ public: typedef void (*UnpairCallback)(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_userdata); // 0 is an invalid ID - virtual ID create(CollisionObject3DSW *p_object_, int p_subindex = 0) = 0; + virtual ID create(CollisionObject3DSW *p_object_, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false) = 0; virtual void move(ID p_id, const AABB &p_aabb) = 0; virtual void set_static(ID p_id, bool p_static) = 0; virtual void remove(ID p_id) = 0; diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp index 293a7e6606..459deb1356 100644 --- a/servers/physics_3d/collision_object_3d_sw.cpp +++ b/servers/physics_3d/collision_object_3d_sw.cpp @@ -146,22 +146,23 @@ void CollisionObject3DSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; - if (s.bpid == 0) { - s.bpid = space->get_broadphase()->create(this, i); - space->get_broadphase()->set_static(s.bpid, _static); - } //not quite correct, should compute the next matrix.. AABB shape_aabb = s.shape->get_aabb(); Transform xform = transform * s.xform; shape_aabb = xform.xform(shape_aabb); + shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05); s.aabb_cache = shape_aabb; - s.aabb_cache = s.aabb_cache.grow((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05); Vector3 scale = xform.get_basis().get_scale(); s.area_cache = s.shape->get_area() * scale.x * scale.y * scale.z; - space->get_broadphase()->move(s.bpid, s.aabb_cache); + if (s.bpid == 0) { + s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static); + space->get_broadphase()->set_static(s.bpid, _static); + } + + space->get_broadphase()->move(s.bpid, shape_aabb); } } @@ -172,18 +173,19 @@ void CollisionObject3DSW::_update_shapes_with_motion(const Vector3 &p_motion) { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; - if (s.bpid == 0) { - s.bpid = space->get_broadphase()->create(this, i); - space->get_broadphase()->set_static(s.bpid, _static); - } //not quite correct, should compute the next matrix.. AABB shape_aabb = s.shape->get_aabb(); Transform xform = transform * s.xform; shape_aabb = xform.xform(shape_aabb); - shape_aabb = shape_aabb.merge(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion + shape_aabb.merge_with(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion s.aabb_cache = shape_aabb; + if (s.bpid == 0) { + s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static); + space->get_broadphase()->set_static(s.bpid, _static); + } + space->get_broadphase()->move(s.bpid, shape_aabb); } } diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h index 2571335c43..7b44726ef5 100644 --- a/servers/physics_3d/constraint_3d_sw.h +++ b/servers/physics_3d/constraint_3d_sw.h @@ -31,14 +31,13 @@ #ifndef CONSTRAINT_SW_H #define CONSTRAINT_SW_H -#include "body_3d_sw.h" +class Body3DSW; +class SoftBody3DSW; class Constraint3DSW { Body3DSW **_body_ptr; int _body_count; uint64_t island_step; - Constraint3DSW *island_next; - Constraint3DSW *island_list_next; int priority; bool disabled_collisions_between_bodies; @@ -60,15 +59,12 @@ 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_ Constraint3DSW *get_island_next() const { return island_next; } - _FORCE_INLINE_ void set_island_next(Constraint3DSW *p_next) { island_next = p_next; } - - _FORCE_INLINE_ Constraint3DSW *get_island_list_next() const { return island_list_next; } - _FORCE_INLINE_ void set_island_list_next(Constraint3DSW *p_next) { island_list_next = p_next; } - _FORCE_INLINE_ Body3DSW **get_body_ptr() const { return _body_ptr; } _FORCE_INLINE_ int get_body_count() const { return _body_count; } + virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const { return nullptr; } + virtual int get_soft_body_count() const { return 0; } + _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; } _FORCE_INLINE_ int get_priority() const { return priority; } @@ -76,6 +72,7 @@ public: _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; } virtual bool setup(real_t p_step) = 0; + virtual bool pre_solve(real_t p_step) = 0; virtual void solve(real_t p_step) = 0; virtual ~Constraint3DSW() {} diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp index 9c4493f4a2..e9efddf165 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp @@ -109,6 +109,13 @@ ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Trans } bool ConeTwistJoint3DSW::setup(real_t p_timestep) { + dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + m_appliedImpulse = real_t(0.); //set bias, sign, clear accumulator @@ -261,8 +268,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) { real_t impulse = depth * tau / p_timestep * jacDiagABInv - rel_vel * jacDiagABInv; m_appliedImpulse += impulse; Vector3 impulse_vector = normal * impulse; - A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin); - B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin); + if (dynamic_A) { + A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin); + } + if (dynamic_B) { + B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin); + } } } @@ -283,8 +294,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) { Vector3 impulse = m_swingAxis * impulseMag; - A->apply_torque_impulse(impulse); - B->apply_torque_impulse(-impulse); + if (dynamic_A) { + A->apply_torque_impulse(impulse); + } + if (dynamic_B) { + B->apply_torque_impulse(-impulse); + } } // solve twist limit @@ -299,8 +314,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) { Vector3 impulse = m_twistAxis * impulseMag; - A->apply_torque_impulse(impulse); - B->apply_torque_impulse(-impulse); + if (dynamic_A) { + A->apply_torque_impulse(impulse); + } + if (dynamic_B) { + B->apply_torque_impulse(-impulse); + } } } } diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h index 4e4d4e7f0c..b871ea50db 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h @@ -102,10 +102,10 @@ public: bool m_solveSwingLimit; public: - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; } + virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; } - virtual bool setup(real_t p_timestep); - virtual void solve(real_t p_timestep); + virtual bool setup(real_t p_step) override; + virtual void solve(real_t p_step) override; ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame); diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp index 13b389251f..7c504764a7 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp @@ -82,7 +82,7 @@ int G6DOFRotationalLimitMotor3DSW::testLimitValue(real_t test_value) { real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits( real_t timeStep, Vector3 &axis, real_t jacDiagABInv, - Body3DSW *body0, Body3DSW *body1) { + Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic) { if (!needApplyTorques()) { return 0.0f; } @@ -138,8 +138,10 @@ real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits( Vector3 motorImp = clippedMotorImpulse * axis; - body0->apply_torque_impulse(motorImp); - if (body1) { + if (p_body0_dynamic) { + body0->apply_torque_impulse(motorImp); + } + if (body1 && p_body1_dynamic) { body1->apply_torque_impulse(-motorImp); } @@ -154,6 +156,7 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( real_t jacDiagABInv, Body3DSW *body1, const Vector3 &pointInA, Body3DSW *body2, const Vector3 &pointInB, + bool p_body1_dynamic, bool p_body2_dynamic, int limit_index, const Vector3 &axis_normal_on_a, const Vector3 &anchorPos) { @@ -205,8 +208,12 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse; Vector3 impulse_vector = axis_normal_on_a * normalImpulse; - body1->apply_impulse(impulse_vector, rel_pos1); - body2->apply_impulse(-impulse_vector, rel_pos2); + if (p_body1_dynamic) { + body1->apply_impulse(impulse_vector, rel_pos1); + } + if (p_body2_dynamic) { + body2->apply_impulse(-impulse_vector, rel_pos2); + } return normalImpulse; } @@ -303,6 +310,13 @@ bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) { } bool Generic6DOFJoint3DSW::setup(real_t p_timestep) { + dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + // Clear accumulated impulses for the next simulation step m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.)); int i; @@ -380,6 +394,7 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) { jacDiagABInv, A, pointInA, B, pointInB, + dynamic_A, dynamic_B, i, linear_axis, m_AnchorPos); } } @@ -394,7 +409,7 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) { angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal(); - m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B); + m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B, dynamic_A, dynamic_B); } } } diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h index d61a033231..8af76cefc2 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h @@ -120,7 +120,7 @@ public: int testLimitValue(real_t test_value); //! apply the correction impulses for two bodies - real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1); + real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic); }; class G6DOFTranslationalLimitMotor3DSW { @@ -166,6 +166,7 @@ public: real_t jacDiagABInv, Body3DSW *body1, const Vector3 &pointInA, Body3DSW *body2, const Vector3 &pointInB, + bool p_body1_dynamic, bool p_body2_dynamic, int limit_index, const Vector3 &axis_normal_on_a, const Vector3 &anchorPos); @@ -234,10 +235,10 @@ protected: public: Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA); - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_6DOF; } + virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_6DOF; } - virtual bool setup(real_t p_timestep); - virtual void solve(real_t p_timestep); + virtual bool setup(real_t p_step) override; + virtual void solve(real_t p_step) override; //! Calcs global transform of the offsets /*! diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp index 2b9f0038b4..bb8858c28a 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp @@ -155,6 +155,13 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo } bool HingeJoint3DSW::setup(real_t p_step) { + dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + m_appliedImpulse = real_t(0.); if (!m_angularOnly) { @@ -275,8 +282,12 @@ void HingeJoint3DSW::solve(real_t p_step) { real_t impulse = depth * tau / p_step * jacDiagABInv - rel_vel * jacDiagABInv; m_appliedImpulse += impulse; Vector3 impulse_vector = normal * impulse; - A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin); - B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin); + if (dynamic_A) { + A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin); + } + if (dynamic_B) { + B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin); + } } } @@ -318,8 +329,12 @@ void HingeJoint3DSW::solve(real_t p_step) { angularError *= (real_t(1.) / denom2) * relaxation; } - A->apply_torque_impulse(-velrelOrthog + angularError); - B->apply_torque_impulse(velrelOrthog - angularError); + if (dynamic_A) { + A->apply_torque_impulse(-velrelOrthog + angularError); + } + if (dynamic_B) { + B->apply_torque_impulse(velrelOrthog - angularError); + } // solve limit if (m_solveLimit) { @@ -333,8 +348,12 @@ void HingeJoint3DSW::solve(real_t p_step) { impulseMag = m_accLimitImpulse - temp; Vector3 impulse = axisA * impulseMag * m_limitSign; - A->apply_torque_impulse(impulse); - B->apply_torque_impulse(-impulse); + if (dynamic_A) { + A->apply_torque_impulse(impulse); + } + if (dynamic_B) { + B->apply_torque_impulse(-impulse); + } } } @@ -355,8 +374,12 @@ void HingeJoint3DSW::solve(real_t p_step) { clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse; Vector3 motorImp = clippedMotorImpulse * axisA; - A->apply_torque_impulse(motorImp + angularLimit); - B->apply_torque_impulse(-motorImp - angularLimit); + if (dynamic_A) { + A->apply_torque_impulse(motorImp + angularLimit); + } + if (dynamic_B) { + B->apply_torque_impulse(-motorImp - angularLimit); + } } } } diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h index b6117aa0bc..2100f5de44 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.h +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h @@ -96,10 +96,10 @@ class HingeJoint3DSW : public Joint3DSW { real_t m_appliedImpulse; public: - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_HINGE; } + virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_HINGE; } - virtual bool setup(real_t p_step); - virtual void solve(real_t p_step); + virtual bool setup(real_t p_step) override; + virtual void solve(real_t p_step) override; real_t get_hinge_angle(); diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp index 9f708ce151..8eb84d1c2f 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp @@ -50,6 +50,13 @@ subject to the following restrictions: #include "pin_joint_3d_sw.h" bool PinJoint3DSW::setup(real_t p_step) { + dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + m_appliedImpulse = real_t(0.); Vector3 normal(0, 0, 0); @@ -119,8 +126,12 @@ void PinJoint3DSW::solve(real_t p_step) { m_appliedImpulse += impulse; Vector3 impulse_vector = normal * impulse; - A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin); - B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin); + if (dynamic_A) { + A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin); + } + if (dynamic_B) { + B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin); + } normal[i] = 0; } diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h index 1875983527..3d91452850 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.h +++ b/servers/physics_3d/joints/pin_joint_3d_sw.h @@ -74,10 +74,10 @@ class PinJoint3DSW : public Joint3DSW { Vector3 m_pivotInB; public: - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_PIN; } + virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_PIN; } - virtual bool setup(real_t p_step); - virtual void solve(real_t p_step); + virtual bool setup(real_t p_step) override; + virtual void solve(real_t p_step) override; void set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value); real_t get_param(PhysicsServer3D::PinJointParam p_param) const; diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp index 0adc471797..8bd1951311 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp @@ -127,6 +127,13 @@ SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform & //----------------------------------------------------------------------------- bool SliderJoint3DSW::setup(real_t p_step) { + dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); + + if (!dynamic_A && !dynamic_B) { + return false; + } + //calculate transforms m_calculatedTransformA = A->get_transform() * m_frameInA; m_calculatedTransformB = B->get_transform() * m_frameInB; @@ -196,8 +203,12 @@ void SliderJoint3DSW::solve(real_t p_step) { // calcutate and apply impulse real_t normalImpulse = softness * (restitution * depth / p_step - damping * rel_vel) * m_jacLinDiagABInv[i]; Vector3 impulse_vector = normal * normalImpulse; - A->apply_impulse(impulse_vector, m_relPosA); - B->apply_impulse(-impulse_vector, m_relPosB); + if (dynamic_A) { + A->apply_impulse(impulse_vector, m_relPosA); + } + if (dynamic_B) { + B->apply_impulse(-impulse_vector, m_relPosB); + } if (m_poweredLinMotor && (!i)) { // apply linear motor if (m_accumulatedLinMotorImpulse < m_maxLinMotorForce) { real_t desiredMotorVel = m_targetLinMotorVelocity; @@ -217,8 +228,12 @@ void SliderJoint3DSW::solve(real_t p_step) { m_accumulatedLinMotorImpulse = new_acc; // apply clamped impulse impulse_vector = normal * normalImpulse; - A->apply_impulse(impulse_vector, m_relPosA); - B->apply_impulse(-impulse_vector, m_relPosB); + if (dynamic_A) { + A->apply_impulse(impulse_vector, m_relPosA); + } + if (dynamic_B) { + B->apply_impulse(-impulse_vector, m_relPosB); + } } } } @@ -252,8 +267,12 @@ void SliderJoint3DSW::solve(real_t p_step) { angularError *= (real_t(1.) / denom2) * m_restitutionOrthoAng * m_softnessOrthoAng; } // apply impulse - A->apply_torque_impulse(-velrelOrthog + angularError); - B->apply_torque_impulse(velrelOrthog - angularError); + if (dynamic_A) { + A->apply_torque_impulse(-velrelOrthog + angularError); + } + if (dynamic_B) { + B->apply_torque_impulse(velrelOrthog - angularError); + } real_t impulseMag; //solve angular limits if (m_solveAngLim) { @@ -264,8 +283,12 @@ void SliderJoint3DSW::solve(real_t p_step) { impulseMag *= m_kAngle * m_softnessDirAng; } Vector3 impulse = axisA * impulseMag; - A->apply_torque_impulse(impulse); - B->apply_torque_impulse(-impulse); + if (dynamic_A) { + A->apply_torque_impulse(impulse); + } + if (dynamic_B) { + B->apply_torque_impulse(-impulse); + } //apply angular motor if (m_poweredAngMotor) { if (m_accumulatedAngMotorImpulse < m_maxAngMotorForce) { @@ -290,8 +313,12 @@ void SliderJoint3DSW::solve(real_t p_step) { m_accumulatedAngMotorImpulse = new_acc; // apply clamped impulse Vector3 motorImp = angImpulse * axisA; - A->apply_torque_impulse(motorImp); - B->apply_torque_impulse(-motorImp); + if (dynamic_A) { + A->apply_torque_impulse(motorImp); + } + if (dynamic_B) { + B->apply_torque_impulse(-motorImp); + } } } } // SliderJointSW::solveConstraint() diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h index f52f6ace27..ef5891d0f9 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.h +++ b/servers/physics_3d/joints/slider_joint_3d_sw.h @@ -240,10 +240,10 @@ public: void set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value); real_t get_param(PhysicsServer3D::SliderJointParam p_param) const; - bool setup(real_t p_step); - void solve(real_t p_step); + virtual bool setup(real_t p_step) override; + virtual void solve(real_t p_step) override; - virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_SLIDER; } + virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_SLIDER; } }; #endif // SLIDER_JOINT_SW_H diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h index 225a71aca9..e2514674ea 100644 --- a/servers/physics_3d/joints_3d_sw.h +++ b/servers/physics_3d/joints_3d_sw.h @@ -35,9 +35,14 @@ #include "constraint_3d_sw.h" class Joint3DSW : public Constraint3DSW { +protected: + bool dynamic_A = false; + bool dynamic_B = false; + public: - virtual bool setup(real_t p_step) { return false; } - virtual void solve(real_t p_step) {} + virtual bool setup(real_t p_step) override { return false; } + virtual bool pre_solve(real_t p_step) override { return true; } + virtual void solve(real_t p_step) override {} void copy_settings_from(Joint3DSW *p_joint) { set_self(p_joint->get_self()); diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index 3d0063b0fa..f3eb1ae48f 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -30,8 +30,7 @@ #include "physics_server_3d_sw.h" -#include "broad_phase_3d_basic.h" -#include "broad_phase_octree.h" +#include "broad_phase_3d_bvh.h" #include "core/debugger/engine_debugger.h" #include "core/os/os.h" #include "joints/cone_twist_joint_3d_sw.h" @@ -857,10 +856,10 @@ int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const { return body->get_max_contacts_reported(); } -void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { +void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); - body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata); + body->set_force_integration_callback(p_callable, p_udata); } void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) { @@ -1755,7 +1754,8 @@ void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, PhysicsServer3DSW *PhysicsServer3DSW::singletonsw = nullptr; PhysicsServer3DSW::PhysicsServer3DSW(bool p_using_threads) { singletonsw = this; - BroadPhase3DSW::create_func = BroadPhaseOctree::_create; + BroadPhase3DSW::create_func = BroadPhase3DBVH::_create; + island_count = 0; active_objects = 0; collision_pairs = 0; diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index f92652bfad..0b42f1d605 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -241,7 +241,7 @@ public: virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override; virtual int body_get_max_contacts_reported(RID p_body) const override; - virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override; + virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override; virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h index 49ae60db92..69d0fcf3ed 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.h +++ b/servers/physics_3d/physics_server_3d_wrap_mt.h @@ -249,7 +249,7 @@ public: FUNC2(body_set_omit_force_integration, RID, bool); FUNC1RC(bool, body_is_omitting_force_integration, RID); - FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &); + FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &); FUNC2(body_set_ray_pickable, RID, bool); diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index bf0946a0e2..ccd37ca742 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -30,10 +30,28 @@ #include "shape_3d_sw.h" +#include "core/io/image.h" #include "core/math/geometry_3d.h" #include "core/math/quick_hull.h" #include "core/templates/sort_array.h" +// HeightMapShape3DSW is based on Bullet btHeightfieldTerrainShape. + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002 #define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998 @@ -891,6 +909,9 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve const Vector3 *vertices = mesh.vertices.ptr(); int vc = mesh.vertices.size(); + r_amount = 0; + ERR_FAIL_COND_MSG(vc == 0, "Convex polygon shape has no vertices."); + //find vertex first real_t max = 0; int vtx = 0; @@ -1614,7 +1635,7 @@ ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() { /* HEIGHT MAP SHAPE */ -Vector<real_t> HeightMapShape3DSW::get_heights() const { +Vector<float> HeightMapShape3DSW::get_heights() const { return heights; } @@ -1626,10 +1647,6 @@ int HeightMapShape3DSW::get_depth() const { return depth; } -real_t HeightMapShape3DSW::get_cell_size() const { - return cell_size; -} - void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { //not very useful, but not very used either p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal, 0), r_min, r_max); @@ -1640,7 +1657,198 @@ Vector3 HeightMapShape3DSW::get_support(const Vector3 &p_normal) const { return get_aabb().get_support(p_normal); } +struct _HeightmapSegmentCullParams { + Vector3 from; + Vector3 to; + Vector3 dir; + + Vector3 result; + Vector3 normal; + + const HeightMapShape3DSW *heightmap = nullptr; + FaceShape3DSW *face = nullptr; +}; + +_FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) { + Vector3 res; + Vector3 normal; + if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal)) { + p_params.result = res; + p_params.normal = normal; + return true; + } + + return false; +} + +_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, int p_x, int p_z) { + // First triangle. + p_params.heightmap->_get_point(p_x, p_z, p_params.face->vertex[0]); + p_params.heightmap->_get_point(p_x + 1, p_z, p_params.face->vertex[1]); + p_params.heightmap->_get_point(p_x, p_z + 1, p_params.face->vertex[2]); + p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal; + if (_heightmap_face_cull_segment(p_params)) { + return true; + } + + // Second triangle. + p_params.face->vertex[0] = p_params.face->vertex[1]; + p_params.heightmap->_get_point(p_x + 1, p_z + 1, p_params.face->vertex[1]); + p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal; + if (_heightmap_face_cull_segment(p_params)) { + return true; + } + + return false; +} + bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const { + if (heights.is_empty()) { + return false; + } + + Vector3 local_begin = p_begin + local_origin; + Vector3 local_end = p_end + local_origin; + + FaceShape3DSW face; + face.backface_collision = false; + + _HeightmapSegmentCullParams params; + params.from = p_begin; + params.to = p_end; + params.dir = (p_end - p_begin).normalized(); + params.heightmap = this; + params.face = &face; + + // Quantize the ray begin/end. + int begin_x = floor(local_begin.x); + int begin_z = floor(local_begin.z); + int end_x = floor(local_end.x); + int end_z = floor(local_end.z); + + if ((begin_x == end_x) && (begin_z == end_z)) { + // Simple case for rays that don't traverse the grid horizontally. + // Just perform a test on the given cell. + int x = CLAMP(begin_x, 0, width - 2); + int z = CLAMP(begin_z, 0, depth - 2); + if (_heightmap_cell_cull_segment(params, x, z)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + } else { + // Perform grid query from projected ray. + Vector2 ray_dir_proj(local_end.x - local_begin.x, local_end.z - local_begin.z); + real_t ray_dist_proj = ray_dir_proj.length(); + + if (ray_dist_proj < CMP_EPSILON) { + ray_dir_proj = Vector2(); + } else { + ray_dir_proj /= ray_dist_proj; + } + + const int x_step = (ray_dir_proj.x > CMP_EPSILON) ? 1 : ((ray_dir_proj.x < -CMP_EPSILON) ? -1 : 0); + const int z_step = (ray_dir_proj.y > CMP_EPSILON) ? 1 : ((ray_dir_proj.y < -CMP_EPSILON) ? -1 : 0); + + const real_t infinite = 1e20; + const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_proj.x) : infinite; + const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_proj.y) : infinite; + + real_t cross_x; // At which value of `param` we will cross a x-axis lane? + real_t cross_z; // At which value of `param` we will cross a z-axis lane? + + // X initialization. + if (x_step != 0) { + if (x_step == 1) { + cross_x = (ceil(local_begin.x) - local_begin.x) * delta_x; + } else { + cross_x = (local_begin.x - floor(local_begin.x)) * delta_x; + } + } else { + cross_x = infinite; // Will never cross on X. + } + + // Z initialization. + if (z_step != 0) { + if (z_step == 1) { + cross_z = (ceil(local_begin.z) - local_begin.z) * delta_z; + } else { + cross_z = (local_begin.z - floor(local_begin.z)) * delta_z; + } + } else { + cross_z = infinite; // Will never cross on Z. + } + + int x = floor(local_begin.x); + int z = floor(local_begin.z); + + // Workaround cases where the ray starts at an integer position. + if (Math::abs(cross_x) < CMP_EPSILON) { + cross_x += delta_x; + // If going backwards, we should ignore the position we would get by the above flooring, + // because the ray is not heading in that direction. + if (x_step == -1) { + x -= 1; + } + } + + if (Math::abs(cross_z) < CMP_EPSILON) { + cross_z += delta_z; + if (z_step == -1) { + z -= 1; + } + } + + // Start inside the grid. + int x_start = CLAMP(x, 0, width - 2); + int z_start = CLAMP(z, 0, depth - 2); + + // Adjust initial cross values. + cross_x += delta_x * x_step * (x_start - x); + cross_z += delta_z * z_step * (z_start - z); + + x = x_start; + z = z_start; + + if (_heightmap_cell_cull_segment(params, x, z)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + + real_t dist = 0.0; + while (true) { + if (cross_x < cross_z) { + // X lane. + x += x_step; + // Assign before advancing the param, + // to be in sync with the initialization step. + dist = cross_x; + cross_x += delta_x; + } else { + // Z lane. + z += z_step; + dist = cross_z; + cross_z += delta_z; + } + + // Stop when outside the grid. + if ((x < 0) || (z < 0) || (x >= width - 1) || (z >= depth - 1)) { + break; + } + + if (_heightmap_cell_cull_segment(params, x, z)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + + if (dist > ray_dist_proj) { + break; + } + } + } + return false; } @@ -1652,7 +1860,66 @@ Vector3 HeightMapShape3DSW::get_closest_point_to(const Vector3 &p_point) const { return Vector3(); } +void HeightMapShape3DSW::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const { + const AABB &aabb = get_aabb(); + + Vector3 pos_local = aabb.position + local_origin; + + Vector3 clamped_point(p_point); + clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + aabb.size.x); + clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + aabb.size.y); + clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.x + aabb.size.z); + + r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5); + r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5); + r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5); +} + void HeightMapShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const { + if (heights.is_empty()) { + return; + } + + AABB local_aabb = p_local_aabb; + local_aabb.position += local_origin; + + // Quantize the aabb, and adjust the start/end ranges. + int aabb_min[3]; + int aabb_max[3]; + _get_cell(local_aabb.position, aabb_min[0], aabb_min[1], aabb_min[2]); + _get_cell(local_aabb.position + local_aabb.size, aabb_max[0], aabb_max[1], aabb_max[2]); + + // Expand the min/max quantized values. + // This is to catch the case where the input aabb falls between grid points. + for (int i = 0; i < 3; ++i) { + aabb_min[i]--; + aabb_max[i]++; + } + + int start_x = MAX(0, aabb_min[0]); + int end_x = MIN(width - 1, aabb_max[0]); + int start_z = MAX(0, aabb_min[2]); + int end_z = MIN(depth - 1, aabb_max[2]); + + FaceShape3DSW face; + face.backface_collision = true; + + for (int z = start_z; z < end_z; z++) { + for (int x = start_x; x < end_x; x++) { + // First triangle. + _get_point(x, z, face.vertex[0]); + _get_point(x + 1, z, face.vertex[1]); + _get_point(x, z + 1, face.vertex[2]); + face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal; + p_callback(p_userdata, &face); + + // Second triangle. + face.vertex[0] = face.vertex[1]; + _get_point(x + 1, z + 1, face.vertex[1]); + face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal; + p_callback(p_userdata, &face); + } + } } Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const { @@ -1665,58 +1932,102 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -void HeightMapShape3DSW::_setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size) { +void HeightMapShape3DSW::_setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { heights = p_heights; width = p_width; depth = p_depth; - cell_size = p_cell_size; - - const real_t *r = heights.ptr(); + // Initialize aabb. AABB aabb; + aabb.position = Vector3(0.0, p_min_height, 0.0); + aabb.size = Vector3(p_width - 1, p_max_height - p_min_height, p_depth - 1); - for (int i = 0; i < depth; i++) { - for (int j = 0; j < width; j++) { - real_t h = r[i * width + j]; + // Initialize origin as the aabb center. + local_origin = aabb.position + 0.5 * aabb.size; + local_origin.y = 0.0; - Vector3 pos(j * cell_size, h, i * cell_size); - if (i == 0 || j == 0) { - aabb.position = pos; - } else { - aabb.expand_to(pos); - } - } - } + aabb.position -= local_origin; configure(aabb); } void HeightMapShape3DSW::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY); + Dictionary d = p_data; ERR_FAIL_COND(!d.has("width")); ERR_FAIL_COND(!d.has("depth")); - ERR_FAIL_COND(!d.has("cell_size")); ERR_FAIL_COND(!d.has("heights")); int width = d["width"]; int depth = d["depth"]; - real_t cell_size = d["cell_size"]; - Vector<real_t> heights = d["heights"]; - ERR_FAIL_COND(width <= 0); - ERR_FAIL_COND(depth <= 0); - ERR_FAIL_COND(cell_size <= CMP_EPSILON); - ERR_FAIL_COND(heights.size() != (width * depth)); - _setup(heights, width, depth, cell_size); + ERR_FAIL_COND(width <= 0.0); + ERR_FAIL_COND(depth <= 0.0); + + Variant heights_variant = d["heights"]; + Vector<float> heights_buffer; + if (heights_variant.get_type() == Variant::PACKED_FLOAT32_ARRAY) { + // Ready-to-use heights can be passed. + heights_buffer = heights_variant; + } else if (heights_variant.get_type() == Variant::OBJECT) { + // If an image is passed, we have to convert it. + // This would be expensive to do with a script, so it's nice to have it here. + Ref<Image> image = heights_variant; + ERR_FAIL_COND(image.is_null()); + ERR_FAIL_COND(image->get_format() != Image::FORMAT_RF); + + PackedByteArray im_data = image->get_data(); + heights_buffer.resize(image->get_width() * image->get_height()); + + float *w = heights_buffer.ptrw(); + float *rp = (float *)im_data.ptr(); + for (int i = 0; i < heights_buffer.size(); ++i) { + w[i] = rp[i]; + } + } else { + ERR_FAIL_MSG("Expected PackedFloat32Array or float Image."); + } + + // Compute min and max heights or use precomputed values. + real_t min_height = 0.0; + real_t max_height = 0.0; + if (d.has("min_height") && d.has("max_height")) { + min_height = d["min_height"]; + max_height = d["max_height"]; + } else { + int heights_size = heights.size(); + for (int i = 0; i < heights_size; ++i) { + float h = heights[i]; + if (h < min_height) { + min_height = h; + } else if (h > max_height) { + max_height = h; + } + } + } + + ERR_FAIL_COND(min_height > max_height); + + ERR_FAIL_COND(heights_buffer.size() != (width * depth)); + + // If specified, min and max height will be used as precomputed values. + _setup(heights_buffer, width, depth, min_height, max_height); } Variant HeightMapShape3DSW::get_data() const { - ERR_FAIL_V(Variant()); + Dictionary d; + d["width"] = width; + d["depth"] = depth; + + const AABB &aabb = get_aabb(); + d["min_height"] = aabb.position.y; + d["max_height"] = aabb.position.y + aabb.size.y; + + d["heights"] = heights; + + return d; } HeightMapShape3DSW::HeightMapShape3DSW() { - width = 0; - depth = 0; - cell_size = 0; } diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index 988e76c699..4d2b6ffbed 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -81,7 +81,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const = 0; - _FORCE_INLINE_ AABB get_aabb() const { return aabb; } + _FORCE_INLINE_ const AABB &get_aabb() const { return aabb; } _FORCE_INLINE_ bool is_configured() const { return configured; } virtual bool is_concave() const { return false; } @@ -389,21 +389,29 @@ public: }; struct HeightMapShape3DSW : public ConcaveShape3DSW { - Vector<real_t> heights; - int width; - int depth; - real_t cell_size; + Vector<float> heights; + int width = 0; + int depth = 0; + Vector3 local_origin; - //void _cull_segment(int p_idx,_SegmentCullParams *p_params) const; - //void _cull(int p_idx,_CullParams *p_params) const; + _FORCE_INLINE_ float _get_height(int p_x, int p_z) const { + return heights[(p_z * width) + p_x]; + } + + _FORCE_INLINE_ void _get_point(int p_x, int p_z, Vector3 &r_point) const { + r_point.x = p_x - 0.5 * (width - 1.0); + r_point.y = _get_height(p_x, p_z); + r_point.z = p_z - 0.5 * (depth - 1.0); + } + + void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const; - void _setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size); + void _setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); public: - Vector<real_t> get_heights() const; + Vector<float> get_heights() const; int get_width() const; int get_depth() const; - real_t get_cell_size() const; virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_HEIGHTMAP; } diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h index 6c0451ff45..98e554218b 100644 --- a/servers/physics_3d/soft_body_3d_sw.h +++ b/servers/physics_3d/soft_body_3d_sw.h @@ -106,6 +106,8 @@ class SoftBody3DSW : public CollisionObject3DSW { VSet<RID> exceptions; + uint64_t island_step = 0; + public: SoftBody3DSW(); @@ -124,6 +126,9 @@ public: _FORCE_INLINE_ bool has_exception(const RID &p_exception) const { return exceptions.has(p_exception); } _FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; } + _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; } + virtual void set_space(Space3DSW *p_space); void set_mesh(const Ref<Mesh> &p_mesh); diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp index 9a73e11562..ba18bac611 100644 --- a/servers/physics_3d/step_3d_sw.cpp +++ b/servers/physics_3d/step_3d_sw.cpp @@ -33,109 +33,150 @@ #include "core/os/os.h" -void Step3DSW::_populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island) { +#define BODY_ISLAND_COUNT_RESERVE 128 +#define BODY_ISLAND_SIZE_RESERVE 512 +#define ISLAND_COUNT_RESERVE 128 +#define ISLAND_SIZE_RESERVE 512 +#define CONSTRAINT_COUNT_RESERVE 1024 + +void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) { p_body->set_island_step(_step); - p_body->set_island_next(*p_island); - *p_island = p_body; + + if (p_body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) { + // Only dynamic bodies are tested for activation. + p_body_island.push_back(p_body); + } for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) { - Constraint3DSW *c = (Constraint3DSW *)E->key(); - if (c->get_island_step() == _step) { - continue; //already processed + Constraint3DSW *constraint = (Constraint3DSW *)E->key(); + if (constraint->get_island_step() == _step) { + continue; // Already processed. } - c->set_island_step(_step); - c->set_island_next(*p_constraint_island); - *p_constraint_island = c; + constraint->set_island_step(_step); + p_constraint_island.push_back(constraint); - for (int i = 0; i < c->get_body_count(); i++) { + all_constraints.push_back(constraint); + + // Find connected rigid bodies. + for (int i = 0; i < constraint->get_body_count(); i++) { if (i == E->get()) { continue; } - Body3DSW *b = c->get_body_ptr()[i]; - if (b->get_island_step() == _step || b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) { - continue; //no go + Body3DSW *other_body = constraint->get_body_ptr()[i]; + if (other_body->get_island_step() == _step) { + continue; // Already processed. + } + if (other_body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) { + continue; // Static bodies don't connect islands. } - _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island); + _populate_island(other_body, p_body_island, p_constraint_island); + } + + // Find connected soft bodies. + for (int i = 0; i < constraint->get_soft_body_count(); i++) { + SoftBody3DSW *soft_body = constraint->get_soft_body_ptr(i); + if (soft_body->get_island_step() == _step) { + continue; // Already processed. + } + _populate_island_soft_body(soft_body, p_body_island, p_constraint_island); } } } -void Step3DSW::_setup_island(Constraint3DSW *p_island, real_t p_delta) { - Constraint3DSW *ci = p_island; - while (ci) { - ci->setup(p_delta); - //todo remove from island if process fails - ci = ci->get_island_next(); +void Step3DSW::_populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) { + p_soft_body->set_island_step(_step); + + for (Set<Constraint3DSW *>::Element *E = p_soft_body->get_constraints().front(); E; E = E->next()) { + Constraint3DSW *constraint = (Constraint3DSW *)E->get(); + if (constraint->get_island_step() == _step) { + continue; // Already processed. + } + constraint->set_island_step(_step); + p_constraint_island.push_back(constraint); + + all_constraints.push_back(constraint); + + // Find connected rigid bodies. + for (int i = 0; i < constraint->get_body_count(); i++) { + Body3DSW *body = constraint->get_body_ptr()[i]; + if (body->get_island_step() == _step) { + continue; // Already processed. + } + if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) { + continue; // Static bodies don't connect islands. + } + _populate_island(body, p_body_island, p_constraint_island); + } + } +} + +void Step3DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) { + Constraint3DSW *constraint = all_constraints[p_constraint_index]; + constraint->setup(delta); +} + +void Step3DSW::_pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const { + uint32_t constraint_count = p_constraint_island.size(); + uint32_t valid_constraint_count = 0; + for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { + Constraint3DSW *constraint = p_constraint_island[constraint_index]; + if (p_constraint_island[constraint_index]->pre_solve(delta)) { + // Keep this constraint for solving. + p_constraint_island[valid_constraint_count++] = constraint; + } } + p_constraint_island.resize(valid_constraint_count); } -void Step3DSW::_solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta) { - int at_priority = 1; +void Step3DSW::_solve_island(uint32_t p_island_index, void *p_userdata) { + LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[p_island_index]; - while (p_island) { - for (int i = 0; i < p_iterations; i++) { - Constraint3DSW *ci = p_island; - while (ci) { - ci->solve(p_delta); - ci = ci->get_island_next(); + int current_priority = 1; + + uint32_t constraint_count = constraint_island.size(); + while (constraint_count > 0) { + for (int i = 0; i < iterations; i++) { + // Go through all iterations. + for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { + constraint_island[constraint_index]->solve(delta); } } - at_priority++; - - { - Constraint3DSW *ci = p_island; - Constraint3DSW *prev = nullptr; - while (ci) { - if (ci->get_priority() < at_priority) { - if (prev) { - prev->set_island_next(ci->get_island_next()); //remove - } else { - p_island = ci->get_island_next(); - } - } else { - prev = ci; - } - - ci = ci->get_island_next(); + // Check priority to keep only higher priority constraints. + uint32_t priority_constraint_count = 0; + ++current_priority; + for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { + Constraint3DSW *constraint = constraint_island[constraint_index]; + if (constraint->get_priority() >= current_priority) { + // Keep this constraint for the next iteration. + constraint_island[priority_constraint_count++] = constraint; } } + constraint_count = priority_constraint_count; } } -void Step3DSW::_check_suspend(Body3DSW *p_island, real_t p_delta) { +void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island) const { bool can_sleep = true; - Body3DSW *b = p_island; - while (b) { - if (b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) { - b = b->get_island_next(); - continue; //ignore for static - } + uint32_t body_count = p_body_island.size(); + for (uint32_t body_index = 0; body_index < body_count; ++body_index) { + Body3DSW *body = p_body_island[body_index]; - if (!b->sleep_test(p_delta)) { + if (!body->sleep_test(delta)) { can_sleep = false; } - - b = b->get_island_next(); } - //put all to sleep or wake up everyoen - - b = p_island; - while (b) { - if (b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) { - b = b->get_island_next(); - continue; //ignore for static - } + // Put all to sleep or wake up everyone. + for (uint32_t body_index = 0; body_index < body_count; ++body_index) { + Body3DSW *body = p_body_island[body_index]; - bool active = b->is_active(); + bool active = body->is_active(); if (active == can_sleep) { - b->set_active(!can_sleep); + body->set_active(!can_sleep); } - - b = b->get_island_next(); } } @@ -144,6 +185,9 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { p_space->setup(); //update inertias, etc + iterations = p_iterations; + delta = p_delta; + const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list(); const SelfList<SoftBody3DSW>::List *soft_body_list = &p_space->get_active_soft_body_list(); @@ -179,81 +223,121 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { profile_begtime = profile_endtime; } - /* GENERATE CONSTRAINT ISLANDS */ + /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */ + + uint32_t island_count = 0; + + const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list(); + + while (aml.first()) { + for (const Set<Constraint3DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { + Constraint3DSW *constraint = E->get(); + if (constraint->get_island_step() == _step) { + continue; + } + constraint->set_island_step(_step); + + // Each constraint can be on a separate island for areas as there's no solving phase. + ++island_count; + if (constraint_islands.size() < island_count) { + constraint_islands.resize(island_count); + } + LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1]; + constraint_island.clear(); + + all_constraints.push_back(constraint); + constraint_island.push_back(constraint); + } + p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here + } + + /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */ - Body3DSW *island_list = nullptr; - Constraint3DSW *constraint_island_list = nullptr; b = body_list->first(); - int island_count = 0; + uint32_t body_island_count = 0; while (b) { Body3DSW *body = b->self(); if (body->get_island_step() != _step) { - Body3DSW *island = nullptr; - Constraint3DSW *constraint_island = nullptr; - _populate_island(body, &island, &constraint_island); - - island->set_island_list_next(island_list); - island_list = island; + ++body_island_count; + if (body_islands.size() < body_island_count) { + body_islands.resize(body_island_count); + } + LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1]; + body_island.clear(); + body_island.reserve(BODY_ISLAND_SIZE_RESERVE); - if (constraint_island) { - constraint_island->set_island_list_next(constraint_island_list); - constraint_island_list = constraint_island; - island_count++; + ++island_count; + if (constraint_islands.size() < island_count) { + constraint_islands.resize(island_count); } - } - b = b->next(); - } + LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1]; + constraint_island.clear(); + constraint_island.reserve(ISLAND_SIZE_RESERVE); - p_space->set_island_count(island_count); + _populate_island(body, body_island, constraint_island); - const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list(); + if (body_island.is_empty()) { + --body_island_count; + } - while (aml.first()) { - for (const Set<Constraint3DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { - Constraint3DSW *c = E->get(); - if (c->get_island_step() == _step) { - continue; + if (constraint_island.is_empty()) { + --island_count; } - c->set_island_step(_step); - c->set_island_next(nullptr); - c->set_island_list_next(constraint_island_list); - constraint_island_list = c; } - p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here + b = b->next(); } + /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE SOFT BODIES */ + sb = soft_body_list->first(); while (sb) { - for (const Set<Constraint3DSW *>::Element *E = sb->self()->get_constraints().front(); E; E = E->next()) { - Constraint3DSW *c = E->get(); - if (c->get_island_step() == _step) - continue; - c->set_island_step(_step); - c->set_island_next(NULL); - c->set_island_list_next(constraint_island_list); - constraint_island_list = c; + SoftBody3DSW *soft_body = sb->self(); + + if (soft_body->get_island_step() != _step) { + ++body_island_count; + if (body_islands.size() < body_island_count) { + body_islands.resize(body_island_count); + } + LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1]; + body_island.clear(); + body_island.reserve(BODY_ISLAND_SIZE_RESERVE); + + ++island_count; + if (constraint_islands.size() < island_count) { + constraint_islands.resize(island_count); + } + LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1]; + constraint_island.clear(); + constraint_island.reserve(ISLAND_SIZE_RESERVE); + + _populate_island_soft_body(soft_body, body_island, constraint_island); + + if (body_island.is_empty()) { + --body_island_count; + } + + if (constraint_island.is_empty()) { + --island_count; + } } sb = sb->next(); } + p_space->set_island_count((int)island_count); + { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } - /* SETUP CONSTRAINT ISLANDS */ + /* SETUP CONSTRAINTS / PROCESS COLLISIONS */ - { - Constraint3DSW *ci = constraint_island_list; - while (ci) { - _setup_island(ci, p_delta); - ci = ci->get_island_list_next(); - } - } + uint32_t total_contraint_count = all_constraints.size(); + work_pool.do_work(total_contraint_count, this, &Step3DSW::_setup_contraint, nullptr); { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); @@ -261,15 +345,21 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { profile_begtime = profile_endtime; } + /* PRE-SOLVE CONSTRAINT ISLANDS */ + + // Warning: This doesn't run on threads, because it involves thread-unsafe processing. + for (uint32_t island_index = 0; island_index < island_count; ++island_index) { + _pre_solve_island(constraint_islands[island_index]); + } + /* SOLVE CONSTRAINT ISLANDS */ - { - Constraint3DSW *ci = constraint_island_list; - while (ci) { - //iterating each island separatedly improves cache efficiency - _solve_island(ci, p_iterations, p_delta); - ci = ci->get_island_list_next(); - } + // Warning: _solve_island modifies the constraint islands for optimization purpose, + // their content is not reliable after these calls and shouldn't be used anymore. + if (island_count > 1) { + work_pool.do_work(island_count, this, &Step3DSW::_solve_island, nullptr); + } else if (island_count > 0) { + _solve_island(0); } { //profile @@ -289,12 +379,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { /* SLEEP / WAKE UP ISLANDS */ - { - Body3DSW *bi = island_list; - while (bi) { - _check_suspend(bi, p_delta); - bi = bi->get_island_list_next(); - } + for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) { + _check_suspend(body_islands[island_index]); } /* UPDATE SOFT BODY CONSTRAINTS */ @@ -311,6 +397,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { profile_begtime = profile_endtime; } + all_constraints.clear(); + p_space->update(); p_space->unlock(); _step++; @@ -318,4 +406,14 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { Step3DSW::Step3DSW() { _step = 1; + + body_islands.reserve(BODY_ISLAND_COUNT_RESERVE); + constraint_islands.reserve(ISLAND_COUNT_RESERVE); + all_constraints.reserve(CONSTRAINT_COUNT_RESERVE); + + work_pool.init(); +} + +Step3DSW::~Step3DSW() { + work_pool.finish(); } diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h index 55c48ec0eb..9c60004b24 100644 --- a/servers/physics_3d/step_3d_sw.h +++ b/servers/physics_3d/step_3d_sw.h @@ -33,17 +33,32 @@ #include "space_3d_sw.h" +#include "core/templates/local_vector.h" +#include "core/templates/thread_work_pool.h" + class Step3DSW { uint64_t _step; - void _populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island); - void _setup_island(Constraint3DSW *p_island, real_t p_delta); - void _solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta); - void _check_suspend(Body3DSW *p_island, real_t p_delta); + int iterations = 0; + real_t delta = 0.0; + + ThreadWorkPool work_pool; + + LocalVector<LocalVector<Body3DSW *>> body_islands; + LocalVector<LocalVector<Constraint3DSW *>> constraint_islands; + LocalVector<Constraint3DSW *> all_constraints; + + void _populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island); + void _populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island); + void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr); + void _pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const; + void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr); + void _check_suspend(const LocalVector<Body3DSW *> &p_body_island) const; public: void step(Space3DSW *p_space, real_t p_delta, int p_iterations); Step3DSW(); + ~Step3DSW(); }; #endif // STEP__SW_H diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 83ebc0c55b..384179f2c3 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -176,11 +176,11 @@ real_t PhysicsShapeQueryParameters2D::get_margin() const { return margin; } -void PhysicsShapeQueryParameters2D::set_collision_mask(int p_collision_mask) { +void PhysicsShapeQueryParameters2D::set_collision_mask(uint32_t p_collision_mask) { collision_mask = p_collision_mask; } -int PhysicsShapeQueryParameters2D::get_collision_mask() const { +uint32_t PhysicsShapeQueryParameters2D::get_collision_mask() const { return collision_mask; } @@ -647,7 +647,7 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer2D::body_set_omit_force_integration); ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer2D::body_is_omitting_force_integration); - ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant())); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 28f22ce06b..a5cf3f3a46 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -128,8 +128,8 @@ public: void set_margin(real_t p_margin); real_t get_margin() const; - void set_collision_mask(int p_collision_mask); - int get_collision_mask() const; + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; void set_collide_with_bodies(bool p_enable); bool is_collide_with_bodies_enabled() const; @@ -477,7 +477,7 @@ public: virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0; virtual bool body_is_omitting_force_integration(RID p_body) const = 0; - virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0; + virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0; virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 586845de99..80a9bd4c0b 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -172,11 +172,11 @@ real_t PhysicsShapeQueryParameters3D::get_margin() const { return margin; } -void PhysicsShapeQueryParameters3D::set_collision_mask(int p_collision_mask) { +void PhysicsShapeQueryParameters3D::set_collision_mask(uint32_t p_collision_mask) { collision_mask = p_collision_mask; } -int PhysicsShapeQueryParameters3D::get_collision_mask() const { +uint32_t PhysicsShapeQueryParameters3D::get_collision_mask() const { return collision_mask; } @@ -550,7 +550,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer3D::body_set_omit_force_integration); ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer3D::body_is_omitting_force_integration); - ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 69f5c1c0ad..c434109865 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -125,8 +125,8 @@ public: void set_margin(real_t p_margin); real_t get_margin() const; - void set_collision_mask(int p_collision_mask); - int get_collision_mask() const; + void set_collision_mask(uint32_t p_collision_mask); + uint32_t get_collision_mask() const; void set_exclude(const Vector<RID> &p_exclude); Vector<RID> get_exclude() const; @@ -486,7 +486,7 @@ public: virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0; virtual bool body_is_omitting_force_integration(RID p_body) const = 0; - virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0; + virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0; virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0; diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 7f3fc2f8f4..67003a6f64 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -923,10 +923,15 @@ void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transfo void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); + ERR_FAIL_COND(!p_mesh.is_valid()); Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>(); ERR_FAIL_COND(!m); m->mesh = p_mesh; + if (canvas_item->skeleton.is_valid()) { + m->mesh_instance = RSG::storage->mesh_instance_create(p_mesh); + RSG::storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton); + } m->texture = p_texture; @@ -996,8 +1001,30 @@ void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, boo void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - + if (canvas_item->skeleton == p_skeleton) { + return; + } canvas_item->skeleton = p_skeleton; + + Item::Command *c = canvas_item->commands; + + while (c) { + if (c->type == Item::Command::TYPE_MESH) { + Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c); + if (canvas_item->skeleton.is_valid()) { + if (cm->mesh_instance.is_null()) { + cm->mesh_instance = RSG::storage->mesh_instance_create(cm->mesh); + } + RSG::storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton); + } else { + if (cm->mesh_instance.is_valid()) { + RSG::storage->free(cm->mesh_instance); + cm->mesh_instance = RID(); + } + } + } + c = c->next; + } } void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) { diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index f08986b021..0e9ef616cb 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -246,10 +246,16 @@ public: RID mesh; Transform2D transform; Color modulate; + RID mesh_instance; RID texture; CommandMesh() { type = TYPE_MESH; } + ~CommandMesh() { + if (mesh_instance.is_valid()) { + RendererStorage::base_singleton->free(mesh_instance); + } + } }; struct CommandMultiMesh : public Command { @@ -262,7 +268,6 @@ public: struct CommandParticles : public Command { RID particles; - RID texture; CommandParticles() { type = TYPE_PARTICLES; } diff --git a/servers/rendering/renderer_rd/SCsub b/servers/rendering/renderer_rd/SCsub index 6a2e682c67..64e613ab91 100644 --- a/servers/rendering/renderer_rd/SCsub +++ b/servers/rendering/renderer_rd/SCsub @@ -4,4 +4,6 @@ Import("env") env.add_source_files(env.servers_sources, "*.cpp") +SConscript("forward_clustered/SCsub") +SConscript("forward_mobile/SCsub") SConscript("shaders/SCsub") diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index 0fdd864d47..2669a73014 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -86,13 +86,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() { Vector<uint8_t> vertex_data; vertex_data.resize(sizeof(float) * icosphere_vertex_count * 3); - copymem(vertex_data.ptrw(), icosphere_vertices, vertex_data.size()); + memcpy(vertex_data.ptrw(), icosphere_vertices, vertex_data.size()); sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); Vector<uint8_t> index_data; index_data.resize(sizeof(uint32_t) * icosphere_triangle_count * 3); - copymem(index_data.ptrw(), icosphere_triangle_indices, index_data.size()); + memcpy(index_data.ptrw(), icosphere_triangle_indices, index_data.size()); sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); @@ -130,13 +130,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() { Vector<uint8_t> vertex_data; vertex_data.resize(sizeof(float) * cone_vertex_count * 3); - copymem(vertex_data.ptrw(), cone_vertices, vertex_data.size()); + memcpy(vertex_data.ptrw(), cone_vertices, vertex_data.size()); cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); Vector<uint8_t> index_data; index_data.resize(sizeof(uint32_t) * cone_triangle_count * 3); - copymem(index_data.ptrw(), cone_triangle_indices, index_data.size()); + memcpy(index_data.ptrw(), cone_triangle_indices, index_data.size()); cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); @@ -184,13 +184,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() { Vector<uint8_t> vertex_data; vertex_data.resize(sizeof(float) * box_vertex_count * 3); - copymem(vertex_data.ptrw(), box_vertices, vertex_data.size()); + memcpy(vertex_data.ptrw(), box_vertices, vertex_data.size()); box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); Vector<uint8_t> index_data; index_data.resize(sizeof(uint32_t) * box_triangle_count * 3); - copymem(index_data.ptrw(), box_triangle_indices, index_data.size()); + memcpy(index_data.ptrw(), box_triangle_indices, index_data.size()); box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index bc304aedd8..563e08fdcb 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -226,7 +226,7 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te } void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { - zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); + memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); copy_to_fb.push_constant.use_section = true; copy_to_fb.push_constant.section[0] = p_uv_rect.position.x; @@ -247,7 +247,7 @@ void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer } void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { - zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); + memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); if (p_flip_y) { copy_to_fb.push_constant.flip_y = true; @@ -275,7 +275,7 @@ void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, } void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; } @@ -309,7 +309,7 @@ void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const } void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; copy.push_constant.section[1] = 0; @@ -329,7 +329,7 @@ void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, } void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; } @@ -353,7 +353,7 @@ void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_ } void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; } @@ -375,7 +375,7 @@ void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, } void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; copy.push_constant.section[1] = 0; @@ -397,7 +397,7 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i } void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); uint32_t base_flags = 0; copy.push_constant.section[0] = p_region.position.x; @@ -430,7 +430,7 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back } void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; uint32_t base_flags = 0; @@ -657,7 +657,7 @@ void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_bas } void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; copy.push_constant.section[1] = 0; @@ -694,7 +694,7 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe } void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { - zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant)); + memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); tonemap.push_constant.use_bcs = p_settings.use_bcs; tonemap.push_constant.bcs[0] = p_settings.brightness; @@ -1294,7 +1294,7 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size } void EffectsRD::cubemap_roughness(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) { - zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; roughness.push_constant.roughness = p_roughness; @@ -1368,7 +1368,7 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { SkyPushConstant sky_push_constant; - zeromem(&sky_push_constant, sizeof(SkyPushConstant)); + memset(&sky_push_constant, 0, sizeof(SkyPushConstant)); sky_push_constant.proj[0] = p_camera.matrix[2][0]; sky_push_constant.proj[1] = p_camera.matrix[0][0]; @@ -1510,7 +1510,7 @@ EffectsRD::EffectsRD() { copy_modes.push_back("\n#define MODE_CUBEMAP_ARRAY_TO_PANORAMA\n"); copy.shader.initialize(copy_modes); - zeromem(©.push_constant, sizeof(CopyPushConstant)); + memset(©.push_constant, 0, sizeof(CopyPushConstant)); copy.shader_version = copy.shader.version_create(); for (int i = 0; i < COPY_MODE_MAX; i++) { diff --git a/servers/rendering/renderer_rd/forward_clustered/SCsub b/servers/rendering/renderer_rd/forward_clustered/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/rendering/renderer_rd/forward_clustered/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 7a19495f48..16c6273ff6 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* renderer_scene_render_forward_clustered.cpp */ +/* render_forward_clustered.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,508 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "renderer_scene_render_forward_clustered.h" +#include "render_forward_clustered.h" #include "core/config/project_settings.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_server_default.h" -/* SCENE SHADER */ -void RendererSceneRenderForwardClustered::ShaderData::set_code(const String &p_code) { - //compile +using namespace RendererSceneRenderImplementation; - code = p_code; - valid = false; - ubo_size = 0; - uniforms.clear(); - uses_screen_texture = false; - - if (code == String()) { - return; //just invalid, but no error - } - - ShaderCompilerRD::GeneratedCode gen_code; - - int blend_mode = BLEND_MODE_MIX; - int depth_testi = DEPTH_TEST_ENABLED; - int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; - int cull = CULL_BACK; - - uses_point_size = false; - uses_alpha = false; - uses_blend_alpha = false; - uses_depth_pre_pass = false; - uses_discard = false; - uses_roughness = false; - uses_normal = false; - bool wireframe = false; - - unshaded = false; - uses_vertex = false; - uses_sss = false; - uses_transmittance = false; - uses_screen_texture = false; - uses_depth_texture = false; - uses_normal_texture = false; - uses_time = false; - writes_modelview_or_projection = false; - uses_world_coordinates = false; - - int depth_drawi = DEPTH_DRAW_OPAQUE; - - ShaderCompilerRD::IdentifierActions actions; - - actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD); - actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX); - actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB); - actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); - - actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); - actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); - - actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED); - actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE); - actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS); - - actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED); - - actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED); - actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT); - actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK); - - actions.render_mode_flags["unshaded"] = &unshaded; - actions.render_mode_flags["wireframe"] = &wireframe; - - actions.usage_flag_pointers["ALPHA"] = &uses_alpha; - actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; - - actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; - actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; - - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; - actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; - actions.usage_flag_pointers["DISCARD"] = &uses_discard; - actions.usage_flag_pointers["TIME"] = &uses_time; - actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; - actions.usage_flag_pointers["NORMAL"] = &uses_normal; - actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; - - actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; - actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; - - actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; - actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; - actions.write_flag_pointers["VERTEX"] = &uses_vertex; - - actions.uniforms = &uniforms; - - RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; - - Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); - - ERR_FAIL_COND(err != OK); - - if (version.is_null()) { - version = scene_singleton->shader.scene_shader.version_create(); - } - - depth_draw = DepthDraw(depth_drawi); - depth_test = DepthTest(depth_testi); - -#if 0 - print_line("**compiling shader:"); - print_line("**defines:\n"); - for (int i = 0; i < gen_code.defines.size(); i++) { - print_line(gen_code.defines[i]); - } - print_line("\n**uniforms:\n" + gen_code.uniforms); - print_line("\n**vertex_globals:\n" + gen_code.vertex_global); - print_line("\n**vertex_code:\n" + gen_code.vertex); - print_line("\n**fragment_globals:\n" + gen_code.fragment_global); - print_line("\n**fragment_code:\n" + gen_code.fragment); - print_line("\n**light_code:\n" + gen_code.light); -#endif - scene_singleton->shader.scene_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); - ERR_FAIL_COND(!scene_singleton->shader.scene_shader.version_is_valid(version)); - - ubo_size = gen_code.uniform_total_size; - ubo_offsets = gen_code.uniform_offsets; - texture_uniforms = gen_code.texture_uniforms; - - //blend modes - - // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage - if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { - blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; - } - - RD::PipelineColorBlendState::Attachment blend_attachment; - - switch (blend_mode) { - case BLEND_MODE_MIX: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - - } break; - case BLEND_MODE_ADD: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - uses_blend_alpha = true; //force alpha used because of blend - - } break; - case BLEND_MODE_SUB: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT; - blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - uses_blend_alpha = true; //force alpha used because of blend - - } break; - case BLEND_MODE_MUL: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; - uses_blend_alpha = true; //force alpha used because of blend - } break; - case BLEND_MODE_ALPHA_TO_COVERAGE: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; - } - } - - RD::PipelineColorBlendState blend_state_blend; - blend_state_blend.attachments.push_back(blend_attachment); - RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1); - RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2); - RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1); - RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2); - - //update pipelines - - RD::PipelineDepthStencilState depth_stencil_state; - - if (depth_test != DEPTH_TEST_DISABLED) { - depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; - } - - for (int i = 0; i < CULL_VARIANT_MAX; i++) { - RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = { - { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK }, - { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT }, - { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED } - }; - - RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull]; - - for (int j = 0; j < RS::PRIMITIVE_MAX; j++) { - RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = { - RD::RENDER_PRIMITIVE_POINTS, - RD::RENDER_PRIMITIVE_LINES, - RD::RENDER_PRIMITIVE_LINESTRIPS, - RD::RENDER_PRIMITIVE_TRIANGLES, - RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, - }; - - RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; - - for (int k = 0; k < SHADER_VERSION_MAX; k++) { - if (!static_cast<RendererSceneRenderForwardClustered *>(singleton)->shader.scene_shader.is_variant_enabled(k)) { - continue; - } - RD::PipelineRasterizationState raster_state; - raster_state.cull_mode = cull_mode_rd; - raster_state.wireframe = wireframe; - - RD::PipelineColorBlendState blend_state; - RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; - RD::PipelineMultisampleState multisample_state; - - if (uses_alpha || uses_blend_alpha) { - // only allow these flags to go through if we have some form of msaa - if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { - multisample_state.enable_alpha_to_coverage = true; - } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { - multisample_state.enable_alpha_to_coverage = true; - multisample_state.enable_alpha_to_one = true; - } - - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_blend; - if (depth_draw == DEPTH_DRAW_OPAQUE) { - depth_stencil.enable_depth_write = false; //alpha does not draw depth - } - } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { - if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, blend state contains nothing - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else { - blend_state = blend_state_opaque; //writes to normal and roughness in opaque way - } - } else { - pipelines[i][j][k].clear(); - continue; // do not use this version (will error if using it is attempted) - } - } else { - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_opaque; - } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, leave empty - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { - blend_state = blend_state_depth_normal_roughness; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { - blend_state = blend_state_depth_normal_roughness_giprobe; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { - blend_state = RD::PipelineColorBlendState(); //no color targets for SDF - } else { - //specular write - blend_state = blend_state_opaque_specular; - depth_stencil.enable_depth_test = false; - depth_stencil.enable_depth_write = false; - } - } - - RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); - pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); - } - } - } - - valid = true; -} - -void RendererSceneRenderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { - if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); - } else { - default_texture_params[p_name] = p_texture; - } -} - -void RendererSceneRenderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { - Map<int, StringName> order; - - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { - continue; - } - - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); - } else { - order[E->get().order] = E->key(); - } - } - - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); - p_param_list->push_back(pi); - } -} - -void RendererSceneRenderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; - } - - RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); - p_param_list->push_back(p); - } -} - -bool RendererSceneRenderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const { - if (!uniforms.has(p_param)) { - return false; - } - - return uniforms[p_param].texture_order >= 0; -} - -bool RendererSceneRenderForwardClustered::ShaderData::is_animated() const { - return false; -} - -bool RendererSceneRenderForwardClustered::ShaderData::casts_shadows() const { - return false; -} - -Variant RendererSceneRenderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const { - if (uniforms.has(p_parameter)) { - ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; - Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); - } - return Variant(); -} - -RS::ShaderNativeSourceCode RendererSceneRenderForwardClustered::ShaderData::get_native_source_code() const { - RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; - - return scene_singleton->shader.scene_shader.version_get_native_source_code(version); -} - -RendererSceneRenderForwardClustered::ShaderData::ShaderData() { - valid = false; - uses_screen_texture = false; -} - -RendererSceneRenderForwardClustered::ShaderData::~ShaderData() { - RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; - ERR_FAIL_COND(!scene_singleton); - //pipeline variants will clear themselves if shader is gone - if (version.is_valid()) { - scene_singleton->shader.scene_shader.version_free(version); - } -} - -RendererStorageRD::ShaderData *RendererSceneRenderForwardClustered::_create_shader_func() { - ShaderData *shader_data = memnew(ShaderData); - return shader_data; -} - -void RendererSceneRenderForwardClustered::MaterialData::set_render_priority(int p_priority) { - priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits -} - -void RendererSceneRenderForwardClustered::MaterialData::set_next_pass(RID p_pass) { - next_pass = p_pass; -} - -void RendererSceneRenderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; - - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); - } - - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); - - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); - } - - if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { - // This material does not require an uniform set, so don't create it. - return; - } - - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } - - Vector<RD::Uniform> uniforms; - - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } - - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); -} - -RendererSceneRenderForwardClustered::MaterialData::~MaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } -} - -RendererStorageRD::MaterialData *RendererSceneRenderForwardClustered::_create_material_func(ShaderData *p_shader) { - MaterialData *material_data = memnew(MaterialData); - material_data->shader_data = p_shader; - material_data->last_frame = false; - //update will happen later anyway so do nothing. - return material_data; -} - -RendererSceneRenderForwardClustered::RenderBufferDataForward::~RenderBufferDataForward() { +RenderForwardClustered::RenderBufferDataForwardClustered::~RenderBufferDataForwardClustered() { clear(); } -void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_specular() { +void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular() { if (!specular.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; @@ -583,7 +93,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_specul } } -void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_giprobe() { +void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() { if (!giprobe_buffer.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UINT; @@ -619,7 +129,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_giprob } } -void RendererSceneRenderForwardClustered::RenderBufferDataForward::clear() { +void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { if (giprobe_buffer != RID()) { RD::get_singleton()->free(giprobe_buffer); giprobe_buffer = RID(); @@ -673,7 +183,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::clear() { } } -void RendererSceneRenderForwardClustered::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { clear(); msaa = p_msaa; @@ -740,7 +250,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::configure(RID } } -void RendererSceneRenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) { +void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb) { if (rb->normal_roughness_buffer.is_valid()) { return; } @@ -774,15 +284,13 @@ void RendererSceneRenderForwardClustered::_allocate_normal_roughness_texture(Ren fb.push_back(rb->normal_roughness_buffer_msaa); rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); } - - _render_buffers_clear_uniform_set(rb); } -RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForwardClustered::_create_render_buffer_data() { - return memnew(RenderBufferDataForward); +RendererSceneRenderRD::RenderBufferData *RenderForwardClustered::_create_render_buffer_data() { + return memnew(RenderBufferDataForwardClustered); } -bool RendererSceneRenderForwardClustered::free(RID p_rid) { +bool RenderForwardClustered::free(RID p_rid) { if (RendererSceneRenderRD::free(p_rid)) { return true; } @@ -791,15 +299,15 @@ bool RendererSceneRenderForwardClustered::free(RID p_rid) { /// RENDERING /// -template <RendererSceneRenderForwardClustered::PassMode p_pass_mode> -void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { +template <RenderForwardClustered::PassMode p_pass_mode> +void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; //global scope bindings RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); RID prev_material_uniform_set; @@ -826,7 +334,7 @@ void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice: push_constant.base_index = i + p_params->element_offset; RID material_uniform_set; - ShaderData *shader; + SceneShaderForwardClustered::ShaderData *shader; void *mesh_surface; if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too @@ -845,59 +353,59 @@ void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice: } //find cull variant - ShaderData::CullVariant cull_variant; + SceneShaderForwardClustered::ShaderData::CullVariant cull_variant; if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { - cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; + cull_variant = SceneShaderForwardClustered::ShaderData::CULL_VARIANT_DOUBLE_SIDED; } else { bool mirror = surf->owner->mirror; if (p_params->reverse_cull) { mirror = !mirror; } - cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; + cull_variant = mirror ? SceneShaderForwardClustered::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardClustered::ShaderData::CULL_VARIANT_NORMAL; } RS::PrimitiveType primitive = surf->primitive; RID xforms_uniform_set = surf->owner->transforms_uniform_set; - ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. + SceneShaderForwardClustered::ShaderVersion shader_version = SceneShaderForwardClustered::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. switch (p_params->pass_mode) { case PASS_MODE_COLOR: case PASS_MODE_COLOR_TRANSPARENT: { if (element_info.uses_lightmap) { - shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS; } else if (element_info.uses_forward_gi) { - shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; } else { - shader_version = SHADER_VERSION_COLOR_PASS; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS; } } break; case PASS_MODE_COLOR_SPECULAR: { if (element_info.uses_lightmap) { - shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; } else { - shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; } } break; case PASS_MODE_SHADOW: case PASS_MODE_DEPTH: { - shader_version = SHADER_VERSION_DEPTH_PASS; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS; } break; case PASS_MODE_SHADOW_DP: { - shader_version = SHADER_VERSION_DEPTH_PASS_DP; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_DP; } break; case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; } break; case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE; } break; case PASS_MODE_DEPTH_MATERIAL: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; } break; case PASS_MODE_SDF: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_SDF; + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_SDF; } break; } @@ -956,12 +464,16 @@ void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice: RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant)); uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat; + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) { + instance_count /= surf->owner->trail_steps; + } + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); i += element_info.repeat - 1; //skip equal elements } } -void RendererSceneRenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { +void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { //use template for faster performance (pass mode comparisons are inlined) switch (p_params->pass_mode) { @@ -998,7 +510,7 @@ void RendererSceneRenderForwardClustered::_render_list(RenderingDevice::DrawList } } -void RendererSceneRenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { +void RenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { uint32_t render_total = p_params->element_count; uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); uint32_t render_from = p_thread * render_total / total_threads; @@ -1006,7 +518,7 @@ void RendererSceneRenderForwardClustered::_render_list_thread_function(uint32_t _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); } -void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { +void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); p_params->framebuffer_format = fb_format; @@ -1014,7 +526,7 @@ void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListPa //multi threaded thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForwardClustered::_render_list_thread_function, p_params); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardClustered::_render_list_thread_function, p_params); RD::get_singleton()->draw_list_end(p_params->barrier); } else { //single threaded @@ -1024,21 +536,21 @@ void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListPa } } -void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { - //CameraMatrix projection = p_cam_projection; +void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { + //CameraMatrix projection = p_render_data->cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down CameraMatrix correction; correction.set_depth_correction(p_flip_y); - CameraMatrix projection = correction * p_cam_projection; + CameraMatrix projection = correction * p_render_data->cam_projection; //store camera into ubo RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); - RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + RendererStorageRD::store_transform(p_render_data->cam_transform, scene_state.ubo.camera_matrix); + RendererStorageRD::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); - scene_state.ubo.z_far = p_zfar; - scene_state.ubo.z_near = p_znear; + scene_state.ubo.z_far = p_render_data->z_far; + scene_state.ubo.z_near = p_render_data->z_near; scene_state.ubo.pancake_shadows = p_pancake_shadows; @@ -1056,17 +568,17 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; - scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size); - scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32; + scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_render_data->cluster_size); + scene_state.ubo.max_cluster_element_count_div_32 = p_render_data->cluster_max_elements / 32; { - uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1; - uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1; + uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_render_data->cluster_size + 1; + uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_render_data->cluster_size + 1; scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32); scene_state.ubo.cluster_width = cluster_screen_width; } - if (p_shadow_atlas.is_valid()) { - Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); + if (p_render_data->shadow_atlas.is_valid()) { + Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas); scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; } @@ -1082,22 +594,22 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, scene_state.ubo.volumetric_fog_enabled = false; scene_state.ubo.fog_enabled = false; - if (p_render_buffers.is_valid()) { - RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + if (p_render_data->render_buffers.is_valid()) { + RenderBufferDataForwardClustered *render_buffers = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers); if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { scene_state.ubo.gi_upscale_for_msaa = true; } - if (render_buffers_has_volumetric_fog(p_render_buffers)) { + if (render_buffers_has_volumetric_fog(p_render_data->render_buffers)) { scene_state.ubo.volumetric_fog_enabled = true; - float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers); + float fog_end = render_buffers_get_volumetric_fog_end(p_render_data->render_buffers); if (fog_end > 0.0) { scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; } else { scene_state.ubo.volumetric_fog_inv_length = 1.0; } - float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup + float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_data->render_buffers); //reverse lookup if (fog_detail_spread > 0.0) { scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; } else { @@ -1106,26 +618,26 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, } } #if 0 - if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers); - scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers); + if (p_render_data->render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) { + scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_data->render_buffers); + scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_data->render_buffers); scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance scene_state.ubo.sdfgi_cascade_probe_size[1] = scene_state.ubo.sdfgi_probe_axis_size - 1; scene_state.ubo.sdfgi_cascade_probe_size[2] = scene_state.ubo.sdfgi_probe_axis_size - 1; - float csize = render_buffers_get_sdfgi_cascade_size(p_render_buffers); + float csize = render_buffers_get_sdfgi_cascade_size(p_render_data->render_buffers); scene_state.ubo.sdfgi_probe_to_uvw = 1.0 / float(scene_state.ubo.sdfgi_cascade_probe_size[0]); float occ_bias = 0.0; scene_state.ubo.sdfgi_occlusion_bias = occ_bias / csize; - scene_state.ubo.sdfgi_use_occlusion = render_buffers_is_sdfgi_using_occlusion(p_render_buffers); - scene_state.ubo.sdfgi_energy = render_buffers_get_sdfgi_energy(p_render_buffers); + scene_state.ubo.sdfgi_use_occlusion = render_buffers_is_sdfgi_using_occlusion(p_render_data->render_buffers); + scene_state.ubo.sdfgi_energy = render_buffers_get_sdfgi_energy(p_render_data->render_buffers); float cascade_voxel_size = (csize / scene_state.ubo.sdfgi_cascade_probe_size[0]); float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size; scene_state.ubo.sdfgi_occlusion_clamp[0] = occlusion_clamp; scene_state.ubo.sdfgi_occlusion_clamp[1] = occlusion_clamp; scene_state.ubo.sdfgi_occlusion_clamp[2] = occlusion_clamp; - scene_state.ubo.sdfgi_normal_bias = (render_buffers_get_sdfgi_normal_bias(p_render_buffers) / csize) * scene_state.ubo.sdfgi_cascade_probe_size[0]; + scene_state.ubo.sdfgi_normal_bias = (render_buffers_get_sdfgi_normal_bias(p_render_data->render_buffers) / csize) * scene_state.ubo.sdfgi_cascade_probe_size[0]; //vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) ); //vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx; @@ -1146,14 +658,14 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, for (uint32_t i = 0; i < scene_state.ubo.sdfgi_cascade_count; i++) { SceneState::UBO::SDFGICascade &c = scene_state.ubo.sdfgi_cascades[i]; - Vector3 pos = render_buffers_get_sdfgi_cascade_offset(p_render_buffers, i); - pos -= p_cam_transform.origin; //make pos local to camera, to reduce numerical error + Vector3 pos = render_buffers_get_sdfgi_cascade_offset(p_render_data->render_buffers, i); + pos -= p_render_data->cam_transform.origin; //make pos local to camera, to reduce numerical error c.position[0] = pos.x; c.position[1] = pos.y; c.position[2] = pos.z; - c.to_probe = 1.0 / render_buffers_get_sdfgi_cascade_probe_size(p_render_buffers, i); + c.to_probe = 1.0 / render_buffers_get_sdfgi_cascade_probe_size(p_render_data->render_buffers, i); - Vector3i probe_ofs = render_buffers_get_sdfgi_cascade_probe_offset(p_render_buffers, i); + Vector3i probe_ofs = render_buffers_get_sdfgi_cascade_probe_offset(p_render_data->render_buffers, i); c.probe_world_offset[0] = probe_ofs.x; c.probe_world_offset[1] = probe_ofs.y; c.probe_world_offset[2] = probe_ofs.z; @@ -1170,18 +682,18 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, scene_state.ubo.use_reflection_cubemap = false; scene_state.ubo.ssao_enabled = false; - } else if (is_environment(p_environment)) { - RS::EnvironmentBG env_bg = environment_get_background(p_environment); - RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment); + } else if (is_environment(p_render_data->environment)) { + RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment); + RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment); - float bg_energy = environment_get_bg_energy(p_environment); + float bg_energy = environment_get_bg_energy(p_render_data->environment); scene_state.ubo.ambient_light_color_energy[3] = bg_energy; - scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_environment); + scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment); //ambient if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { - Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_environment); + Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment); color = color.to_linear(); scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy; @@ -1190,15 +702,15 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, scene_state.ubo.use_ambient_light = true; scene_state.ubo.use_ambient_cubemap = false; } else { - float energy = environment_get_ambient_light_energy(p_environment); - Color color = environment_get_ambient_light_color(p_environment); + float energy = environment_get_ambient_light_energy(p_render_data->environment); + Color color = environment_get_ambient_light_color(p_render_data->environment); color = color.to_linear(); scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; scene_state.ubo.ambient_light_color_energy[1] = color.g * energy; scene_state.ubo.ambient_light_color_energy[2] = color.b * energy; - Basis sky_transform = environment_get_sky_orientation(p_environment); - sky_transform = sky_transform.inverse() * p_cam_transform.basis; + Basis sky_transform = environment_get_sky_orientation(p_render_data->environment); + sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis; RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; @@ -1206,43 +718,43 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, } //specular - RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_environment); + RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment); if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { scene_state.ubo.use_reflection_cubemap = true; } else { scene_state.ubo.use_reflection_cubemap = false; } - scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_environment); - scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_environment); - scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_environment); + scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_render_data->environment); + scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment); + scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment); - Color ao_color = environment_get_ao_color(p_environment).to_linear(); + Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear(); scene_state.ubo.ao_color[0] = ao_color.r; scene_state.ubo.ao_color[1] = ao_color.g; scene_state.ubo.ao_color[2] = ao_color.b; scene_state.ubo.ao_color[3] = ao_color.a; - scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); - scene_state.ubo.fog_density = environment_get_fog_density(p_environment); - scene_state.ubo.fog_height = environment_get_fog_height(p_environment); - scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment); + scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment); + scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); + scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment); + scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment); if (scene_state.ubo.fog_height_density >= 0.0001) { scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; } - scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); + scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment); - Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); - float fog_energy = environment_get_fog_light_energy(p_environment); + Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear(); + float fog_energy = environment_get_fog_light_energy(p_render_data->environment); scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; - scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); + scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment); } else { - if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { + if (p_render_data->reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { scene_state.ubo.use_ambient_light = false; } else { scene_state.ubo.use_ambient_light = true; @@ -1274,7 +786,7 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); } -void RendererSceneRenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) { +void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) { if (scene_state.instance_data[p_render_list].size() > 0) { if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) { if (scene_state.instance_buffer[p_render_list] != RID()) { @@ -1287,7 +799,7 @@ void RendererSceneRenderForwardClustered::_update_instance_data_buffer(RenderLis RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); } } -void RendererSceneRenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { +void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { RenderList *rl = &render_list[p_render_list]; uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); @@ -1355,7 +867,7 @@ void RendererSceneRenderForwardClustered::_fill_instance_data(RenderListType p_r } } -void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) { +void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) { if (p_render_list == RENDER_LIST_OPAQUE) { scene_state.used_sss = false; scene_state.used_screen_texture = false; @@ -1364,9 +876,9 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren } uint32_t lightmap_captures_used = 0; - Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); - near_plane.d += p_cam_projection.get_z_near(); - float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near(); + Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); + near_plane.d += p_render_data->cam_projection.get_z_near(); + float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near(); RenderList *rl = &render_list[p_render_list]; _update_dirty_geometry_instances(); @@ -1380,8 +892,8 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren //fill list - for (int i = 0; i < (int)p_instances.size(); i++) { - GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>(p_instances[i]); + for (int i = 0; i < (int)p_render_data->instances->size(); i++) { + GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>((*p_render_data->instances)[i]); Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); inst->depth = near_plane.distance_to(support_min); @@ -1431,7 +943,7 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren uses_lightmap = true; } - } else if (!low_end) { + } else { if (p_using_opaque_gi) { flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; } @@ -1475,13 +987,13 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren // LOD - if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) { + if (p_render_data->screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) { //lod - Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_lod_plane.normal); - Vector3 lod_support_max = inst->transformed_aabb.get_support(p_lod_plane.normal); + Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal); + Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal); - float distance_min = p_lod_plane.distance_to(lod_support_min); - float distance_max = p_lod_plane.distance_to(lod_support_max); + float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min); + float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max); float distance = 0.0; @@ -1494,7 +1006,7 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren distance = -distance_max; } - surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold); + surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); } else { surf->sort.lod_index = 0; } @@ -1549,14 +1061,14 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren } } -void RendererSceneRenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) { +void RenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) { scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { scene_state.giprobe_ids[i] = p_giprobes[i]; } } -void RendererSceneRenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { +void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { scene_state.lightmaps_used = 0; for (int i = 0; i < (int)p_lightmaps.size(); i++) { if (i >= (int)scene_state.max_lightmaps) { @@ -1578,28 +1090,21 @@ void RendererSceneRenderForwardClustered::_setup_lightmaps(const PagedArray<RID> } } -void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) { - RenderBufferDataForward *render_buffer = nullptr; - if (p_render_buffer.is_valid()) { - render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); +void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { + RenderBufferDataForwardClustered *render_buffer = nullptr; + if (p_render_data->render_buffers.is_valid()) { + render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers); } - RendererSceneEnvironmentRD *env = get_environment(p_environment); + RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment); //first of all, make a new render pass //fill up ubo RENDER_TIMESTAMP("Setup 3D Scene"); - float lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); - Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - p_screen_lod_threshold = 0.0; - } - //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; - Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); + Vector2 vp_he = p_render_data->cam_projection.get_viewport_half_extents(); scene_state.ubo.viewport_size[0] = vp_he.x; scene_state.ubo.viewport_size[1] = vp_he.y; scene_state.ubo.directional_light_count = 0; @@ -1616,6 +1121,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con bool using_ssr = false; bool using_sdfgi = false; bool using_giprobe = false; + bool reverse_cull = false; if (render_buffer) { screen_size.x = render_buffer->width; @@ -1623,29 +1129,29 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con opaque_framebuffer = render_buffer->color_fb; - if (!low_end && p_gi_probes.size() > 0) { + if (p_render_data->gi_probes->size() > 0) { using_giprobe = true; } - if (!p_environment.is_valid() && using_giprobe) { + if (!p_render_data->environment.is_valid() && using_giprobe) { depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE; - } else if (p_environment.is_valid() && (environment_is_ssr_enabled(p_environment) || environment_is_sdfgi_enabled(p_environment) || using_giprobe)) { - if (environment_is_sdfgi_enabled(p_environment)) { + } else if (p_render_data->environment.is_valid() && (environment_is_ssr_enabled(p_render_data->environment) || environment_is_sdfgi_enabled(p_render_data->environment) || using_giprobe)) { + if (environment_is_sdfgi_enabled(p_render_data->environment)) { depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe using_sdfgi = true; } else { depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } - if (environment_is_ssr_enabled(p_environment)) { + if (environment_is_ssr_enabled(p_render_data->environment)) { render_buffer->ensure_specular(); using_separate_specular = true; using_ssr = true; opaque_specular_framebuffer = render_buffer->color_specular_fb; } - } else if (p_environment.is_valid() && (environment_is_ssao_enabled(p_environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { + } else if (p_render_data->environment.is_valid() && (environment_is_ssao_enabled(p_render_data->environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } @@ -1670,31 +1176,34 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con } alpha_framebuffer = opaque_framebuffer; - } else if (p_reflection_probe.is_valid()) { - uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe); + } else if (p_render_data->reflection_probe.is_valid()) { + uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe); screen_size.x = resolution; screen_size.y = resolution; - opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass); - depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_reflection_probe, p_reflection_probe_pass); + opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); + depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); alpha_framebuffer = opaque_framebuffer; - if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { - p_environment = RID(); //no environment on interiors + if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + p_render_data->environment = RID(); //no environment on interiors + env = nullptr; } + + reverse_cull = true; // for some reason our views are inverted } else { ERR_FAIL(); //bug? } RD::get_singleton()->draw_command_begin_label("Render Setup"); - _setup_lightmaps(p_lightmaps, p_cam_transform); - _setup_giprobes(p_gi_probes); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform); + _setup_giprobes(*p_render_data->gi_probes); + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) - _fill_render_list(RENDER_LIST_OPAQUE, p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe, lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_giprobe); render_list[RENDER_LIST_OPAQUE].sort_by_key(); render_list[RENDER_LIST_ALPHA].sort_by_depth(); _fill_instance_data(RENDER_LIST_OPAQUE); @@ -1702,7 +1211,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con RD::get_singleton()->draw_command_end_label(); - bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; if (using_sss) { using_separate_specular = true; @@ -1719,26 +1228,26 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black - } else if (is_environment(p_environment)) { - RS::EnvironmentBG bg_mode = environment_get_background(p_environment); - float bg_energy = environment_get_bg_energy(p_environment); + } else if (is_environment(p_render_data->environment)) { + RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment); + float bg_energy = environment_get_bg_energy(p_render_data->environment); switch (bg_mode) { case RS::ENV_BG_CLEAR_COLOR: { clear_color = p_default_bg_color; clear_color.r *= bg_energy; clear_color.g *= bg_energy; clear_color.b *= bg_energy; - if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { + if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); } } break; case RS::ENV_BG_COLOR: { - clear_color = environment_get_bg_color(p_environment); + clear_color = environment_get_bg_color(p_render_data->environment); clear_color.r *= bg_energy; clear_color.g *= bg_energy; clear_color.b *= bg_energy; - if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { + if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); } @@ -1758,21 +1267,21 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con } } // setup sky if used for ambient, reflections, or background - if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); RD::get_singleton()->draw_command_begin_label("Setup Sky"); - CameraMatrix projection = p_cam_projection; - if (p_reflection_probe.is_valid()) { + CameraMatrix projection = p_render_data->cam_projection; + if (p_render_data->reflection_probe.is_valid()) { CameraMatrix correction; correction.set_depth_correction(true); - projection = correction * p_cam_projection; + projection = correction * p_render_data->cam_projection; } - sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this); + sky.setup(env, p_render_data->render_buffers, projection, p_render_data->cam_transform, screen_size, this); RID sky_rid = env->sky; if (sky_rid.is_valid()) { - sky.update(env, projection, p_cam_transform, time); + sky.update(env, projection, p_render_data->cam_transform, time); radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid); } else { // do not try to draw sky if invalid @@ -1786,13 +1295,13 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; - bool depth_pre_pass = !low_end && depth_framebuffer.is_valid(); + bool depth_pre_pass = depth_framebuffer.is_valid(); - bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); + bool using_ssao = depth_pre_pass && p_render_data->render_buffers.is_valid() && p_render_data->environment.is_valid() && environment_is_ssao_enabled(p_render_data->environment); bool continue_depth = false; if (depth_pre_pass) { //depth pre pass - bool needs_pre_resolve = _needs_post_prepass_render(using_sdfgi || using_giprobe); + bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_giprobe); if (needs_pre_resolve) { RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)"); } else { @@ -1803,21 +1312,21 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); RD::get_singleton()->draw_list_end(); //start compute processes here, so they run at the same time as depth pre-pass - _post_prepass_render(using_sdfgi || using_giprobe); + _post_prepass_render(p_render_data, using_sdfgi || using_giprobe); } RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID()); bool finish_depth = using_ssao || using_sdfgi || using_giprobe; - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear); RD::get_singleton()->draw_command_end_label(); if (needs_pre_resolve) { - _pre_resolve_render(using_sdfgi || using_giprobe); + _pre_resolve_render(p_render_data, using_sdfgi || using_giprobe); } if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -1838,17 +1347,17 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con continue_depth = !finish_depth; } - _pre_opaque_render(using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID()); + _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID()); RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); - scene_state.ubo.directional_light_count = _get_render_state_directional_light_count(); + scene_state.ubo.directional_light_count = p_render_data->directional_light_count; - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid()); RENDER_TIMESTAMP("Render Opaque Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true); bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; @@ -1869,7 +1378,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con } RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); _render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); if (will_continue_color && using_separate_specular) { // close the specular framebuffer, as it's no longer used @@ -1887,11 +1396,11 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con CameraMatrix dc; dc.set_depth_correction(true); - CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); + CameraMatrix cm = (dc * p_render_data->cam_projection) * CameraMatrix(p_render_data->cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); RD::get_singleton()->draw_command_begin_label("Debug GIProbes"); - for (int i = 0; i < (int)p_gi_probes.size(); i++) { - gi.debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); + for (int i = 0; i < (int)p_render_data->gi_probes->size(); i++) { + gi.debug_giprobe((*p_render_data->gi_probes)[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); } RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); @@ -1904,10 +1413,10 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con CameraMatrix dc; dc.set_depth_correction(true); - CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); + CameraMatrix cm = (dc * p_render_data->cam_projection) * CameraMatrix(p_render_data->cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); RD::get_singleton()->draw_command_begin_label("Debug SDFGI"); - _debug_sdfgi_probes(p_render_buffer, draw_list, opaque_framebuffer, cm); + _debug_sdfgi_probes(p_render_data->render_buffers, draw_list, opaque_framebuffer, cm); RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); } @@ -1915,14 +1424,14 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con if (draw_sky || draw_sky_fog_only) { RENDER_TIMESTAMP("Render Sky"); - CameraMatrix projection = p_cam_projection; - if (p_reflection_probe.is_valid()) { + CameraMatrix projection = p_render_data->cam_projection; + if (p_render_data->reflection_probe.is_valid()) { CameraMatrix correction; correction.set_depth_correction(true); - projection = correction * p_cam_projection; + projection = correction * p_render_data->cam_projection; } RD::get_singleton()->draw_command_begin_label("Draw Sky"); - sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time); + sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_render_data->cam_transform, time); RD::get_singleton()->draw_command_end_label(); } @@ -1941,14 +1450,14 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con if (using_sss) { RENDER_TIMESTAMP("Sub Surface Scattering"); RD::get_singleton()->draw_command_begin_label("Process Sub Surface Scattering"); - _process_sss(p_render_buffer, p_cam_projection); + _process_sss(p_render_data->render_buffers, p_render_data->cam_projection); RD::get_singleton()->draw_command_end_label(); } if (using_ssr) { RENDER_TIMESTAMP("Screen Space Reflection"); RD::get_singleton()->draw_command_begin_label("Process Screen Space Reflections"); - _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); + _process_ssr(p_render_data->render_buffers, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); RD::get_singleton()->draw_command_end_label(); } else { //just mix specular back @@ -1961,12 +1470,12 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); - rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); + rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); { - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); } @@ -1981,7 +1490,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_render_shadow_begin() { +void RenderForwardClustered::_render_shadow_begin() { scene_state.shadow_passes.clear(); RD::get_singleton()->draw_command_begin_label("Shadow Setup"); _update_render_base_uniform_set(); @@ -1989,23 +1498,36 @@ void RendererSceneRenderForwardClustered::_render_shadow_begin() { render_list[RENDER_LIST_SECONDARY].clear(); scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); } -void RendererSceneRenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { +void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; + RenderDataRD render_data; + render_data.cam_projection = p_projection; + render_data.cam_transform = p_transform; + render_data.z_far = p_zfar; + render_data.z_near = 0.0; + render_data.cluster_size = 1; + render_data.cluster_max_elements = 32; + render_data.instances = &p_instances; + render_data.lod_camera_plane = p_camera_plane; + render_data.lod_distance_multiplier = p_lod_distance_multiplier; + scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake, shadow_pass_index); + _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - p_screen_lod_threshold = 0.0; + render_data.screen_lod_threshold = 0.0; + } else { + render_data.screen_lod_threshold = p_screen_lod_threshold; } PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size(); - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_projection, p_transform, false, false, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, true); + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, true); uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); @@ -2024,8 +1546,8 @@ void RendererSceneRenderForwardClustered::_render_shadow_append(RID p_framebuffe shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete shadow_pass.camera_plane = p_camera_plane; - shadow_pass.screen_lod_threshold = p_screen_lod_threshold; - shadow_pass.lod_distance_multiplier = p_lod_distance_multiplier; + shadow_pass.screen_lod_threshold = render_data.screen_lod_threshold; + shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier; shadow_pass.framebuffer = p_framebuffer; shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); @@ -2036,19 +1558,19 @@ void RendererSceneRenderForwardClustered::_render_shadow_append(RID p_framebuffe } } -void RendererSceneRenderForwardClustered::_render_shadow_process() { +void RenderForwardClustered::_render_shadow_process() { _update_instance_data_buffer(RENDER_LIST_SECONDARY); //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time) for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { //render passes need to be configured after instance buffer is done, since they need the latest version SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; - shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>(), false, i); + shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i); } RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_render_shadow_end(uint32_t p_barrier) { +void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) { RD::get_singleton()->draw_command_begin_label("Shadow Render"); for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { @@ -2063,23 +1585,32 @@ void RendererSceneRenderForwardClustered::_render_shadow_end(uint32_t p_barrier) RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { +void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { RENDER_TIMESTAMP("Setup Render Collider Heightfield"); RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); + RenderDataRD render_data; + render_data.cam_projection = p_cam_projection; + render_data.cam_transform = p_cam_transform; + render_data.z_near = 0.0; + render_data.z_far = p_cam_projection.get_z_far(); + render_data.cluster_size = 1; + render_data.cluster_max_elements = 32; + render_data.instances = &p_instances; + _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); + _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false); PassMode pass_mode = PASS_MODE_SHADOW; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); _fill_instance_data(RENDER_LIST_SECONDARY); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); RENDER_TIMESTAMP("Render Collider Heightfield"); @@ -2091,24 +1622,31 @@ void RendererSceneRenderForwardClustered::_render_particle_collider_heightfield( RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { +void RenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering Material"); RD::get_singleton()->draw_command_begin_label("Render Material"); + RenderDataRD render_data; + render_data.cam_projection = p_cam_projection; + render_data.cam_transform = p_cam_transform; + render_data.cluster_size = 1; + render_data.cluster_max_elements = 32; + render_data.instances = &p_instances; + _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = false; - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); _fill_instance_data(RENDER_LIST_SECONDARY); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); RENDER_TIMESTAMP("Render Material"); @@ -2129,24 +1667,29 @@ void RendererSceneRenderForwardClustered::_render_material(const Transform &p_ca RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { +void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering UV2"); RD::get_singleton()->draw_command_begin_label("Render UV2"); + RenderDataRD render_data; + render_data.cluster_size = 1; + render_data.cluster_max_elements = 32; + render_data.instances = &p_instances; + _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = true; - _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); _fill_instance_data(RENDER_LIST_SECONDARY); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); RENDER_TIMESTAMP("Render Material"); @@ -2183,6 +1726,7 @@ void RendererSceneRenderForwardClustered::_render_uv2(const PagedArray<GeometryI _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative } render_list_params.uv_offset = Vector2(); + render_list_params.force_wireframe = false; _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles RD::get_singleton()->draw_list_end(); @@ -2191,18 +1735,23 @@ void RendererSceneRenderForwardClustered::_render_uv2(const PagedArray<GeometryI RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { +void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { RENDER_TIMESTAMP("Render SDFGI"); RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel"); + RenderDataRD render_data; + render_data.cluster_size = 1; + render_data.cluster_max_elements = 32; + render_data.instances = &p_instances; + _update_render_base_uniform_set(); - RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForwardClustered *render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers); ERR_FAIL_COND(!render_buffer); PassMode pass_mode = PASS_MODE_SDF; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); _fill_instance_data(RENDER_LIST_SECONDARY); @@ -2234,28 +1783,26 @@ void RendererSceneRenderForwardClustered::_render_sdfgi(RID p_render_buffers, co fb_size.x = p_size[right_axis]; fb_size.y = p_size[up_axis]; - Transform cam_xform; - cam_xform.origin = center + axis * half_extents; - cam_xform.basis.set_axis(0, right); - cam_xform.basis.set_axis(1, up); - cam_xform.basis.set_axis(2, axis); + render_data.cam_transform.origin = center + axis * half_extents; + render_data.cam_transform.basis.set_axis(0, right); + render_data.cam_transform.basis.set_axis(1, up); + render_data.cam_transform.basis.set_axis(2, axis); - //print_line("pass: " + itos(i) + " xform " + cam_xform); + //print_line("pass: " + itos(i) + " xform " + render_data.cam_transform); float h_size = half_extents[right_axis]; float v_size = half_extents[up_axis]; float d_size = half_extents[i] * 2.0; - CameraMatrix camera_proj; - camera_proj.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); + render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); //print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size)); Transform to_bounds; to_bounds.origin = p_bounds.position; to_bounds.basis.scale(p_bounds.size); - RendererStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); + RendererStorageRD::store_transform(to_bounds.affine_inverse() * render_data.cam_transform, scene_state.ubo.sdf_to_bounds); - _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); @@ -2272,14 +1819,14 @@ void RendererSceneRenderForwardClustered::_render_sdfgi(RID p_render_buffers, co RD::get_singleton()->draw_command_end_label(); } -void RendererSceneRenderForwardClustered::_base_uniforms_changed() { +void RenderForwardClustered::_base_uniforms_changed() { if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } render_base_uniform_set = RID(); } -void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() { +void RenderForwardClustered::_update_render_base_uniform_set() { if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); @@ -2314,7 +1861,7 @@ void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() { RD::Uniform u; u.binding = 2; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.ids.push_back(shadow_sampler); + u.ids.push_back(scene_shader.shadow_sampler); uniforms.push_back(u); } @@ -2393,7 +1940,7 @@ void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() { uniforms.push_back(u); } - if (!low_end) { + { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 13; @@ -2401,17 +1948,17 @@ void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() { uniforms.push_back(u); } - render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET); + render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET); } } -RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) { +RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) { //there should always be enough uniform buffers for render passes, otherwise bugs ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID()); - RenderBufferDataForward *rb = nullptr; - if (p_render_buffers.is_valid()) { - rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForwardClustered *rb = nullptr; + if (p_render_data && p_render_data->render_buffers.is_valid()) { + rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers); } //default render buffer and scene state uniform set @@ -2431,7 +1978,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; RID instance_buffer = scene_state.instance_buffer[p_render_list]; if (instance_buffer == RID()) { - instance_buffer = default_vec4_xform_buffer; // any buffer will do since its not used + instance_buffer = scene_shader.default_vec4_xform_buffer; // any buffer will do since its not used } u.ids.push_back(instance_buffer); uniforms.push_back(u); @@ -2451,7 +1998,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi } { - RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID(); RD::Uniform u; u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; @@ -2468,8 +2015,8 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi u.binding = 4; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; - if (p_shadow_atlas.is_valid()) { - texture = shadow_atlas_get_texture(p_shadow_atlas); + if (p_render_data && p_render_data->shadow_atlas.is_valid()) { + texture = shadow_atlas_get_texture(p_render_data->shadow_atlas); } if (!texture.is_valid()) { texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); @@ -2495,8 +2042,8 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi u.ids.resize(scene_state.max_lightmaps); RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { - if (i < p_lightmaps.size()) { - RID base = lightmap_instance_get_lightmap(p_lightmaps[i]); + if (p_render_data && i < p_render_data->lightmaps->size()) { + RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]); RID texture = storage->lightmap_get_texture(base); RID rd_texture = storage->texture_get_rd_texture(texture); u.ids.write[i] = rd_texture; @@ -2514,8 +2061,8 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi u.ids.resize(MAX_GI_PROBES); RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); for (int i = 0; i < MAX_GI_PROBES; i++) { - if (i < (int)p_gi_probes.size()) { - RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]); + if (p_render_data && i < (int)p_render_data->gi_probes->size()) { + RID tex = gi.gi_probe_instance_get_texture((*p_render_data->gi_probes)[i]); if (!tex.is_valid()) { tex = default_tex; } @@ -2532,7 +2079,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; + RID cb = (p_render_data && p_render_data->cluster_buffer.is_valid()) ? p_render_data->cluster_buffer : scene_shader.default_vec4_xform_buffer; u.ids.push_back(cb); uniforms.push_back(u); } @@ -2549,13 +2096,13 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 10; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); + RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_data->render_buffers) : RID(); RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } - if (!low_end) { + { { RD::Uniform u; u.binding = 11; @@ -2569,7 +2116,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 12; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); + RID aot = rb ? render_buffers_get_ao_texture(p_render_data->render_buffers) : RID(); RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); @@ -2579,7 +2126,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 13; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID ambient_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_ambient_texture(p_render_buffers) : RID(); + RID ambient_buffer = rb ? render_buffers_get_gi_ambient_texture(p_render_data->render_buffers) : RID(); RID texture = ambient_buffer.is_valid() ? ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); @@ -2589,7 +2136,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 14; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID reflection_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_reflection_texture(p_render_buffers) : RID(); + RID reflection_buffer = rb ? render_buffers_get_gi_reflection_texture(p_render_data->render_buffers) : RID(); RID texture = reflection_buffer.is_valid() ? reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); @@ -2599,8 +2146,8 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi u.binding = 15; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID t; - if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers); + if (rb && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) { + t = render_buffers_get_sdfgi_irradiance_probes(p_render_data->render_buffers); } else { t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); } @@ -2611,8 +2158,8 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 16; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); + if (rb && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) { + u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_data->render_buffers)); } else { u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } @@ -2622,7 +2169,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::Uniform u; u.binding = 17; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer()); + u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_data->render_buffers) : render_buffers_get_default_gi_probe_buffer()); uniforms.push_back(u); } { @@ -2630,8 +2177,8 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi u.binding = 18; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID vfog = RID(); - if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { - vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); + if (rb && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) { + vfog = render_buffers_get_volumetric_fog_texture(p_render_data->render_buffers); if (vfog.is_null()) { vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } @@ -2651,11 +2198,11 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi RD::get_singleton()->free(render_pass_uniform_sets[p_index]); } - render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); + render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET); return render_pass_uniform_sets[p_index]; } -RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { +RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { RD::get_singleton()->free(sdfgi_pass_uniform_set); } @@ -2748,7 +2295,7 @@ RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RI RD::Uniform u; u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - RID cb = default_vec4_xform_buffer; + RID cb = scene_shader.default_vec4_xform_buffer; u.ids.push_back(cb); uniforms.push_back(u); } @@ -2784,28 +2331,19 @@ RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RI uniforms.push_back(u); } - sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET); + sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET); return sdfgi_pass_uniform_set; } -void RendererSceneRenderForwardClustered::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) { -} - -void RendererSceneRenderForwardClustered::_render_buffers_uniform_set_changed(RID p_render_buffers) { - RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); - - _render_buffers_clear_uniform_set(rb); -} - -RID RendererSceneRenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) { - RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); +RID RenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) { + RenderBufferDataForwardClustered *rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers); return rb->normal_roughness_buffer; } -RendererSceneRenderForwardClustered *RendererSceneRenderForwardClustered::singleton = nullptr; +RenderForwardClustered *RenderForwardClustered::singleton = nullptr; -void RendererSceneRenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { +void RenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); if (ginstance->dirty_list_element.in_list()) { return; @@ -2825,7 +2363,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_mark_dirty(Geometry geometry_instance_dirty_list.add(&ginstance->dirty_list_element); } -void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { +void RenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; @@ -2853,10 +2391,10 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_ma flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; } - if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) { + if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED) { //material is only meant for alpha pass flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) { + if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) { flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; } @@ -2866,11 +2404,15 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_ma flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; } - MaterialData *material_shadow = nullptr; + if (p_material->shader_data->uses_particle_trails) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS; + } + + SceneShaderForwardClustered::MaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; - material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + material_shadow = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D); RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh); @@ -2921,15 +2463,15 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_ma sdcache->sort.priority = p_material->priority; } -void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { +void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { RID m_src; m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; - MaterialData *material = nullptr; + SceneShaderForwardClustered::MaterialData *material = nullptr; if (m_src.is_valid()) { - material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2940,8 +2482,8 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(Geometr storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); } } else { - material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - m_src = default_material; + material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D); + m_src = scene_shader.default_material; } ERR_FAIL_COND(!material); @@ -2950,7 +2492,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(Geometr while (material->next_pass.is_valid()) { RID next_pass = material->next_pass; - material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); if (!material || !material->shader_data->valid) { break; } @@ -2961,7 +2503,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(Geometr } } -void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) { +void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); if (ginstance->data->dirty_dependencies) { @@ -3022,8 +2564,9 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst for (int j = 0; j < draw_passes; j++) { RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); - if (!mesh.is_valid()) + if (!mesh.is_valid()) { continue; + } const RID *materials = nullptr; uint32_t surface_count; @@ -3036,7 +2579,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst } } - ginstance->instance_count = storage->particles_get_amount(ginstance->data->base); + ginstance->instance_count = storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps); } break; @@ -3050,52 +2593,35 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; } if (storage->multimesh_uses_colors(ginstance->data->base)) { ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; } if (storage->multimesh_uses_custom_data(ginstance->data->base)) { ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; } - ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (false) { // 2D particles - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + //for particles, stride is the trail size + ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT); if (!storage->particles_is_using_local_coords(ginstance->data->base)) { store_transform = false; } - ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { if (storage->skeleton_is_valid(ginstance->data->skeleton)) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON; - ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); + ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); if (ginstance->data->dirty_dependencies) { storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); } @@ -3105,7 +2631,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst ginstance->store_transform_cache = store_transform; ginstance->can_sdfgi = false; - if (!lightmap_instance_is_valid(ginstance->lightmap_instance) && !low_end) { + if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) { if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { ginstance->can_sdfgi = true; } @@ -3119,24 +2645,25 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst ginstance->dirty_list_element.remove_from_list(); } -void RendererSceneRenderForwardClustered::_update_dirty_geometry_instances() { +void RenderForwardClustered::_update_dirty_geometry_instances() { while (geometry_instance_dirty_list.first()) { _geometry_instance_update(geometry_instance_dirty_list.first()->self()); } } -void RendererSceneRenderForwardClustered::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { +void RenderForwardClustered::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { switch (p_notification) { case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_PARTICLES: case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { - static_cast<RendererSceneRenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); + static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); } break; case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_tracker->userdata); if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { - ginstance->instance_count = static_cast<RendererSceneRenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); + ginstance->instance_count = static_cast<RenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); } } break; default: { @@ -3144,11 +2671,11 @@ void RendererSceneRenderForwardClustered::_geometry_instance_dependency_changed( } break; } } -void RendererSceneRenderForwardClustered::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { - static_cast<RendererSceneRenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); +void RenderForwardClustered::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { + static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); } -RendererSceneRender::GeometryInstance *RendererSceneRenderForwardClustered::geometry_instance_create(RID p_base) { +RendererSceneRender::GeometryInstance *RenderForwardClustered::geometry_instance_create(RID p_base) { RS::InstanceType type = storage->get_base_type(p_base); ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); @@ -3165,34 +2692,34 @@ RendererSceneRender::GeometryInstance *RendererSceneRenderForwardClustered::geom return ginstance; } -void RendererSceneRenderForwardClustered::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { +void RenderForwardClustered::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->data->skeleton = p_skeleton; _geometry_instance_mark_dirty(ginstance); ginstance->data->dirty_dependencies = true; } -void RendererSceneRenderForwardClustered::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { +void RenderForwardClustered::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->data->material_override = p_override; _geometry_instance_mark_dirty(ginstance); ginstance->data->dirty_dependencies = true; } -void RendererSceneRenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { +void RenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->data->surface_materials = p_materials; _geometry_instance_mark_dirty(ginstance); ginstance->data->dirty_dependencies = true; } -void RendererSceneRenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { +void RenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->mesh_instance = p_mesh_instance; _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { +void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->transform = p_transform; @@ -3209,24 +2736,24 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_transform(Geomet ginstance->lod_model_scale = max_scale; } -void RendererSceneRenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { +void RenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->lod_bias = p_lod_bias; } -void RendererSceneRenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { +void RenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->data->use_baked_light = p_enable; _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { +void RenderForwardClustered::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->data->use_dynamic_gi = p_enable; _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { +void RenderForwardClustered::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->lightmap_instance = p_lightmap_instance; @@ -3234,7 +2761,7 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_use_lightmap(Geo ginstance->lightmap_slice_index = p_lightmap_slice_index; _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { +void RenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); if (p_sh9) { @@ -3242,7 +2769,7 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_lightmap_capture ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); } - copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); + memcpy(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); } else { if (ginstance->lightmap_sh != nullptr) { geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); @@ -3251,13 +2778,13 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_lightmap_capture } _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { +void RenderForwardClustered::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->shader_parameters_offset = p_offset; _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { +void RenderForwardClustered::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); @@ -3265,13 +2792,13 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_cast_double_side _geometry_instance_mark_dirty(ginstance); } -void RendererSceneRenderForwardClustered::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { +void RenderForwardClustered::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->layer_mask = p_layer_mask; } -void RendererSceneRenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) { +void RenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); if (ginstance->lightmap_sh != nullptr) { @@ -3287,28 +2814,28 @@ void RendererSceneRenderForwardClustered::geometry_instance_free(GeometryInstanc geometry_instance_alloc.free(ginstance); } -uint32_t RendererSceneRenderForwardClustered::geometry_instance_get_pair_mask() { +uint32_t RenderForwardClustered::geometry_instance_get_pair_mask() { return (1 << RS::INSTANCE_GI_PROBE); } -void RendererSceneRenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { +void RenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { } -void RendererSceneRenderForwardClustered::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { +void RenderForwardClustered::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { } -void RendererSceneRenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { +void RenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { } -Transform RendererSceneRenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) { +Transform RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance); ERR_FAIL_COND_V(!ginstance, Transform()); return ginstance->transform; } -AABB RendererSceneRenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) { +AABB RenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance); ERR_FAIL_COND_V(!ginstance, AABB()); return ginstance->data->aabb; } -void RendererSceneRenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { +void RenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); if (p_gi_probe_instance_count > 0) { @@ -3324,19 +2851,14 @@ void RendererSceneRenderForwardClustered::geometry_instance_pair_gi_probe_instan } } -RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(RendererStorageRD *p_storage) : +RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) : RendererSceneRenderRD(p_storage) { singleton = this; - low_end = is_low_end(); /* SCENE SHADER */ { String defines; - if (low_end) { - defines += "\n#define LOW_END_MODE \n"; - } - defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; if (is_using_radiance_cubemap_array()) { defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; @@ -3346,7 +2868,7 @@ RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(Rendere { //lightmaps - scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS; + scene_state.max_lightmaps = MAX_LIGHTMAPS; defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; @@ -3362,267 +2884,13 @@ RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(Rendere defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n"; } - Vector<String> shader_versions; - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); - shader_versions.push_back(""); - shader_versions.push_back("\n#define USE_FORWARD_GI\n"); - shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); - shader_versions.push_back("\n#define USE_LIGHTMAP\n"); - shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); - shader.scene_shader.initialize(shader_versions, defines); - - if (is_low_end()) { - //disable the high end versions - shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); - } - } - - storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); - storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); - - { - //shader compiler - ShaderCompilerRD::DefaultIdentifierActions actions; - - actions.renames["WORLD_MATRIX"] = "world_matrix"; - actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix"; - actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix"; - actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; - actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; - actions.renames["MODELVIEW_MATRIX"] = "modelview"; - actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; - - actions.renames["VERTEX"] = "vertex"; - actions.renames["NORMAL"] = "normal"; - actions.renames["TANGENT"] = "tangent"; - actions.renames["BINORMAL"] = "binormal"; - actions.renames["POSITION"] = "position"; - actions.renames["UV"] = "uv_interp"; - actions.renames["UV2"] = "uv2_interp"; - actions.renames["COLOR"] = "color_interp"; - actions.renames["POINT_SIZE"] = "gl_PointSize"; - actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; - - actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; - actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; - actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; - actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; - - //builtins - - actions.renames["TIME"] = "scene_data.time"; - actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; - - actions.renames["FRAGCOORD"] = "gl_FragCoord"; - actions.renames["FRONT_FACING"] = "gl_FrontFacing"; - actions.renames["NORMAL_MAP"] = "normal_map"; - actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; - actions.renames["ALBEDO"] = "albedo"; - actions.renames["ALPHA"] = "alpha"; - actions.renames["METALLIC"] = "metallic"; - actions.renames["SPECULAR"] = "specular"; - actions.renames["ROUGHNESS"] = "roughness"; - actions.renames["RIM"] = "rim"; - actions.renames["RIM_TINT"] = "rim_tint"; - actions.renames["CLEARCOAT"] = "clearcoat"; - actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; - actions.renames["ANISOTROPY"] = "anisotropy"; - actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions.renames["SSS_STRENGTH"] = "sss_strength"; - actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; - actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; - actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; - actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; - actions.renames["BACKLIGHT"] = "backlight"; - actions.renames["AO"] = "ao"; - actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; - actions.renames["EMISSION"] = "emission"; - actions.renames["POINT_COORD"] = "gl_PointCoord"; - actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; - actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "color_buffer"; - actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; - actions.renames["DEPTH"] = "gl_FragDepth"; - actions.renames["OUTPUT_IS_SRGB"] = "true"; - actions.renames["FOG"] = "custom_fog"; - actions.renames["RADIANCE"] = "custom_radiance"; - actions.renames["IRRADIANCE"] = "custom_irradiance"; - actions.renames["BONE_INDICES"] = "bone_attrib"; - actions.renames["BONE_WEIGHTS"] = "weight_attrib"; - actions.renames["CUSTOM0"] = "custom0_attrib"; - actions.renames["CUSTOM1"] = "custom1_attrib"; - actions.renames["CUSTOM2"] = "custom2_attrib"; - actions.renames["CUSTOM3"] = "custom3_attrib"; - - //for light - actions.renames["VIEW"] = "view"; - actions.renames["LIGHT_COLOR"] = "light_color"; - actions.renames["LIGHT"] = "light"; - actions.renames["ATTENUATION"] = "attenuation"; - actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation"; - actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; - actions.renames["SPECULAR_LIGHT"] = "specular_light"; - - actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; - actions.usage_defines["BINORMAL"] = "@TANGENT"; - actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; - actions.usage_defines["RIM_TINT"] = "@RIM"; - actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; - actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; - actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; - actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; - actions.usage_defines["AO"] = "#define AO_USED\n"; - actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; - actions.usage_defines["UV"] = "#define UV_USED\n"; - actions.usage_defines["UV2"] = "#define UV2_USED\n"; - actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; - actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; - actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; - actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; - actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; - actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; - actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; - actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; - actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; - actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; - - actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; - actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; - actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; - actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; - - actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; - actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - - actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - - actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; - actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; - actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; - - actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; - actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; - actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - - bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); - - if (!force_lambert) { - actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; - } - - actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; - actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; - actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - - actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; - - bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); - - if (!force_blinn) { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } - - actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; - actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; - actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; - actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; - actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; - - actions.sampler_array_name = "material_samplers"; - actions.base_texture_binding_index = 1; - actions.texture_layout_set = MATERIAL_UNIFORM_SET; - actions.base_uniform_string = "material."; - actions.base_varying_index = 10; - - actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; - actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; - actions.global_buffer_array_variable = "global_variables.data"; - actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; - - shader.compiler.initialize(actions); - } - - { - //default material and shader - default_shader = storage->shader_allocate(); - storage->shader_initialize(default_shader); - storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n"); - default_material = storage->material_allocate(); - storage->material_initialize(default_material); - storage->material_set_shader(default_material, default_shader); - - MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); - if (!low_end) { - default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); - } - } - - { - overdraw_material_shader = storage->shader_allocate(); - storage->shader_initialize(overdraw_material_shader); - storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); - overdraw_material = storage->material_allocate(); - storage->material_initialize(overdraw_material); - storage->material_set_shader(overdraw_material, overdraw_material_shader); - - wireframe_material_shader = storage->shader_allocate(); - storage->shader_initialize(wireframe_material_shader); - storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); - wireframe_material = storage->material_allocate(); - storage->material_initialize(wireframe_material); - storage->material_set_shader(wireframe_material, wireframe_material_shader); - } - - { - default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); - Vector<RD::Uniform> uniforms; - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(default_vec4_xform_buffer); - u.binding = 0; - uniforms.push_back(u); - - default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, TRANSFORMS_UNIFORM_SET); - } - { - RD::SamplerState sampler; - sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; - sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; - sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; - shadow_sampler = RD::get_singleton()->sampler_create(sampler); + scene_shader.init(p_storage, defines); } render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); } -RendererSceneRenderForwardClustered::~RendererSceneRenderForwardClustered() { +RenderForwardClustered::~RenderForwardClustered() { directional_shadow_atlas_set_size(0); //clear base uniform set if still valid @@ -3636,17 +2904,6 @@ RendererSceneRenderForwardClustered::~RendererSceneRenderForwardClustered() { RD::get_singleton()->free(sdfgi_pass_uniform_set); } - RD::get_singleton()->free(default_vec4_xform_buffer); - RD::get_singleton()->free(shadow_sampler); - - storage->free(wireframe_material_shader); - storage->free(overdraw_material_shader); - storage->free(default_shader); - - storage->free(wireframe_material); - storage->free(overdraw_material); - storage->free(default_material); - { for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { RD::get_singleton()->free(scene_state.uniform_buffers[i]); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 98e2a7efcc..bed3c3b219 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* renderer_scene_render_forward_clustered.h */ +/* render_forward_clustered.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,12 +32,17 @@ #define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H #include "core/templates/paged_allocator.h" +#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h" -class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { +namespace RendererSceneRenderImplementation { + +class RenderForwardClustered : public RendererSceneRenderRD { + friend SceneShaderForwardClustered; + enum { SCENE_UNIFORM_SET = 0, RENDER_PASS_UNIFORM_SET = 1, @@ -63,155 +68,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { /* Scene Shader */ - enum ShaderVersion { - SHADER_VERSION_DEPTH_PASS, - SHADER_VERSION_DEPTH_PASS_DP, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, - SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, - SHADER_VERSION_DEPTH_PASS_WITH_SDF, - SHADER_VERSION_COLOR_PASS, - SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, - SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_LIGHTMAP_COLOR_PASS, - SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_MAX - }; - - struct { - SceneForwardClusteredShaderRD scene_shader; - ShaderCompilerRD compiler; - } shader; - - /* Material */ - - struct ShaderData : public RendererStorageRD::ShaderData { - enum BlendMode { //used internally - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_ALPHA_TO_COVERAGE - }; - - enum DepthDraw { - DEPTH_DRAW_DISABLED, - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS - }; - - enum DepthTest { - DEPTH_TEST_DISABLED, - DEPTH_TEST_ENABLED - }; - - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - - enum CullVariant { - CULL_VARIANT_NORMAL, - CULL_VARIANT_REVERSED, - CULL_VARIANT_DOUBLE_SIDED, - CULL_VARIANT_MAX - - }; - - enum AlphaAntiAliasing { - ALPHA_ANTIALIASING_OFF, - ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, - ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE - }; - - bool valid; - RID version; - uint32_t vertex_input_mask; - PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; - - String path; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; - Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; - - Vector<uint32_t> ubo_offsets; - uint32_t ubo_size; - - String code; - Map<StringName, RID> default_texture_params; - - DepthDraw depth_draw; - DepthTest depth_test; - - bool uses_point_size; - bool uses_alpha; - bool uses_blend_alpha; - bool uses_alpha_clip; - bool uses_depth_pre_pass; - bool uses_discard; - bool uses_roughness; - bool uses_normal; - - bool unshaded; - bool uses_vertex; - bool uses_sss; - bool uses_transmittance; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_normal_texture; - bool uses_time; - bool writes_modelview_or_projection; - bool uses_world_coordinates; - - uint64_t last_pass = 0; - uint32_t index = 0; - - virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); - virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; - - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - virtual RS::ShaderNativeSourceCode get_native_source_code() const; - - ShaderData(); - virtual ~ShaderData(); - }; - - RendererStorageRD::ShaderData *_create_shader_func(); - static RendererStorageRD::ShaderData *_create_shader_funcs() { - return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_shader_func(); - } - - struct MaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; - ShaderData *shader_data; - RID uniform_buffer; - RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; - uint64_t last_pass = 0; - uint32_t index = 0; - RID next_pass; - uint8_t priority; - virtual void set_render_priority(int p_priority); - virtual void set_next_pass(RID p_pass); - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~MaterialData(); - }; - - RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); - static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { - return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); - } + SceneShaderForwardClustered scene_shader; /* Framebuffer */ - struct RenderBufferDataForward : public RenderBufferData { + struct RenderBufferDataForwardClustered : public RenderBufferData { //for rendering, may be MSAAd RID color; @@ -244,13 +105,12 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { void clear(); virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); - ~RenderBufferDataForward(); + ~RenderBufferDataForwardClustered(); }; virtual RenderBufferData *_create_render_buffer_data(); - void _allocate_normal_roughness_texture(RenderBufferDataForward *rb); + void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb); - RID shadow_sampler; RID render_base_uniform_set; LocalVector<RID> render_pass_uniform_sets; RID sdfgi_pass_uniform_set; @@ -258,13 +118,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { uint64_t lightmap_texture_array_version = 0xFFFFFFFF; virtual void _base_uniforms_changed(); - void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb); - virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); void _update_render_base_uniform_set(); RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); - RID _setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas = false, int p_index = 0); + RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); enum PassMode { PASS_MODE_COLOR, @@ -336,12 +194,13 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, - INSTANCE_DATA_FLAG_SKELETON = 1 << 19, + INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16, + INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF, + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24, }; struct SceneState { + // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code struct UBO { float projection_matrix[16]; float inv_projection_matrix[16]; @@ -488,21 +347,9 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { } scene_state; - static RendererSceneRenderForwardClustered *singleton; + static RenderForwardClustered *singleton; - RID default_shader; - RID default_material; - RID overdraw_material_shader; - RID overdraw_material; - RID wireframe_material_shader; - RID wireframe_material; - RID default_shader_rd; - RID default_shader_sdfgi_rd; - - RID default_vec4_xform_buffer; - RID default_vec4_xform_uniform_set; - - void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); + void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); void _setup_giprobes(const PagedArray<RID> &p_giprobes); void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform); @@ -526,7 +373,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { void _update_instance_data_buffer(RenderListType p_render_list); void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); - void _fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, const Plane &p_lod_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, bool p_append = false); + void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false); Map<Size2i, RID> sdfgi_framebuffer_size_cache; @@ -550,6 +397,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { FLAG_USES_DEPTH_TEXTURE = 8192, FLAG_USES_NORMAL_TEXTURE = 16384, FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, + FLAG_USES_PARTICLE_TRAILS = 65536, }; union { @@ -578,11 +426,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { void *surface = nullptr; RID material_uniform_set; - ShaderData *shader = nullptr; + SceneShaderForwardClustered::ShaderData *shader = nullptr; void *surface_shadow = nullptr; RID material_uniform_set_shadow; - ShaderData *shader_shadow = nullptr; + SceneShaderForwardClustered::ShaderData *shader_shadow = nullptr; GeometryInstanceSurfaceDataCache *next = nullptr; GeometryInstanceForwardClustered *owner = nullptr; @@ -605,6 +453,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { uint32_t layer_mask = 1; RID transforms_uniform_set; uint32_t instance_count = 0; + uint32_t trail_steps = 1; RID mesh_instance; bool can_sdfgi = false; //used during setup @@ -650,14 +499,12 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc; PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh; - void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); void _geometry_instance_update(GeometryInstance *p_geometry_instance); void _update_dirty_geometry_instances(); - bool low_end = false; - /* Render List */ struct RenderList { @@ -719,7 +566,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { RenderList render_list[RENDER_LIST_MAX]; protected: - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color); virtual void _render_shadow_begin(); virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); @@ -760,7 +607,8 @@ public: virtual bool free(RID p_rid); - RendererSceneRenderForwardClustered(RendererStorageRD *p_storage); - ~RendererSceneRenderForwardClustered(); + RenderForwardClustered(RendererStorageRD *p_storage); + ~RenderForwardClustered(); }; +} // namespace RendererSceneRenderImplementation #endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H 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 new file mode 100644 index 0000000000..f7ed0205af --- /dev/null +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -0,0 +1,806 @@ +/*************************************************************************/ +/* scene_shader_forward_clustered.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "scene_shader_forward_clustered.h" +#include "core/config/project_settings.h" +#include "render_forward_clustered.h" + +using namespace RendererSceneRenderImplementation; + +void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + uses_screen_texture = false; + + if (code == String()) { + return; //just invalid, but no error + } + + ShaderCompilerRD::GeneratedCode gen_code; + + int blend_mode = BLEND_MODE_MIX; + int depth_testi = DEPTH_TEST_ENABLED; + int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; + int cull = CULL_BACK; + + uses_point_size = false; + uses_alpha = false; + uses_blend_alpha = false; + uses_depth_pre_pass = false; + uses_discard = false; + uses_roughness = false; + uses_normal = false; + bool wireframe = false; + + unshaded = false; + uses_vertex = false; + uses_sss = false; + uses_transmittance = false; + uses_screen_texture = false; + uses_depth_texture = false; + uses_normal_texture = false; + uses_time = false; + writes_modelview_or_projection = false; + uses_world_coordinates = false; + uses_particle_trails = false; + + int depth_drawi = DEPTH_DRAW_OPAQUE; + + ShaderCompilerRD::IdentifierActions actions; + actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX; + actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT; + actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT; + + actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD); + actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX); + actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB); + actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); + + actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + + actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED); + actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE); + actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS); + + actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED); + + actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED); + actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT); + actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK); + + actions.render_mode_flags["unshaded"] = &unshaded; + actions.render_mode_flags["wireframe"] = &wireframe; + actions.render_mode_flags["particle_trails"] = &uses_particle_trails; + + actions.usage_flag_pointers["ALPHA"] = &uses_alpha; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + + actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; + actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; + + actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; + actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; + actions.usage_flag_pointers["DISCARD"] = &uses_discard; + actions.usage_flag_pointers["TIME"] = &uses_time; + actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; + actions.usage_flag_pointers["NORMAL"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; + + actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; + actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; + + actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["VERTEX"] = &uses_vertex; + + actions.uniforms = &uniforms; + + SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); + + ERR_FAIL_COND(err != OK); + + if (version.is_null()) { + version = shader_singleton->shader.version_create(); + } + + depth_draw = DepthDraw(depth_drawi); + depth_test = DepthTest(depth_testi); + +#if 0 + print_line("**compiling shader:"); + print_line("**defines:\n"); + for (int i = 0; i < gen_code.defines.size(); i++) { + print_line(gen_code.defines[i]); + } + + Map<String, String>::Element * el = gen_code.code.front(); + while (el) { + print_line("\n**code " + el->key() + ":\n" + el->value()); + + el = el->next(); + } + + print_line("\n**uniforms:\n" + gen_code.uniforms); + print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX]); + print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT]); +#endif + shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines); + ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + //blend modes + + // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { + blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; + } + + RD::PipelineColorBlendState::Attachment blend_attachment; + + switch (blend_mode) { + case BLEND_MODE_MIX: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + } break; + case BLEND_MODE_ADD: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_SUB: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_MUL: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + uses_blend_alpha = true; //force alpha used because of blend + } break; + case BLEND_MODE_ALPHA_TO_COVERAGE: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + } + } + + RD::PipelineColorBlendState blend_state_blend; + blend_state_blend.attachments.push_back(blend_attachment); + RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2); + RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2); + + //update pipelines + + RD::PipelineDepthStencilState depth_stencil_state; + + if (depth_test != DEPTH_TEST_DISABLED) { + depth_stencil_state.enable_depth_test = true; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; + } + + for (int i = 0; i < CULL_VARIANT_MAX; i++) { + RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = { + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED } + }; + + RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull]; + + for (int j = 0; j < RS::PRIMITIVE_MAX; j++) { + RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = { + RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_LINESTRIPS, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, + }; + + RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; + + for (int k = 0; k < SHADER_VERSION_MAX; k++) { + if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(k)) { + continue; + } + RD::PipelineRasterizationState raster_state; + raster_state.cull_mode = cull_mode_rd; + raster_state.wireframe = wireframe; + + RD::PipelineColorBlendState blend_state; + RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; + RD::PipelineMultisampleState multisample_state; + + if (uses_alpha || uses_blend_alpha) { + // only allow these flags to go through if we have some form of msaa + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + multisample_state.enable_alpha_to_coverage = true; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + multisample_state.enable_alpha_to_coverage = true; + multisample_state.enable_alpha_to_one = true; + } + + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_blend; + if (depth_draw == DEPTH_DRAW_OPAQUE) { + depth_stencil.enable_depth_write = false; //alpha does not draw depth + } + } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { + if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, blend state contains nothing + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else { + blend_state = blend_state_opaque; //writes to normal and roughness in opaque way + } + } else { + pipelines[i][j][k].clear(); + continue; // do not use this version (will error if using it is attempted) + } + } else { + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_opaque; + } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, leave empty + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { + blend_state = blend_state_depth_normal_roughness; + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { + blend_state = blend_state_depth_normal_roughness_giprobe; + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { + blend_state = RD::PipelineColorBlendState(); //no color targets for SDF + } else { + //specular write + blend_state = blend_state_opaque_specular; + depth_stencil.enable_depth_test = false; + depth_stencil.enable_depth_write = false; + } + } + + RID shader_variant = shader_singleton->shader.version_get_shader(version, k); + pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); + } + } + } + + valid = true; +} + +void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { + if (!p_texture.is_valid()) { + default_texture_params.erase(p_name); + } else { + default_texture_params[p_name] = p_texture; + } +} + +void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { + Map<int, StringName> order; + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + continue; + } + + if (E->get().texture_order >= 0) { + order[E->get().texture_order + 100000] = E->key(); + } else { + order[E->get().order] = E->key(); + } + } + + for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); + pi.name = E->get(); + p_param_list->push_back(pi); + } +} + +void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RendererStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p_param_list->push_back(p); + } +} + +bool SceneShaderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool SceneShaderForwardClustered::ShaderData::is_animated() const { + return false; +} + +bool SceneShaderForwardClustered::ShaderData::casts_shadows() const { + return false; +} + +Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + } + return Variant(); +} + +RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const { + SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + + return shader_singleton->shader.version_get_native_source_code(version); +} + +SceneShaderForwardClustered::ShaderData::ShaderData() { + valid = false; + uses_screen_texture = false; +} + +SceneShaderForwardClustered::ShaderData::~ShaderData() { + SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + ERR_FAIL_COND(!shader_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + shader_singleton->shader.version_free(version); + } +} + +RendererStorageRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() { + ShaderData *shader_data = memnew(ShaderData); + return shader_data; +} + +void SceneShaderForwardClustered::MaterialData::set_render_priority(int p_priority) { + priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits +} + +void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) { + next_pass = p_pass; +} + +void SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + + if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { + p_uniform_dirty = true; + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + uniform_buffer = RID(); + } + + ubo_data.resize(shader_data->ubo_size); + if (ubo_data.size()) { + uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); + memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear + } + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + //check whether buffer changed + if (p_uniform_dirty && ubo_data.size()) { + update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); + } + + uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); + + if ((uint32_t)texture_cache.size() != tex_uniform_count) { + texture_cache.resize(tex_uniform_count); + p_textures_dirty = true; + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + if (p_textures_dirty && tex_uniform_count) { + update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); + } + + if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { + // This material does not require an uniform set, so don't create it. + return; + } + + if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + //no reason to update uniform set, only UBO (or nothing) was needed to update + return; + } + + Vector<RD::Uniform> uniforms; + + { + if (shader_data->ubo_size) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(uniform_buffer); + uniforms.push_back(u); + } + + const RID *textures = texture_cache.ptrw(); + for (uint32_t i = 0; i < tex_uniform_count; i++) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1 + i; + u.ids.push_back(textures[i]); + uniforms.push_back(u); + } + } + + uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET); +} + +SceneShaderForwardClustered::MaterialData::~MaterialData() { + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + } + + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + } +} + +RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) { + MaterialData *material_data = memnew(MaterialData); + material_data->shader_data = p_shader; + material_data->last_frame = false; + //update will happen later anyway so do nothing. + return material_data; +} + +SceneShaderForwardClustered *SceneShaderForwardClustered::singleton = nullptr; + +SceneShaderForwardClustered::SceneShaderForwardClustered() { + // there should be only one of these, contained within our RenderFM singleton. + singleton = this; +} + +SceneShaderForwardClustered::~SceneShaderForwardClustered() { + RD::get_singleton()->free(default_vec4_xform_buffer); + RD::get_singleton()->free(shadow_sampler); + + storage->free(wireframe_material_shader); + storage->free(overdraw_material_shader); + storage->free(default_shader); + + storage->free(wireframe_material); + storage->free(overdraw_material); + storage->free(default_material); +} + +void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const String p_defines) { + storage = p_storage; + + { + Vector<String> shader_versions; + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); + shader_versions.push_back(""); + shader_versions.push_back("\n#define USE_FORWARD_GI\n"); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); + shader_versions.push_back("\n#define USE_LIGHTMAP\n"); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); + shader.initialize(shader_versions, p_defines); + } + + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); + + { + //shader compiler + ShaderCompilerRD::DefaultIdentifierActions actions; + + actions.renames["WORLD_MATRIX"] = "world_matrix"; + actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix"; + actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix"; + actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; + actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; + actions.renames["MODELVIEW_MATRIX"] = "modelview"; + actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; + + actions.renames["VERTEX"] = "vertex"; + actions.renames["NORMAL"] = "normal"; + actions.renames["TANGENT"] = "tangent"; + actions.renames["BINORMAL"] = "binormal"; + actions.renames["POSITION"] = "position"; + actions.renames["UV"] = "uv_interp"; + actions.renames["UV2"] = "uv2_interp"; + actions.renames["COLOR"] = "color_interp"; + actions.renames["POINT_SIZE"] = "gl_PointSize"; + actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; + + actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; + actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; + actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; + actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; + + //builtins + + actions.renames["TIME"] = "scene_data.time"; + actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; + + actions.renames["FRAGCOORD"] = "gl_FragCoord"; + actions.renames["FRONT_FACING"] = "gl_FrontFacing"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; + actions.renames["ALBEDO"] = "albedo"; + actions.renames["ALPHA"] = "alpha"; + actions.renames["METALLIC"] = "metallic"; + actions.renames["SPECULAR"] = "specular"; + actions.renames["ROUGHNESS"] = "roughness"; + actions.renames["RIM"] = "rim"; + actions.renames["RIM_TINT"] = "rim_tint"; + actions.renames["CLEARCOAT"] = "clearcoat"; + actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions.renames["ANISOTROPY"] = "anisotropy"; + actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; + actions.renames["SSS_STRENGTH"] = "sss_strength"; + actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; + actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; + actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; + actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; + actions.renames["BACKLIGHT"] = "backlight"; + actions.renames["AO"] = "ao"; + actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; + actions.renames["EMISSION"] = "emission"; + actions.renames["POINT_COORD"] = "gl_PointCoord"; + actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; + actions.renames["SCREEN_UV"] = "screen_uv"; + actions.renames["SCREEN_TEXTURE"] = "color_buffer"; + actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; + actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; + actions.renames["DEPTH"] = "gl_FragDepth"; + actions.renames["OUTPUT_IS_SRGB"] = "true"; + actions.renames["FOG"] = "custom_fog"; + actions.renames["RADIANCE"] = "custom_radiance"; + actions.renames["IRRADIANCE"] = "custom_irradiance"; + actions.renames["BONE_INDICES"] = "bone_attrib"; + actions.renames["BONE_WEIGHTS"] = "weight_attrib"; + actions.renames["CUSTOM0"] = "custom0_attrib"; + actions.renames["CUSTOM1"] = "custom1_attrib"; + actions.renames["CUSTOM2"] = "custom2_attrib"; + actions.renames["CUSTOM3"] = "custom3_attrib"; + + //for light + actions.renames["VIEW"] = "view"; + actions.renames["LIGHT_COLOR"] = "light_color"; + actions.renames["LIGHT"] = "light"; + actions.renames["ATTENUATION"] = "attenuation"; + actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation"; + actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; + actions.renames["SPECULAR_LIGHT"] = "specular_light"; + + actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; + actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; + actions.usage_defines["BINORMAL"] = "@TANGENT"; + actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; + actions.usage_defines["RIM_TINT"] = "@RIM"; + actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; + actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; + actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; + actions.usage_defines["AO"] = "#define AO_USED\n"; + actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; + actions.usage_defines["UV"] = "#define UV_USED\n"; + actions.usage_defines["UV2"] = "#define UV2_USED\n"; + actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; + actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; + actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; + actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; + actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; + actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + + actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; + actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; + actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; + actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; + + actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; + actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; + actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; + actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + + actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + + actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; + actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; + actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; + + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; + actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n"; + + bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); + + if (!force_lambert) { + actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + + actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; + actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; + actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + + actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; + + bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); + + if (!force_blinn) { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + + actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; + actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; + actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; + actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; + actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + + actions.sampler_array_name = "material_samplers"; + actions.base_texture_binding_index = 1; + actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET; + actions.base_uniform_string = "material."; + actions.base_varying_index = 10; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + actions.global_buffer_array_variable = "global_variables.data"; + actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; + + compiler.initialize(actions); + } + + { + //default material and shader + default_shader = storage->shader_allocate(); + storage->shader_initialize(default_shader); + storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n"); + default_material = storage->material_allocate(); + storage->material_initialize(default_material); + storage->material_set_shader(default_material, default_shader); + + MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); + default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + } + + { + overdraw_material_shader = storage->shader_allocate(); + storage->shader_initialize(overdraw_material_shader); + storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + overdraw_material = storage->material_allocate(); + storage->material_initialize(overdraw_material); + storage->material_set_shader(overdraw_material, overdraw_material_shader); + + wireframe_material_shader = storage->shader_allocate(); + storage->shader_initialize(wireframe_material_shader); + storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); + wireframe_material = storage->material_allocate(); + storage->material_initialize(wireframe_material); + storage->material_set_shader(wireframe_material, wireframe_material_shader); + } + + { + default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(default_vec4_xform_buffer); + u.binding = 0; + uniforms.push_back(u); + + default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardClustered::TRANSFORMS_UNIFORM_SET); + } + { + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.enable_compare = true; + sampler.compare_op = RD::COMPARE_OP_LESS; + shadow_sampler = RD::get_singleton()->sampler_create(sampler); + } +} diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h new file mode 100644 index 0000000000..7c8879686b --- /dev/null +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -0,0 +1,211 @@ +/*************************************************************************/ +/* scene_shader_forward_clustered.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RSSR_SCENE_SHADER_FC_H +#define RSSR_SCENE_SHADER_FC_H + +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h" + +namespace RendererSceneRenderImplementation { + +class SceneShaderForwardClustered { +private: + static SceneShaderForwardClustered *singleton; + +public: + RendererStorageRD *storage; + + enum ShaderVersion { + SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + SHADER_VERSION_DEPTH_PASS_WITH_SDF, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, + SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_MAX + }; + + struct ShaderData : public RendererStorageRD::ShaderData { + enum BlendMode { //used internally + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_ALPHA_TO_COVERAGE + }; + + enum DepthDraw { + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS + }; + + enum DepthTest { + DEPTH_TEST_DISABLED, + DEPTH_TEST_ENABLED + }; + + enum Cull { + CULL_DISABLED, + CULL_FRONT, + CULL_BACK + }; + + enum CullVariant { + CULL_VARIANT_NORMAL, + CULL_VARIANT_REVERSED, + CULL_VARIANT_DOUBLE_SIDED, + CULL_VARIANT_MAX + + }; + + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE + }; + + bool valid; + RID version; + uint32_t vertex_input_mask; + PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + + String path; + + Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; + Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + + Vector<uint32_t> ubo_offsets; + uint32_t ubo_size; + + String code; + Map<StringName, RID> default_texture_params; + + DepthDraw depth_draw; + DepthTest depth_test; + + bool uses_point_size; + bool uses_alpha; + bool uses_blend_alpha; + bool uses_alpha_clip; + bool uses_depth_pre_pass; + bool uses_discard; + bool uses_roughness; + bool uses_normal; + bool uses_particle_trails; + + bool unshaded; + bool uses_vertex; + bool uses_sss; + bool uses_transmittance; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_texture; + bool uses_time; + bool writes_modelview_or_projection; + bool uses_world_coordinates; + + uint64_t last_pass = 0; + uint32_t index = 0; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; + + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + ShaderData(); + virtual ~ShaderData(); + }; + + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func(); + } + + struct MaterialData : public RendererStorageRD::MaterialData { + uint64_t last_frame; + ShaderData *shader_data; + RID uniform_buffer; + RID uniform_set; + Vector<RID> texture_cache; + Vector<uint8_t> ubo_data; + uint64_t last_pass = 0; + uint32_t index = 0; + RID next_pass; + uint8_t priority; + virtual void set_render_priority(int p_priority); + virtual void set_next_pass(RID p_pass); + virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~MaterialData(); + }; + + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<SceneShaderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); + } + + SceneForwardClusteredShaderRD shader; + ShaderCompilerRD compiler; + + RID default_shader; + RID default_material; + RID overdraw_material_shader; + RID overdraw_material; + RID wireframe_material_shader; + RID wireframe_material; + RID default_shader_rd; + RID default_shader_sdfgi_rd; + + RID default_vec4_xform_buffer; + RID default_vec4_xform_uniform_set; + + RID shadow_sampler; + + SceneShaderForwardClustered(); + ~SceneShaderForwardClustered(); + + void init(RendererStorageRD *p_storage, const String p_defines); +}; + +} // namespace RendererSceneRenderImplementation +#endif // !RSSR_SCENE_SHADER_FM_H diff --git a/servers/rendering/renderer_rd/forward_mobile/SCsub b/servers/rendering/renderer_rd/forward_mobile/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/rendering/renderer_rd/forward_mobile/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp new file mode 100644 index 0000000000..4e93fa5333 --- /dev/null +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -0,0 +1,2135 @@ +/*************************************************************************/ +/* render_forward_mobile.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "render_forward_mobile.h" +#include "core/config/project_settings.h" +#include "servers/rendering/rendering_device.h" +#include "servers/rendering/rendering_server_default.h" + +using namespace RendererSceneRenderImplementation; + +/* Render buffer */ + +void RenderForwardMobile::RenderBufferDataForwardMobile::clear() { + if (color_msaa.is_valid()) { + RD::get_singleton()->free(color_msaa); + color_msaa = RID(); + } + + if (depth_msaa.is_valid()) { + RD::get_singleton()->free(depth_msaa); + depth_msaa = RID(); + } + + color = RID(); + depth = RID(); + color_fb = RID(); +} + +void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { + clear(); + + msaa = p_msaa; + + width = p_width; + height = p_height; + + color = p_color_buffer; + depth = p_depth_buffer; + + // re-introduce setting up msaa? For now we ignore this... + + if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { + Vector<RID> fb; + fb.push_back(p_color_buffer); + fb.push_back(depth); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = p_width; + tf.height = p_height; + tf.texture_type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { + RD::TEXTURE_SAMPLES_1, + RD::TEXTURE_SAMPLES_2, + RD::TEXTURE_SAMPLES_4, + RD::TEXTURE_SAMPLES_8, + RD::TEXTURE_SAMPLES_16 + }; + + texture_samples = ts[p_msaa]; + tf.samples = texture_samples; + + color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector<RID> fb; + fb.push_back(color_msaa); + fb.push_back(depth_msaa); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + } +} + +RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() { + clear(); +} + +RendererSceneRenderRD::RenderBufferData *RenderForwardMobile::_create_render_buffer_data() { + return memnew(RenderBufferDataForwardMobile); +} + +bool RenderForwardMobile::free(RID p_rid) { + if (RendererSceneRenderRD::free(p_rid)) { + return true; + } + return false; +} + +/* Render functions */ + +RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) { + //there should always be enough uniform buffers for render passes, otherwise bugs + ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID()); + + RenderBufferDataForwardMobile *rb = nullptr; + if (p_render_data && p_render_data->render_buffers.is_valid()) { + rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_data->render_buffers); + } + + // default render buffer and scene state uniform set + // loaded into set 1 + + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.uniform_buffers[p_index]); + uniforms.push_back(u); + } + + { + RID radiance_texture; + if (p_radiance_texture.is_valid()) { + radiance_texture = p_radiance_texture; + } else { + radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + } + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID(); + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (ref_texture.is_valid()) { + u.ids.push_back(ref_texture); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); + } + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture; + if (p_render_data && p_render_data->shadow_atlas.is_valid()) { + texture = shadow_atlas_get_texture(p_render_data->shadow_atlas); + } + if (!texture.is_valid()) { + texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + } + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { + u.ids.push_back(directional_shadow_get_texture()); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + } + uniforms.push_back(u); + } + + /* we have limited ability to keep textures like this so we're moving this to a set we change before drawing geometry and just pushing the needed texture in */ + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + if (p_render_data && i < p_render_data->lightmaps->size()) { + RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]); + RID texture = storage->lightmap_get_texture(base); + RID rd_texture = storage->texture_get_rd_texture(texture); + u.ids.write[i] = rd_texture; + } else { + u.ids.write[i] = default_tex; + } + } + + uniforms.push_back(u); + } + + /* + { + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + for (int i = 0; i < MAX_GI_PROBES; i++) { + if (i < (int)p_gi_probes.size()) { + RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]); + if (!tex.is_valid()) { + tex = default_tex; + } + u.ids.write[i] = tex; + } else { + u.ids.write[i] = default_tex; + } + } + + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); + } + */ + + { + 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); + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_data->render_buffers) : RID(); + RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + if (p_index >= (int)render_pass_uniform_sets.size()) { + render_pass_uniform_sets.resize(p_index + 1); + } + + if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) { + RD::get_singleton()->free(render_pass_uniform_sets[p_index]); + } + + render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET); + return render_pass_uniform_sets[p_index]; +} + +void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { + // This probably needs to change... + scene_state.lightmaps_used = 0; + for (int i = 0; i < (int)p_lightmaps.size(); i++) { + if (i >= (int)scene_state.max_lightmaps) { + break; + } + + RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + + Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; + to_lm = to_lm.inverse().transposed(); //will transform normals + RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); + scene_state.lightmap_ids[i] = p_lightmaps[i]; + scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap); + + scene_state.lightmaps_used++; + } + if (scene_state.lightmaps_used > 0) { + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER); + } +} + +void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { + RenderBufferDataForwardMobile *render_buffer = nullptr; + if (p_render_data->render_buffers.is_valid()) { + render_buffer = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_data->render_buffers); + } + RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment); + + RENDER_TIMESTAMP("Setup 3D Scene"); + + Vector2 vp_he = p_render_data->cam_projection.get_viewport_half_extents(); + scene_state.ubo.viewport_size[0] = vp_he.x; + scene_state.ubo.viewport_size[1] = vp_he.y; + scene_state.ubo.directional_light_count = 0; + + Size2i screen_size; + RID opaque_framebuffer; + RID alpha_framebuffer; + bool reverse_cull = false; + + // I don't think we support either of these in our mobile renderer so probably should phase them out + bool using_ssr = false; + bool using_sss = false; + + if (render_buffer) { + // setup rendering to render buffer + screen_size.x = render_buffer->width; + screen_size.y = render_buffer->height; + + opaque_framebuffer = render_buffer->color_fb; + alpha_framebuffer = opaque_framebuffer; + } else if (p_render_data->reflection_probe.is_valid()) { + uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe); + screen_size.x = resolution; + screen_size.y = resolution; + + opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); + alpha_framebuffer = opaque_framebuffer; + + if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + p_render_data->environment = RID(); //no environment on interiors + env = nullptr; + } + + reverse_cull = true; + } else { + ERR_FAIL(); //bug? + } + + RD::get_singleton()->draw_command_begin_label("Render Setup"); + + _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform); + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); + + _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) + + _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); + render_list[RENDER_LIST_OPAQUE].sort_by_key(); + render_list[RENDER_LIST_ALPHA].sort_by_depth(); + + // we no longer use this... + _fill_instance_data(RENDER_LIST_OPAQUE); + _fill_instance_data(RENDER_LIST_ALPHA); + + RD::get_singleton()->draw_command_end_label(); + + // note, no depth prepass here! + + // setup environment + RID radiance_texture; + bool draw_sky = false; + bool draw_sky_fog_only = false; + + Color clear_color = p_default_bg_color; + bool keep_color = false; + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { + clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black + } else if (is_environment(p_render_data->environment)) { + RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment); + float bg_energy = environment_get_bg_energy(p_render_data->environment); + switch (bg_mode) { + case RS::ENV_BG_CLEAR_COLOR: { + clear_color = p_default_bg_color; + clear_color.r *= bg_energy; + clear_color.g *= bg_energy; + clear_color.b *= bg_energy; + /* + if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) { + draw_sky_fog_only = true; + storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); + } + */ + } break; + case RS::ENV_BG_COLOR: { + clear_color = environment_get_bg_color(p_render_data->environment); + clear_color.r *= bg_energy; + clear_color.g *= bg_energy; + clear_color.b *= bg_energy; + /* + if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) { + draw_sky_fog_only = true; + storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); + } + */ + } break; + case RS::ENV_BG_SKY: { + draw_sky = true; + } break; + case RS::ENV_BG_CANVAS: { + keep_color = true; + } break; + case RS::ENV_BG_KEEP: { + keep_color = true; + } break; + case RS::ENV_BG_CAMERA_FEED: { + } break; + default: { + } + } + // setup sky if used for ambient, reflections, or background + if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + RENDER_TIMESTAMP("Setup Sky"); + RD::get_singleton()->draw_command_begin_label("Setup Sky"); + CameraMatrix projection = p_render_data->cam_projection; + if (p_render_data->reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + projection = correction * p_render_data->cam_projection; + } + + sky.setup(env, p_render_data->render_buffers, projection, p_render_data->cam_transform, screen_size, this); + + RID sky_rid = env->sky; + if (sky_rid.is_valid()) { + sky.update(env, projection, p_render_data->cam_transform, time); + radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid); + } else { + // do not try to draw sky if invalid + draw_sky = false; + } + RD::get_singleton()->draw_command_end_label(); + } + } else { + clear_color = p_default_bg_color; + } + + // opaque pass + + // !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here + // does trigger shadow map rendering so kinda important + _pre_opaque_render(p_render_data, false, false, RID(), RID()); + + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); + + scene_state.ubo.directional_light_count = p_render_data->directional_light_count; + + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid()); + + RENDER_TIMESTAMP("Render Opaque Pass"); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true); + + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; + bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; + + { + bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); + bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); + + // regular forward for now + Vector<Color> c; + c.push_back(clear_color.to_linear()); + + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); + } + + RD::get_singleton()->draw_command_end_label(); + + if (draw_sky || draw_sky_fog_only) { + RENDER_TIMESTAMP("Render Sky"); + + CameraMatrix projection = p_render_data->cam_projection; + if (p_render_data->reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + projection = correction * p_render_data->cam_projection; + } + RD::get_singleton()->draw_command_begin_label("Draw Sky"); + sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_render_data->cam_transform, time); + RD::get_singleton()->draw_command_end_label(); + } + + if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); + /* + if (using_separate_specular) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular); + } + */ + } + + if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); + } + + // transparent pass + RENDER_TIMESTAMP("Render Transparent Pass"); + + RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); + + rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true); + + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); + + { + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + } + + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->draw_command_begin_label("Resolve"); + + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); + } + + RD::get_singleton()->draw_command_end_label(); +} + +/* these are being called from RendererSceneRenderRD::_pre_opaque_render */ + +void RenderForwardMobile::_render_shadow_begin() { + scene_state.shadow_passes.clear(); + RD::get_singleton()->draw_command_begin_label("Shadow Setup"); + _update_render_base_uniform_set(); + + render_list[RENDER_LIST_SECONDARY].clear(); +} + +void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { + uint32_t shadow_pass_index = scene_state.shadow_passes.size(); + + SceneState::ShadowPass shadow_pass; + + RenderDataRD render_data; + render_data.cam_projection = p_projection; + render_data.cam_transform = p_transform; + render_data.z_near = 0.0; + render_data.z_far = p_zfar; + render_data.instances = &p_instances; + render_data.lod_camera_plane = p_camera_plane; + render_data.lod_distance_multiplier = p_lod_distance_multiplier; + + scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; + + _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + render_data.screen_lod_threshold = 0.0; + } else { + render_data.screen_lod_threshold = p_screen_lod_threshold; + } + + PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; + + uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size(); + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true); + uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; + render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); + _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); + + { + //regular forward for now + bool flip_cull = p_use_dp_flip; + if (p_flip_y) { + flip_cull = !flip_cull; + } + + shadow_pass.element_from = render_list_from; + shadow_pass.element_count = render_list_size; + shadow_pass.flip_cull = flip_cull; + shadow_pass.pass_mode = pass_mode; + + shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete + shadow_pass.camera_plane = p_camera_plane; + shadow_pass.screen_lod_threshold = render_data.screen_lod_threshold; + shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier; + + shadow_pass.framebuffer = p_framebuffer; + shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); + shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE; + shadow_pass.rect = p_rect; + + scene_state.shadow_passes.push_back(shadow_pass); + } +} + +void RenderForwardMobile::_render_shadow_process() { + //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time) + + for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { + //render passes need to be configured after instance buffer is done, since they need the latest version + SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) { + RD::get_singleton()->draw_command_begin_label("Shadow Render"); + + for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { + SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); + _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); + } + + if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) { + RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier); + } + RD::get_singleton()->draw_command_end_label(); +} + +/* */ + +void RenderForwardMobile::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { + RENDER_TIMESTAMP("Setup Rendering Material"); + + RD::get_singleton()->draw_command_begin_label("Render Material"); + + _update_render_base_uniform_set(); + + scene_state.ubo.dual_paraboloid_side = 0; + scene_state.ubo.material_uv2_mode = false; + + RenderDataRD render_data; + render_data.cam_projection = p_cam_projection; + render_data.cam_transform = p_cam_transform; + render_data.instances = &p_instances; + + _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); + + PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); + + RENDER_TIMESTAMP("Render Material"); + + { + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set); + //regular forward for now + Vector<Color> clear; + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); + RD::get_singleton()->draw_list_end(); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { + RENDER_TIMESTAMP("Setup Rendering UV2"); + + RD::get_singleton()->draw_command_begin_label("Render UV2"); + + _update_render_base_uniform_set(); + + scene_state.ubo.dual_paraboloid_side = 0; + scene_state.ubo.material_uv2_mode = true; + + RenderDataRD render_data; + render_data.instances = &p_instances; + + _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); + + PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); + + RENDER_TIMESTAMP("Render Material"); + + { + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true); + //regular forward for now + Vector<Color> clear; + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + + const int uv_offset_count = 9; + static const Vector2 uv_offsets[uv_offset_count] = { + Vector2(-1, 1), + Vector2(1, 1), + Vector2(1, -1), + Vector2(-1, -1), + Vector2(-1, 0), + Vector2(1, 0), + Vector2(0, -1), + Vector2(0, 1), + Vector2(0, 0), + + }; + + for (int i = 0; i < uv_offset_count; i++) { + Vector2 ofs = uv_offsets[i]; + ofs.x /= p_region.size.width; + ofs.y /= p_region.size.height; + render_list_params.uv_offset = ofs; + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative + } + render_list_params.uv_offset = Vector2(); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles + + RD::get_singleton()->draw_list_end(); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RenderForwardMobile::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { + // we don't do GI in low end.. +} + +void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { + RENDER_TIMESTAMP("Setup Render Collider Heightfield"); + + RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); + + _update_render_base_uniform_set(); + scene_state.ubo.dual_paraboloid_side = 0; + + RenderDataRD render_data; + render_data.cam_projection = p_cam_projection; + render_data.cam_transform = p_cam_transform; + render_data.z_near = 0.0; + render_data.z_far = p_cam_projection.get_z_far(); + render_data.instances = &p_instances; + + _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false); + + PassMode pass_mode = PASS_MODE_SHADOW; + + _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); + + RENDER_TIMESTAMP("Render Collider Heightfield"); + + { + //regular forward for now + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set); + _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); + } + RD::get_singleton()->draw_command_end_label(); +} + +void RenderForwardMobile::_base_uniforms_changed() { + if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { + RD::get_singleton()->free(render_base_uniform_set); + } + render_base_uniform_set = RID(); +} + +void RenderForwardMobile::_update_render_base_uniform_set() { + if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { + if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { + RD::get_singleton()->free(render_base_uniform_set); + } + + // This is all loaded into set 0 + + lightmap_texture_array_version = storage->lightmap_array_get_version(); + + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 1; + u.ids.resize(12); + RID *ids_ptr = u.ids.ptrw(); + ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.ids.push_back(scene_shader.shadow_sampler); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_omni_light_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_spot_light_buffer()); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_reflection_probe_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(get_directional_light_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.lightmap_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.lightmap_capture_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID decal_atlas = storage->decal_atlas_get_texture(); + u.ids.push_back(decal_atlas); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID decal_atlas = storage->decal_atlas_get_texture_srgb(); + u.ids.push_back(decal_atlas); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_decal_buffer()); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 12; + u.ids.push_back(storage->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + + render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET); + } +} + +RID RenderForwardMobile::_render_buffers_get_normal_texture(RID p_render_buffers) { + // RenderBufferDataForwardMobile *rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffers); + + // We don't have this. This is for debugging + // return rb->normal_roughness_buffer; + return RID(); +} + +void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) { + if (p_render_list == RENDER_LIST_OPAQUE) { + scene_state.used_sss = false; + scene_state.used_screen_texture = false; + scene_state.used_normal_texture = false; + scene_state.used_depth_texture = false; + } + uint32_t lightmap_captures_used = 0; + + Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); + near_plane.d += p_render_data->cam_projection.get_z_near(); + float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near(); + + RenderList *rl = &render_list[p_render_list]; + + // Parse any updates on our geometry, updates surface caches and such + _update_dirty_geometry_instances(); + + if (!p_append) { + rl->clear(); + if (p_render_list == RENDER_LIST_OPAQUE) { + render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too + } + } + + //fill list + + for (int i = 0; i < (int)p_render_data->instances->size(); i++) { + GeometryInstanceForwardMobile *inst = static_cast<GeometryInstanceForwardMobile *>((*p_render_data->instances)[i]); + + Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); + inst->depth = near_plane.distance_to(support_min); + uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); + + uint32_t flags = inst->base_flags; //fill flags if appropriate + + bool uses_lightmap = false; + // bool uses_gi = false; + + if (p_render_list == RENDER_LIST_OPAQUE) { + if (inst->lightmap_instance.is_valid()) { + int32_t lightmap_cull_index = -1; + for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { + if (scene_state.lightmap_ids[j] == inst->lightmap_instance) { + lightmap_cull_index = j; + break; + } + } + if (lightmap_cull_index >= 0) { + inst->gi_offset_cache = inst->lightmap_slice_index << 16; + inst->gi_offset_cache |= lightmap_cull_index; + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; + if (scene_state.lightmap_has_sh[lightmap_cull_index]) { + flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; + } + uses_lightmap = true; + } else { + inst->gi_offset_cache = 0xFFFFFFFF; + } + + } else if (inst->lightmap_sh) { + if (lightmap_captures_used < scene_state.max_lightmap_captures) { + const Color *src_capture = inst->lightmap_sh->sh; + LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; + for (int j = 0; j < 9; j++) { + lcd.sh[j * 4 + 0] = src_capture[j].r; + lcd.sh[j * 4 + 1] = src_capture[j].g; + lcd.sh[j * 4 + 2] = src_capture[j].b; + lcd.sh[j * 4 + 3] = src_capture[j].a; + } + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; + inst->gi_offset_cache = lightmap_captures_used; + lightmap_captures_used++; + uses_lightmap = true; + } + } + } + inst->flags_cache = flags; + + GeometryInstanceSurfaceDataCache *surf = inst->surface_caches; + + while (surf) { + surf->sort.uses_lightmap = 0; + + // LOD + + if (p_render_data->screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) { + //lod + Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal); + Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal); + + float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min); + float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max); + + float distance = 0.0; + + if (distance_min * distance_max < 0.0) { + //crossing plane + distance = 0.0; + } else if (distance_min >= 0.0) { + distance = distance_min; + } else if (distance_max <= 0.0) { + distance = -distance_max; + } + + surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + } else { + surf->lod_index = 0; + } + + // ADD Element + if (p_pass_mode == PASS_MODE_COLOR) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + rl->add_element(surf); + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + render_list[RENDER_LIST_ALPHA].add_element(surf); + // if (uses_gi) { + // surf->sort.uses_forward_gi = 1; + // } + } + + if (uses_lightmap) { + surf->sort.uses_lightmap = 1; // This needs to become our lightmap index but we'll do that in a separate PR. + } + + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { + scene_state.used_sss = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { + scene_state.used_screen_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) { + scene_state.used_normal_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { + scene_state.used_depth_texture = true; + } + + } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { + rl->add_element(surf); + } + } else { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + rl->add_element(surf); + } + } + + surf->sort.depth_layer = depth_layer; + + surf = surf->next; + } + } +} + +void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { + //!BAS! need to go through this and find out what we don't need anymore + + // This populates our UBO with main scene data that is pushed into set 1 + + //CameraMatrix projection = p_render_data->cam_projection; + //projection.flip_y(); // Vulkan and modern APIs use Y-Down + CameraMatrix correction; + correction.set_depth_correction(p_flip_y); + CameraMatrix projection = correction * p_render_data->cam_projection; + + //store camera into ubo + RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); + RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); + RendererStorageRD::store_transform(p_render_data->cam_transform, scene_state.ubo.camera_matrix); + RendererStorageRD::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + + scene_state.ubo.z_far = p_render_data->z_far; + scene_state.ubo.z_near = p_render_data->z_near; + + scene_state.ubo.pancake_shadows = p_pancake_shadows; + + RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + + scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); + scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); + scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); + scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); + + Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); + scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; + scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; + + if (p_render_data->shadow_atlas.is_valid()) { + Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas); + scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; + scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; + } + { + Vector2 dss = directional_shadow_get_size(); + scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x; + scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y; + } + + //time global variables + scene_state.ubo.time = time; + + /* + scene_state.ubo.gi_upscale_for_msaa = false; + scene_state.ubo.volumetric_fog_enabled = false; + scene_state.ubo.fog_enabled = false; + + if (p_render_data->render_buffers.is_valid()) { + RenderBufferDataForwardMobile *render_buffers = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_data->render_buffers); + if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { + scene_state.ubo.gi_upscale_for_msaa = true; + } + + if (render_buffers_has_volumetric_fog(p_render_data->render_buffers)) { + scene_state.ubo.volumetric_fog_enabled = true; + float fog_end = render_buffers_get_volumetric_fog_end(p_render_data->render_buffers); + if (fog_end > 0.0) { + scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; + } else { + scene_state.ubo.volumetric_fog_inv_length = 1.0; + } + + float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_data->render_buffers); //reverse lookup + if (fog_detail_spread > 0.0) { + scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; + } else { + scene_state.ubo.volumetric_fog_detail_spread = 1.0; + } + } + } + + */ + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { + scene_state.ubo.use_ambient_light = true; + scene_state.ubo.ambient_light_color_energy[0] = 1; + scene_state.ubo.ambient_light_color_energy[1] = 1; + scene_state.ubo.ambient_light_color_energy[2] = 1; + scene_state.ubo.ambient_light_color_energy[3] = 1.0; + scene_state.ubo.use_ambient_cubemap = false; + scene_state.ubo.use_reflection_cubemap = false; + scene_state.ubo.ssao_enabled = false; + + } else if (is_environment(p_render_data->environment)) { + RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment); + RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment); + + float bg_energy = environment_get_bg_energy(p_render_data->environment); + scene_state.ubo.ambient_light_color_energy[3] = bg_energy; + + scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment); + + //ambient + if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { + Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment); + color = color.to_linear(); + + scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy; + scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy; + scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy; + scene_state.ubo.use_ambient_light = true; + scene_state.ubo.use_ambient_cubemap = false; + } else { + float energy = environment_get_ambient_light_energy(p_render_data->environment); + Color color = environment_get_ambient_light_color(p_render_data->environment); + color = color.to_linear(); + scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; + scene_state.ubo.ambient_light_color_energy[1] = color.g * energy; + scene_state.ubo.ambient_light_color_energy[2] = color.b * energy; + + Basis sky_transform = environment_get_sky_orientation(p_render_data->environment); + sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis; + RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); + + scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; + scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; + } + + //specular + RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment); + if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { + scene_state.ubo.use_reflection_cubemap = true; + } else { + scene_state.ubo.use_reflection_cubemap = false; + } + + scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_render_data->environment); + scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment); + scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment); + + Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear(); + scene_state.ubo.ao_color[0] = ao_color.r; + scene_state.ubo.ao_color[1] = ao_color.g; + scene_state.ubo.ao_color[2] = ao_color.b; + scene_state.ubo.ao_color[3] = ao_color.a; + + scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment); + scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); + scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment); + scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment); + if (scene_state.ubo.fog_height_density >= 0.0001) { + scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; + } + scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment); + + Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear(); + float fog_energy = environment_get_fog_light_energy(p_render_data->environment); + + scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; + scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; + scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; + + scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment); + + } else { + if (p_render_data->reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + scene_state.ubo.use_ambient_light = false; + } else { + scene_state.ubo.use_ambient_light = true; + Color clear_color = p_default_bg_color; + clear_color = clear_color.to_linear(); + scene_state.ubo.ambient_light_color_energy[0] = clear_color.r; + scene_state.ubo.ambient_light_color_energy[1] = clear_color.g; + scene_state.ubo.ambient_light_color_energy[2] = clear_color.b; + scene_state.ubo.ambient_light_color_energy[3] = 1.0; + } + + scene_state.ubo.use_ambient_cubemap = false; + scene_state.ubo.use_reflection_cubemap = false; + scene_state.ubo.ssao_enabled = false; + } + + scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); + scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); + scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); + + if (p_index >= (int)scene_state.uniform_buffers.size()) { + uint32_t from = scene_state.uniform_buffers.size(); + scene_state.uniform_buffers.resize(p_index + 1); + render_pass_uniform_sets.resize(p_index + 1); + for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { + scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); + } + } + RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); +} + +void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { + // !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer? + + RenderList *rl = &render_list[p_render_list]; + uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); + + rl->element_info.resize(p_offset + element_total); + + for (uint32_t i = 0; i < element_total; i++) { + GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; + RenderElementInfo &element_info = rl->element_info[p_offset + i]; + + element_info.lod_index = surface->lod_index; + element_info.uses_lightmap = surface->sort.uses_lightmap; + } +} + +/// RENDERING /// + +void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + //use template for faster performance (pass mode comparisons are inlined) + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: { + _render_list_template<PASS_MODE_COLOR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_TRANSPARENT: { + _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW: { + _render_list_template<PASS_MODE_SHADOW>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW_DP: { + _render_list_template<PASS_MODE_SHADOW_DP>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_MATERIAL: { + _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + } +} + +void RenderForwardMobile::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { + uint32_t render_total = p_params->element_count; + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t render_from = p_thread * render_total / total_threads; + uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); + _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); +} + +void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); + p_params->framebuffer_format = fb_format; + + if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, p_params); + RD::get_singleton()->draw_list_end(p_params->barrier); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(p_params->barrier); + } +} + +template <RenderForwardMobile::PassMode p_pass_mode> +void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + RD::DrawListID draw_list = p_draw_list; + RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; + + //global scope bindings + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); + + RID prev_material_uniform_set; + + RID prev_vertex_array_rd; + RID prev_index_array_rd; + RID prev_pipeline_rd; + RID prev_xforms_uniform_set; + + bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP); + + for (uint32_t i = p_from_element; i < p_to_element; i++) { + const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; + const RenderElementInfo &element_info = p_params->element_info[i]; + const GeometryInstanceForwardMobile *inst = surf->owner; + + // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant; + GeometryInstanceForwardMobile::PushConstant push_constant; + + if (inst->store_transform_cache) { + RendererStorageRD::store_transform(inst->transform, push_constant.transform); + } else { + RendererStorageRD::store_transform(Transform(), push_constant.transform); + } + + push_constant.flags = inst->flags_cache; + push_constant.gi_offset = inst->gi_offset_cache; + push_constant.layer_mask = inst->layer_mask; + push_constant.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset); + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + // abuse lightmap_uv_scale[0] here, should not be needed here + push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x; + push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y; + } else { + push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x; + push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y; + push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; + push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; + }; + + _fill_instance_indices(inst->omni_lights, inst->omni_light_count, push_constant.omni_lights, inst->spot_lights, inst->spot_light_count, push_constant.spot_lights, inst->reflection_probes, inst->reflection_probe_count, push_constant.reflection_probes, inst->decals, inst->decals_count, push_constant.decals, push_constant.layer_mask); + + RID material_uniform_set; + SceneShaderForwardMobile::ShaderData *shader; + void *mesh_surface; + + if (shadow_pass) { + material_uniform_set = surf->material_uniform_set_shadow; + shader = surf->shader_shadow; + mesh_surface = surf->surface_shadow; + + } else { + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; + mesh_surface = surf->surface; + } + + if (!mesh_surface) { + continue; + } + + //find cull variant + SceneShaderForwardMobile::ShaderData::CullVariant cull_variant; + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { + cull_variant = SceneShaderForwardMobile::ShaderData::CULL_VARIANT_DOUBLE_SIDED; + } else { + bool mirror = surf->owner->mirror; + if (p_params->reverse_cull) { + mirror = !mirror; + } + cull_variant = mirror ? SceneShaderForwardMobile::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardMobile::ShaderData::CULL_VARIANT_NORMAL; + } + + RS::PrimitiveType primitive = surf->primitive; + RID xforms_uniform_set = surf->owner->transforms_uniform_set; + + SceneShaderForwardMobile::ShaderVersion shader_version = SceneShaderForwardMobile::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: + case PASS_MODE_COLOR_TRANSPARENT: { + if (element_info.uses_lightmap) { + shader_version = SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS; + } else { + shader_version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS; + } + } break; + case PASS_MODE_SHADOW: { + shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS; + } break; + case PASS_MODE_SHADOW_DP: { + shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_DP; + } break; + case PASS_MODE_DEPTH_MATERIAL: { + shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; + } break; + } + + PipelineCacheRD *pipeline = nullptr; + + pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; + + RD::VertexFormatID vertex_format = -1; + RID vertex_array_rd; + RID index_array_rd; + + //skeleton and blend shape + if (surf->owner->mesh_instance.is_valid()) { + storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } else { + storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } + + index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + + if (prev_vertex_array_rd != vertex_array_rd) { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); + prev_vertex_array_rd = vertex_array_rd; + } + + if (prev_index_array_rd != index_array_rd) { + if (index_array_rd.is_valid()) { + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd); + } + prev_index_array_rd = index_array_rd; + } + + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); + + if (pipeline_rd != prev_pipeline_rd) { + // checking with prev shader does not make so much sense, as + // the pipeline may still be different. + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd); + prev_pipeline_rd = pipeline_rd; + } + + if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET); + prev_xforms_uniform_set = xforms_uniform_set; + } + + if (material_uniform_set != prev_material_uniform_set) { + //update uniform set + if (material_uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); + } + + prev_material_uniform_set = material_uniform_set; + } + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant)); + + uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1; + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) { + instance_count /= surf->owner->trail_steps; + } + + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); + } +} + +/* Geometry instance */ + +RendererSceneRender::GeometryInstance *RenderForwardMobile::geometry_instance_create(RID p_base) { + RS::InstanceType type = storage->get_base_type(p_base); + ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); + + GeometryInstanceForwardMobile *ginstance = geometry_instance_alloc.alloc(); + ginstance->data = memnew(GeometryInstanceForwardMobile::Data); + + ginstance->data->base = p_base; + ginstance->data->base_type = type; + + _geometry_instance_mark_dirty(ginstance); + + return ginstance; +} + +void RenderForwardMobile::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->skeleton = p_skeleton; + + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} + +void RenderForwardMobile::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_override = p_override; + + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} + +void RenderForwardMobile::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->surface_materials = p_materials; + + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} + +void RenderForwardMobile::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->mesh_instance = p_mesh_instance; + + _geometry_instance_mark_dirty(ginstance); +} + +void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->transform = p_transform; + ginstance->mirror = p_transform.basis.determinant() < 0; + ginstance->data->aabb = p_aabb; + ginstance->transformed_aabb = p_transformed_aabb; + + Vector3 model_scale_vec = p_transform.basis.get_scale_abs(); + // handle non uniform scale here + + float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); + float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); + ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; + + ginstance->lod_model_scale = max_scale; +} + +void RenderForwardMobile::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->layer_mask = p_layer_mask; +} + +void RenderForwardMobile::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lod_bias = p_lod_bias; +} + +void RenderForwardMobile::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_baked_light = p_enable; + + _geometry_instance_mark_dirty(ginstance); +} + +void RenderForwardMobile::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { + // !BAS! do we support this in mobile? + // GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + // ERR_FAIL_COND(!ginstance); + // ginstance->data->use_dynamic_gi = p_enable; + // _geometry_instance_mark_dirty(ginstance); +} + +void RenderForwardMobile::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lightmap_instance = p_lightmap_instance; + ginstance->lightmap_uv_scale = p_lightmap_uv_scale; + ginstance->lightmap_slice_index = p_lightmap_slice_index; + _geometry_instance_mark_dirty(ginstance); +} + +void RenderForwardMobile::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_sh9) { + if (ginstance->lightmap_sh == nullptr) { + ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); + } + + memcpy(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); + } else { + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + ginstance->lightmap_sh = nullptr; + } + } + _geometry_instance_mark_dirty(ginstance); +} + +void RenderForwardMobile::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->shader_parameters_offset = p_offset; + _geometry_instance_mark_dirty(ginstance); +} + +void RenderForwardMobile::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->data->cast_double_sided_shadows = p_enable; + _geometry_instance_mark_dirty(ginstance); +} + +Transform RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance); + ERR_FAIL_COND_V(!ginstance, Transform()); + return ginstance->transform; +} + +AABB RenderForwardMobile::geometry_instance_get_aabb(GeometryInstance *p_instance) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance); + ERR_FAIL_COND_V(!ginstance, AABB()); + return ginstance->data->aabb; +} + +void RenderForwardMobile::geometry_instance_free(GeometryInstance *p_geometry_instance) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + } + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + memdelete(ginstance->data); + geometry_instance_alloc.free(ginstance); +} + +uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() { + return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL)); +} + +void RenderForwardMobile::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->omni_light_count = 0; + ginstance->spot_light_count = 0; + + for (uint32_t i = 0; i < p_light_instance_count; i++) { + RS::LightType type = light_instance_get_type(p_light_instances[i]); + switch (type) { + case RS::LIGHT_OMNI: { + if (ginstance->omni_light_count < (uint32_t)MAX_RDL_CULL) { + ginstance->omni_lights[ginstance->omni_light_count] = p_light_instances[i]; + ginstance->omni_light_count++; + } + } break; + case RS::LIGHT_SPOT: { + if (ginstance->spot_light_count < (uint32_t)MAX_RDL_CULL) { + ginstance->spot_lights[ginstance->spot_light_count] = p_light_instances[i]; + ginstance->spot_light_count++; + } + } break; + default: + break; + } + } +} + +void RenderForwardMobile::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL; + for (uint32_t i = 0; i < ginstance->reflection_probe_count; i++) { + ginstance->reflection_probes[i] = p_reflection_probe_instances[i]; + } +} + +void RenderForwardMobile::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL; + for (uint32_t i = 0; i < ginstance->decals_count; i++) { + ginstance->decals[i] = p_decal_instances[i]; + } +} + +void RenderForwardMobile::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { + // We do not have this here! +} + +void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + if (ginstance->dirty_list_element.in_list()) { + return; + } + + //clear surface caches + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + + ginstance->surface_caches = nullptr; + + geometry_instance_dirty_list.add(&ginstance->dirty_list_element); +} + +void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { + bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; + bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); + bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha; + + uint32_t flags = 0; + + if (p_material->shader_data->uses_sss) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; + } + + if (p_material->shader_data->uses_screen_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + } + + if (p_material->shader_data->uses_depth_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + } + + if (p_material->shader_data->uses_normal_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; + } + + if (ginstance->data->cast_double_sided_shadows) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; + } + + if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) { + //material is only meant for alpha pass + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; + if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + } else { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + + if (p_material->shader_data->uses_particle_trails) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS; + } + + SceneShaderForwardMobile::MaterialData *material_shadow = nullptr; + void *surface_shadow = nullptr; + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; + material_shadow = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D); + + RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh); + + if (shadow_mesh.is_valid()) { + surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface); + } + + } else { + material_shadow = p_material; + } + + GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc(); + + sdcache->flags = flags; + + sdcache->shader = p_material->shader_data; + sdcache->material_uniform_set = p_material->uniform_set; + sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface); + sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface); + sdcache->surface_index = p_surface; + + if (ginstance->data->dirty_dependencies) { + storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); + } + + //shadow + sdcache->shader_shadow = material_shadow->shader_data; + sdcache->material_uniform_set_shadow = material_shadow->uniform_set; + + sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface; + + sdcache->owner = ginstance; + + sdcache->next = ginstance->surface_caches; + ginstance->surface_caches = sdcache; + + //sortkey + + sdcache->sort.sort_key1 = 0; + sdcache->sort.sort_key2 = 0; + + sdcache->sort.surface_index = p_surface; + sdcache->sort.material_id_low = p_material_id & 0x0000FFFF; + sdcache->sort.material_id_hi = p_material_id >> 16; + sdcache->sort.shader_id = p_shader_id; + sdcache->sort.geometry_id = p_mesh.get_local_index(); + // sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; + sdcache->sort.priority = p_material->priority; +} + +void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { + RID m_src; + + m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; + + SceneShaderForwardMobile::MaterialData *material = nullptr; + + if (m_src.is_valid()) { + material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (material) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + } else { + material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D); + m_src = scene_shader.default_material; + } + + ERR_FAIL_COND(!material); + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + +void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry_instance) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_begin(); + } + + //add geometry for drawing + switch (ginstance->data->base_type) { + case RS::INSTANCE_MESH: { + const RID *materials = nullptr; + uint32_t surface_count; + RID mesh = ginstance->data->base; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + //if no materials, no surfaces. + const RID *inst_materials = ginstance->data->surface_materials.ptr(); + uint32_t surf_mat_count = ginstance->data->surface_materials.size(); + + for (uint32_t j = 0; j < surface_count; j++) { + RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j]; + _geometry_instance_add_surface(ginstance, j, material, mesh); + } + } + + ginstance->instance_count = 1; + + } break; + + case RS::INSTANCE_MULTIMESH: { + RID mesh = storage->multimesh_get_mesh(ginstance->data->base); + if (mesh.is_valid()) { + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t j = 0; j < surface_count; j++) { + _geometry_instance_add_surface(ginstance, j, materials[j], mesh); + } + } + + ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + + } break; +#if 0 + case RS::INSTANCE_IMMEDIATE: { + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + ERR_CONTINUE(!immediate); + + _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + + } break; +#endif + case RS::INSTANCE_PARTICLES: { + int draw_passes = storage->particles_get_draw_passes(ginstance->data->base); + + for (int j = 0; j < draw_passes; j++) { + RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); + if (!mesh.is_valid()) { + continue; + } + + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t k = 0; k < surface_count; k++) { + _geometry_instance_add_surface(ginstance, k, materials[k], mesh); + } + } + } + + ginstance->instance_count = storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps); + + } break; + + default: { + } + } + + //Fill push constant + + bool store_transform = true; + + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + } + if (storage->multimesh_uses_colors(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + } + if (storage->multimesh_uses_custom_data(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + } + + ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + if (false) { // 2D particles + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + } + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + + //for particles, stride is the trail size + ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT); + + if (!storage->particles_is_using_local_coords(ginstance->data->base)) { + store_transform = false; + } + ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { + if (storage->skeleton_is_valid(ginstance->data->skeleton)) { + ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (ginstance->data->dirty_dependencies) { + storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); + } + } + } + + ginstance->store_transform_cache = store_transform; + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_end(); + ginstance->data->dirty_dependencies = false; + } + + ginstance->dirty_list_element.remove_from_list(); +} + +void RenderForwardMobile::_update_dirty_geometry_instances() { + while (geometry_instance_dirty_list.first()) { + _geometry_instance_update(geometry_instance_dirty_list.first()->self()); + } +} + +void RenderForwardMobile::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_PARTICLES: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { + static_cast<RenderForwardMobile *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata); + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->instance_count = static_cast<RenderForwardMobile *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + } break; + default: { + //rest of notifications of no interest + } break; + } +} +void RenderForwardMobile::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { + static_cast<RenderForwardMobile *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); +} + +/* misc */ + +bool RenderForwardMobile::is_dynamic_gi_supported() const { + return false; +} + +bool RenderForwardMobile::is_clustered_enabled() const { + return false; +} + +bool RenderForwardMobile::is_volumetric_supported() const { + return false; +} + +uint32_t RenderForwardMobile::get_max_elements() const { + return 256; +} + +RenderForwardMobile *RenderForwardMobile::singleton = nullptr; + +RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) : + RendererSceneRenderRD(p_storage) { + singleton = this; + + String defines; + + defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; + if (is_using_radiance_cubemap_array()) { + defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + } + // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; + defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n"; + + { + //lightmaps + scene_state.max_lightmaps = 2; + defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; + defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; + + scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps); + } + { + //captures + scene_state.max_lightmap_captures = 2048; + scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures); + scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures); + } + { + defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n"; + } + + scene_shader.init(p_storage, defines); + + // !BAS! maybe we need a mobile version of this setting? + render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); +} + +RenderForwardMobile::~RenderForwardMobile() { + directional_shadow_atlas_set_size(0); + + //clear base uniform set if still valid + for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) { + if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) { + RD::get_singleton()->free(render_pass_uniform_sets[i]); + } + } + + { + for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { + RD::get_singleton()->free(scene_state.uniform_buffers[i]); + } + RD::get_singleton()->free(scene_state.lightmap_buffer); + RD::get_singleton()->free(scene_state.lightmap_capture_buffer); + memdelete_arr(scene_state.lightmap_captures); + } +} diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h new file mode 100644 index 0000000000..bf911319f2 --- /dev/null +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -0,0 +1,603 @@ +/*************************************************************************/ +/* render_forward_mobile.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H +#define RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H + +#include "core/templates/paged_allocator.h" +#include "servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" + +namespace RendererSceneRenderImplementation { + +class RenderForwardMobile : public RendererSceneRenderRD { + friend SceneShaderForwardMobile; + +protected: + /* Scene Shader */ + + enum { + SCENE_UNIFORM_SET = 0, + RENDER_PASS_UNIFORM_SET = 1, + TRANSFORMS_UNIFORM_SET = 2, + MATERIAL_UNIFORM_SET = 3 + }; + + enum { + MAX_LIGHTMAPS = 8, + MAX_RDL_CULL = 8, // maximum number of reflection probes, decals or lights we can cull per geometry instance + INSTANCE_DATA_BUFFER_MIN_SIZE = 4096 + }; + + enum RenderListType { + RENDER_LIST_OPAQUE, //used for opaque objects + RENDER_LIST_ALPHA, //used for transparent objects + RENDER_LIST_SECONDARY, //used for shadows and other objects + RENDER_LIST_MAX + }; + + /* Scene Shader */ + + SceneShaderForwardMobile scene_shader; + + /* Render Buffer */ + + struct RenderBufferDataForwardMobile : public RenderBufferData { + RID color; + RID depth; + // RID normal_roughness_buffer; + + RS::ViewportMSAA msaa; + RD::TextureSamples texture_samples; + + RID color_msaa; + RID depth_msaa; + // RID normal_roughness_buffer_msaa; + + RID color_fb; + int width, height; + + void clear(); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); + + ~RenderBufferDataForwardMobile(); + }; + + virtual RenderBufferData *_create_render_buffer_data(); + + /* Rendering */ + + enum PassMode { + PASS_MODE_COLOR, + // PASS_MODE_COLOR_SPECULAR, + PASS_MODE_COLOR_TRANSPARENT, + PASS_MODE_SHADOW, + PASS_MODE_SHADOW_DP, + // PASS_MODE_DEPTH, + // PASS_MODE_DEPTH_NORMAL_ROUGHNESS, + // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, + PASS_MODE_DEPTH_MATERIAL, + // PASS_MODE_SDF, + }; + + struct GeometryInstanceForwardMobile; + struct GeometryInstanceSurfaceDataCache; + struct RenderElementInfo; + + struct RenderListParameters { + GeometryInstanceSurfaceDataCache **elements = nullptr; + RenderElementInfo *element_info = nullptr; + int element_count = 0; + bool reverse_cull = false; + PassMode pass_mode = PASS_MODE_COLOR; + // bool no_gi = false; + RID render_pass_uniform_set; + bool force_wireframe = false; + Vector2 uv_offset; + Plane lod_plane; + float lod_distance_multiplier = 0.0; + float screen_lod_threshold = 0.0; + RD::FramebufferFormatID framebuffer_format = 0; + uint32_t element_offset = 0; + uint32_t barrier = RD::BARRIER_MASK_ALL; + + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { + elements = p_elements; + element_info = p_element_info; + element_count = p_element_count; + reverse_cull = p_reverse_cull; + pass_mode = p_pass_mode; + // no_gi = p_no_gi; + render_pass_uniform_set = p_render_pass_uniform_set; + force_wireframe = p_force_wireframe; + uv_offset = p_uv_offset; + lod_plane = p_lod_plane; + lod_distance_multiplier = p_lod_distance_multiplier; + screen_lod_threshold = p_screen_lod_threshold; + element_offset = p_element_offset; + barrier = p_barrier; + } + }; + + RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color); + + virtual void _render_shadow_begin(); + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); + virtual void _render_shadow_process(); + virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances); + + uint64_t lightmap_texture_array_version = 0xFFFFFFFF; + + virtual void _base_uniforms_changed(); + void _update_render_base_uniform_set(); + virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); + + void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false); + void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); + // void _update_instance_data_buffer(RenderListType p_render_list); + + static RenderForwardMobile *singleton; + + void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); + void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform); + + RID render_base_uniform_set; + LocalVector<RID> render_pass_uniform_sets; + + /* Light map */ + + struct LightmapData { + float normal_xform[12]; + }; + + struct LightmapCaptureData { + float sh[9 * 4]; + }; + + /* Scene state */ + + struct SceneState { + // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code + struct UBO { + float projection_matrix[16]; + float inv_projection_matrix[16]; + + float camera_matrix[16]; + float inv_camera_matrix[16]; + + float viewport_size[2]; + float screen_pixel_size[2]; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; + + uint32_t directional_penumbra_shadow_samples; + uint32_t directional_soft_shadow_samples; + uint32_t penumbra_shadow_samples; + uint32_t soft_shadow_samples; + + float ambient_light_color_energy[4]; + + float ambient_color_sky_mix; + uint32_t use_ambient_light; + uint32_t use_ambient_cubemap; + uint32_t use_reflection_cubemap; + + float radiance_inverse_xform[12]; + + float shadow_atlas_pixel_size[2]; + float directional_shadow_pixel_size[2]; + + uint32_t directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + uint32_t ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + uint32_t roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uint32_t roughness_limiter_pad[2]; + + float ao_color[4]; + + // Fog + uint32_t fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + float fog_light_color[3]; + float fog_sun_scatter; + + float fog_aerial_perspective; + uint32_t material_uv2_mode; + + float time; + float reflection_multiplier; + + uint32_t pancake_shadows; + uint32_t pad1; + uint32_t pad2; + uint32_t pad3; + }; + + UBO ubo; + + LocalVector<RID> uniform_buffers; + + // !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in + LightmapData lightmaps[MAX_LIGHTMAPS]; + RID lightmap_ids[MAX_LIGHTMAPS]; + bool lightmap_has_sh[MAX_LIGHTMAPS]; + uint32_t lightmaps_used = 0; + uint32_t max_lightmaps; + RID lightmap_buffer; + + LightmapCaptureData *lightmap_captures; + uint32_t max_lightmap_captures; + RID lightmap_capture_buffer; + + bool used_screen_texture = false; + bool used_normal_texture = false; + bool used_depth_texture = false; + bool used_sss = false; + + struct ShadowPass { + uint32_t element_from; + uint32_t element_count; + bool flip_cull; + PassMode pass_mode; + + RID rp_uniform_set; + Plane camera_plane; + float lod_distance_multiplier; + float screen_lod_threshold; + + RID framebuffer; + RD::InitialAction initial_depth_action; + RD::FinalAction final_depth_action; + Rect2i rect; + }; + + LocalVector<ShadowPass> shadow_passes; + } scene_state; + + /* Render List */ + + // !BAS! Render list can probably be reused between clustered and mobile? + struct RenderList { + LocalVector<GeometryInstanceSurfaceDataCache *> elements; + LocalVector<RenderElementInfo> element_info; + + void clear() { + elements.clear(); + element_info.clear(); + } + + //should eventually be replaced by radix + + struct SortByKey { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); + } + }; + + void sort_by_key() { + SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + void sort_by_key_range(uint32_t p_from, uint32_t p_size) { + SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter; + sorter.sort(elements.ptr() + p_from, p_size); + } + + struct SortByDepth { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->owner->depth < B->owner->depth); + } + }; + + void sort_by_depth() { //used for shadows + + SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + struct SortByReverseDepthAndPriority { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority); + } + }; + + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + + SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) { + elements.push_back(p_element); + } + }; + + struct RenderElementInfo { + uint32_t uses_lightmap : 1; + uint32_t lod_index : 8; + uint32_t reserved : 23; + }; + + template <PassMode p_pass_mode> + _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + LocalVector<RD::DrawListID> thread_draw_lists; + void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); + void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); + + uint32_t render_list_thread_threshold = 500; + + RenderList render_list[RENDER_LIST_MAX]; + + /* Geometry instance */ + + // check which ones of these apply, probably all except GI and SDFGI + enum { + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, + INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, + INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, + INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, + INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, + INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16, + INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF, + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24, + }; + + struct GeometryInstanceLightmapSH { + Color sh[9]; + }; + + // Cached data for drawing surfaces + struct GeometryInstanceSurfaceDataCache { + enum { + FLAG_PASS_DEPTH = 1, + FLAG_PASS_OPAQUE = 2, + FLAG_PASS_ALPHA = 4, + FLAG_PASS_SHADOW = 8, + FLAG_USES_SHARED_SHADOW_MATERIAL = 128, + FLAG_USES_SUBSURFACE_SCATTERING = 2048, + FLAG_USES_SCREEN_TEXTURE = 4096, + FLAG_USES_DEPTH_TEXTURE = 8192, + FLAG_USES_NORMAL_TEXTURE = 16384, + FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, + FLAG_USES_PARTICLE_TRAILS = 65536, + }; + + union { + struct { + // !BAS! CHECK BITS!!! + + uint64_t surface_index : 10; + uint64_t geometry_id : 32; + uint64_t material_id_low : 16; + + uint64_t material_id_hi : 16; + uint64_t shader_id : 32; + uint64_t uses_lightmap : 4; // sort by lightmap id here, not whether its yes/no (is 4 bits enough?) + uint64_t depth_layer : 4; + uint64_t priority : 8; + + // uint64_t lod_index : 8; // no need to sort on LOD + // uint64_t uses_forward_gi : 1; // no GI here, remove + }; + struct { + uint64_t sort_key1; + uint64_t sort_key2; + }; + } sort; + + RS::PrimitiveType primitive = RS::PRIMITIVE_MAX; + uint32_t flags = 0; + uint32_t surface_index = 0; + uint32_t lod_index = 0; + + void *surface = nullptr; + RID material_uniform_set; + SceneShaderForwardMobile::ShaderData *shader = nullptr; + + void *surface_shadow = nullptr; + RID material_uniform_set_shadow; + SceneShaderForwardMobile::ShaderData *shader_shadow = nullptr; + + GeometryInstanceSurfaceDataCache *next = nullptr; + GeometryInstanceForwardMobile *owner = nullptr; + }; + + // !BAS! GeometryInstanceForwardClustered and GeometryInstanceForwardMobile will likely have a lot of overlap + // may need to think about making this its own class like GeometryInstanceRD? + + struct GeometryInstanceForwardMobile : public GeometryInstance { + // setup + uint32_t base_flags = 0; + uint32_t flags_cache = 0; + + // this structure maps to our push constant in our shader and is populated right before our draw call + struct PushConstant { + float transform[16]; + uint32_t flags; + uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables + uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint32_t layer_mask = 1; + float lightmap_uv_scale[4]; // doubles as uv_offset when needed + uint32_t reflection_probes[2]; // packed reflection probes + uint32_t omni_lights[2]; // packed omni lights + uint32_t spot_lights[2]; // packed spot lights + uint32_t decals[2]; // packed spot lights + }; + + // PushConstant push_constant; // we populate this from our instance data + + //used during rendering + uint32_t layer_mask = 1; + RID transforms_uniform_set; + float depth = 0; + bool mirror = false; + Transform transform; + bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform + bool non_uniform_scale = false; + AABB transformed_aabb; //needed for LOD + float lod_bias = 0.0; + float lod_model_scale = 1.0; + int32_t shader_parameters_offset = -1; + uint32_t instance_count = 0; + uint32_t trail_steps = 1; + RID mesh_instance; + + // lightmap + uint32_t gi_offset_cache = 0; // !BAS! Should rename this to lightmap_offset_cache, in forward clustered this was shared between gi and lightmap + uint32_t lightmap_slice_index; + Rect2 lightmap_uv_scale; + RID lightmap_instance; + GeometryInstanceLightmapSH *lightmap_sh = nullptr; + + // culled light info + uint32_t reflection_probe_count; + RID reflection_probes[MAX_RDL_CULL]; + uint32_t omni_light_count; + RID omni_lights[MAX_RDL_CULL]; + uint32_t spot_light_count; + RID spot_lights[MAX_RDL_CULL]; + uint32_t decals_count; + RID decals[MAX_RDL_CULL]; + + GeometryInstanceSurfaceDataCache *surface_caches = nullptr; + + // do we use this? + SelfList<GeometryInstanceForwardMobile> dirty_list_element; + + struct Data { + //data used less often goes into regular heap + RID base; + RS::InstanceType base_type; + + RID skeleton; + Vector<RID> surface_materials; + RID material_override; + AABB aabb; + + bool use_baked_light = false; + bool cast_double_sided_shadows = false; + // bool mirror = false; // !BAS! Does not seem used, we already have this in the main struct + + bool dirty_dependencies = false; + + RendererStorage::DependencyTracker dependency_tracker; + }; + + Data *data = nullptr; + + GeometryInstanceForwardMobile() : + dirty_list_element(this) {} + }; + +public: + static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); + static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); + + SelfList<GeometryInstanceForwardMobile>::List geometry_instance_dirty_list; + + PagedAllocator<GeometryInstanceForwardMobile> geometry_instance_alloc; + PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc; + PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh; + + void _geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); + void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); + void _geometry_instance_update(GeometryInstance *p_geometry_instance); + void _update_dirty_geometry_instances(); + + virtual GeometryInstance *geometry_instance_create(RID p_base); + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials); + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); + + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); + + virtual uint32_t geometry_instance_get_pair_mask(); + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); + + virtual bool free(RID p_rid); + + virtual bool is_dynamic_gi_supported() const; + virtual bool is_clustered_enabled() const; + virtual bool is_volumetric_supported() const; + virtual uint32_t get_max_elements() const; + + RenderForwardMobile(RendererStorageRD *p_storage); + ~RenderForwardMobile(); +}; +} // namespace RendererSceneRenderImplementation +#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H 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 new file mode 100644 index 0000000000..b9220cc514 --- /dev/null +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -0,0 +1,833 @@ +/*************************************************************************/ +/* scene_shader_forward_mobile.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "scene_shader_forward_mobile.h" +#include "core/config/project_settings.h" +#include "render_forward_mobile.h" + +using namespace RendererSceneRenderImplementation; + +/* ShaderData */ + +void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + uses_screen_texture = false; + + if (code == String()) { + return; //just invalid, but no error + } + + ShaderCompilerRD::GeneratedCode gen_code; + + int blend_mode = BLEND_MODE_MIX; + int depth_testi = DEPTH_TEST_ENABLED; + int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; + int cull = CULL_BACK; + + uses_point_size = false; + uses_alpha = false; + uses_blend_alpha = false; + uses_depth_pre_pass = false; + uses_discard = false; + uses_roughness = false; + uses_normal = false; + bool wireframe = false; + + unshaded = false; + uses_vertex = false; + uses_sss = false; + uses_transmittance = false; + uses_screen_texture = false; + uses_depth_texture = false; + uses_normal_texture = false; + uses_time = false; + writes_modelview_or_projection = false; + uses_world_coordinates = false; + uses_particle_trails = false; + + int depth_drawi = DEPTH_DRAW_OPAQUE; + + ShaderCompilerRD::IdentifierActions actions; + actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX; + actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT; + actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT; + + actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD); + actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX); + actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB); + actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); + + actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + + actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED); + actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE); + actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS); + + actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED); + + actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED); + actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT); + actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK); + + actions.render_mode_flags["unshaded"] = &unshaded; + actions.render_mode_flags["wireframe"] = &wireframe; + actions.render_mode_flags["particle_trails"] = &uses_particle_trails; + + actions.usage_flag_pointers["ALPHA"] = &uses_alpha; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + + // actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; + // actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; + + actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; + actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; + actions.usage_flag_pointers["DISCARD"] = &uses_discard; + actions.usage_flag_pointers["TIME"] = &uses_time; + actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; + actions.usage_flag_pointers["NORMAL"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; + + actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; + actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; + + actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["VERTEX"] = &uses_vertex; + + actions.uniforms = &uniforms; + + 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); + + if (version.is_null()) { + version = shader_singleton->shader.version_create(); + } + + depth_draw = DepthDraw(depth_drawi); + depth_test = DepthTest(depth_testi); + +#if 0 + print_line("**compiling shader:"); + print_line("**defines:\n"); + for (int i = 0; i < gen_code.defines.size(); i++) { + print_line(gen_code.defines[i]); + } + + Map<String, String>::Element * el = gen_code.code.front(); + while (el) { + print_line("\n**code " + el->key() + ":\n" + el->value()); + + el = el->next(); + } + + print_line("\n**uniforms:\n" + gen_code.uniforms); + print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX]); + print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT]); +#endif + + shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines); + ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + //blend modes + + // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { + blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; + } + + RD::PipelineColorBlendState::Attachment blend_attachment; + + switch (blend_mode) { + case BLEND_MODE_MIX: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + } break; + case BLEND_MODE_ADD: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_SUB: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_MUL: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + uses_blend_alpha = true; //force alpha used because of blend + } break; + case BLEND_MODE_ALPHA_TO_COVERAGE: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + } + } + + RD::PipelineColorBlendState blend_state_blend; + blend_state_blend.attachments.push_back(blend_attachment); + RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2); + RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2); + + //update pipelines + + RD::PipelineDepthStencilState depth_stencil_state; + + if (depth_test != DEPTH_TEST_DISABLED) { + depth_stencil_state.enable_depth_test = true; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; + } + + for (int i = 0; i < CULL_VARIANT_MAX; i++) { + RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = { + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED } + }; + + RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull]; + + for (int j = 0; j < RS::PRIMITIVE_MAX; j++) { + RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = { + RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_LINESTRIPS, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, + }; + + RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; + + for (int k = 0; k < SHADER_VERSION_MAX; k++) { + if (!static_cast<SceneShaderForwardMobile *>(singleton)->shader.is_variant_enabled(k)) { + continue; + } + RD::PipelineRasterizationState raster_state; + raster_state.cull_mode = cull_mode_rd; + raster_state.wireframe = wireframe; + + RD::PipelineColorBlendState blend_state; + RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; + RD::PipelineMultisampleState multisample_state; + + if (uses_alpha || uses_blend_alpha) { + // only allow these flags to go through if we have some form of msaa + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + multisample_state.enable_alpha_to_coverage = true; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + multisample_state.enable_alpha_to_coverage = true; + multisample_state.enable_alpha_to_one = true; + } + + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_blend; + if (depth_draw == DEPTH_DRAW_OPAQUE) { + depth_stencil.enable_depth_write = false; //alpha does not draw depth + } + } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, blend state contains nothing + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else { + pipelines[i][j][k].clear(); + continue; // do not use this version (will error if using it is attempted) + } + + /* + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_blend; + if (depth_draw == DEPTH_DRAW_OPAQUE) { + depth_stencil.enable_depth_write = false; //alpha does not draw depth + } + } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { + if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, blend state contains nothing + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else { + blend_state = blend_state_opaque; //writes to normal and roughness in opaque way + } + } else { + pipelines[i][j][k].clear(); + continue; // do not use this version (will error if using it is attempted) + } + */ + } else { + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_opaque; + } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, leave empty + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else { + // ??? + } + + /* + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_opaque; + } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, leave empty + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { + blend_state = blend_state_depth_normal_roughness; + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { + blend_state = blend_state_depth_normal_roughness_giprobe; + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { + blend_state = RD::PipelineColorBlendState(); //no color targets for SDF + } else { + //specular write + blend_state = blend_state_opaque_specular; + depth_stencil.enable_depth_test = false; + depth_stencil.enable_depth_write = false; + } + */ + } + + RID shader_variant = shader_singleton->shader.version_get_shader(version, k); + pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); + } + } + } + + valid = true; +} + +void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { + if (!p_texture.is_valid()) { + default_texture_params.erase(p_name); + } else { + default_texture_params[p_name] = p_texture; + } +} + +void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { + Map<int, StringName> order; + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + continue; + } + + if (E->get().texture_order >= 0) { + order[E->get().texture_order + 100000] = E->key(); + } else { + order[E->get().order] = E->key(); + } + } + + for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); + pi.name = E->get(); + p_param_list->push_back(pi); + } +} + +void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RendererStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p_param_list->push_back(p); + } +} + +bool SceneShaderForwardMobile::ShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool SceneShaderForwardMobile::ShaderData::is_animated() const { + return false; +} + +bool SceneShaderForwardMobile::ShaderData::casts_shadows() const { + return false; +} + +Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + } + return Variant(); +} + +RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const { + SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; + + return shader_singleton->shader.version_get_native_source_code(version); +} + +SceneShaderForwardMobile::ShaderData::ShaderData() { + valid = false; + uses_screen_texture = false; +} + +SceneShaderForwardMobile::ShaderData::~ShaderData() { + SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; + ERR_FAIL_COND(!shader_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + shader_singleton->shader.version_free(version); + } +} + +RendererStorageRD::ShaderData *SceneShaderForwardMobile::_create_shader_func() { + ShaderData *shader_data = memnew(ShaderData); + return shader_data; +} + +void SceneShaderForwardMobile::MaterialData::set_render_priority(int p_priority) { + priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits +} + +void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) { + next_pass = p_pass; +} + +void SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; + + if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { + p_uniform_dirty = true; + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + uniform_buffer = RID(); + } + + ubo_data.resize(shader_data->ubo_size); + if (ubo_data.size()) { + uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); + memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear + } + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + //check whether buffer changed + if (p_uniform_dirty && ubo_data.size()) { + update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); + } + + uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); + + if ((uint32_t)texture_cache.size() != tex_uniform_count) { + texture_cache.resize(tex_uniform_count); + p_textures_dirty = true; + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + if (p_textures_dirty && tex_uniform_count) { + update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); + } + + if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { + // This material does not require an uniform set, so don't create it. + return; + } + + if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + //no reason to update uniform set, only UBO (or nothing) was needed to update + return; + } + + Vector<RD::Uniform> uniforms; + + { + if (shader_data->ubo_size) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(uniform_buffer); + uniforms.push_back(u); + } + + const RID *textures = texture_cache.ptrw(); + for (uint32_t i = 0; i < tex_uniform_count; i++) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1 + i; + u.ids.push_back(textures[i]); + uniforms.push_back(u); + } + } + + uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET); +} + +SceneShaderForwardMobile::MaterialData::~MaterialData() { + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + } + + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + } +} + +RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) { + MaterialData *material_data = memnew(MaterialData); + material_data->shader_data = p_shader; + material_data->last_frame = false; + //update will happen later anyway so do nothing. + return material_data; +} + +/* Scene Shader */ + +SceneShaderForwardMobile *SceneShaderForwardMobile::singleton = nullptr; + +SceneShaderForwardMobile::SceneShaderForwardMobile() { + // there should be only one of these, contained within our RenderForwardMobile singleton. + singleton = this; +} + +void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p_defines) { + storage = p_storage; + + /* SCENE SHADER */ + + { + Vector<String> shader_versions; + shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS + shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // !BAS! SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here... + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP (maybe rename to SHADER_VERSION_SHADOW_PASS_DP?) + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + shader.initialize(shader_versions, p_defines); + } + + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); + + { + //shader compiler + ShaderCompilerRD::DefaultIdentifierActions actions; + + actions.renames["WORLD_MATRIX"] = "world_matrix"; + actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix"; + actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix"; + actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; + actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; + actions.renames["MODELVIEW_MATRIX"] = "modelview"; + actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; + + actions.renames["VERTEX"] = "vertex"; + actions.renames["NORMAL"] = "normal"; + actions.renames["TANGENT"] = "tangent"; + actions.renames["BINORMAL"] = "binormal"; + actions.renames["POSITION"] = "position"; + actions.renames["UV"] = "uv_interp"; + actions.renames["UV2"] = "uv2_interp"; + actions.renames["COLOR"] = "color_interp"; + actions.renames["POINT_SIZE"] = "gl_PointSize"; + actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; + + actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; + actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; + actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; + actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; + + //builtins + + actions.renames["TIME"] = "scene_data.time"; + actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; + + actions.renames["FRAGCOORD"] = "gl_FragCoord"; + actions.renames["FRONT_FACING"] = "gl_FrontFacing"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; + actions.renames["ALBEDO"] = "albedo"; + actions.renames["ALPHA"] = "alpha"; + actions.renames["METALLIC"] = "metallic"; + actions.renames["SPECULAR"] = "specular"; + actions.renames["ROUGHNESS"] = "roughness"; + actions.renames["RIM"] = "rim"; + actions.renames["RIM_TINT"] = "rim_tint"; + actions.renames["CLEARCOAT"] = "clearcoat"; + actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions.renames["ANISOTROPY"] = "anisotropy"; + actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; + actions.renames["SSS_STRENGTH"] = "sss_strength"; + actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; + actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; + actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; + actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; + actions.renames["BACKLIGHT"] = "backlight"; + actions.renames["AO"] = "ao"; + actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; + actions.renames["EMISSION"] = "emission"; + actions.renames["POINT_COORD"] = "gl_PointCoord"; + actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; + actions.renames["SCREEN_UV"] = "screen_uv"; + actions.renames["SCREEN_TEXTURE"] = "color_buffer"; + actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; + actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; + actions.renames["DEPTH"] = "gl_FragDepth"; + actions.renames["OUTPUT_IS_SRGB"] = "true"; + actions.renames["FOG"] = "custom_fog"; + actions.renames["RADIANCE"] = "custom_radiance"; + actions.renames["IRRADIANCE"] = "custom_irradiance"; + actions.renames["BONE_INDICES"] = "bone_attrib"; + actions.renames["BONE_WEIGHTS"] = "weight_attrib"; + actions.renames["CUSTOM0"] = "custom0_attrib"; + actions.renames["CUSTOM1"] = "custom1_attrib"; + actions.renames["CUSTOM2"] = "custom2_attrib"; + actions.renames["CUSTOM3"] = "custom3_attrib"; + + //for light + actions.renames["VIEW"] = "view"; + actions.renames["LIGHT_COLOR"] = "light_color"; + actions.renames["LIGHT"] = "light"; + actions.renames["ATTENUATION"] = "attenuation"; + actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation"; + actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; + actions.renames["SPECULAR_LIGHT"] = "specular_light"; + + actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; + actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; + actions.usage_defines["BINORMAL"] = "@TANGENT"; + actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; + actions.usage_defines["RIM_TINT"] = "@RIM"; + actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; + actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; + actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; + actions.usage_defines["AO"] = "#define AO_USED\n"; + actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; + actions.usage_defines["UV"] = "#define UV_USED\n"; + actions.usage_defines["UV2"] = "#define UV2_USED\n"; + actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; + actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; + actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; + actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; + actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; + actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + + actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; + actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; + actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; + actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; + + actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; + actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; + actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; + actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + + actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + + actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; + actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; + actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; + + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; + actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n"; + + bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); + if (!force_lambert) { + actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + + actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; + actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; + actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + + actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; + + bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); + if (!force_blinn) { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + + actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; + actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; + actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; + actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; + actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + + actions.sampler_array_name = "material_samplers"; + actions.base_texture_binding_index = 1; + actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET; + actions.base_uniform_string = "material."; + actions.base_varying_index = 10; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + actions.global_buffer_array_variable = "global_variables.data"; + actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; + + compiler.initialize(actions); + } + + { + //default material and shader + default_shader = storage->shader_allocate(); + storage->shader_initialize(default_shader); + storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n"); + default_material = storage->material_allocate(); + storage->material_initialize(default_material); + storage->material_set_shader(default_material, default_shader); + + MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); + } + + { + overdraw_material_shader = storage->shader_allocate(); + storage->shader_initialize(overdraw_material_shader); + storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + overdraw_material = storage->material_allocate(); + storage->material_initialize(overdraw_material); + storage->material_set_shader(overdraw_material, overdraw_material_shader); + + wireframe_material_shader = storage->shader_allocate(); + storage->shader_initialize(wireframe_material_shader); + storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); + wireframe_material = storage->material_allocate(); + storage->material_initialize(wireframe_material); + storage->material_set_shader(wireframe_material, wireframe_material_shader); + } + + { + default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(default_vec4_xform_buffer); + u.binding = 0; + uniforms.push_back(u); + + default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardMobile::TRANSFORMS_UNIFORM_SET); + } + { + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.enable_compare = true; + sampler.compare_op = RD::COMPARE_OP_LESS; + shadow_sampler = RD::get_singleton()->sampler_create(sampler); + } +} + +SceneShaderForwardMobile::~SceneShaderForwardMobile() { + RD::get_singleton()->free(default_vec4_xform_buffer); + RD::get_singleton()->free(shadow_sampler); + + storage->free(wireframe_material_shader); + storage->free(overdraw_material_shader); + storage->free(default_shader); + + storage->free(wireframe_material); + storage->free(overdraw_material); + storage->free(default_material); +} diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h new file mode 100644 index 0000000000..1517197d25 --- /dev/null +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -0,0 +1,203 @@ +/*************************************************************************/ +/* scene_shader_forward_mobile.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RSSR_SCENE_SHADER_FM_H +#define RSSR_SCENE_SHADER_FM_H + +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl.gen.h" + +namespace RendererSceneRenderImplementation { + +class SceneShaderForwardMobile { +private: + static SceneShaderForwardMobile *singleton; + RendererStorageRD *storage; + +public: + enum ShaderVersion { + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_SHADOW_PASS, + SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + SHADER_VERSION_MAX + }; + + struct ShaderData : public RendererStorageRD::ShaderData { + enum BlendMode { //used internally + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_ALPHA_TO_COVERAGE + }; + + enum DepthDraw { + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS + }; + + enum DepthTest { + DEPTH_TEST_DISABLED, + DEPTH_TEST_ENABLED + }; + + enum Cull { + CULL_DISABLED, + CULL_FRONT, + CULL_BACK + }; + + enum CullVariant { + CULL_VARIANT_NORMAL, + CULL_VARIANT_REVERSED, + CULL_VARIANT_DOUBLE_SIDED, + CULL_VARIANT_MAX + + }; + + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE + }; + + bool valid; + RID version; + uint32_t vertex_input_mask; + PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + + String path; + + Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; + Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + + Vector<uint32_t> ubo_offsets; + uint32_t ubo_size; + + String code; + Map<StringName, RID> default_texture_params; + + DepthDraw depth_draw; + DepthTest depth_test; + + bool uses_point_size; + bool uses_alpha; + bool uses_blend_alpha; + bool uses_alpha_clip; + bool uses_depth_pre_pass; + bool uses_discard; + bool uses_roughness; + bool uses_normal; + bool uses_particle_trails; + + bool unshaded; + bool uses_vertex; + bool uses_sss; + bool uses_transmittance; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_texture; + bool uses_time; + bool writes_modelview_or_projection; + bool uses_world_coordinates; + + uint64_t last_pass = 0; + uint32_t index = 0; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; + + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + ShaderData(); + virtual ~ShaderData(); + }; + + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast<SceneShaderForwardMobile *>(singleton)->_create_shader_func(); + } + + struct MaterialData : public RendererStorageRD::MaterialData { + uint64_t last_frame; + ShaderData *shader_data; + RID uniform_buffer; + RID uniform_set; + Vector<RID> texture_cache; + Vector<uint8_t> ubo_data; + uint64_t last_pass = 0; + uint32_t index = 0; + RID next_pass; + uint8_t priority; + virtual void set_render_priority(int p_priority); + virtual void set_next_pass(RID p_pass); + virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~MaterialData(); + }; + + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); + } + + SceneForwardMobileShaderRD shader; + ShaderCompilerRD compiler; + + RID default_shader; + RID default_material; + RID overdraw_material_shader; + RID overdraw_material; + RID wireframe_material_shader; + RID wireframe_material; + RID default_shader_rd; + + RID default_vec4_xform_buffer; + RID default_vec4_xform_uniform_set; + + RID shadow_sampler; + + SceneShaderForwardMobile(); + ~SceneShaderForwardMobile(); + + void init(RendererStorageRD *p_storage, const String p_defines); +}; + +} // namespace RendererSceneRenderImplementation +#endif // !RSSR_SCENE_SHADER_FM_H diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 7d6e2fa8e4..f448698976 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -304,7 +304,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve index_buffer.resize(p_indices.size() * sizeof(int32_t)); { uint8_t *w = index_buffer.ptrw(); - copymem(w, p_indices.ptr(), sizeof(int32_t) * p_indices.size()); + memcpy(w, p_indices.ptr(), sizeof(int32_t) * p_indices.size()); } pb.index_buffer = RD::get_singleton()->index_buffer_create(p_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, index_buffer); pb.indices = RD::get_singleton()->index_array_create(pb.index_buffer, 0, p_indices.size()); @@ -705,286 +705,128 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item case Item::Command::TYPE_MESH: case Item::Command::TYPE_MULTIMESH: case Item::Command::TYPE_PARTICLES: { - ERR_PRINT("FIXME: Mesh, MultiMesh and Particles render commands are unimplemented currently, they need to be ported to the 4.0 rendering architecture."); -#ifndef _MSC_VER -#warning Item::Command types for Mesh, MultiMesh and Particles need to be implemented. -#endif - // See #if 0'ed code below to port from GLES3. - } break; - -#if 0 - case Item::Command::TYPE_MESH: { - Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); - _set_texture_rect_mode(false); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + RID mesh; + RID mesh_instance; + RID texture; + Color modulate(1, 1, 1, 1); + float world_backup[6]; + int instance_count = 1; + + for (int j = 0; j < 6; j++) { + world_backup[j] = push_constant.world[j]; } - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform); - - RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); - if (mesh_data) { - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; - // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing - glBindVertexArray(s->array_id); - - glVertexAttrib4f(RS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a); + if (c->type == Item::Command::TYPE_MESH) { + const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c); + mesh = m->mesh; + mesh_instance = m->mesh_instance; + texture = m->texture; + modulate = m->modulate; + _update_transform_2d_to_mat2x3(base_transform * m->transform, push_constant.world); + } else if (c->type == Item::Command::TYPE_MULTIMESH) { + const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c); + RID multimesh = mm->multimesh; + mesh = storage->multimesh_get_mesh(multimesh); + texture = mm->texture; + + if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) { + break; + } - if (s->index_array_len) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } + instance_count = storage->multimesh_get_instances_to_draw(multimesh); - glBindVertexArray(0); + RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET); + push_constant.flags |= 1; //multimesh, trails disabled + if (storage->multimesh_uses_colors(multimesh)) { + push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS; } - } - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); + if (storage->multimesh_uses_custom_data(multimesh)) { + push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA; + } + } else if (c->type == Item::Command::TYPE_PARTICLES) { + const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c); + ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D); + if (storage->particles_is_inactive(pt->particles)) { + break; + } + int dpc = storage->particles_get_draw_passes(pt->particles); + if (dpc == 0) { + break; //nothing to draw + } + uint32_t divisor = 1; + instance_count = storage->particles_get_amount(pt->particles, divisor); - } break; - case Item::Command::TYPE_MULTIMESH: { - Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c); + RID uniform_set = storage->particles_get_instance_buffer_uniform_set(pt->particles, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET); - RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); + push_constant.flags |= divisor; + instance_count /= divisor; - if (!multi_mesh) - break; + push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS; + push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA; - RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh); + mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored + texture = pt->texture; + } - if (!mesh_data) + if (mesh.is_null()) { break; + } - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); + _bind_canvas_texture(p_draw_list, texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); - //reset shader and force rebind - state.using_texture_rect = true; - _set_texture_rect_mode(false); + uint32_t surf_count = storage->mesh_get_surface_count(mesh); + static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP }; - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } + push_constant.modulation[0] = base_color.r * modulate.r; + push_constant.modulation[1] = base_color.g * modulate.g; + push_constant.modulation[2] = base_color.b * modulate.b; + push_constant.modulation[3] = base_color.a * modulate.a; - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - - if (amount == -1) { - amount = multi_mesh->size; + for (int j = 0; j < 4; j++) { + push_constant.src_rect[j] = 0; + push_constant.dst_rect[j] = 0; + push_constant.ninepatch_margins[j] = 0; } - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; - // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing - glBindVertexArray(s->instancing_array_id); + for (uint32_t j = 0; j < surf_count; j++) { + void *surface = storage->mesh_get_surface(mesh, j); - glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer + RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface); + ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX); - int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4; - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4)); - glVertexAttribDivisor(9, 1); + uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask(); - int color_ofs; + RID vertex_array; + RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID; - if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) { - glEnableVertexAttribArray(10); - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4)); - glVertexAttribDivisor(10, 1); - color_ofs = 12 * 4; + if (mesh_instance.is_valid()) { + storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format); } else { - glDisableVertexAttribArray(10); - glVertexAttrib4f(10, 0, 0, 1, 0); - color_ofs = 8 * 4; + storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format); } - int custom_data_ofs = color_ofs; - - switch (multi_mesh->color_format) { - case RS::MULTIMESH_COLOR_NONE: { - glDisableVertexAttribArray(11); - glVertexAttrib4f(11, 1, 1, 1, 1); - } break; - case RS::MULTIMESH_COLOR_8BIT: { - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - glVertexAttribDivisor(11, 1); - custom_data_ofs += 4; - - } break; - case RS::MULTIMESH_COLOR_FLOAT: { - glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); - glVertexAttribDivisor(11, 1); - custom_data_ofs += 4 * 4; - } break; - } + RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - switch (multi_mesh->custom_data_format) { - case RS::MULTIMESH_CUSTOM_DATA_NONE: { - glDisableVertexAttribArray(12); - glVertexAttrib4f(12, 1, 1, 1, 1); - } break; - case RS::MULTIMESH_CUSTOM_DATA_8BIT: { - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); - glVertexAttribDivisor(12, 1); - - } break; - case RS::MULTIMESH_CUSTOM_DATA_FLOAT: { - glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); - glVertexAttribDivisor(12, 1); - } break; - } + RID index_array = storage->mesh_surface_get_index_array(surface, 0); - if (s->index_array_len) { - glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); - } else { - glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); + if (index_array.is_valid()) { + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, index_array); } - glBindVertexArray(0); - } - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - } break; - case Item::Command::TYPE_PARTICLES: { - Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); - - RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); - if (!particles) - break; - - if (particles->inactive && !particles->emitting) - break; - - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white - - RenderingServerDefault::redraw_request(); - - storage->particles_request_process(particles_cmd->particles); - //enable instancing - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); - //reset shader and force rebind - state.using_texture_rect = true; - _set_texture_rect_mode(false); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0)); - } - - if (!particles->use_local_coords) { - Transform2D inv_xf; - inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); - inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); - inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y)); - inv_xf.affine_invert(); + RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, vertex_array); + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf); + RD::get_singleton()->draw_list_draw(p_draw_list, index_array.is_valid(), instance_count); } - glBindVertexArray(data.particle_quad_array); //use particle quad array - glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer - - int stride = sizeof(float) * 4 * 6; - - int amount = particles->amount; - - if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount); - } else { - //split - int split = int(Math::ceil(particles->phase * particles->amount)); - - if (amount - split > 0) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0)); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split); - } - - if (split > 0) { - glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); - glVertexAttribDivisor(10, 1); - glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr); - glVertexAttribDivisor(11, 1); - glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); - glVertexAttribDivisor(12, 1); - - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split); - } + for (int j = 0; j < 6; j++) { + push_constant.world[j] = world_backup[j]; } - glBindVertexArray(0); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); - state.using_texture_rect = true; - _set_texture_rect_mode(false); - } break; -#endif case Item::Command::TYPE_TRANSFORM: { const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); _update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world); @@ -1437,6 +1279,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p Item *canvas_group_owner = nullptr; + bool update_skeletons = false; + while (ci) { if (ci->copy_back_buffer && canvas_group_owner == nullptr) { backbuffer_copy = true; @@ -1472,9 +1316,27 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p } } + if (ci->skeleton.is_valid()) { + const Item::Command *c = ci->commands; + + while (c) { + if (c->type == Item::Command::TYPE_MESH) { + const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c); + if (cm->mesh_instance.is_valid()) { + storage->mesh_instance_check_for_update(cm->mesh_instance); + update_skeletons = true; + } + } + } + } + if (ci->canvas_group_owner != nullptr) { if (canvas_group_owner == nullptr) { //Canvas group begins here, render until before this item + if (update_skeletons) { + storage->update_mesh_instances(); + update_skeletons = false; + } _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); item_count = 0; @@ -1494,6 +1356,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p } if (ci == canvas_group_owner) { + if (update_skeletons) { + storage->update_mesh_instances(); + update_skeletons = false; + } + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true); item_count = 0; @@ -1506,6 +1373,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p if (backbuffer_copy) { //render anything pending, including clearing if no items + if (update_skeletons) { + storage->update_mesh_instances(); + update_skeletons = false; + } _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); item_count = 0; @@ -1518,6 +1389,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p items[item_count++] = ci; if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) { + if (update_skeletons) { + storage->update_mesh_instances(); + update_skeletons = false; + } + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); //then reset item_count = 0; @@ -2012,6 +1888,9 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { uses_screen_texture = false; ShaderCompilerRD::IdentifierActions actions; + actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX; + actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT; + actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT; actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD); actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX); @@ -2048,7 +1927,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { print_line("\n**fragment_code:\n" + gen_code.fragment); print_line("\n**light_code:\n" + gen_code.light); #endif - canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); + canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines); ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index cb947d7180..8129cc6c9b 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -67,12 +67,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender { }; enum { - FLAGS_INSTANCING_STRIDE_MASK = 0xF, - FLAGS_INSTANCING_ENABLED = (1 << 4), - FLAGS_INSTANCING_HAS_COLORS = (1 << 5), - FLAGS_INSTANCING_COLOR_8BIT = (1 << 6), - FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 7), - FLAGS_INSTANCING_CUSTOM_DATA_8_BIT = (1 << 8), + + FLAGS_INSTANCING_MASK = 0x7F, + FLAGS_INSTANCING_HAS_COLORS = (1 << 7), + FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8), FLAGS_CLIP_RECT_UV = (1 << 9), FLAGS_TRANSPOSE_RECT = (1 << 10), diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index d5ac05d1d1..cb3e67e990 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -175,5 +175,14 @@ RendererCompositorRD::RendererCompositorRD() { storage = memnew(RendererStorageRD); canvas = memnew(RendererCanvasRenderRD(storage)); - scene = memnew(RendererSceneRenderForwardClustered(storage)); + + uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end"); + uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + + if (back_end == 1 || textures_per_stage < 48) { + scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage)); + } else { // back_end == 0 + // default to our high end renderer + scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage)); + } } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 67a843452b..b3865de2bf 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -34,8 +34,9 @@ #include "core/os/os.h" #include "core/templates/thread_work_pool.h" #include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h" +#include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h" #include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h" -#include "servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" class RendererCompositorRD : public RendererCompositor { diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index 4e4e553605..b289b17fad 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -1367,7 +1367,7 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr } } -void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render) { +void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) { /* Update general SDFGI Buffer */ SDFGIData sdfgi_data; @@ -1564,7 +1564,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, //clear dispatch indirect data SDFGIShader::PreprocessPushConstant push_constant; - zeromem(&push_constant, sizeof(SDFGIShader::PreprocessPushConstant)); + memset(&push_constant, 0, sizeof(SDFGIShader::PreprocessPushConstant)); RENDER_TIMESTAMP("Scroll SDF"); @@ -2602,7 +2602,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); GIProbeDynamicPushConstant push_constant; - zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); + memset(&push_constant, 0, sizeof(GIProbeDynamicPushConstant)); push_constant.limits[0] = octree_size.x; push_constant.limits[1] = octree_size.y; push_constant.limits[2] = octree_size.z; @@ -2992,6 +2992,7 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p } } default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES); + half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution"); } void RendererSceneGIRD::free() { @@ -3097,10 +3098,10 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_ } if (giprobes_changed) { - if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { - RD::get_singleton()->free(rb->gi_uniform_set); + if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) { + RD::get_singleton()->free(rb->gi.uniform_set); } - rb->gi_uniform_set = RID(); + rb->gi.uniform_set = RID(); if (rb->volumetric_fog) { if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { RD::get_singleton()->free(rb->volumetric_fog->uniform_set); @@ -3125,7 +3126,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ ERR_FAIL_COND(rb == nullptr); RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment); - if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != half_resolution) { + if (rb->ambient_buffer.is_null() || rb->gi.using_half_size_gi != half_resolution) { if (rb->ambient_buffer.is_valid()) { RD::get_singleton()->free(rb->ambient_buffer); RD::get_singleton()->free(rb->reflection_buffer); @@ -3142,9 +3143,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - rb->using_half_size_gi = half_resolution; - - p_scene_render->_render_buffers_uniform_set_changed(p_render_buffers); + rb->gi.using_half_size_gi = half_resolution; } PushConstant push_constant; @@ -3187,7 +3186,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ push_constant.cam_rotation[10] = p_transform.basis[2][2]; push_constant.cam_rotation[11] = 0; - if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { + if (rb->gi.uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) { Vector<RD::Uniform> uniforms; { RD::Uniform u; @@ -3340,22 +3339,22 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ uniforms.push_back(u); } - rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0); + rb->gi.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0); } Mode mode; - if (rb->using_half_size_gi) { + if (rb->gi.using_half_size_gi) { mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE); } else { mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE); } RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi_uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi.uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); - if (rb->using_half_size_gi) { + if (rb->gi.using_half_size_gi) { RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1); } else { RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index c0f3318538..59f5f374d1 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -48,7 +48,8 @@ #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" -// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound +// Forward declare RenderDataRD and RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound +struct RenderDataRD; class RendererSceneRenderRD; class RendererSceneGIRD { @@ -529,7 +530,7 @@ public: void debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture); void debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); - void pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render); + void pre_process_gi(const Transform &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render); void render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render); void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render); }; @@ -561,6 +562,9 @@ public: RID full_buffer; RID full_dispatch; RID full_mask; + + RID uniform_set; + bool using_half_size_gi = false; }; struct SDFGIData { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 4cf296f0db..1f01de1333 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -58,8 +58,6 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment rb->sdfgi->erase(); memdelete(rb->sdfgi); rb->sdfgi = nullptr; - - _render_buffers_uniform_set_changed(p_render_buffers); } return; } @@ -78,8 +76,6 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment if (sdfgi == nullptr) { // re-create rb->sdfgi = gi.create_sdfgi(env, p_world_position, requested_history_size); - - _render_buffers_uniform_set_changed(p_render_buffers); } else { //check for updates rb->sdfgi->update(env, p_world_position); @@ -317,7 +313,7 @@ void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS:: RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - if (low_end) { + if (!is_dynamic_gi_supported()) { return; } @@ -379,7 +375,7 @@ void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_ena RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - if (low_end) { + if (!is_volumetric_supported()) { return; } @@ -410,10 +406,6 @@ void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - if (low_end) { - return; - } - env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance); } @@ -429,10 +421,6 @@ void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - if (low_end) { - return; - } - env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect); } @@ -522,9 +510,13 @@ RID RendererSceneRenderRD::reflection_atlas_create() { ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count"); ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size"); - ra.cluster_builder = memnew(ClusterBuilderRD); - ra.cluster_builder->set_shared(&cluster_builder_shared); - ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID()); + if (is_clustered_enabled()) { + ra.cluster_builder = memnew(ClusterBuilderRD); + ra.cluster_builder->set_shared(&cluster_builder_shared); + ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID()); + } else { + ra.cluster_builder = nullptr; + } return reflection_atlas_owner.make_rid(ra); } @@ -537,7 +529,10 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref return; //no changes } - ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID()); + if (ra->cluster_builder) { + // only if we're using our cluster + ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID()); + } ra->size = p_reflection_size; ra->count = p_reflection_count; @@ -1340,7 +1335,7 @@ void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, } bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { - if (low_end) { + if (!is_dynamic_gi_supported()) { return false; } @@ -1348,7 +1343,7 @@ bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { } void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) { - if (low_end) { + if (!is_dynamic_gi_supported()) { return; } @@ -1534,7 +1529,6 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri if (rb->blur[0].texture.is_null()) { _allocate_blur_textures(rb); - _render_buffers_uniform_set_changed(p_render_buffers); } storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality); @@ -1586,7 +1580,6 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb if (rb->blur[0].texture.is_null()) { _allocate_blur_textures(rb); - _render_buffers_uniform_set_changed(p_render_buffers); } storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection); @@ -1712,7 +1705,6 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final"); - _render_buffers_uniform_set_changed(p_render_buffers); } ssao_using_half_size = ssao_half_size; uniform_sets_are_invalid = true; @@ -1739,30 +1731,28 @@ 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); } -void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +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); - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment); + RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment); //glow (if enabled) - CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); + CameraEffects *camfx = camera_effects_owner.getornull(p_render_data->camera_effects); bool can_use_effects = rb->width >= 8 && rb->height >= 8; if (can_use_effects && camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0) { if (rb->blur[0].texture.is_null()) { _allocate_blur_textures(rb); - _render_buffers_uniform_set_changed(p_render_buffers); } 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_projection.get_z_near(), p_projection.get_z_far(), p_projection.is_orthogonal()); + 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); } if (can_use_effects && env && env->auto_exposure) { if (rb->luminance.current.is_null()) { _allocate_luminance_textures(rb); - _render_buffers_uniform_set_changed(p_render_buffers); } bool set_immediate = env->auto_exposure_version != rb->auto_exposure_version; @@ -1783,7 +1773,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende if (rb->blur[1].texture.is_null()) { _allocate_blur_textures(rb); - _render_buffers_uniform_set_changed(p_render_buffers); } for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { @@ -1874,7 +1863,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende storage->render_target_disable_clear_request(rb->render_target); } -void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) { +void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) { EffectsRD *effects = storage->get_effects(); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -1933,6 +1922,13 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID RID reflection_texture = rb->reflection_buffer; effects->copy_to_fb_rect(ambient_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture); } + + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) { + if (p_occlusion_buffer.is_valid()) { + Size2 rtsize = storage->render_target_get_size(rb->render_target); + effects->copy_to_fb_rect(storage->texture_get_rd_texture(p_occlusion_buffer), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize), true, false); + } + } } void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { @@ -2124,10 +2120,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; rb->use_debanding = p_use_debanding; - if (rb->cluster_builder == nullptr) { - rb->cluster_builder = memnew(ClusterBuilderRD); + + if (is_clustered_enabled()) { + if (rb->cluster_builder == nullptr) { + rb->cluster_builder = memnew(ClusterBuilderRD); + } + rb->cluster_builder->set_shared(&cluster_builder_shared); } - rb->cluster_builder->set_shared(&cluster_builder_shared); _free_render_buffer_data(rb); @@ -2168,9 +2167,10 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p } rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa); - _render_buffers_uniform_set_changed(p_render_buffers); - rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); + if (is_clustered_enabled()) { + rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); + } } void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) { @@ -2318,6 +2318,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti Vector3 extents = storage->reflection_probe_get_extents(base_probe); + rpi->cull_mask = storage->reflection_probe_get_cull_mask(base_probe); + reflection_ubo.box_extents[0] = extents.x; reflection_ubo.box_extents[1] = extents.y; reflection_ubo.box_extents[2] = extents.z; @@ -2346,13 +2348,15 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti Transform proj = (p_camera_inverse_transform * transform).inverse(); RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix); - current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents); + if (current_cluster_builder != nullptr) { + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents); + } rpi->last_pass = RSG::rasterizer->get_frame_number(); } if (cluster.reflection_count) { - RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(RendererSceneSkyRD::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); + RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(Cluster::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); } } @@ -2550,6 +2554,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); light_data.softshadow_angle = angular_diameter; + light_data.bake_mode = storage->light_get_bake_mode(base); if (angular_diameter <= 0.0) { light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF @@ -2617,6 +2622,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const light_data.color[1] = linear_col.g * energy; light_data.color[2] = linear_col.b * energy; light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0; + light_data.bake_mode = storage->light_get_bake_mode(base); float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); light_data.inv_radius = 1.0 / radius; @@ -2736,8 +2742,11 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const } li->light_index = index; + li->cull_mask = storage->light_get_cull_mask(base); - current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); + if (current_cluster_builder != nullptr) { + current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); + } r_positional_light_count++; } @@ -2805,6 +2814,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const DecalInstance *di = cluster.decal_sort[i].instance; RID decal = di->decal; + di->render_index = i; + di->cull_mask = storage->decal_get_cull_mask(decal); + Transform xform = di->transform; float fade = 1.0; @@ -2909,7 +2921,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const dd.upper_fade = storage->decal_get_upper_fade(decal); dd.lower_fade = storage->decal_get_lower_fade(decal); - current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents); + if (current_cluster_builder != nullptr) { + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents); + } } if (cluster.decal_count > 0) { @@ -2917,6 +2931,116 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const } } +void RendererSceneRenderRD::_fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words) { + // first zero out our indices + for (uint32_t i = 0; i < p_max_dst_words; i++) { + p_omni_light_indices[i] = 0; + p_spot_light_indices[i] = 0; + p_reflection_probe_indices[i] = 0; + p_decal_instance_indices[i] = 0; + } + + { + // process omni lights + uint32_t dword = 0; + uint32_t shift = 0; + + for (uint32_t i = 0; i < p_omni_light_instance_count && dword < p_max_dst_words; i++) { + LightInstance *li = light_instance_owner.getornull(p_omni_light_instances[i]); + + if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) { + p_omni_light_indices[dword] += li->light_index << shift; + if (shift == 24) { + dword++; + shift = 0; + } else { + shift += 8; + } + } + } + + if (dword < 2) { + // put in ending mark + p_omni_light_indices[dword] += 0xFF << shift; + } + } + + { + // process spot lights + uint32_t dword = 0; + uint32_t shift = 0; + + for (uint32_t i = 0; i < p_spot_light_instance_count && dword < p_max_dst_words; i++) { + LightInstance *li = light_instance_owner.getornull(p_spot_light_instances[i]); + + if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) { + p_spot_light_indices[dword] += li->light_index << shift; + if (shift == 24) { + dword++; + shift = 0; + } else { + shift += 8; + } + } + } + + if (dword < 2) { + // put in ending mark + p_spot_light_indices[dword] += 0xFF << shift; + } + } + + { + // process reflection probes + uint32_t dword = 0; + uint32_t shift = 0; + + for (uint32_t i = 0; i < p_reflection_probe_instance_count && dword < p_max_dst_words; i++) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_instances[i]); + + if ((rpi->cull_mask & p_layer_mask) && (rpi->render_index < 255)) { + p_reflection_probe_indices[dword] += rpi->render_index << shift; + if (shift == 24) { + dword++; + shift = 0; + } else { + shift += 8; + } + } + } + + if (dword < 2) { + // put in ending mark + p_reflection_probe_indices[dword] += 0xFF << shift; + } + } + + { + // process decals + uint32_t dword = 0; + uint32_t shift = 0; + + for (uint32_t i = 0; i < p_decal_instance_count && dword < p_max_dst_words; i++) { + DecalInstance *decal = decal_instance_owner.getornull(p_decal_instances[i]); + + if ((decal->cull_mask & p_layer_mask) && (decal->render_index < 255)) { + p_decal_instance_indices[dword] += decal->render_index << shift; + if (shift == 24) { + dword++; + shift = 0; + } else { + shift += 8; + } + } + } + + if (dword < 2) { + // put in ending mark + p_decal_instance_indices[dword] += 0xFF << shift; + } + } +} + void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { ERR_FAIL_COND(!rb->volumetric_fog); @@ -2943,6 +3067,7 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { } void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { + ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment); @@ -2955,7 +3080,6 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e //validate if (!env || !env->volumetric_fog_enabled || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) { _volumetric_fog_erase(rb); - _render_buffers_uniform_set_changed(p_render_buffers); } } @@ -2991,7 +3115,6 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); - _render_buffers_uniform_set_changed(p_render_buffers); Vector<RD::Uniform> uniforms; { @@ -3336,13 +3459,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e rb->volumetric_fog->prev_cam_transform = p_cam_transform; } -uint32_t RendererSceneRenderRD::_get_render_state_directional_light_count() const { - return render_state.directional_light_count; -} - -bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) { - if (render_state.render_buffers.is_valid()) { - RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); +bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) { + if (p_render_data->render_buffers.is_valid()) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); if (rb->sdfgi != nullptr) { return true; } @@ -3350,34 +3469,34 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) { return false; } -void RendererSceneRenderRD::_post_prepass_render(bool p_use_gi) { - if (render_state.render_buffers.is_valid()) { +void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) { + if (p_render_data->render_buffers.is_valid()) { if (p_use_gi) { - RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { return; } - RendererSceneEnvironmentRD *env = environment_owner.getornull(render_state.environment); + RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment); rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky)); } } } -void RendererSceneRenderRD::_pre_resolve_render(bool p_use_gi) { - if (render_state.render_buffers.is_valid()) { +void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi) { + if (p_render_data->render_buffers.is_valid()) { if (p_use_gi) { RD::get_singleton()->compute_list_end(); } } } -void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer) { +void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer) { // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time - if (render_state.render_buffers.is_valid() && p_use_gi) { - RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); + if (p_render_data->render_buffers.is_valid() && p_use_gi) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { return; @@ -3390,8 +3509,8 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R render_state.shadows.clear(); render_state.directional_shadows.clear(); - Plane camera_plane(render_state.cam_transform.origin, -render_state.cam_transform.basis.get_axis(Vector3::AXIS_Z)); - float lod_distance_multiplier = render_state.cam_projection.get_lod_multiplier(); + Plane camera_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); + float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier(); { for (int i = 0; i < render_state.render_shadow_count; i++) { @@ -3408,7 +3527,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R //cube shadows are rendered in their own way for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, true, true, true); + _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true); } if (render_state.directional_shadows.size()) { @@ -3422,7 +3541,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R // Render GI bool render_shadows = render_state.directional_shadows.size() || render_state.shadows.size(); - bool render_gi = render_state.render_buffers.is_valid() && p_use_gi; + bool render_gi = p_render_data->render_buffers.is_valid() && p_use_gi; if (render_shadows && render_gi) { RENDER_TIMESTAMP("Render GI + Render Shadows (parallel)"); @@ -3438,11 +3557,11 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R //render directional shadows for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false); + _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false); } //render positional shadows for (uint32_t i = 0; i < render_state.shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true); + _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true); } _render_shadow_process(); @@ -3450,7 +3569,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R //start GI if (render_gi) { - gi.process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes, this); + gi.process_gi(p_render_data->render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, *p_render_data->gi_probes, this); } //Do shadow rendering (in parallel with GI) @@ -3462,9 +3581,9 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier } - if (render_state.render_buffers.is_valid()) { + if (p_render_data->render_buffers.is_valid()) { if (p_use_ssao) { - _process_ssao(render_state.render_buffers, render_state.environment, p_normal_roughness_buffer, render_state.cam_projection); + _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_buffer, p_render_data->cam_projection); } } @@ -3472,32 +3591,32 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); if (current_cluster_builder) { - current_cluster_builder->begin(render_state.cam_transform, render_state.cam_projection, !render_state.reflection_probe.is_valid()); + current_cluster_builder->begin(p_render_data->cam_transform, p_render_data->cam_projection, !p_render_data->reflection_probe.is_valid()); } bool using_shadows = true; - if (render_state.reflection_probe.is_valid()) { - if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(render_state.reflection_probe))) { + if (p_render_data->reflection_probe.is_valid()) { + if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { using_shadows = false; } } else { //do not render reflections when rendering a reflection probe - _setup_reflections(*render_state.reflection_probes, render_state.cam_transform.affine_inverse(), render_state.environment); + _setup_reflections(*p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment); } uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; - _setup_lights(*render_state.lights, render_state.cam_transform, render_state.shadow_atlas, using_shadows, directional_light_count, positional_light_count); - _setup_decals(*render_state.decals, render_state.cam_transform.affine_inverse()); + _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count); + _setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse()); - render_state.directional_light_count = directional_light_count; + p_render_data->directional_light_count = directional_light_count; if (current_cluster_builder) { current_cluster_builder->bake_cluster(); } - if (render_state.render_buffers.is_valid()) { + if (p_render_data->render_buffers.is_valid()) { bool directional_shadows = false; for (uint32_t i = 0; i < directional_light_count; i++) { if (cluster.directional_lights[i].shadow_enabled) { @@ -3505,37 +3624,52 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R break; } } - _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count); + if (is_volumetric_supported()) { + _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count); + } } } -void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) { +void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) { // getting this here now so we can direct call a bunch of things more easily RenderBuffers *rb = nullptr; if (p_render_buffers.is_valid()) { rb = render_buffers_owner.getornull(p_render_buffers); - ERR_FAIL_COND(!rb); // !BAS! Do we fail here or skip the parts that won't work. can't really see a case why we would be rendering without buffers.... + ERR_FAIL_COND(!rb); } //assign render data + RenderDataRD render_data; { - render_state.render_buffers = p_render_buffers; - render_state.cam_transform = p_cam_transform; - render_state.cam_projection = p_cam_projection; - render_state.cam_ortogonal = p_cam_projection.is_orthogonal(); - render_state.instances = &p_instances; - render_state.lights = &p_lights; - render_state.reflection_probes = &p_reflection_probes; - render_state.gi_probes = &p_gi_probes; - render_state.decals = &p_decals; - render_state.lightmaps = &p_lightmaps; - render_state.environment = p_environment; - render_state.camera_effects = p_camera_effects; - render_state.shadow_atlas = p_shadow_atlas; - render_state.reflection_atlas = p_reflection_atlas; - render_state.reflection_probe = p_reflection_probe; - render_state.reflection_probe_pass = p_reflection_probe_pass; - render_state.screen_lod_threshold = p_screen_lod_threshold; + render_data.render_buffers = p_render_buffers; + + render_data.cam_transform = p_cam_transform; + render_data.cam_projection = p_cam_projection; + render_data.cam_ortogonal = p_cam_projection.is_orthogonal(); // !BAS! Shouldn't this be p_cam_ortogonal ? + render_data.z_near = p_cam_projection.get_z_near(); + render_data.z_far = p_cam_projection.get_z_far(); + + render_data.instances = &p_instances; + render_data.lights = &p_lights; + render_data.reflection_probes = &p_reflection_probes; + render_data.gi_probes = &p_gi_probes; + render_data.decals = &p_decals; + render_data.lightmaps = &p_lightmaps; + render_data.environment = p_environment; + render_data.camera_effects = p_camera_effects; + render_data.shadow_atlas = p_shadow_atlas; + render_data.reflection_atlas = p_reflection_atlas; + render_data.reflection_probe = p_reflection_probe; + render_data.reflection_probe_pass = p_reflection_probe_pass; + + render_data.lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); + render_data.lod_camera_plane = Plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + render_data.screen_lod_threshold = 0.0; + } else { + render_data.screen_lod_threshold = p_screen_lod_threshold; + } render_state.render_shadows = p_render_shadows; render_state.render_shadow_count = p_render_shadow_count; @@ -3547,9 +3681,9 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & PagedArray<RID> empty; if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - render_state.lights = ∅ - render_state.reflection_probes = ∅ - render_state.gi_probes = ∅ + render_data.lights = ∅ + render_data.reflection_probes = ∅ + render_data.gi_probes = ∅ } //sdfgi first @@ -3570,18 +3704,20 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & } //assign render indices to giprobes - for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { - RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]); - if (giprobe_inst) { - giprobe_inst->render_index = i; + if (is_dynamic_gi_supported()) { + for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { + RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]); + if (giprobe_inst) { + giprobe_inst->render_index = i; + } } } - if (render_buffers_owner.owns(render_state.render_buffers)) { - RenderBuffers *rs_rb = render_buffers_owner.getornull(render_state.render_buffers); - current_cluster_builder = rs_rb->cluster_builder; - } else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe); + if (render_buffers_owner.owns(render_data.render_buffers)) { + // render_data.render_buffers == p_render_buffers so we can use our already retrieved rb + current_cluster_builder = rb->cluster_builder; + } else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_data.reflection_probe); ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas); if (!ra) { ERR_PRINT("reflection probe has no reflection atlas! Bug?"); @@ -3590,26 +3726,32 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & current_cluster_builder = ra->cluster_builder; } } else { - ERR_PRINT("No cluster builder, bug"); //should never happen, will crash + ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash current_cluster_builder = nullptr; } if (rb != nullptr && rb->sdfgi != nullptr) { rb->sdfgi->update_cascades(); - rb->sdfgi->pre_process_gi(p_cam_transform, this); + rb->sdfgi->pre_process_gi(p_cam_transform, &render_data, this); } render_state.gi_probe_count = 0; if (rb != nullptr && rb->sdfgi != nullptr) { - gi.setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count, this); + gi.setup_giprobes(render_data.render_buffers, render_data.cam_transform, *render_data.gi_probes, render_state.gi_probe_count, this); rb->sdfgi->update_light(); } render_state.depth_prepass_used = false; //calls _pre_opaque_render between depth pre-pass and opaque pass - _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, *render_state.gi_probes, p_lightmaps, p_environment, current_cluster_builder->get_cluster_buffer(), current_cluster_builder->get_cluster_size(), current_cluster_builder->get_max_cluster_elements(), p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold); + if (current_cluster_builder != nullptr) { + render_data.cluster_buffer = current_cluster_builder->get_cluster_buffer(); + render_data.cluster_size = current_cluster_builder->get_cluster_size(); + render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); + } + + _render_scene(&render_data, clear_color); if (p_render_buffers.is_valid()) { if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { @@ -3630,13 +3772,15 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & default: { } } - current_cluster_builder->debug(elem_type); + if (current_cluster_builder != nullptr) { + current_cluster_builder->debug(elem_type); + } } RENDER_TIMESTAMP("Tonemap"); - _render_buffers_post_process_and_tonemap(p_render_buffers, p_environment, p_camera_effects, p_cam_projection); - _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas); + _render_buffers_post_process_and_tonemap(&render_data); + _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex); if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) { rb->sdfgi->debug_draw(p_cam_projection, p_cam_transform, rb->width, rb->height, rb->render_target, rb->texture); } @@ -4076,12 +4220,27 @@ int RendererSceneRenderRD::get_max_directional_lights() const { return cluster.max_directional_lights; } -bool RendererSceneRenderRD::is_low_end() const { - return low_end; +bool RendererSceneRenderRD::is_dynamic_gi_supported() const { + // usable by default (unless low end = true) + return true; +} + +bool RendererSceneRenderRD::is_clustered_enabled() const { + // used by default. + return true; +} + +bool RendererSceneRenderRD::is_volumetric_supported() const { + // usable by default (unless low end = true) + return true; +} + +uint32_t RendererSceneRenderRD::get_max_elements() const { + return GLOBAL_GET("rendering/limits/cluster_builder/max_clustered_elements"); } RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { - max_cluster_elements = GLOBAL_GET("rendering/limits/cluster_builder/max_clustered_elements"); + max_cluster_elements = get_max_elements(); storage = p_storage; singleton = this; @@ -4089,21 +4248,13 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size"); directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits"); - uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); - - low_end = GLOBAL_GET("rendering/driver/rd_renderer/use_low_end_renderer"); - - if (textures_per_stage < 48) { - low_end = true; - } - /* SKY SHADER */ sky.init(storage); /* GI */ - if (!low_end) { + if (is_dynamic_gi_supported()) { gi.init(storage, &sky); } @@ -4141,7 +4292,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); } - if (!low_end) { + if (is_volumetric_supported()) { String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; Vector<String> volumetric_fog_modes; volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); @@ -4188,8 +4339,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter")); cull_argument.set_page_pool(&cull_argument_pool); - - gi.half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution"); } RendererSceneRenderRD::~RendererSceneRenderRD() { @@ -4201,7 +4350,7 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { RD::get_singleton()->free(sky.sky_scene_state.uniform_set); } - if (!low_end) { + if (is_dynamic_gi_supported()) { gi.free(); volumetric_fog.shader.version_free(volumetric_fog.shader_version); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 001cfeb74d..1f82ae6dec 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -43,6 +43,40 @@ #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" +struct RenderDataRD { + RID render_buffers = RID(); + + Transform cam_transform = Transform(); + CameraMatrix cam_projection = CameraMatrix(); + bool cam_ortogonal = false; + + float z_near = 0.0; + float z_far = 0.0; + + const PagedArray<RendererSceneRender::GeometryInstance *> *instances = nullptr; + const PagedArray<RID> *lights = nullptr; + const PagedArray<RID> *reflection_probes = nullptr; + const PagedArray<RID> *gi_probes = nullptr; + const PagedArray<RID> *decals = nullptr; + const PagedArray<RID> *lightmaps = nullptr; + RID environment = RID(); + RID camera_effects = RID(); + RID shadow_atlas = RID(); + RID reflection_atlas = RID(); + RID reflection_probe = RID(); + int reflection_probe_pass = 0; + + float lod_distance_multiplier = 0.0; + Plane lod_camera_plane = Plane(); + float screen_lod_threshold = 0.0; + + RID cluster_buffer = RID(); + uint32_t cluster_size = 0; + uint32_t cluster_max_elements = 0; + + uint32_t directional_light_count = 0; +}; + class RendererSceneRenderRD : public RendererSceneRender { friend RendererSceneSkyRD; friend RendererSceneGIRD; @@ -62,7 +96,7 @@ protected: void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform); void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0; + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0; virtual void _render_shadow_begin() = 0; virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0; @@ -79,19 +113,17 @@ protected: RenderBufferData *render_buffers_get_data(RID p_render_buffers); virtual void _base_uniforms_changed() = 0; - virtual void _render_buffers_uniform_set_changed(RID p_render_buffers) = 0; virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0; void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera); - bool _needs_post_prepass_render(bool p_use_gi); - void _post_prepass_render(bool p_use_gi); - void _pre_resolve_render(bool p_use_gi); + bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); + void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); + void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi); - void _pre_opaque_render(bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer); - uint32_t _get_render_state_directional_light_count() const; + void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer); // needed for a single argument calls (material and uv2) PagedArrayPool<GeometryInstance *> cull_argument_pool; @@ -150,6 +182,7 @@ private: uint32_t render_step = 0; uint64_t last_pass = 0; uint32_t render_index = 0; + uint32_t cull_mask = 0; Transform transform; }; @@ -161,6 +194,8 @@ private: struct DecalInstance { RID decal; Transform transform; + uint32_t render_index; + uint32_t cull_mask; }; mutable RID_Owner<DecalInstance> decal_instance_owner; @@ -305,6 +340,7 @@ private: uint64_t last_scene_shadow_pass = 0; uint64_t last_pass = 0; uint32_t light_index = 0; + uint32_t cull_mask = 0; uint32_t light_directional_index = 0; uint32_t current_shadow_atlas_key = 0; @@ -383,9 +419,9 @@ private: RID texture; //main texture for rendering to, must be filled after done rendering RID depth_texture; //main depth texture - RID gi_uniform_set; RendererSceneGIRD::SDFGI *sdfgi = nullptr; VolumetricFog *volumetric_fog = nullptr; + RendererSceneGIRD::RenderBuffersGI gi; ClusterBuilderRD *cluster_builder = nullptr; @@ -428,9 +464,6 @@ private: RID ambient_buffer; RID reflection_buffer; - bool using_half_size_gi = false; - - RendererSceneGIRD::RenderBuffersGI gi; }; /* GI */ @@ -444,14 +477,16 @@ private: void _allocate_blur_textures(RenderBuffers *rb); void _allocate_luminance_textures(RenderBuffers *rb); - void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas); - void _render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection); + void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer); + void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data); /* Cluster */ struct Cluster { /* Scene State UBO */ + // !BAS! Most data here is not just used by our clustering logic but also by other lighting implementations. Maybe rename this struct to something more appropriate + enum { REFLECTION_AMBIENT_DISABLED = 0, REFLECTION_AMBIENT_ENVIRONMENT = 1, @@ -465,8 +500,8 @@ private: uint32_t mask; float ambient[3]; // ambient color, float intensity; - bool exterior; - bool box_project; + uint32_t exterior; + uint32_t box_project; uint32_t ambient_mode; uint32_t pad; float local_matrix[16]; // up to here for spot and omni, rest is for directional @@ -495,7 +530,7 @@ private: float soft_shadow_scale; uint32_t mask; float shadow_volumetric_fog_fade; - uint32_t pad; + uint32_t bake_mode; float projector_rect[4]; }; @@ -512,7 +547,8 @@ private: uint32_t shadow_enabled; float fade_from; float fade_to; - uint32_t pad[3]; + uint32_t pad[2]; + uint32_t bake_mode; float shadow_volumetric_fog_fade; float shadow_bias[4]; float shadow_normal_bias[4]; @@ -589,38 +625,19 @@ private: } cluster; struct RenderState { - RID render_buffers; - Transform cam_transform; - CameraMatrix cam_projection; - bool cam_ortogonal = false; - const PagedArray<GeometryInstance *> *instances = nullptr; - const PagedArray<RID> *lights = nullptr; - const PagedArray<RID> *reflection_probes = nullptr; - const PagedArray<RID> *gi_probes = nullptr; - const PagedArray<RID> *decals = nullptr; - const PagedArray<RID> *lightmaps = nullptr; - RID environment; - RID camera_effects; - RID shadow_atlas; - RID reflection_atlas; - RID reflection_probe; - int reflection_probe_pass = 0; - float screen_lod_threshold = 0.0; - - const RenderShadowData *render_shadows = nullptr; + const RendererSceneRender::RenderShadowData *render_shadows = nullptr; int render_shadow_count = 0; - const RenderSDFGIData *render_sdfgi_regions = nullptr; + const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr; int render_sdfgi_region_count = 0; - const RenderSDFGIUpdateData *sdfgi_update_data = nullptr; + const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr; - uint32_t directional_light_count = 0; uint32_t gi_probe_count = 0; LocalVector<int> cube_shadows; LocalVector<int> shadows; LocalVector<int> directional_shadows; - bool depth_prepass_used; + bool depth_prepass_used; // this does not seem used anywhere... } render_state; struct VolumetricFog { @@ -719,7 +736,6 @@ private: */ uint32_t max_cluster_elements = 512; - bool low_end = false; void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true); @@ -1089,6 +1105,8 @@ public: return li->transform; } + void _fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words = 2); + /* gi light probes */ RID gi_probe_instance_create(RID p_base); @@ -1129,7 +1147,7 @@ public: float render_buffers_get_volumetric_fog_end(RID p_render_buffers); float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr); + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr); void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); @@ -1193,7 +1211,10 @@ public: void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); - bool is_low_end() const; + virtual bool is_dynamic_gi_supported() const; + virtual bool is_clustered_enabled() const; + virtual bool is_volumetric_supported() const; + virtual uint32_t get_max_elements() const; RendererSceneRenderRD(RendererStorageRD *p_storage); ~RendererSceneRenderRD(); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 769335ac16..54c6e81110 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -50,6 +50,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { ShaderCompilerRD::GeneratedCode gen_code; ShaderCompilerRD::IdentifierActions actions; + actions.entry_point_stages["sky"] = ShaderCompilerRD::STAGE_FRAGMENT; uses_time = false; uses_half_res = false; @@ -110,7 +111,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { print_line("\n**light_code:\n" + gen_code.light); #endif - scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); + scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines); ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; @@ -759,7 +760,7 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { sky_shader.default_shader = storage->shader_allocate(); storage->shader_initialize(sky_shader.default_shader); - storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n"); + storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void sky() { COLOR = vec3(0.0); } \n"); sky_shader.default_material = storage->material_allocate(); storage->material_initialize(sky_shader.default_material); @@ -840,7 +841,7 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { sky_scene_state.fog_shader = storage->shader_allocate(); storage->shader_initialize(sky_scene_state.fog_shader); - storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n"); + storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void sky() { COLOR = clear_color.rgb; } \n"); sky_scene_state.fog_material = storage->material_allocate(); storage->material_initialize(sky_scene_state.fog_material); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index ba5ace8f31..f419875d58 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -756,7 +756,7 @@ void RendererStorageRD::texture_3d_initialize(RID p_texture, Image::Format p_for for (int i = 0; i < p_data.size(); i++) { uint32_t s = images[i]->get_data().size(); - copymem(&all_data.write[offset], images[i]->get_data().ptr(), s); + memcpy(&all_data.write[offset], images[i]->get_data().ptr(), s); { Texture::BufferSlice3D slice; slice.size.width = images[i]->get_width(); @@ -919,7 +919,7 @@ void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image> for (int i = 0; i < p_data.size(); i++) { uint32_t s = images[i]->get_data().size(); - copymem(&all_data.write[offset], images[i]->get_data().ptr(), s); + memcpy(&all_data.write[offset], images[i]->get_data().ptr(), s); offset += s; } } @@ -2108,13 +2108,13 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_INT: case ShaderLanguage::TYPE_UINT: case ShaderLanguage::TYPE_FLOAT: { - zeromem(data, 4); + memset(data, 0, 4); } break; case ShaderLanguage::TYPE_BVEC2: case ShaderLanguage::TYPE_IVEC2: case ShaderLanguage::TYPE_UVEC2: case ShaderLanguage::TYPE_VEC2: { - zeromem(data, 8); + memset(data, 0, 8); } break; case ShaderLanguage::TYPE_BVEC3: case ShaderLanguage::TYPE_IVEC3: @@ -2124,16 +2124,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_IVEC4: case ShaderLanguage::TYPE_UVEC4: case ShaderLanguage::TYPE_VEC4: { - zeromem(data, 16); + memset(data, 0, 16); } break; case ShaderLanguage::TYPE_MAT2: { - zeromem(data, 32); + memset(data, 0, 32); } break; case ShaderLanguage::TYPE_MAT3: { - zeromem(data, 48); + memset(data, 0, 48); } break; case ShaderLanguage::TYPE_MAT4: { - zeromem(data, 64); + memset(data, 0, 64); } break; default: { @@ -3412,10 +3412,10 @@ void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); { const uint8_t *r = buffer.ptr(); - copymem(w, r, buffer.size()); + memcpy(w, r, buffer.size()); } } else { - zeromem(w, multimesh->instances * multimesh->stride_cache * sizeof(float)); + memset(w, 0, multimesh->instances * multimesh->stride_cache * sizeof(float)); } } uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -3771,7 +3771,7 @@ Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const { { float *w = ret.ptrw(); const uint8_t *r = buffer.ptr(); - copymem(w, r, buffer.size()); + memcpy(w, r, buffer.size()); } return ret; @@ -3873,6 +3873,18 @@ void RendererStorageRD::particles_initialize(RID p_rid) { particles_owner.initialize_rid(p_rid, Particles()); } +void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + if (particles->mode == p_mode) { + return; + } + + _particles_free_data(particles); + + particles->mode = p_mode; +} + void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -3888,22 +3900,37 @@ bool RendererStorageRD::particles_get_emitting(RID p_particles) { } void RendererStorageRD::_particles_free_data(Particles *particles) { - if (!particles->particle_buffer.is_valid()) { - return; + if (particles->particle_buffer.is_valid()) { + RD::get_singleton()->free(particles->particle_buffer); + particles->particle_buffer = RID(); + RD::get_singleton()->free(particles->particle_instance_buffer); + particles->particle_instance_buffer = RID(); + } + + if (particles->frame_params_buffer.is_valid()) { + RD::get_singleton()->free(particles->frame_params_buffer); + particles->frame_params_buffer = RID(); } - RD::get_singleton()->free(particles->particle_buffer); - RD::get_singleton()->free(particles->frame_params_buffer); - RD::get_singleton()->free(particles->particle_instance_buffer); particles->particles_transforms_buffer_uniform_set = RID(); - particles->particle_buffer = RID(); + if (RD::get_singleton()->uniform_set_is_valid(particles->trail_bind_pose_uniform_set)) { + RD::get_singleton()->free(particles->trail_bind_pose_uniform_set); + } + particles->trail_bind_pose_uniform_set = RID(); + + if (particles->trail_bind_pose_buffer.is_valid()) { + RD::get_singleton()->free(particles->trail_bind_pose_buffer); + particles->trail_bind_pose_buffer = RID(); + } if (RD::get_singleton()->uniform_set_is_valid(particles->collision_textures_uniform_set)) { RD::get_singleton()->free(particles->collision_textures_uniform_set); } + particles->collision_textures_uniform_set = RID(); if (particles->particles_sort_buffer.is_valid()) { RD::get_singleton()->free(particles->particles_sort_buffer); particles->particles_sort_buffer = RID(); + particles->particles_sort_uniform_set = RID(); } if (particles->emission_buffer != nullptr) { @@ -3912,6 +3939,12 @@ void RendererStorageRD::_particles_free_data(Particles *particles) { RD::get_singleton()->free(particles->emission_storage_buffer); particles->emission_storage_buffer = RID(); } + + if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) { + //will need to be re-created + RD::get_singleton()->free(particles->particles_material_uniform_set); + } + particles->particles_material_uniform_set = RID(); } void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { @@ -3926,38 +3959,12 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { particles->amount = p_amount; - if (particles->amount > 0) { - particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * p_amount); - particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * 1); - particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * p_amount); - //needs to clear it - - { - Vector<RD::Uniform> uniforms; - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 1; - u.ids.push_back(particles->particle_buffer); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 2; - u.ids.push_back(particles->particle_instance_buffer); - uniforms.push_back(u); - } - - particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0); - } - } - particles->prev_ticks = 0; particles->phase = 0; particles->prev_phase = 0; particles->clear = true; + + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); } void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { @@ -4013,6 +4020,22 @@ void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { ERR_FAIL_COND(!particles); particles->fixed_fps = p_fps; + + _particles_free_data(particles); + + particles->prev_ticks = 0; + particles->phase = 0; + particles->prev_phase = 0; + particles->clear = true; + + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); +} + +void RendererStorageRD::particles_set_interpolate(RID p_particles, bool p_enable) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->interpolate = p_enable; } void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { @@ -4022,6 +4045,42 @@ void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_e particles->fractional_delta = p_enable; } +void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, float p_length) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + ERR_FAIL_COND(p_length < 0.1); + p_length = MIN(10.0, p_length); + + particles->trails_enabled = p_enable; + particles->trail_length = p_length; + + _particles_free_data(particles); + + particles->prev_ticks = 0; + particles->phase = 0; + particles->prev_phase = 0; + particles->clear = true; + + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); +} + +void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) { + _particles_free_data(particles); + + particles->prev_ticks = 0; + particles->phase = 0; + particles->prev_phase = 0; + particles->clear = true; + } + particles->trail_bind_poses = p_bind_poses; + particles->trail_bind_poses_dirty = true; + + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); +} + void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -4029,6 +4088,13 @@ void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float particles->collision_base_size = p_size; } +void RendererStorageRD::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->transform_align = p_transform_align; +} + void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -4068,7 +4134,7 @@ void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles ERR_FAIL_COND(particles->emission_buffer != nullptr); particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4); - zeromem(particles->emission_buffer_data.ptrw(), particles->emission_buffer_data.size()); + memset(particles->emission_buffer_data.ptrw(), 0, particles->emission_buffer_data.size()); particles->emission_buffer = (ParticleEmissionBuffer *)particles->emission_buffer_data.ptrw(); particles->emission_buffer->particle_max = particles->amount; @@ -4152,8 +4218,13 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); + int total_amount = particles->amount; + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + total_amount *= particles->trail_bind_poses.size(); + } + Vector<ParticleData> data; - data.resize(particles->amount); + data.resize(total_amount); Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer); @@ -4162,8 +4233,9 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { AABB aabb; if (buffer.size()) { bool first = true; + const ParticleData *particle_data = (const ParticleData *)data.ptr(); - for (int i = 0; i < particles->amount; i++) { + for (int i = 0; i < total_amount; i++) { if (particle_data[i].active) { Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]); if (!particles->use_local_coords) { @@ -4224,14 +4296,12 @@ RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->collisions.insert(p_particles_collision_instance); } void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->collisions.erase(p_particles_collision_instance); } @@ -4286,7 +4356,12 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0); - ParticlesFrameParams &frame_params = p_particles->frame_params; + //move back history (if there is any) + for (uint32_t i = p_particles->frame_history.size() - 1; i > 0; i--) { + p_particles->frame_history[i] = p_particles->frame_history[i - 1]; + } + //update current frame + ParticlesFrameParams &frame_params = p_particles->frame_history[0]; if (p_particles->clear) { p_particles->cycle_number = 0; @@ -4317,6 +4392,10 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta } frame_params.cycle = p_particles->cycle_number; + frame_params.frame = p_particles->frame_counter++; + frame_params.pad0 = 0; + frame_params.pad1 = 0; + frame_params.pad2 = 0; { //collision and attractors @@ -4515,12 +4594,18 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta ParticlesShader::PushConstant push_constant; + int process_amount = p_particles->amount; + + if (p_particles->trails_enabled && p_particles->trail_bind_poses.size() > 1) { + process_amount *= p_particles->trail_bind_poses.size(); + } push_constant.clear = p_particles->clear; push_constant.total_particles = p_particles->amount; push_constant.lifetime = p_particles->lifetime; - push_constant.trail_size = 1; + push_constant.trail_size = p_particles->trail_params.size(); push_constant.use_fractional_delta = p_particles->fractional_delta; push_constant.sub_emitter_mode = !p_particles->emitting && p_particles->emission_buffer && (p_particles->emission_buffer->particle_count > 0 || p_particles->force_sub_emit); + push_constant.trail_pass = false; p_particles->force_sub_emit = false; //reset @@ -4553,7 +4638,17 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta p_particles->clear = false; - RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params); + if (p_particles->trail_params.size() > 1) { + //fill the trail params + for (uint32_t i = 0; i < p_particles->trail_params.size(); i++) { + uint32_t src_idx = i * p_particles->frame_history.size() / p_particles->trail_params.size(); + p_particles->trail_params[i] = p_particles->frame_history[src_idx]; + } + } else { + p_particles->trail_params[0] = p_particles->frame_history[0]; + } + + RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams) * p_particles->trail_params.size(), p_particles->trail_params.ptr()); ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES); if (!m) { @@ -4575,27 +4670,45 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1); + if (p_particles->trails_enabled && p_particles->trail_bind_poses.size() > 1) { + //trails requires two passes in order to catch particle starts + RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount / p_particles->trail_bind_poses.size(), 1, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + + push_constant.trail_pass = true; + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount - p_particles->amount, 1, 1); + } else { + RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount, 1, 1); + } RD::get_singleton()->compute_list_end(); } -void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) { +void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) { - return; //uninteresting for other modes + if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { + return; + } + + if (particles->particle_buffer.is_null()) { + return; //particles have not processed yet } + bool do_sort = particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH; + //copy to sort buffer - if (particles->particles_sort_buffer == RID()) { + if (do_sort && particles->particles_sort_buffer == RID()) { uint32_t size = particles->amount; if (size & 1) { size++; //make multiple of 16 } size *= sizeof(float) * 2; particles->particles_sort_buffer = RD::get_singleton()->storage_buffer_create(size); + { Vector<RD::Uniform> uniforms; @@ -4611,41 +4724,109 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & } } + ParticlesShader::CopyPushConstant copy_push_constant; + + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + int fixed_fps = 60.0; + if (particles->fixed_fps > 0) { + fixed_fps = particles->fixed_fps; + } + + copy_push_constant.trail_size = particles->trail_bind_poses.size(); + copy_push_constant.trail_total = particles->frame_history.size(); + copy_push_constant.frame_delta = 1.0 / fixed_fps; + } else { + copy_push_constant.trail_size = 1; + copy_push_constant.trail_total = 1; + copy_push_constant.frame_delta = 0.0; + } + copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0; + copy_push_constant.total_particles = particles->amount; + Vector3 axis = -p_axis; // cameras look to z negative if (particles->use_local_coords) { axis = particles->emission_transform.basis.xform_inv(axis).normalized(); } - ParticlesShader::CopyPushConstant copy_push_constant; - copy_push_constant.total_particles = particles->amount; copy_push_constant.sort_direction[0] = axis.x; copy_push_constant.sort_direction[1] = axis.y; copy_push_constant.sort_direction[2] = axis.z; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); - RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); + copy_push_constant.align_up[0] = p_up_axis.x; + copy_push_constant.align_up[1] = p_up_axis.y; + copy_push_constant.align_up[2] = p_up_axis.z; - RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); + copy_push_constant.align_mode = particles->transform_align; - RD::get_singleton()->compute_list_end(); + if (do_sort) { + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); - effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount); + RD::get_singleton()->compute_list_end(); + effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount); + } + + copy_push_constant.total_particles *= copy_push_constant.total_particles; - compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER]); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : (particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES)]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); + if (do_sort) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, copy_push_constant.total_particles, 1, 1); RD::get_singleton()->compute_list_end(); } +void RendererStorageRD::_particles_update_buffers(Particles *particles) { + if (particles->amount > 0 && particles->particle_buffer.is_null()) { + int total_amount = particles->amount; + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + total_amount *= particles->trail_bind_poses.size(); + } + + uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3; + + particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * total_amount); + + particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount); + //needs to clear it + + { + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(particles->particle_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(particles->particle_instance_buffer); + uniforms.push_back(u); + } + + particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0); + } + } +} void RendererStorageRD::update_particles() { while (particle_update_list) { //use transform feedback to process particles @@ -4657,6 +4838,8 @@ void RendererStorageRD::update_particles() { particles->update_list = nullptr; particles->dirty = false; + _particles_update_buffers(particles); + if (particles->restart_request) { particles->prev_ticks = 0; particles->phase = 0; @@ -4688,14 +4871,84 @@ void RendererStorageRD::update_particles() { } } +#ifndef _MSC_VER +#warning Should use display refresh rate for all this +#endif + + float screen_hz = 60; + + int fixed_fps = 0; + if (particles->fixed_fps > 0) { + fixed_fps = particles->fixed_fps; + } else if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + fixed_fps = screen_hz; + } + { + //update trails + int history_size = 1; + int trail_steps = 1; + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + history_size = MAX(1, int(particles->trail_length * fixed_fps)); + trail_steps = particles->trail_bind_poses.size(); + } + + if (uint32_t(history_size) != particles->frame_history.size()) { + particles->frame_history.resize(history_size); + memset(particles->frame_history.ptr(), 0, sizeof(ParticlesFrameParams) * history_size); + } + + if (uint32_t(trail_steps) != particles->trail_params.size() || particles->frame_params_buffer.is_null()) { + particles->trail_params.resize(trail_steps); + if (particles->frame_params_buffer.is_valid()) { + RD::get_singleton()->free(particles->frame_params_buffer); + } + particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * trail_steps); + } + + if (particles->trail_bind_poses.size() > 1 && particles->trail_bind_pose_buffer.is_null()) { + particles->trail_bind_pose_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 16 * particles->trail_bind_poses.size()); + particles->trail_bind_poses_dirty = true; + } + + if (particles->trail_bind_pose_uniform_set.is_null()) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + if (particles->trail_bind_pose_buffer.is_valid()) { + u.ids.push_back(particles->trail_bind_pose_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + + particles->trail_bind_pose_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 2); + } + + if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses_dirty) { + if (particles_shader.pose_update_buffer.size() < uint32_t(particles->trail_bind_poses.size()) * 16) { + particles_shader.pose_update_buffer.resize(particles->trail_bind_poses.size() * 16); + } + + for (int i = 0; i < particles->trail_bind_poses.size(); i++) { + store_transform(particles->trail_bind_poses[i], &particles_shader.pose_update_buffer[i * 16]); + } + + RD::get_singleton()->buffer_update(particles->trail_bind_pose_buffer, 0, particles->trail_bind_poses.size() * 16 * sizeof(float), particles_shader.pose_update_buffer.ptr()); + } + } + bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0; if (particles->clear && particles->pre_process_time > 0.0) { float frame_time; - if (particles->fixed_fps > 0) - frame_time = 1.0 / particles->fixed_fps; - else + if (fixed_fps > 0) { + frame_time = 1.0 / fixed_fps; + } else { frame_time = 1.0 / 30.0; + } float todo = particles->pre_process_time; @@ -4705,14 +4958,14 @@ void RendererStorageRD::update_particles() { } } - if (particles->fixed_fps > 0) { + if (fixed_fps > 0) { float frame_time; float decr; if (zero_time_scale) { frame_time = 0.0; - decr = 1.0 / particles->fixed_fps; + decr = 1.0 / fixed_fps; } else { - frame_time = 1.0 / particles->fixed_fps; + frame_time = 1.0 / fixed_fps; decr = frame_time; } float delta = RendererCompositorRD::singleton->get_frame_delta_time(); @@ -4731,24 +4984,48 @@ void RendererStorageRD::update_particles() { particles->frame_remainder = todo; } else { - if (zero_time_scale) + if (zero_time_scale) { _particles_process(particles, 0.0); - else + } else { _particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time()); + } } //copy particles to instance buffer - if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) { + if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { + //does not need view dependent operation, do copy here ParticlesShader::CopyPushConstant copy_push_constant; - copy_push_constant.total_particles = particles->amount; + + int total_amount = particles->amount; + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + total_amount *= particles->trail_bind_poses.size(); + } + + copy_push_constant.total_particles = total_amount; + copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0; + copy_push_constant.align_mode = particles->transform_align; + copy_push_constant.align_up[0] = 0; + copy_push_constant.align_up[1] = 0; + copy_push_constant.align_up[2] = 0; + + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + copy_push_constant.trail_size = particles->trail_bind_poses.size(); + copy_push_constant.trail_total = particles->frame_history.size(); + copy_push_constant.frame_delta = 1.0 / fixed_fps; + } else { + copy_push_constant.trail_size = 1; + copy_push_constant.trail_total = 1; + copy_push_constant.frame_delta = 0.0; + } RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, total_amount, 1, 1); RD::get_singleton()->compute_list_end(); } @@ -4779,6 +5056,8 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { ShaderCompilerRD::GeneratedCode gen_code; ShaderCompilerRD::IdentifierActions actions; + actions.entry_point_stages["start"] = ShaderCompilerRD::STAGE_COMPUTE; + actions.entry_point_stages["process"] = ShaderCompilerRD::STAGE_COMPUTE; /* uses_time = false; @@ -4799,7 +5078,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { version = base_singleton->particles_shader.shader.version_create(); } - base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.uniforms, gen_code.compute_global, gen_code.compute, gen_code.defines); + base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_COMPUTE], gen_code.defines); ERR_FAIL_COND(!base_singleton->particles_shader.shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; @@ -5226,7 +5505,7 @@ void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool if (skeleton->size) { skeleton->data.resize(skeleton->size * (skeleton->use_2d ? 8 : 12)); skeleton->buffer = RD::get_singleton()->storage_buffer_create(skeleton->data.size() * sizeof(float)); - zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float)); + memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float)); _skeleton_make_dirty(skeleton); @@ -6868,7 +7147,7 @@ RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) { Vector<uint8_t> pv; pv.resize(16 * 4); - zeromem(pv.ptrw(), 16 * 4); + memset(pv.ptrw(), 0, 16 * 4); Vector<Vector<uint8_t>> vpv; rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); @@ -7355,7 +7634,7 @@ void RendererStorageRD::_update_decal_atlas() { v_offsetsv.resize(base_size); int *v_offsets = v_offsetsv.ptrw(); - zeromem(v_offsets, sizeof(int) * base_size); + memset(v_offsets, 0, sizeof(int) * base_size); int max_height = 0; @@ -7919,7 +8198,6 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements); } else { //texture - //texture for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) { Material *material = material_owner.getornull(E->get()); ERR_CONTINUE(!material); @@ -8112,7 +8390,7 @@ void RendererStorageRD::_update_global_variables() { if (total_regions / global_variables.buffer_dirty_region_count <= 4) { // 25% of regions dirty, just update all buffer RD::get_singleton()->buffer_update(global_variables.buffer, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size, global_variables.buffer_values); - zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * total_regions); + memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * total_regions); } else { uint32_t region_byte_size = sizeof(GlobalVariables::Value) * GlobalVariables::BUFFER_DIRTY_REGION_SIZE; @@ -8321,9 +8599,10 @@ bool RendererStorageRD::free(RID p_rid) { light_owner.free(p_rid); } else if (particles_owner.owns(p_rid)) { + update_particles(); Particles *particles = particles_owner.getornull(p_rid); - _particles_free_data(particles); particles->dependency.deleted_notify(p_rid); + _particles_free_data(particles); particles_owner.free(p_rid); } else if (particles_collision_owner.owns(p_rid)) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); @@ -8400,10 +8679,10 @@ RendererStorageRD::RendererStorageRD() { global_variables.buffer_size = GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size"); global_variables.buffer_size = MAX(4096, global_variables.buffer_size); global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size); - zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size); + memset(global_variables.buffer_values, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size); global_variables.buffer_usage = memnew_arr(GlobalVariables::ValueUsage, global_variables.buffer_size); global_variables.buffer_dirty_regions = memnew_arr(bool, global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE); - zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE); + memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE); global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size); material_update_list = nullptr; @@ -8822,7 +9101,6 @@ RendererStorageRD::RendererStorageRD() { sdf_versions.push_back(""); //one only giprobe_sdf_shader.initialize(sdf_versions); giprobe_sdf_shader_version = giprobe_sdf_shader.version_create(); - giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector<String>()); giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0); giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader); } @@ -8861,14 +9139,14 @@ RendererStorageRD::RendererStorageRD() { actions.renames["COLOR"] = "PARTICLE.color"; actions.renames["VELOCITY"] = "PARTICLE.velocity"; //actions.renames["MASS"] = "mass"; ? - actions.renames["ACTIVE"] = "PARTICLE.is_active"; + actions.renames["ACTIVE"] = "particle_active"; actions.renames["RESTART"] = "restart"; actions.renames["CUSTOM"] = "PARTICLE.custom"; actions.renames["TRANSFORM"] = "PARTICLE.xform"; actions.renames["TIME"] = "FRAME.time"; actions.renames["LIFETIME"] = "params.lifetime"; actions.renames["DELTA"] = "local_delta"; - actions.renames["NUMBER"] = "particle"; + actions.renames["NUMBER"] = "particle_number"; actions.renames["INDEX"] = "index"; //actions.renames["GRAVITY"] = "current_gravity"; actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform"; @@ -8911,7 +9189,7 @@ RendererStorageRD::RendererStorageRD() { // default material and shader for particles shader particles_shader.default_shader = shader_allocate(); shader_initialize(particles_shader.default_shader); - shader_set_code(particles_shader.default_shader, "shader_type particles; void compute() { COLOR = vec4(1.0); } \n"); + shader_set_code(particles_shader.default_shader, "shader_type particles; void process() { COLOR = vec4(1.0); } \n"); particles_shader.default_material = material_allocate(); material_initialize(particles_shader.default_material); material_set_shader(particles_shader.default_material, particles_shader.default_shader); @@ -8958,6 +9236,7 @@ RendererStorageRD::RendererStorageRD() { { Vector<String> copy_modes; copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n"); + copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define MODE_2D\n"); copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n"); copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n"); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index cd3d4604eb..49f7f3dba6 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -580,6 +580,7 @@ private: RID buffer; //storage buffer RID uniform_set_3d; + RID uniform_set_2d; bool dirty = false; MultiMesh *dirty_list = nullptr; @@ -660,6 +661,11 @@ private: float time; float delta; + uint32_t frame; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + uint32_t random_seed; uint32_t attractor_count; uint32_t collider_count; @@ -691,23 +697,30 @@ private: }; struct Particles { - bool inactive; - float inactive_time; - bool emitting; - bool one_shot; - int amount; - float lifetime; - float pre_process_time; - float explosiveness; - float randomness; - bool restart_request; - AABB custom_aabb; - bool use_local_coords; + RS::ParticlesMode mode = RS::PARTICLES_MODE_3D; + bool inactive = true; + float inactive_time = 0.0; + bool emitting = false; + bool one_shot = false; + int amount = 0; + float lifetime = 1.0; + float pre_process_time = 0.0; + float explosiveness = 0.0; + float randomness = 0.0; + bool restart_request = false; + AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)); + bool use_local_coords = true; RID process_material; + uint32_t frame_counter = 0; + RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED; - RS::ParticlesDrawOrder draw_order; + RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX; Vector<RID> draw_passes; + Vector<Transform> trail_bind_poses; + bool trail_bind_poses_dirty = false; + RID trail_bind_pose_buffer; + RID trail_bind_pose_uniform_set; RID particle_buffer; RID particle_instance_buffer; @@ -730,21 +743,22 @@ private: RID sub_emitter; - float phase; - float prev_phase; - uint64_t prev_ticks; - uint32_t random_seed; + float phase = 0.0; + float prev_phase = 0.0; + uint64_t prev_ticks = 0; + uint32_t random_seed = 0; - uint32_t cycle_number; + uint32_t cycle_number = 0; - float speed_scale; + float speed_scale = 1.0; - int fixed_fps; - bool fractional_delta; - float frame_remainder; - float collision_base_size; + int fixed_fps = 30; + bool interpolate = true; + bool fractional_delta = false; + float frame_remainder = 0; + float collision_base_size = 0.01; - bool clear; + bool clear = true; bool force_sub_emit = false; @@ -757,39 +771,21 @@ private: Set<RID> collisions; - Particles() : - inactive(true), - inactive_time(0.0), - emitting(false), - one_shot(false), - amount(0), - lifetime(1.0), - pre_process_time(0.0), - explosiveness(0.0), - randomness(0.0), - restart_request(false), - custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))), - use_local_coords(true), - draw_order(RS::PARTICLES_DRAW_ORDER_INDEX), - prev_ticks(0), - random_seed(0), - cycle_number(0), - speed_scale(1.0), - fixed_fps(0), - fractional_delta(false), - frame_remainder(0), - collision_base_size(0.01), - clear(true) { - } - Dependency dependency; - ParticlesFrameParams frame_params; + float trail_length = 1.0; + bool trails_enabled = false; + LocalVector<ParticlesFrameParams> frame_history; + LocalVector<ParticlesFrameParams> trail_params; + + Particles() { + } }; void _particles_process(Particles *p_particles, float p_delta); void _particles_allocate_emission_buffer(Particles *particles); void _particles_free_data(Particles *particles); + void _particles_update_buffers(Particles *particles); struct ParticlesShader { struct PushConstant { @@ -801,7 +797,7 @@ private: uint32_t use_fractional_delta; uint32_t sub_emitter_mode; uint32_t can_emit; - uint32_t pad; + uint32_t trail_pass; }; ParticlesShaderRD shader; @@ -816,10 +812,19 @@ private: struct CopyPushConstant { float sort_direction[3]; uint32_t total_particles; + + uint32_t trail_size; + uint32_t trail_total; + float frame_delta; + float frame_remainder; + + float align_up[3]; + uint32_t align_mode; }; enum { COPY_MODE_FILL_INSTANCES, + COPY_MODE_FILL_INSTANCES_2D, COPY_MODE_FILL_SORT_BUFFER, COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER, COPY_MODE_MAX, @@ -829,6 +834,8 @@ private: RID copy_shader_version; RID copy_pipelines[COPY_MODE_MAX]; + LocalVector<float> pose_update_buffer; + } particles_shader; Particles *particle_update_list = nullptr; @@ -1695,6 +1702,21 @@ public: return multimesh->uniform_set_3d; } + _FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + if (!multimesh->uniform_set_2d.is_valid()) { + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(multimesh->buffer); + uniforms.push_back(u); + multimesh->uniform_set_2d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set); + } + + return multimesh->uniform_set_2d; + } + /* IMMEDIATE API */ RID immediate_allocate() { return RID(); } @@ -2089,6 +2111,7 @@ public: RID particles_allocate(); void particles_initialize(RID p_particles_collision); + void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode); void particles_set_emitting(RID p_particles, bool p_emitting); void particles_set_amount(RID p_particles, int p_amount); void particles_set_lifetime(RID p_particles, float p_lifetime); @@ -2101,10 +2124,17 @@ public: void particles_set_use_local_coordinates(RID p_particles, bool p_enable); void particles_set_process_material(RID p_particles, RID p_material); void particles_set_fixed_fps(RID p_particles, int p_fps); + void particles_set_interpolate(RID p_particles, bool p_enable); void particles_set_fractional_delta(RID p_particles, bool p_enable); void particles_set_collision_base_size(RID p_particles, float p_size); + void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align); + + void particles_set_trails(RID p_particles, bool p_enable, float p_length); + void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses); + void particles_restart(RID p_particles); void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); + void particles_set_subemitter(RID p_particles, RID p_subemitter_particles); void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order); @@ -2122,15 +2152,27 @@ public: int particles_get_draw_passes(RID p_particles) const; RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; - void particles_set_view_axis(RID p_particles, const Vector3 &p_axis); + void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis); virtual bool particles_is_inactive(RID p_particles) const; - _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) { + _FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D); + return particles->mode; + } + + _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, 0); - return particles->amount; + if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { + r_trail_divisor = particles->trail_bind_poses.size(); + } else { + r_trail_divisor = 1; + } + + return particles->amount * r_trail_divisor; } _FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) { @@ -2144,6 +2186,8 @@ public: Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, RID()); if (particles->particles_transforms_buffer_uniform_set.is_null()) { + _particles_update_buffers(particles); + Vector<RD::Uniform> uniforms; { diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 8135d388e1..24ac85bb35 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -535,9 +535,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge struct_code += "}"; struct_code += ";\n"; - r_gen_code.vertex_global += struct_code; - r_gen_code.fragment_global += struct_code; - r_gen_code.compute_global += struct_code; + for (int j = 0; j < STAGE_MAX; j++) { + r_gen_code.stage_globals[j] += struct_code; + } } int max_texture_uniforms = 0; @@ -590,9 +590,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge ucode += " " + _mkid(E->key()); ucode += ";\n"; if (SL::is_sampler_type(E->get().type)) { - r_gen_code.vertex_global += ucode; - r_gen_code.fragment_global += ucode; - r_gen_code.compute_global += ucode; + for (int j = 0; j < STAGE_MAX; j++) { + r_gen_code.stage_globals[j] += ucode; + } GeneratedCode::Texture texture; texture.name = E->key(); @@ -608,7 +608,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge r_gen_code.texture_uniforms.write[E->get().texture_order] = texture; } else { if (!uses_uniforms) { - r_gen_code.defines.push_back(String("#define USE_MATERIAL_UNIFORMS\n")); uses_uniforms = true; } uniform_defines.write[E->get().order] = ucode; @@ -707,9 +706,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge vcode += "]"; } vcode += ";\n"; - r_gen_code.vertex_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode; - r_gen_code.fragment_global += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode; - r_gen_code.compute_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode; + + r_gen_code.stage_globals[STAGE_VERTEX] += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode; + r_gen_code.stage_globals[STAGE_FRAGMENT] += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode; + index++; } @@ -725,7 +725,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge gcode += ";\n"; } gcode += "} frag_to_light;\n"; - r_gen_code.fragment_global += gcode; + r_gen_code.stage_globals[STAGE_FRAGMENT] += gcode; } for (int i = 0; i < pnode->vconstants.size(); i++) { @@ -747,9 +747,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge gcode += "="; gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); gcode += ";\n"; - r_gen_code.vertex_global += gcode; - r_gen_code.fragment_global += gcode; - r_gen_code.compute_global += gcode; + for (int j = 0; j < STAGE_MAX; j++) { + r_gen_code.stage_globals[j] += gcode; + } } Map<StringName, String> function_code; @@ -765,9 +765,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge //place functions in actual code - Set<StringName> added_vtx; - Set<StringName> added_fragment; //share for light - Set<StringName> added_compute; //share for light + Set<StringName> added_funcs_per_stage[STAGE_MAX]; for (int i = 0; i < pnode->functions.size(); i++) { SL::FunctionNode *fnode = pnode->functions[i].function; @@ -776,24 +774,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge current_func_name = fnode->name; - if (fnode->name == vertex_name) { - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx); - r_gen_code.vertex = function_code[vertex_name]; - } - - if (fnode->name == fragment_name) { - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); - r_gen_code.fragment = function_code[fragment_name]; - } - - if (fnode->name == light_name) { - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); - r_gen_code.light = function_code[light_name]; - } - - if (fnode->name == compute_name) { - _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.compute_global, added_compute); - r_gen_code.compute = function_code[compute_name]; + if (p_actions.entry_point_stages.has(fnode->name)) { + Stage stage = p_actions.entry_point_stages[fnode->name]; + _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.stage_globals[stage], added_funcs_per_stage[stage]); + r_gen_code.code[fnode->name] = function_code[fnode->name]; } function = nullptr; @@ -858,7 +842,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge SL::VariableNode *vnode = (SL::VariableNode *)p_node; bool use_fragment_varying = false; - if (current_func_name != vertex_name) { + if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) { if (p_assigning) { if (shader->varyings.has(vnode->name)) { use_fragment_varying = true; @@ -921,10 +905,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } if (vnode->name == time_name) { - if (current_func_name == vertex_name) { + if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX) { r_gen_code.uses_vertex_time = true; } - if (current_func_name == fragment_name || current_func_name == light_name) { + if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_FRAGMENT) { r_gen_code.uses_fragment_time = true; } } @@ -1003,7 +987,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge SL::ArrayNode *anode = (SL::ArrayNode *)p_node; bool use_fragment_varying = false; - if (current_func_name != vertex_name) { + if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) { if (anode->assign_expression != nullptr) { use_fragment_varying = true; } else { @@ -1059,10 +1043,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } if (anode->name == time_name) { - if (current_func_name == vertex_name) { + if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX) { r_gen_code.uses_vertex_time = true; } - if (current_func_name == fragment_name || current_func_name == light_name) { + if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_FRAGMENT) { r_gen_code.uses_fragment_time = true; } } @@ -1309,7 +1293,7 @@ ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName & } Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types(), _get_variable_type); + Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_variable_type); if (err != OK) { Vector<String> shader = p_code.split("\n"); @@ -1322,13 +1306,10 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide } r_gen_code.defines.clear(); - r_gen_code.vertex = String(); - r_gen_code.vertex_global = String(); - r_gen_code.fragment = String(); - r_gen_code.fragment_global = String(); - r_gen_code.compute = String(); - r_gen_code.compute_global = String(); - r_gen_code.light = String(); + r_gen_code.code.clear(); + for (int i = 0; i < STAGE_MAX; i++) { + r_gen_code.stage_globals[i] = String(); + } r_gen_code.uses_fragment_time = false; r_gen_code.uses_vertex_time = false; r_gen_code.uses_global_textures = false; @@ -1348,10 +1329,6 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) { actions = p_actions; - vertex_name = "vertex"; - fragment_name = "fragment"; - compute_name = "compute"; - light_name = "light"; time_name = "TIME"; List<String> func_list; diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 6575829e73..2da127ffa3 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -38,7 +38,16 @@ class ShaderCompilerRD { public: + enum Stage { + STAGE_VERTEX, + STAGE_FRAGMENT, + STAGE_COMPUTE, + STAGE_MAX + }; + struct IdentifierActions { + Map<StringName, Stage> entry_point_stages; + Map<StringName, Pair<int *, int>> render_mode_values; Map<StringName, bool *> render_mode_flags; Map<StringName, bool *> usage_flag_pointers; @@ -63,13 +72,9 @@ public: Vector<uint32_t> uniform_offsets; uint32_t uniform_total_size; String uniforms; - String vertex_global; - String vertex; - String fragment_global; - String fragment; - String light; - String compute_global; - String compute; + String stage_globals[STAGE_MAX]; + + Map<String, String> code; bool uses_global_textures; bool uses_fragment_time; @@ -103,10 +108,6 @@ private: const ShaderLanguage::ShaderNode *shader; const ShaderLanguage::FunctionNode *function; StringName current_func_name; - StringName vertex_name; - StringName fragment_name; - StringName light_name; - StringName compute_name; StringName time_name; Set<StringName> texture_functions; diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index e4a39ff813..f7242a2b17 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -30,146 +30,83 @@ #include "shader_rd.h" -#include "core/string/string_builder.h" #include "renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" -void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) { - name = p_name; - //split vertex and shader code (thank you, shader compiler programmers from you know what company). - if (p_vertex_code) { - String defines_tag = "\nVERSION_DEFINES"; - String globals_tag = "\nVERTEX_SHADER_GLOBALS"; - String material_tag = "\nMATERIAL_UNIFORMS"; - String code_tag = "\nVERTEX_SHADER_CODE"; - String code = p_vertex_code; - - int cpos = code.find(defines_tag); - if (cpos != -1) { - vertex_codev = code.substr(0, cpos).ascii(); - code = code.substr(cpos + defines_tag.length(), code.length()); - } - - cpos = code.find(material_tag); - - if (cpos == -1) { - vertex_code0 = code.ascii(); - } else { - vertex_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + material_tag.length(), code.length()); - - cpos = code.find(globals_tag); - - if (cpos == -1) { - vertex_code1 = code.ascii(); - } else { - vertex_code1 = code.substr(0, cpos).ascii(); - String code2 = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code2.find(code_tag); - if (cpos == -1) { - vertex_code2 = code2.ascii(); - } else { - vertex_code2 = code2.substr(0, cpos).ascii(); - vertex_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); +void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { + Vector<String> lines = String(p_code).split("\n"); + + String text; + + for (int i = 0; i < lines.size(); i++) { + String l = lines[i]; + bool push_chunk = false; + + StageTemplate::Chunk chunk; + + if (l.begins_with("#VERSION_DEFINES")) { + chunk.type = StageTemplate::Chunk::TYPE_VERSION_DEFINES; + push_chunk = true; + } else if (l.begins_with("#GLOBALS")) { + switch (p_stage_type) { + case STAGE_TYPE_VERTEX: + chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS; + break; + case STAGE_TYPE_FRAGMENT: + chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS; + break; + case STAGE_TYPE_COMPUTE: + chunk.type = StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS; + break; + default: { } } - } - } - if (p_fragment_code) { - String defines_tag = "\nVERSION_DEFINES"; - String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; - String material_tag = "\nMATERIAL_UNIFORMS"; - String code_tag = "\nFRAGMENT_SHADER_CODE"; - String light_code_tag = "\nLIGHT_SHADER_CODE"; - String code = p_fragment_code; - - int cpos = code.find(defines_tag); - if (cpos != -1) { - fragment_codev = code.substr(0, cpos).ascii(); - code = code.substr(cpos + defines_tag.length(), code.length()); + push_chunk = true; + } else if (l.begins_with("#MATERIAL_UNIFORMS")) { + chunk.type = StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS; + push_chunk = true; + } else if (l.begins_with("#CODE")) { + chunk.type = StageTemplate::Chunk::TYPE_CODE; + push_chunk = true; + chunk.code = l.replace_first("#CODE", String()).replace(":", "").strip_edges().to_upper(); + } else { + text += l + "\n"; } - cpos = code.find(material_tag); - if (cpos == -1) { - fragment_code0 = code.ascii(); - } else { - fragment_code0 = code.substr(0, cpos).ascii(); - //print_line("CODE0:\n"+String(fragment_code0.get_data())); - code = code.substr(cpos + material_tag.length(), code.length()); - cpos = code.find(globals_tag); - - if (cpos == -1) { - fragment_code1 = code.ascii(); - } else { - fragment_code1 = code.substr(0, cpos).ascii(); - //print_line("CODE1:\n"+String(fragment_code1.get_data())); - - String code2 = code.substr(cpos + globals_tag.length(), code.length()); - cpos = code2.find(light_code_tag); - - if (cpos == -1) { - fragment_code2 = code2.ascii(); - } else { - fragment_code2 = code2.substr(0, cpos).ascii(); - //print_line("CODE2:\n"+String(fragment_code2.get_data())); - - String code3 = code2.substr(cpos + light_code_tag.length(), code2.length()); - - cpos = code3.find(code_tag); - if (cpos == -1) { - fragment_code3 = code3.ascii(); - } else { - fragment_code3 = code3.substr(0, cpos).ascii(); - //print_line("CODE3:\n"+String(fragment_code3.get_data())); - fragment_code4 = code3.substr(cpos + code_tag.length(), code3.length()).ascii(); - //print_line("CODE4:\n"+String(fragment_code4.get_data())); - } - } + if (push_chunk) { + if (text != String()) { + StageTemplate::Chunk text_chunk; + text_chunk.type = StageTemplate::Chunk::TYPE_TEXT; + text_chunk.text = text.utf8(); + stage_templates[p_stage_type].chunks.push_back(text_chunk); + text = String(); } + stage_templates[p_stage_type].chunks.push_back(chunk); } } + if (text != String()) { + StageTemplate::Chunk text_chunk; + text_chunk.type = StageTemplate::Chunk::TYPE_TEXT; + text_chunk.text = text.utf8(); + stage_templates[p_stage_type].chunks.push_back(text_chunk); + text = String(); + } +} + +void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) { + name = p_name; if (p_compute_code) { + _add_stage(p_compute_code, STAGE_TYPE_COMPUTE); is_compute = true; - - String defines_tag = "\nVERSION_DEFINES"; - String globals_tag = "\nCOMPUTE_SHADER_GLOBALS"; - String material_tag = "\nMATERIAL_UNIFORMS"; - String code_tag = "\nCOMPUTE_SHADER_CODE"; - String code = p_compute_code; - - int cpos = code.find(defines_tag); - if (cpos != -1) { - compute_codev = code.substr(0, cpos).ascii(); - code = code.substr(cpos + defines_tag.length(), code.length()); + } else { + is_compute = false; + if (p_vertex_code) { + _add_stage(p_vertex_code, STAGE_TYPE_VERTEX); } - - cpos = code.find(material_tag); - - if (cpos == -1) { - compute_code0 = code.ascii(); - } else { - compute_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + material_tag.length(), code.length()); - - cpos = code.find(globals_tag); - - if (cpos == -1) { - compute_code1 = code.ascii(); - } else { - compute_code1 = code.substr(0, cpos).ascii(); - String code2 = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code2.find(code_tag); - if (cpos == -1) { - compute_code2 = code2.ascii(); - } else { - compute_code2 = code2.substr(0, cpos).ascii(); - compute_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); - } - } + if (p_fragment_code) { + _add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT); } } } @@ -198,6 +135,49 @@ void ShaderRD::_clear_version(Version *p_version) { } } +void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template) { + for (uint32_t i = 0; i < p_template.chunks.size(); i++) { + const StageTemplate::Chunk &chunk = p_template.chunks[i]; + switch (chunk.type) { + case StageTemplate::Chunk::TYPE_VERSION_DEFINES: { + builder.append("\n"); //make sure defines begin at newline + builder.append(general_defines.get_data()); + builder.append(variant_defines[p_variant].get_data()); + for (int j = 0; j < p_version->custom_defines.size(); j++) { + builder.append(p_version->custom_defines[j].get_data()); + } + builder.append("\n"); //make sure defines begin at newline + if (p_version->uniforms.size()) { + builder.append("#define MATERIAL_UNIFORMS_USED\n"); + } + for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) { + builder.append(String("#define ") + String(E->key()) + "_CODE_USED\n"); + } + } break; + case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: { + builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) + } break; + case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: { + builder.append(p_version->vertex_globals.get_data()); // vertex globals + } break; + case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: { + builder.append(p_version->fragment_globals.get_data()); // fragment globals + } break; + case StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS: { + builder.append(p_version->compute_globals.get_data()); // compute globals + } break; + case StageTemplate::Chunk::TYPE_CODE: { + if (p_version->code_sections.has(chunk.code)) { + builder.append(p_version->code_sections[chunk.code].get_data()); + } + } break; + case StageTemplate::Chunk::TYPE_TEXT: { + builder.append(chunk.text.get_data()); + } break; + } + } +} + void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { if (!variants_enabled[p_variant]) { return; //variant is disabled, return @@ -214,29 +194,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { //vertex stage StringBuilder builder; - - builder.append(vertex_codev.get_data()); // version info (if exists) - builder.append("\n"); //make sure defines begin at newline - builder.append(general_defines.get_data()); - builder.append(variant_defines[p_variant].get_data()); - - for (int j = 0; j < p_version->custom_defines.size(); j++) { - builder.append(p_version->custom_defines[j].get_data()); - } - - builder.append(vertex_code0.get_data()); //first part of vertex - - builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) - - builder.append(vertex_code1.get_data()); //second part of vertex - - builder.append(p_version->vertex_globals.get_data()); // vertex globals - - builder.append(vertex_code2.get_data()); //third part of vertex - - builder.append(p_version->vertex_code.get_data()); // code - - builder.append(vertex_code3.get_data()); //fourth of vertex + _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX]); current_source = builder.as_string(); RD::ShaderStageData stage; @@ -254,33 +212,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { current_stage = RD::SHADER_STAGE_FRAGMENT; StringBuilder builder; - - builder.append(fragment_codev.get_data()); // version info (if exists) - builder.append("\n"); //make sure defines begin at newline - - builder.append(general_defines.get_data()); - builder.append(variant_defines[p_variant].get_data()); - for (int j = 0; j < p_version->custom_defines.size(); j++) { - builder.append(p_version->custom_defines[j].get_data()); - } - - builder.append(fragment_code0.get_data()); //first part of fragment - - builder.append(p_version->uniforms.get_data()); //uniforms (same for fragment and fragment) - - builder.append(fragment_code1.get_data()); //first part of fragment - - builder.append(p_version->fragment_globals.get_data()); // fragment globals - - builder.append(fragment_code2.get_data()); //third part of fragment - - builder.append(p_version->fragment_light.get_data()); // fragment light - - builder.append(fragment_code3.get_data()); //fourth part of fragment - - builder.append(p_version->fragment_code.get_data()); // fragment code - - builder.append(fragment_code4.get_data()); //fourth part of fragment + _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT]); current_source = builder.as_string(); RD::ShaderStageData stage; @@ -298,32 +230,10 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { current_stage = RD::SHADER_STAGE_COMPUTE; StringBuilder builder; - - builder.append(compute_codev.get_data()); // version info (if exists) - builder.append("\n"); //make sure defines begin at newline - builder.append(base_compute_defines.get_data()); - builder.append(general_defines.get_data()); - builder.append(variant_defines[p_variant].get_data()); - - for (int j = 0; j < p_version->custom_defines.size(); j++) { - builder.append(p_version->custom_defines[j].get_data()); - } - - builder.append(compute_code0.get_data()); //first part of compute - - builder.append(p_version->uniforms.get_data()); //uniforms (same for compute and fragment) - - builder.append(compute_code1.get_data()); //second part of compute - - builder.append(p_version->compute_globals.get_data()); // compute globals - - builder.append(compute_code2.get_data()); //third part of compute - - builder.append(p_version->compute_code.get_data()); // code - - builder.append(compute_code3.get_data()); //fourth of compute + _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_COMPUTE]); current_source = builder.as_string(); + RD::ShaderStageData stage; stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error); if (stage.spir_v.size() == 0) { @@ -364,29 +274,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio //vertex stage StringBuilder builder; - - builder.append(vertex_codev.get_data()); // version info (if exists) - builder.append("\n"); //make sure defines begin at newline - builder.append(general_defines.get_data()); - builder.append(variant_defines[i].get_data()); - - for (int j = 0; j < version->custom_defines.size(); j++) { - builder.append(version->custom_defines[j].get_data()); - } - - builder.append(vertex_code0.get_data()); //first part of vertex - - builder.append(version->uniforms.get_data()); //uniforms (same for vertex and fragment) - - builder.append(vertex_code1.get_data()); //second part of vertex - - builder.append(version->vertex_globals.get_data()); // vertex globals - - builder.append(vertex_code2.get_data()); //third part of vertex - - builder.append(version->vertex_code.get_data()); // code - - builder.append(vertex_code3.get_data()); //fourth of vertex + _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX]); RS::ShaderNativeSourceCode::Version::Stage stage; stage.name = "vertex"; @@ -399,32 +287,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio //fragment stage StringBuilder builder; - - builder.append(fragment_codev.get_data()); // version info (if exists) - builder.append("\n"); //make sure defines begin at newline - builder.append(general_defines.get_data()); - builder.append(variant_defines[i].get_data()); - for (int j = 0; j < version->custom_defines.size(); j++) { - builder.append(version->custom_defines[j].get_data()); - } - - builder.append(fragment_code0.get_data()); //first part of fragment - - builder.append(version->uniforms.get_data()); //uniforms (same for fragment and fragment) - - builder.append(fragment_code1.get_data()); //first part of fragment - - builder.append(version->fragment_globals.get_data()); // fragment globals - - builder.append(fragment_code2.get_data()); //third part of fragment - - builder.append(version->fragment_light.get_data()); // fragment light - - builder.append(fragment_code3.get_data()); //fourth part of fragment - - builder.append(version->fragment_code.get_data()); // fragment code - - builder.append(fragment_code4.get_data()); //fourth part of fragment + _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT]); RS::ShaderNativeSourceCode::Version::Stage stage; stage.name = "fragment"; @@ -437,30 +300,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio //compute stage StringBuilder builder; - - builder.append(compute_codev.get_data()); // version info (if exists) - builder.append("\n"); //make sure defines begin at newline - builder.append(base_compute_defines.get_data()); - builder.append(general_defines.get_data()); - builder.append(variant_defines[i].get_data()); - - for (int j = 0; j < version->custom_defines.size(); j++) { - builder.append(version->custom_defines[j].get_data()); - } - - builder.append(compute_code0.get_data()); //first part of compute - - builder.append(version->uniforms.get_data()); //uniforms (same for compute and fragment) - - builder.append(compute_code1.get_data()); //second part of compute - - builder.append(version->compute_globals.get_data()); // compute globals - - builder.append(compute_code2.get_data()); //third part of compute - - builder.append(version->compute_code.get_data()); // code - - builder.append(compute_code3.get_data()); //fourth of compute + _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_COMPUTE]); RS::ShaderNativeSourceCode::Version::Stage stage; stage.name = "compute"; @@ -518,17 +358,18 @@ void ShaderRD::_compile_version(Version *p_version) { p_version->valid = true; } -void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines) { +void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines) { ERR_FAIL_COND(is_compute); Version *version = version_owner.getornull(p_version); ERR_FAIL_COND(!version); version->vertex_globals = p_vertex_globals.utf8(); - version->vertex_code = p_vertex_code.utf8(); - version->fragment_light = p_fragment_light.utf8(); version->fragment_globals = p_fragment_globals.utf8(); - version->fragment_code = p_fragment_code.utf8(); version->uniforms = p_uniforms.utf8(); + version->code_sections.clear(); + for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) { + version->code_sections[StringName(E->key().to_upper())] = E->get().utf8(); + } version->custom_defines.clear(); for (int i = 0; i < p_custom_defines.size(); i++) { @@ -542,15 +383,20 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S } } -void ShaderRD::version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines) { +void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines) { ERR_FAIL_COND(!is_compute); Version *version = version_owner.getornull(p_version); ERR_FAIL_COND(!version); + version->compute_globals = p_compute_globals.utf8(); - version->compute_code = p_compute_code.utf8(); version->uniforms = p_uniforms.utf8(); + version->code_sections.clear(); + for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) { + version->code_sections[StringName(E->key().to_upper())] = E->get().utf8(); + } + version->custom_defines.clear(); for (int i = 0; i < p_custom_defines.size(); i++) { version->custom_defines.push_back(p_custom_defines[i].utf8()); diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index e0f4dcf2d0..f20d539621 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -32,7 +32,9 @@ #define SHADER_RD_H #include "core/os/mutex.h" +#include "core/string/string_builder.h" #include "core/templates/hash_map.h" +#include "core/templates/local_vector.h" #include "core/templates/map.h" #include "core/templates/rid_owner.h" #include "core/variant/variant.h" @@ -52,12 +54,9 @@ class ShaderRD { struct Version { CharString uniforms; CharString vertex_globals; - CharString vertex_code; CharString compute_globals; - CharString compute_code; - CharString fragment_light; CharString fragment_globals; - CharString fragment_code; + Map<StringName, CharString> code_sections; Vector<CharString> custom_defines; RID *variants; //same size as version defines @@ -76,31 +75,44 @@ class ShaderRD { RID_Owner<Version> version_owner; - CharString fragment_codev; //for version and extensions - CharString fragment_code0; - CharString fragment_code1; - CharString fragment_code2; - CharString fragment_code3; - CharString fragment_code4; - - CharString vertex_codev; //for version and extensions - CharString vertex_code0; - CharString vertex_code1; - CharString vertex_code2; - CharString vertex_code3; + struct StageTemplate { + struct Chunk { + enum Type { + TYPE_VERSION_DEFINES, + TYPE_MATERIAL_UNIFORMS, + TYPE_VERTEX_GLOBALS, + TYPE_FRAGMENT_GLOBALS, + TYPE_COMPUTE_GLOBALS, + TYPE_CODE, + TYPE_TEXT + }; + + Type type; + StringName code; + CharString text; + }; + LocalVector<Chunk> chunks; + }; bool is_compute = false; - CharString compute_codev; //for version and extensions - CharString compute_code0; - CharString compute_code1; - CharString compute_code2; - CharString compute_code3; - const char *name; CharString base_compute_defines; + enum StageType { + STAGE_TYPE_VERTEX, + STAGE_TYPE_FRAGMENT, + STAGE_TYPE_COMPUTE, + STAGE_TYPE_MAX, + }; + + StageTemplate stage_templates[STAGE_TYPE_MAX]; + + void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template); + + void _add_stage(const char *p_code, StageType p_stage_type); + protected: ShaderRD(); void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name); @@ -108,8 +120,8 @@ protected: public: RID version_create(); - void version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines); - void version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines); + void version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines); + void version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines); _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl index 63f086a83d..b70e0b6bd5 100644 --- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define BLOCK_SIZE 8 diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 3b39edc70e..cf4c77db0d 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #ifdef USE_ATTRIBUTES layout(location = 0) in vec2 vertex_attrib; @@ -26,17 +26,15 @@ layout(location = 3) out vec2 pixel_size_interp; #endif -#ifdef USE_MATERIAL_UNIFORMS +#ifdef MATERIAL_UNIFORMS_USED layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ + +#MATERIAL_UNIFORMS + } material; #endif -/* clang-format off */ -VERTEX_SHADER_GLOBALS -/* clang-format on */ +#GLOBALS void main() { vec4 instance_custom = vec4(0.0); @@ -86,40 +84,84 @@ void main() { mat4 world_matrix = mat4(vec4(draw_data.world_x, 0.0, 0.0), vec4(draw_data.world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data.world_ofs, 0.0, 1.0)); -#if 0 - if (draw_data.flags & FLAGS_INSTANCING_ENABLED) { - uint offset = draw_data.flags & FLAGS_INSTANCING_STRIDE_MASK; - offset *= gl_InstanceIndex; - mat4 instance_xform = mat4( - vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), 0.0, texelFetch(instancing_buffer, offset + 3)), - vec4(texelFetch(instancing_buffer, offset + 4), texelFetch(instancing_buffer, offset + 5), 0.0, texelFetch(instancing_buffer, offset + 7)), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); - offset += 8; - if (draw_data.flags & FLAGS_INSTANCING_HAS_COLORS) { - vec4 instance_color; - if (draw_data.flags & FLAGS_INSTANCING_COLOR_8_BIT) { - uint bits = floatBitsToUint(texelFetch(instancing_buffer, offset)); - instance_color = unpackUnorm4x8(bits); - offset += 1; - } else { - instance_color = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3)); - offset += 4; - } +#define FLAGS_INSTANCING_MASK 0x7F +#define FLAGS_INSTANCING_HAS_COLORS (1 << 7) +#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8) + + uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK; + +#ifdef USE_ATTRIBUTES + + if (instancing > 1) { + // trails + + uint stride = 2 + 1 + 1; //particles always uses this format - color *= instance_color; + uint trail_size = instancing; + + uint offset = trail_size * stride * gl_InstanceIndex; + + mat4 matrix; + vec4 pcolor; + { + uint boffset = offset + bone_attrib.x * stride; + matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x; + pcolor = transforms.data[boffset + 3] * weight_attrib.x; } - if (draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA) { - if (draw_data.flags & FLAGS_INSTANCING_CUSTOM_DATA_8_BIT) { - uint bits = floatBitsToUint(texelFetch(instancing_buffer, offset)); - instance_custom = unpackUnorm4x8(bits); - } else { - instance_custom = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3)); + if (weight_attrib.y > 0.001) { + uint boffset = offset + bone_attrib.y * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y; + pcolor += transforms.data[boffset + 3] * weight_attrib.y; + } + if (weight_attrib.z > 0.001) { + uint boffset = offset + bone_attrib.z * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z; + pcolor += transforms.data[boffset + 3] * weight_attrib.z; + } + if (weight_attrib.w > 0.001) { + uint boffset = offset + bone_attrib.w * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w; + pcolor += transforms.data[boffset + 3] * weight_attrib.w; + } + + instance_custom = transforms.data[offset + 4]; + + color *= pcolor; + + matrix = transpose(matrix); + world_matrix = world_matrix * matrix; + + } else +#endif // USE_ATTRIBUTES + + if (instancing == 1) { + uint stride = 2; + { + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) { + stride += 1; + } + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { + stride += 1; } } - } -#endif + uint offset = stride * gl_InstanceIndex; + + mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + offset += 2; + + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) { + color *= transforms.data[offset]; + offset += 1; + } + + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { + instance_custom = transforms.data[offset]; + } + + matrix = transpose(matrix); + world_matrix = world_matrix * matrix; + } #if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) if (bool(draw_data.flags & FLAGS_USING_PARTICLES)) { @@ -132,9 +174,7 @@ void main() { float point_size = 1.0; #endif { - /* clang-format off */ -VERTEX_SHADER_CODE - /* clang-format on */ +#CODE : VERTEX } #ifdef USE_NINEPATCH @@ -212,7 +252,7 @@ VERTEX_SHADER_CODE #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "canvas_uniforms_inc.glsl" @@ -228,11 +268,11 @@ layout(location = 3) in vec2 pixel_size_interp; layout(location = 0) out vec4 frag_color; -#ifdef USE_MATERIAL_UNIFORMS +#ifdef MATERIAL_UNIFORMS_USED layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ + +#MATERIAL_UNIFORMS + } material; #endif @@ -260,11 +300,9 @@ vec2 sdf_to_screen_uv(vec2 p_sdf) { return p_sdf * canvas_data.sdf_to_screen; } -/* clang-format off */ -FRAGMENT_SHADER_GLOBALS -/* clang-format on */ +#GLOBALS -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED vec4 light_compute( vec3 light_vertex, @@ -278,9 +316,9 @@ vec4 light_compute( vec2 uv, vec4 color, bool is_directional) { vec4 light = vec4(0.0); - /* clang-format off */ -LIGHT_SHADER_CODE - /* clang-format on */ + +#CODE : LIGHT + return light; } @@ -356,7 +394,7 @@ vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 lig //float distance = length(shadow_pos); vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED , vec3 shadow_modulate #endif @@ -395,7 +433,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv } vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED shadow_color.rgb *= shadow_modulate; #endif @@ -504,11 +542,7 @@ void main() { normal_used = true; #endif - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ +#CODE : FRAGMENT #if defined(NORMAL_MAP_USED) normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth); @@ -543,7 +577,7 @@ FRAGMENT_SHADER_CODE vec2 direction = light_array.data[light_base].position; vec4 light_color = light_array.data[light_base].color; -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED vec4 shadow_modulate = vec4(1.0); light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true); @@ -561,7 +595,7 @@ FRAGMENT_SHADER_CODE vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0); light_color = light_shadow_compute(light_base, light_color, shadow_uv -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED , shadow_modulate.rgb #endif @@ -599,7 +633,7 @@ FRAGMENT_SHADER_CODE vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0); vec4 light_base_color = light_array.data[light_base].color; -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED vec4 shadow_modulate = vec4(1.0); vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height); @@ -657,7 +691,7 @@ FRAGMENT_SHADER_CODE vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0); light_color = light_shadow_compute(light_base, light_color, shadow_uv -#ifdef LIGHT_SHADER_CODE_USED +#ifdef LIGHT_CODE_USED , shadow_modulate.rgb #endif diff --git a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl index 5c25235c58..9f89f4b3b7 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) in highp vec3 vertex; @@ -32,7 +32,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(push_constant, binding = 0, std430) uniform Constants { mat4 projection; diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl index 302ad03b41..65a554e839 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index cf7678ea31..451f9b0089 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -5,12 +5,10 @@ #define SDF_MAX_LENGTH 16384.0 -#define FLAGS_INSTANCING_STRIDE_MASK 0xF -#define FLAGS_INSTANCING_ENABLED (1 << 4) -#define FLAGS_INSTANCING_HAS_COLORS (1 << 5) -#define FLAGS_INSTANCING_COLOR_8BIT (1 << 6) -#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 7) -#define FLAGS_INSTANCING_CUSTOM_DATA_8_BIT (1 << 8) +//1 means enabled, 2+ means trails in use +#define FLAGS_INSTANCING_MASK 0x7F +#define FLAGS_INSTANCING_HAS_COLORS (1 << 7) +#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8) #define FLAGS_CLIP_RECT_UV (1 << 9) #define FLAGS_TRANSPOSE_RECT (1 << 10) diff --git a/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl index 3a4bf4da07..8e616ebe1f 100644 --- a/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl @@ -1,105 +1,3 @@ - #define CLUSTER_COUNTER_SHIFT 20 #define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1) #define CLUSTER_COUNTER_MASK 0xfff - -struct LightData { //this structure needs to be as packed as possible - vec3 position; - float inv_radius; - - vec3 direction; - float size; - - vec3 color; - float attenuation; - - float cone_attenuation; - float cone_angle; - float specular_amount; - bool shadow_enabled; - - vec4 atlas_rect; // rect in the shadow atlas - mat4 shadow_matrix; - float shadow_bias; - float shadow_normal_bias; - float transmittance_bias; - float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle - float soft_shadow_scale; // scales the shadow kernel for blurrier shadows - uint mask; - float shadow_volumetric_fog_fade; - uint pad; - vec4 projector_rect; //projector rect in srgb decal atlas -}; - -#define REFLECTION_AMBIENT_DISABLED 0 -#define REFLECTION_AMBIENT_ENVIRONMENT 1 -#define REFLECTION_AMBIENT_COLOR 2 - -struct ReflectionData { - vec3 box_extents; - float index; - vec3 box_offset; - uint mask; - vec3 ambient; // ambient color - float intensity; - bool exterior; - bool box_project; - uint ambient_mode; - uint pad; - //0-8 is intensity,8-9 is ambient, mode - mat4 local_matrix; // up to here for spot and omni, rest is for directional - // notes: for ambientblend, use distance to edge to blend between already existing global environment -}; - -struct DirectionalLightData { - vec3 direction; - float energy; - vec3 color; - float size; - float specular; - uint mask; - float softshadow_angle; - float soft_shadow_scale; - bool blend_splits; - bool shadow_enabled; - float fade_from; - float fade_to; - uvec3 pad; - float shadow_volumetric_fog_fade; - vec4 shadow_bias; - vec4 shadow_normal_bias; - vec4 shadow_transmittance_bias; - vec4 shadow_z_range; - vec4 shadow_range_begin; - vec4 shadow_split_offsets; - mat4 shadow_matrix1; - mat4 shadow_matrix2; - mat4 shadow_matrix3; - mat4 shadow_matrix4; - vec4 shadow_color1; - vec4 shadow_color2; - vec4 shadow_color3; - vec4 shadow_color4; - vec2 uv_scale1; - vec2 uv_scale2; - vec2 uv_scale3; - vec2 uv_scale4; -}; - -struct DecalData { - mat4 xform; //to decal transform - vec3 inv_extents; - float albedo_mix; - vec4 albedo_rect; - vec4 normal_rect; - vec4 orm_rect; - vec4 emission_rect; - vec4 modulate; - float emission_energy; - uint mask; - float upper_fade; - float lower_fade; - mat3x4 normal_xform; - vec3 normal; - float normal_fade; -}; diff --git a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl index 70a875192c..40da2c6e5c 100644 --- a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl index 8723ea78e4..da7d189281 100644 --- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) in vec3 vertex_attrib; @@ -63,9 +63,9 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES -#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) && defined(GL_KHR_shader_subgroup_vote) +#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) && defined(has_GL_KHR_shader_subgroup_vote) #extension GL_KHR_shader_subgroup_ballot : enable #extension GL_KHR_shader_subgroup_arithmetic : enable diff --git a/servers/rendering/renderer_rd/shaders/cluster_store.glsl b/servers/rendering/renderer_rd/shaders/cluster_store.glsl index 5be0893c4f..b0606efa94 100644 --- a/servers/rendering/renderer_rd/shaders/cluster_store.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_store.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index cdd35dfb3f..4110a95ddb 100644 --- a/servers/rendering/renderer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl index 9751e13b4e..8c68e2dc2f 100644 --- a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) out vec2 uv_interp; @@ -37,7 +37,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(push_constant, binding = 1, std430) uniform Params { vec4 section; diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl index c3ac0bee57..dfbce29119 100644 --- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(push_constant, binding = 1, std430) uniform Params { float z_far; @@ -26,7 +26,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) in vec2 uv_interp; diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl index 7f269b7af3..9fa84657d1 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl @@ -22,7 +22,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define BLOCK_SIZE 8 diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl index 987545fb76..2a774b0eb4 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl @@ -22,7 +22,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define GROUP_SIZE 64 diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl index 5cbb00baa4..ce7c03c1d4 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define GROUP_SIZE 8 diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl new file mode 100644 index 0000000000..ccaad13311 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl @@ -0,0 +1,18 @@ + +struct DecalData { + mat4 xform; //to decal transform + vec3 inv_extents; + float albedo_mix; + vec4 albedo_rect; + vec4 normal_rect; + vec4 orm_rect; + vec4 emission_rect; + vec4 modulate; + float emission_energy; + uint mask; + float upper_fade; + float lower_fade; + mat3x4 normal_xform; + vec3 normal; + float normal_fade; +}; diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index 92a5682572..bfd5c4c88d 100644 --- a/servers/rendering/renderer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/giprobe.glsl index b931461b31..49a493cdc7 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #ifdef MODE_DYNAMIC layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl index 515cc35507..7d4d72967a 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES struct CellData { uint position; // xyz 10 bits @@ -172,7 +172,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) in vec4 color_interp; layout(location = 0) out vec4 frag_color; diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl index 5b3dec0ee7..e20b3f680d 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl index 56b3b7ccb4..5dc2d08a3b 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl new file mode 100644 index 0000000000..2fce258cff --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl @@ -0,0 +1,87 @@ +#define LIGHT_BAKE_DISABLED 0 +#define LIGHT_BAKE_DYNAMIC 1 +#define LIGHT_BAKE_STATIC 2 + +struct LightData { //this structure needs to be as packed as possible + vec3 position; + float inv_radius; + + vec3 direction; + float size; + + vec3 color; + float attenuation; + + float cone_attenuation; + float cone_angle; + float specular_amount; + bool shadow_enabled; + + vec4 atlas_rect; // rect in the shadow atlas + mat4 shadow_matrix; + float shadow_bias; + float shadow_normal_bias; + float transmittance_bias; + float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle + float soft_shadow_scale; // scales the shadow kernel for blurrier shadows + uint mask; + float shadow_volumetric_fog_fade; + uint bake_mode; + vec4 projector_rect; //projector rect in srgb decal atlas +}; + +#define REFLECTION_AMBIENT_DISABLED 0 +#define REFLECTION_AMBIENT_ENVIRONMENT 1 +#define REFLECTION_AMBIENT_COLOR 2 + +struct ReflectionData { + vec3 box_extents; + float index; + vec3 box_offset; + uint mask; + vec3 ambient; // ambient color + float intensity; + bool exterior; + bool box_project; + uint ambient_mode; + uint pad; + //0-8 is intensity,8-9 is ambient, mode + mat4 local_matrix; // up to here for spot and omni, rest is for directional + // notes: for ambientblend, use distance to edge to blend between already existing global environment +}; + +struct DirectionalLightData { + vec3 direction; + float energy; + vec3 color; + float size; + float specular; + uint mask; + float softshadow_angle; + float soft_shadow_scale; + bool blend_splits; + bool shadow_enabled; + float fade_from; + float fade_to; + uvec2 pad; + uint bake_mode; + float shadow_volumetric_fog_fade; + vec4 shadow_bias; + vec4 shadow_normal_bias; + vec4 shadow_transmittance_bias; + vec4 shadow_z_range; + vec4 shadow_range_begin; + vec4 shadow_split_offsets; + mat4 shadow_matrix1; + mat4 shadow_matrix2; + mat4 shadow_matrix3; + mat4 shadow_matrix4; + vec4 shadow_color1; + vec4 shadow_color2; + vec4 shadow_color3; + vec4 shadow_color4; + vec2 uv_scale1; + vec2 uv_scale2; + vec2 uv_scale3; + vec2 uv_scale4; +}; diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl index 8a11c35b78..466442b67a 100644 --- a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl +++ b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define BLOCK_SIZE 8 diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index cb6d8dc7f6..beaff10793 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; @@ -76,6 +76,11 @@ struct FrameParams { float time; float delta; + uint frame; + uint pad0; + uint pad1; + uint pad2; + uint random_seed; uint attractor_count; uint collider_count; @@ -92,10 +97,16 @@ layout(set = 1, binding = 0, std430) restrict buffer FrameHistory { } frame_history; +#define PARTICLE_FLAG_ACTIVE uint(1) +#define PARTICLE_FLAG_STARTED uint(2) +#define PARTICLE_FLAG_TRAILED uint(4) +#define PARTICLE_FRAME_MASK uint(0xFFFF) +#define PARTICLE_FRAME_SHIFT uint(16) + struct ParticleData { mat4 xform; vec3 velocity; - bool is_active; + uint flags; vec4 color; vec4 custom; }; @@ -146,11 +157,11 @@ layout(set = 2, binding = 1) uniform texture2D height_field_texture; /* SET 3: MATERIAL */ -#ifdef USE_MATERIAL_UNIFORMS +#ifdef MATERIAL_UNIFORMS_USED layout(set = 3, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ + +#MATERIAL_UNIFORMS + } material; #endif @@ -162,7 +173,7 @@ layout(push_constant, binding = 0, std430) uniform Params { bool use_fractional_delta; bool sub_emitter_mode; bool can_emit; - uint pad; + bool trail_pass; } params; @@ -196,15 +207,19 @@ bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom return true; } -/* clang-format off */ - -COMPUTE_SHADER_GLOBALS - -/* clang-format on */ +#GLOBALS void main() { uint particle = gl_GlobalInvocationID.x; + if (params.trail_size > 1) { + if (params.trail_pass) { + particle += (particle / (params.trail_size - 1)) + 1; + } else { + particle *= params.trail_size; + } + } + if (particle >= params.total_particles * params.trail_size) { return; //discard } @@ -233,7 +248,7 @@ void main() { PARTICLE.color = vec4(1.0); PARTICLE.custom = vec4(0.0); PARTICLE.velocity = vec3(0.0); - PARTICLE.is_active = false; + PARTICLE.flags = 0; PARTICLE.xform = mat4( vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), @@ -241,6 +256,29 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); } + //clear started flag if set + + if (params.trail_pass) { + //trail started + uint src_idx = index * params.trail_size; + if (bool(particles.data[src_idx].flags & PARTICLE_FLAG_STARTED)) { + //save start conditions for trails + PARTICLE.color = particles.data[src_idx].color; + PARTICLE.custom = particles.data[src_idx].custom; + PARTICLE.velocity = particles.data[src_idx].velocity; + PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start + PARTICLE.xform = particles.data[src_idx].xform; + } + + if (bool(PARTICLE.flags & PARTICLE_FLAG_TRAILED) && ((PARTICLE.flags >> PARTICLE_FRAME_SHIFT) == (FRAME.frame & PARTICLE_FRAME_MASK))) { //check this is trailed and see if it should start now + // we just assume that this is the first frame of the particle, the rest is deterministic + PARTICLE.flags = PARTICLE_FLAG_ACTIVE | (particles.data[src_idx].flags & (PARTICLE_FRAME_MASK << PARTICLE_FRAME_SHIFT)); + return; //- this appears like it should be correct, but it seems not to be.. wonder why. + } + } else { + PARTICLE.flags &= ~PARTICLE_FLAG_STARTED; + } + bool collided = false; vec3 collision_normal = vec3(0.0); float collision_depth = 0.0; @@ -249,14 +287,121 @@ void main() { #if !defined(DISABLE_VELOCITY) - if (PARTICLE.is_active) { + if (bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) { PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta; } #endif - /* Process physics if active */ + if (!params.trail_pass && params.sub_emitter_mode) { + if (!bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) { + int src_index = atomicAdd(src_particles.particle_count, -1) - 1; + + if (src_index >= 0) { + PARTICLE.flags = (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT)); + restart = true; + + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) { + PARTICLE.xform[3] = src_particles.data[src_index].xform[3]; + } else { + PARTICLE.xform[3] = vec4(0, 0, 0, 1); + restart_position = true; + } + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) { + PARTICLE.xform[0] = src_particles.data[src_index].xform[0]; + PARTICLE.xform[1] = src_particles.data[src_index].xform[1]; + PARTICLE.xform[2] = src_particles.data[src_index].xform[2]; + } else { + PARTICLE.xform[0] = vec4(1, 0, 0, 0); + PARTICLE.xform[1] = vec4(0, 1, 0, 0); + PARTICLE.xform[2] = vec4(0, 0, 1, 0); + restart_rotation_scale = true; + } + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) { + PARTICLE.velocity = src_particles.data[src_index].velocity; + } else { + PARTICLE.velocity = vec3(0); + restart_velocity = true; + } + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) { + PARTICLE.color = src_particles.data[src_index].color; + } else { + PARTICLE.color = vec4(1); + restart_color = true; + } - if (PARTICLE.is_active) { + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) { + PARTICLE.custom = src_particles.data[src_index].custom; + } else { + PARTICLE.custom = vec4(0); + restart_custom = true; + } + } + } + + } else if (FRAME.emitting) { + float restart_phase = float(index) / float(params.total_particles); + + if (FRAME.randomness > 0.0) { + uint seed = FRAME.cycle; + if (restart_phase >= FRAME.system_phase) { + seed -= uint(1); + } + seed *= uint(params.total_particles); + seed += uint(index); + float random = float(hash(seed) % uint(65536)) / 65536.0; + restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles); + } + + restart_phase *= (1.0 - FRAME.explosiveness); + + if (FRAME.system_phase > FRAME.prev_system_phase) { + // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed + + if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) { + restart = true; + if (params.use_fractional_delta) { + local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; + } + } + + } else if (FRAME.delta > 0.0) { + if (restart_phase >= FRAME.prev_system_phase) { + restart = true; + if (params.use_fractional_delta) { + local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime; + } + + } else if (restart_phase < FRAME.system_phase) { + restart = true; + if (params.use_fractional_delta) { + local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; + } + } + } + + if (params.trail_pass) { + restart = false; + } + + if (restart) { + PARTICLE.flags = FRAME.emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT)) : 0; + restart_position = true; + restart_rotation_scale = true; + restart_velocity = true; + restart_color = true; + restart_custom = true; + } + } + + bool particle_active = bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE); + + uint particle_number = (PARTICLE.flags >> PARTICLE_FRAME_SHIFT) * uint(params.total_particles) + index; + + if (restart && particle_active) { +#CODE : START + } + + if (particle_active) { for (uint i = 0; i < FRAME.attractor_count; i++) { vec3 dir; float amount; @@ -434,116 +579,12 @@ void main() { } } - if (params.sub_emitter_mode) { - if (!PARTICLE.is_active) { - int src_index = atomicAdd(src_particles.particle_count, -1) - 1; - - if (src_index >= 0) { - PARTICLE.is_active = true; - restart = true; - - if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) { - PARTICLE.xform[3] = src_particles.data[src_index].xform[3]; - } else { - PARTICLE.xform[3] = vec4(0, 0, 0, 1); - restart_position = true; - } - if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) { - PARTICLE.xform[0] = src_particles.data[src_index].xform[0]; - PARTICLE.xform[1] = src_particles.data[src_index].xform[1]; - PARTICLE.xform[2] = src_particles.data[src_index].xform[2]; - } else { - PARTICLE.xform[0] = vec4(1, 0, 0, 0); - PARTICLE.xform[1] = vec4(0, 1, 0, 0); - PARTICLE.xform[2] = vec4(0, 0, 1, 0); - restart_rotation_scale = true; - } - if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) { - PARTICLE.velocity = src_particles.data[src_index].velocity; - } else { - PARTICLE.velocity = vec3(0); - restart_velocity = true; - } - if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) { - PARTICLE.color = src_particles.data[src_index].color; - } else { - PARTICLE.color = vec4(1); - restart_color = true; - } - - if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) { - PARTICLE.custom = src_particles.data[src_index].custom; - } else { - PARTICLE.custom = vec4(0); - restart_custom = true; - } - } - } - - } else if (FRAME.emitting) { - float restart_phase = float(index) / float(params.total_particles); - - if (FRAME.randomness > 0.0) { - uint seed = FRAME.cycle; - if (restart_phase >= FRAME.system_phase) { - seed -= uint(1); - } - seed *= uint(params.total_particles); - seed += uint(index); - float random = float(hash(seed) % uint(65536)) / 65536.0; - restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles); - } - - restart_phase *= (1.0 - FRAME.explosiveness); - - if (FRAME.system_phase > FRAME.prev_system_phase) { - // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed - - if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) { - restart = true; - if (params.use_fractional_delta) { - local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; - } - } - - } else if (FRAME.delta > 0.0) { - if (restart_phase >= FRAME.prev_system_phase) { - restart = true; - if (params.use_fractional_delta) { - local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime; - } - - } else if (restart_phase < FRAME.system_phase) { - restart = true; - if (params.use_fractional_delta) { - local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; - } - } - } - - uint current_cycle = FRAME.cycle; - - if (FRAME.system_phase < restart_phase) { - current_cycle -= uint(1); - } - - uint particle_number = current_cycle * uint(params.total_particles) + particle; - - if (restart) { - PARTICLE.is_active = FRAME.emitting; - restart_position = true; - restart_rotation_scale = true; - restart_velocity = true; - restart_color = true; - restart_custom = true; - } + if (particle_active) { +#CODE : PROCESS } - if (PARTICLE.is_active) { - /* clang-format off */ - -COMPUTE_SHADER_CODE - - /* clang-format on */ + PARTICLE.flags &= ~PARTICLE_FLAG_ACTIVE; + if (particle_active) { + PARTICLE.flags |= PARTICLE_FLAG_ACTIVE; } } diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index 6c782b6045..e2bebadf1a 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -2,14 +2,18 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; +#define PARTICLE_FLAG_ACTIVE uint(1) +#define PARTICLE_FLAG_STARTED uint(2) +#define PARTICLE_FLAG_TRAILED uint(4) + struct ParticleData { mat4 xform; vec3 velocity; - bool is_active; + uint flags; vec4 color; vec4 custom; }; @@ -33,12 +37,30 @@ sort_buffer; #endif // USE_SORT_BUFFER +layout(set = 2, binding = 0, std430) restrict readonly buffer TrailBindPoses { + mat4 data[]; +} +trail_bind_poses; + layout(push_constant, binding = 0, std430) uniform Params { vec3 sort_direction; uint total_particles; + + uint trail_size; + uint trail_total; + float frame_delta; + float frame_remainder; + + vec3 align_up; + uint align_mode; } params; +#define TRANSFORM_ALIGN_DISABLED 0 +#define TRANSFORM_ALIGN_Z_BILLBOARD 1 +#define TRANSFORM_ALIGN_Y_TO_VELOCITY 2 +#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY 3 + void main() { #ifdef MODE_FILL_SORT_BUFFER @@ -47,7 +69,11 @@ void main() { return; //discard } - sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[particle].xform[3].xyz); + uint src_particle = particle; + if (params.trail_size > 1) { + src_particle = src_particle * params.trail_size + params.trail_size / 2; //use trail center for sorting + } + sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[src_particle].xform[3].xyz); sort_buffer.data[particle].y = float(particle); #endif @@ -61,22 +87,96 @@ void main() { } #ifdef USE_SORT_BUFFER - particle = uint(sort_buffer.data[particle].y); //use index from sort buffer + + if (params.trail_size > 1) { + particle = uint(sort_buffer.data[particle / params.trail_size].y) + (particle % params.trail_size); + } else { + particle = uint(sort_buffer.data[particle].y); //use index from sort buffer + } #endif mat4 txform; - if (particles.data[particle].is_active) { - txform = transpose(particles.data[particle].xform); + if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) { + txform = particles.data[particle].xform; + if (params.trail_size > 1) { + // since the steps dont fit precisely in the history frames, must do a tiny bit of + // interpolation to get them close to their intended location. + uint part_ofs = particle % params.trail_size; + float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta; + + txform[3].xyz -= particles.data[particle].velocity * natural_ofs; + } + + switch (params.align_mode) { + case TRANSFORM_ALIGN_DISABLED: { + } break; //nothing + case TRANSFORM_ALIGN_Z_BILLBOARD: { + mat3 local = mat3(normalize(cross(params.align_up, params.sort_direction)), params.align_up, params.sort_direction); + local = local * mat3(txform); + txform[0].xyz = local[0]; + txform[1].xyz = local[1]; + txform[2].xyz = local[2]; + + } break; + case TRANSFORM_ALIGN_Y_TO_VELOCITY: { + vec3 v = particles.data[particle].velocity; + float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0; + if (length(v) > 0.0) { + txform[1].xyz = normalize(v); + } else { + txform[1].xyz = normalize(txform[1].xyz); + } + + txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz)); + txform[2].xyz = vec3(0.0, 0.0, 1.0) * s; + txform[0].xyz *= s; + txform[1].xyz *= s; + } break; + case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: { + vec3 v = particles.data[particle].velocity; + vec3 sv = v - params.sort_direction * dot(params.sort_direction, v); //screen velocity + float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0; + + if (length(sv) == 0) { + sv = params.align_up; + } + + sv = normalize(sv); + + txform[0].xyz = normalize(cross(sv, params.sort_direction)) * s; + txform[1].xyz = sv * s; + txform[2].xyz = params.sort_direction * s; + + } break; + } + + txform[3].xyz += particles.data[particle].velocity * params.frame_remainder; + + if (params.trail_size > 1) { + uint part_ofs = particle % params.trail_size; + txform = txform * trail_bind_poses.data[part_ofs]; + } + + txform = transpose(txform); } else { txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible } +#ifdef MODE_2D + + instances.data[write_offset + 0] = txform[0]; + instances.data[write_offset + 1] = txform[1]; + instances.data[write_offset + 2] = particles.data[particle].color; + instances.data[write_offset + 3] = particles.data[particle].custom; + +#else instances.data[write_offset + 0] = txform[0]; instances.data[write_offset + 1] = txform[1]; instances.data[write_offset + 2] = txform[2]; instances.data[write_offset + 3] = particles.data[particle].color; instances.data[write_offset + 4] = particles.data[particle].custom; +#endif //MODE_2D #endif } diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl index e83c4ca93b..2286a26485 100644 --- a/servers/rendering/renderer_rd/shaders/resolve.glsl +++ b/servers/rendering/renderer_rd/shaders/resolve.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl index 464895928a..7b964675ca 100644 --- a/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl +++ b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl new file mode 100644 index 0000000000..99714b4504 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl @@ -0,0 +1,58 @@ +#ifdef ALPHA_HASH_USED + +float hash_2d(vec2 p) { + return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * + (0.1 + abs(sin(13.0 * p.y + p.x)))); +} + +float hash_3d(vec3 p) { + return hash_2d(vec2(hash_2d(p.xy), p.z)); +} + +float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { + vec3 dx = dFdx(pos); + vec3 dy = dFdx(pos); + float delta_max_sqr = max(length(dx), length(dy)); + float pix_scale = 1.0 / (hash_scale * delta_max_sqr); + + vec2 pix_scales = + vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); + + vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), + hash_3d(floor(pix_scales.y * pos.xyz))); + + float lerp_factor = fract(log2(pix_scale)); + + float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; + + float min_lerp = min(lerp_factor, 1.0 - lerp_factor); + + vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), + (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), + 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / + (2.0 * min_lerp * (1.0 - min_lerp)))); + + float alpha_hash_threshold = + (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; + + return clamp(alpha_hash_threshold, 0.0, 1.0); +} + +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + +float calc_mip_level(vec2 texture_coord) { + vec2 dx = dFdx(texture_coord); + vec2 dy = dFdy(texture_coord); + float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); + return max(0.0, 0.5 * log2(delta_max_sqr)); +} + +float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { + input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number + input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; + return clamp(input_alpha, 0.0, 1.0); +} + +#endif // ALPHA_ANTIALIASING_USED diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index 7b86dac143..1d67a3f1df 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "scene_forward_clustered_inc.glsl" @@ -48,11 +48,11 @@ layout(location = 8) in vec4 custom2_attrib; layout(location = 9) in vec4 custom3_attrib; #endif -#if defined(BONES_USED) +#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS) layout(location = 10) in uvec4 bone_attrib; #endif -#if defined(WEIGHTS_USED) +#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS) layout(location = 11) in vec4 weight_attrib; #endif @@ -81,16 +81,14 @@ layout(location = 5) out vec3 tangent_interp; layout(location = 6) out vec3 binormal_interp; #endif -#ifdef USE_MATERIAL_UNIFORMS +#ifdef MATERIAL_UNIFORMS_USED layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ + +#MATERIAL_UNIFORMS + } material; #endif -invariant gl_Position; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) out float dp_clip; @@ -99,11 +97,9 @@ layout(location = 8) out float dp_clip; layout(location = 9) out flat uint instance_index; -/* clang-format off */ - -VERTEX_SHADER_GLOBALS +invariant gl_Position; -/* clang-format on */ +#GLOBALS void main() { vec4 instance_custom = vec4(0.0); @@ -129,10 +125,72 @@ void main() { if (is_multimesh) { //multimesh, instances are for it - uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; - offset *= gl_InstanceIndex; mat4 matrix; + +#ifdef USE_PARTICLE_TRAILS + uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; + uint stride = 3 + 1 + 1; //particles always uses this format + + uint offset = trail_size * stride * gl_InstanceIndex; + +#ifdef COLOR_USED + vec4 pcolor; +#endif + { + uint boffset = offset + bone_attrib.x * stride; + matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x; +#ifdef COLOR_USED + pcolor = transforms.data[boffset + 3] * weight_attrib.x; +#endif + } + if (weight_attrib.y > 0.001) { + uint boffset = offset + bone_attrib.y * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y; +#ifdef COLOR_USED + pcolor += transforms.data[boffset + 3] * weight_attrib.y; +#endif + } + if (weight_attrib.z > 0.001) { + uint boffset = offset + bone_attrib.z * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z; +#ifdef COLOR_USED + pcolor += transforms.data[boffset + 3] * weight_attrib.z; +#endif + } + if (weight_attrib.w > 0.001) { + uint boffset = offset + bone_attrib.w * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w; +#ifdef COLOR_USED + pcolor += transforms.data[boffset + 3] * weight_attrib.w; +#endif + } + + instance_custom = transforms.data[offset + 4]; + +#ifdef COLOR_USED + color_interp *= pcolor; +#endif + +#else + uint stride = 0; + { + //TODO implement a small lookup table for the stride + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + stride += 2; + } else { + stride += 3; + } + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + stride += 1; + } + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + stride += 1; + } + } + + uint offset = stride * gl_InstanceIndex; + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); offset += 2; @@ -152,6 +210,7 @@ void main() { instance_custom = transforms.data[offset]; } +#endif //transpose matrix = transpose(matrix); world_matrix = world_matrix * matrix; @@ -169,32 +228,6 @@ void main() { vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif -#if 0 - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { - //multimesh, instances are for it - - uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3; - uvec2 bones_23 = uvec2(bone_attrib.y & 0xFFFF, bone_attrib.y >> 16) * 3; - vec2 weights_01 = unpackUnorm2x16(bone_attrib.z); - vec2 weights_23 = unpackUnorm2x16(bone_attrib.w); - - mat4 m = mat4(transforms.data[bones_01.x], transforms.data[bones_01.x + 1], transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; - m += mat4(transforms.data[bones_01.y], transforms.data[bones_01.y + 1], transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; - m += mat4(transforms.data[bones_23.x], transforms.data[bones_23.x + 1], transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; - m += mat4(transforms.data[bones_23.y], transforms.data[bones_23.y + 1], transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; - - //reverse order because its transposed - vertex = (vec4(vertex, 1.0) * m).xyz; - normal = (vec4(normal, 0.0) * m).xyz; - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - - tangent = (vec4(tangent, 0.0) * m).xyz; - binormal = (vec4(binormal, 0.0) * m).xyz; -#endif - } -#endif - #ifdef UV_USED uv_interp = uv_attrib; #endif @@ -230,11 +263,7 @@ void main() { mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix; { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ +#CODE : VERTEX } // using local coordinates (default) @@ -325,7 +354,7 @@ VERTEX_SHADER_CODE #version 450 -VERSION_DEFINES +#VERSION_DEFINES #include "scene_forward_clustered_inc.glsl" @@ -372,19 +401,15 @@ layout(location = 9) in flat uint instance_index; #define LIGHT_TRANSMITTANCE_USED #endif -#ifdef USE_MATERIAL_UNIFORMS +#ifdef MATERIAL_UNIFORMS_USED layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ -} material; -#endif -/* clang-format off */ +#MATERIAL_UNIFORMS -FRAGMENT_SHADER_GLOBALS +} material; +#endif -/* clang-format on */ +#GLOBALS #ifdef MODE_RENDER_DEPTH @@ -396,7 +421,7 @@ layout(location = 2) out vec4 orm_output_buffer; layout(location = 3) out vec4 emission_output_buffer; layout(location = 4) out float depth_output_buffer; -#endif +#endif // MODE_RENDER_MATERIAL #ifdef MODE_RENDER_NORMAL_ROUGHNESS layout(location = 0) out vec4 normal_roughness_output_buffer; @@ -415,1319 +440,19 @@ layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface sc #else layout(location = 0) out vec4 frag_color; -#endif +#endif // MODE_MULTIPLE_RENDER_TARGETS #endif // RENDER DEPTH -#ifdef ALPHA_HASH_USED - -float hash_2d(vec2 p) { - return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * - (0.1 + abs(sin(13.0 * p.y + p.x)))); -} - -float hash_3d(vec3 p) { - return hash_2d(vec2(hash_2d(p.xy), p.z)); -} - -float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { - vec3 dx = dFdx(pos); - vec3 dy = dFdx(pos); - float delta_max_sqr = max(length(dx), length(dy)); - float pix_scale = 1.0 / (hash_scale * delta_max_sqr); - - vec2 pix_scales = - vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); - - vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), - hash_3d(floor(pix_scales.y * pos.xyz))); - - float lerp_factor = fract(log2(pix_scale)); - - float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; - - float min_lerp = min(lerp_factor, 1.0 - lerp_factor); - - vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), - (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), - 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / - (2.0 * min_lerp * (1.0 - min_lerp)))); - - float alpha_hash_threshold = - (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; - - return clamp(alpha_hash_threshold, 0.0, 1.0); -} - -#endif // ALPHA_HASH_USED - -#ifdef ALPHA_ANTIALIASING_EDGE_USED - -float calc_mip_level(vec2 texture_coord) { - vec2 dx = dFdx(texture_coord); - vec2 dy = dFdy(texture_coord); - float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); - return max(0.0, 0.5 * log2(delta_max_sqr)); -} - -float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { - input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number - input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; - return clamp(input_alpha, 0.0, 1.0); -} - -#endif // ALPHA_ANTIALIASING_USED - -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). +#include "scene_forward_aa_inc.glsl" #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} - -float D_GGX(float cos_theta_m, float alpha) { - float alpha2 = alpha * alpha; - float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; - return alpha2 / (M_PI * d * d); -} - -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); -} - -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); -} - -float SchlickFresnel(float u) { - float m = 1.0 - u; - float m2 = m * m; - return m2 * m2 * m; // pow(m,5) -} - -float GTR1(float NdotH, float a) { - if (a >= 1.0) - return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - -vec3 F0(float metallic, float specular, vec3 albedo) { - float dielectric = 0.16 * specular * specular; - // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; - // see https://google.github.io/filament/Filament.md.html - return mix(vec3(dielectric), albedo, vec3(metallic)); -} - -void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, - float transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 B, vec3 T, float anisotropy, -#endif -#ifdef USE_SOFT_SHADOWS - float A, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - -#if defined(USE_LIGHT_SHADER_CODE) - // light is written by the light shader - - vec3 normal = N; - vec3 light = L; - vec3 view = V; - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#else - -#ifdef USE_SOFT_SHADOWS - float NdotL = min(A + dot(N, L), 1.0); -#else - float NdotL = dot(N, L); -#endif - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - vec3 H = normalize(V + L); -#endif - -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) -#ifdef USE_SOFT_SHADOWS - float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); -#else - float cNdotH = clamp(dot(N, H), 0.0, 1.0); -#endif -#endif - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) -#ifdef USE_SOFT_SHADOWS - float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); -#else - float cLdotH = clamp(dot(L, H), 0.0, 1.0); -#endif -#endif - - float metallic = unpackUnorm4x8(orms).z; - if (metallic < 1.0) { - float roughness = unpackUnorm4x8(orms).y; - -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#if defined(DIFFUSE_LAMBERT_WRAP) - // energy conserving lambert wrap shader - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); -#elif defined(DIFFUSE_TOON) - - diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); - -#elif defined(DIFFUSE_BURLEY) - - { - float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; - float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); - float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); - diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ - } -#else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - diffuse_light += light_color * diffuse_brdf_NL * attenuation; - -#if defined(LIGHT_BACKLIGHT_USED) - diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; -#endif - -#if defined(LIGHT_RIM_USED) - float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; -#endif - -#ifdef LIGHT_TRANSMITTANCE_USED - -#ifdef SSS_MODE_SKIN - - { - float scale = 8.25 / transmittance_depth; - float d = scale * abs(transmittance_z); - float dd = -d * d; - vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + - vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + - vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + - vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + - vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + - vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); - - diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); - } -#else - - if (transmittance_depth > 0.0) { - float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0); - - fade = pow(max(0.0, 1.0 - fade), transmittance_curve); - fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); - - diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; - } - -#endif //SSS_MODE_SKIN - -#endif //LIGHT_TRANSMITTANCE_USED - } - - float roughness = unpackUnorm4x8(orms).y; - if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely - - // D - -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float intensity = blinn; - - specular_light += light_color * intensity * attenuation * specular_amount; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - - specular_light += light_color * intensity * attenuation * specular_amount; - -#elif defined(SPECULAR_TOON) - - vec3 R = normalize(-reflect(L, N)); - float RdotV = dot(R, V); - float mid = 1.0 - roughness; - mid *= mid; - float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection - -#elif defined(SPECULAR_DISABLED) - // none.. - -#elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - -#if defined(LIGHT_ANISOTROPY_USED) - - float alpha_ggx = roughness * roughness; - float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha_ggx / aspect; - float ay = alpha_ggx * aspect; - float XdotH = dot(T, H); - float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - -#else - float alpha_ggx = roughness * roughness; - float D = D_GGX(cNdotH, alpha_ggx); - float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); -#endif - // F - float cLdotH5 = SchlickFresnel(cLdotH); - vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - - vec3 specular_brdf_NL = cNdotL * D * F * G; - - specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; -#endif - -#if defined(LIGHT_CLEARCOAT_USED) - -#if !defined(SPECULAR_SCHLICK_GGX) - float cLdotH5 = SchlickFresnel(cLdotH); -#endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; -#endif - } - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); -#endif - -#endif //defined(USE_LIGHT_SHADER_CODE) -} - -#ifndef USE_NO_SHADOWS - -// Interleaved Gradient Noise -// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare -float quick_hash(vec2 pos) { - const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); - return fract(magic.z * fract(dot(pos, magic.xy))); -} - -float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - vec2 pos = coord.xy; - float depth = coord.z; - - //if only one sample is taken, take it from the center - if (scene_data.directional_soft_shadow_samples == 1) { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - } - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - float avg = 0.0; - - for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) { - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0)); - } - - return avg * (1.0 / float(scene_data.directional_soft_shadow_samples)); -} - -float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - vec2 pos = coord.xy; - float depth = coord.z; - - //if only one sample is taken, take it from the center - if (scene_data.soft_shadow_samples == 1) { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - } - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - float avg = 0.0; - - for (uint i = 0; i < scene_data.soft_shadow_samples; i++) { - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0)); - } - - return avg * (1.0 / float(scene_data.soft_shadow_samples)); -} - -float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { - //find blocker - float blocker_count = 0.0; - float blocker_average = 0.0; - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { - vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; - float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; - if (d < pssm_coord.z) { - blocker_average += d; - blocker_count += 1.0; - } - } - - if (blocker_count > 0.0) { - //blockers found, do soft shadow - blocker_average /= blocker_count; - float penumbra = (pssm_coord.z - blocker_average) / blocker_average; - tex_scale *= penumbra; - - float s = 0.0; - for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { - vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; - s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); - } - - return s / float(scene_data.directional_penumbra_shadow_samples); - - } else { - //no blockers found, so no shadow - return 1.0; - } -} - -#endif //USE_NO_SHADOWS - -float get_omni_attenuation(float distance, float inv_range, float decay) { - float nd = distance * inv_range; - nd *= nd; - nd *= nd; // nd^4 - nd = max(1.0 - nd, 0.0); - nd *= nd; // nd^2 - return nd * pow(max(distance, 0.0001), -decay); -} - -float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { -#ifndef USE_NO_SHADOWS - if (omni_lights.data[idx].shadow_enabled) { - // there is a shadowmap - - vec3 light_rel_vec = omni_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - - vec4 v = vec4(vertex, 1.0); - - vec4 splane = (omni_lights.data[idx].shadow_matrix * v); - float shadow_len = length(splane.xyz); //need to remember shadow len from here - - { - vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius; - nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); - v.xyz += nofs; - splane = (omni_lights.data[idx].shadow_matrix * v); - } - - float shadow; - -#ifdef USE_SOFT_SHADOWS - if (omni_lights.data[idx].soft_shadow_size > 0.0) { - //soft shadow - - //find blocker - - float blocker_count = 0.0; - float blocker_average = 0.0; - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - vec3 normal = normalize(splane.xyz); - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(v0, normal)); - vec3 bitangent = normalize(cross(tangent, normal)); - float z_norm = shadow_len * omni_lights.data[idx].inv_radius; - - tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; - bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; - - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - - vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; - - pos = normalize(pos); - vec4 uv_rect = omni_lights.data[idx].atlas_rect; - - if (pos.z >= 0.0) { - pos.z += 1.0; - uv_rect.y += uv_rect.w; - } else { - pos.z = 1.0 - pos.z; - } - - pos.xy /= pos.z; - - pos.xy = pos.xy * 0.5 + 0.5; - pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; - - float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; - if (d < z_norm) { - blocker_average += d; - blocker_count += 1.0; - } - } - - if (blocker_count > 0.0) { - //blockers found, do soft shadow - blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; - tangent *= penumbra; - bitangent *= penumbra; - - z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; - - shadow = 0.0; - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; - - pos = normalize(pos); - vec4 uv_rect = omni_lights.data[idx].atlas_rect; - - if (pos.z >= 0.0) { - pos.z += 1.0; - uv_rect.y += uv_rect.w; - } else { - pos.z = 1.0 - pos.z; - } - - pos.xy /= pos.z; - - pos.xy = pos.xy * 0.5 + 0.5; - pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; - shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); - } - - shadow /= float(scene_data.penumbra_shadow_samples); - - } else { - //no blockers found, so no shadow - shadow = 1.0; - } - } else { -#endif - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - - if (splane.z >= 0.0) { - splane.z += 1.0; - - clamp_rect.y += clamp_rect.w; - - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already - shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); -#ifdef USE_SOFT_SHADOWS - } -#endif - - return shadow; - } -#endif - - return 1.0; -} - -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = omni_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); - float light_attenuation = omni_attenuation; - vec3 color = omni_lights.data[idx].color; - -#ifdef USE_SOFT_SHADOWS - float size_A = 0.0; - - if (omni_lights.data[idx].size > 0.0) { - float t = omni_lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } -#endif - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; //no transmittance by default - transmittance_color.a *= light_attenuation; - { - vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - - //redo shadowmapping, but shrink the model a bit to avoid arctifacts - vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); - - shadow_len = length(splane.xyz); - splane = normalize(splane.xyz); - - if (splane.z >= 0.0) { - splane.z += 1.0; - - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * omni_lights.data[idx].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already - - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius; - } -#endif - -#if 0 - - if (omni_lights.data[idx].projector_rect != vec4(0.0)) { - vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; - local_v = normalize(local_v); - - vec4 atlas_rect = omni_lights.data[idx].projector_rect; - - if (local_v.z >= 0.0) { - local_v.z += 1.0; - atlas_rect.y += atlas_rect.w; - - } else { - local_v.z = 1.0 - local_v.z; - } - - local_v.xy /= local_v.z; - local_v.xy = local_v.xy * 0.5 + 0.5; - vec2 proj_uv = local_v.xy * atlas_rect.zw; - - vec2 proj_uv_ddx; - vec2 proj_uv_ddy; - { - vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; - local_v_ddx = normalize(local_v_ddx); - - if (local_v_ddx.z >= 0.0) { - local_v_ddx.z += 1.0; - } else { - local_v_ddx.z = 1.0 - local_v_ddx.z; - } - - local_v_ddx.xy /= local_v_ddx.z; - local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; - - proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; - - vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; - local_v_ddy = normalize(local_v_ddy); - - if (local_v_ddy.z >= 0.0) { - local_v_ddy.z += 1.0; - } else { - local_v_ddy.z = 1.0 - local_v_ddy.z; - } - - local_v_ddy.xy /= local_v_ddy.z; - local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; - - proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; - } - - vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); - no_shadow = mix(no_shadow, proj.rgb, proj.a); - } -#endif - - light_attenuation *= shadow; - - light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, -#endif -#ifdef USE_SOFT_SHADOWS - size_A, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, - specular_light); -} - -float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { -#ifndef USE_NO_SHADOWS - if (spot_lights.data[idx].shadow_enabled) { - vec3 light_rel_vec = spot_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - vec3 spot_dir = spot_lights.data[idx].direction; - //there is a shadowmap - vec4 v = vec4(vertex, 1.0); - - v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias; - - float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius; - - float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale; - normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z - v.xyz += normal_bias; - - //adjust with bias - z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; - - float shadow; - - vec4 splane = (spot_lights.data[idx].shadow_matrix * v); - splane /= splane.w; - -#ifdef USE_SOFT_SHADOWS - if (spot_lights.data[idx].soft_shadow_size > 0.0) { - //soft shadow - - //find blocker - - vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; - - float blocker_count = 0.0; - float blocker_average = 0.0; - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale; - vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw; - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); - float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; - if (d < z_norm) { - blocker_average += d; - blocker_count += 1.0; - } - } - - if (blocker_count > 0.0) { - //blockers found, do soft shadow - blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; - uv_size *= penumbra; - - shadow = 0.0; - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); - shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); - } - - shadow /= float(scene_data.penumbra_shadow_samples); - - } else { - //no blockers found, so no shadow - shadow = 1.0; - } - - } else { -#endif - //hard shadow - vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); - - shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); -#ifdef USE_SOFT_SHADOWS - } -#endif - - return shadow; - } - -#endif //USE_NO_SHADOWS - - return 1.0; -} - -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, - inout vec3 specular_light) { - vec3 light_rel_vec = spot_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); - vec3 spot_dir = spot_lights.data[idx].direction; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); - float light_attenuation = spot_attenuation; - vec3 color = spot_lights.data[idx].color; - float specular_amount = spot_lights.data[idx].specular_amount; - -#ifdef USE_SOFT_SHADOWS - float size_A = 0.0; - - if (spot_lights.data[idx].size > 0.0) { - float t = spot_lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } -#endif - - /* - if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) { - //use projector texture - } - */ - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; - transmittance_color.a *= light_attenuation; - { - splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); - splane /= splane.w; - splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; - - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - //reconstruct depth - shadow_z /= spot_lights.data[idx].inv_radius; - //distance to light plane - float z = dot(spot_dir, -light_rel_vec); - transmittance_z = z - shadow_z; - } -#endif //LIGHT_TRANSMITTANCE_USED - - light_attenuation *= shadow; - - light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - rim * spot_attenuation, rim_tint, rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, -#endif -#ifdef USE_SOFT_SHADOW - size_A, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, specular_light); -} - -void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) { - vec3 box_extents = reflections.data[ref_index].box_extents; - vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - return; - } - - vec3 ref_vec = normalize(reflect(vertex, normal)); - - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - //make blend more rounded - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - if (reflections.data[ref_index].intensity > 0.0) { // compute reflection - - vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; - - if (reflections.data[ref_index].box_project) { //box project - - vec3 nrdir = normalize(local_ref_vec); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - local_ref_vec = posonbox - reflections.data[ref_index].box_offset; - } - - vec4 reflection; - - reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; - - if (reflections.data[ref_index].exterior) { - reflection.rgb = mix(specular_light, reflection.rgb, blend); - } - - reflection.rgb *= reflections.data[ref_index].intensity; //intensity - reflection.a = blend; - reflection.rgb *= reflection.a; - - reflection_accum += reflection; - } - - switch (reflections.data[ref_index].ambient_mode) { - case REFLECTION_AMBIENT_DISABLED: { - //do nothing - } break; - case REFLECTION_AMBIENT_ENVIRONMENT: { - //do nothing - vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; - - vec4 ambient_out; - - ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; - ambient_out.a = blend; - if (reflections.data[ref_index].exterior) { - ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); - } - - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } break; - case REFLECTION_AMBIENT_COLOR: { - vec4 ambient_out; - ambient_out.a = blend; - ambient_out.rgb = reflections.data[ref_index].ambient; - if (reflections.data[ref_index].exterior) { - ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); - } - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } break; - } -} +#include "scene_forward_lights_inc.glsl" #ifdef USE_FORWARD_GI -//standard voxel cone trace -vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { - float dist = p_bias; - vec4 color = vec4(0.0); - - while (dist < max_distance && color.a < 0.95) { - float diameter = max(1.0, 2.0 * tan_half_angle * dist); - vec3 uvw_pos = (pos + dist * direction) * cell_size; - float half_diameter = diameter * 0.5; - //check if outside, then break - if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) { - break; - } - vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter)); - float a = (1.0 - color.a); - color += a * scolor; - dist += half_diameter; - } - - return color; -} - -vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { - float dist = p_bias; - vec4 color = vec4(0.0); - float radius = max(0.5, tan_half_angle * dist); - float lod_level = log2(radius * 2.0); - - while (dist < max_distance && color.a < 0.95) { - vec3 uvw_pos = (pos + dist * direction) * cell_size; - - //check if outside, then break - if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) { - break; - } - vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level); - lod_level += 1.0; - - float a = (1.0 - color.a); - scolor *= a; - color += scolor; - dist += radius; - radius = max(0.5, tan_half_angle * dist); - } - - return color; -} - -void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) { - position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz; - ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz); - normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz); - - position += normal * gi_probes.data[index].normal_bias; - - //this causes corrupted pixels, i have no idea why.. - if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) { - return; - } - - vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0); - float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); - //float blend=1.0; - - float max_distance = length(gi_probes.data[index].bounds); - vec3 cell_size = 1.0 / gi_probes.data[index].bounds; - - //radiance - -#define MAX_CONE_DIRS 4 - - vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0.707107, 0.0, 0.707107), - vec3(0.0, 0.707107, 0.707107), - vec3(-0.707107, 0.0, 0.707107), - vec3(0.0, -0.707107, 0.707107)); - - float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); - float cone_angle_tan = 0.98269; - - vec3 light = vec3(0.0); - - for (int i = 0; i < MAX_CONE_DIRS; i++) { - vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz); - - vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias); - - if (gi_probes.data[index].blend_ambient) { - cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95)); - } - - light += cone_weights[i] * cone_light.rgb; - } - - light *= gi_probes.data[index].dynamic_range; - out_diff += vec4(light * blend, blend); - - //irradiance - vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias); - if (gi_probes.data[index].blend_ambient) { - irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95)); - } - irr_light.rgb *= gi_probes.data[index].dynamic_range; - //irr_light=vec3(0.0); - - out_spec += vec4(irr_light.rgb * blend, blend); -} - -vec2 octahedron_wrap(vec2 v) { - vec2 signVal; - signVal.x = v.x >= 0.0 ? 1.0 : -1.0; - signVal.y = v.y >= 0.0 ? 1.0 : -1.0; - return (1.0 - abs(v.yx)) * signVal; -} - -vec2 octahedron_encode(vec3 n) { - // https://twitter.com/Stubbesaurus/status/937994790553227264 - n /= (abs(n.x) + abs(n.y) + abs(n.z)); - n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy); - n.xy = n.xy * 0.5 + 0.5; - return n.xy; -} - -void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) { - cascade_pos += cam_normal * sdfgi.normal_bias; - - vec3 base_pos = floor(cascade_pos); - //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal; - ivec3 probe_base_pos = ivec3(base_pos); - - vec4 diffuse_accum = vec4(0.0); - vec3 specular_accum; - - ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade)); - tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; - tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1); - - vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; - - vec3 specular_posf; - - if (use_specular) { - specular_accum = vec3(0.0); - specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; - } - - vec4 light_accum = vec4(0.0); - float weight_accum = 0.0; - - for (uint j = 0; j < 8; j++) { - ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); - ivec3 probe_posi = probe_base_pos; - probe_posi += offset; - - // Compute weight - - vec3 probe_pos = vec3(probe_posi); - vec3 probe_to_pos = cascade_pos - probe_pos; - vec3 probe_dir = normalize(-probe_to_pos); - - vec3 trilinear = vec3(1.0) - abs(probe_to_pos); - float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir)); - - // Compute lightprobe occlusion - - if (sdfgi.use_occlusion) { - ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); - vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); - - vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; - occ_pos.z += float(cascade); - if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures - occ_pos.x += 1.0; - } - - occ_pos *= sdfgi.occlusion_renormalize; - float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask); - - weight *= max(occlusion, 0.01); - } - - // Compute lightprobe texture position - - vec3 diffuse; - vec3 pos_uvw = diffuse_posf; - pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; - pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; - diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb; - - diffuse_accum += vec4(diffuse * weight, weight); - - if (use_specular) { - vec3 specular = vec3(0.0); - vec3 pos_uvw = specular_posf; - pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; - pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; - if (roughness < 0.99) { - specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb; - } - if (roughness > 0.5) { - specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0); - } - - specular_accum += specular * weight; - } - } - - if (diffuse_accum.a > 0.0) { - diffuse_accum.rgb /= diffuse_accum.a; - } - - diffuse_light = diffuse_accum.rgb; - - if (use_specular) { - if (diffuse_accum.a > 0.0) { - specular_accum /= diffuse_accum.a; - } - - specular_light = specular_accum; - } - - { - //process blend - float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5; - float blend_to = blend_from + 2.0; - - vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe; - - float len = length(inner_pos); - - inner_pos = abs(normalize(inner_pos)); - len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - if (len >= blend_from) { - blend = smoothstep(blend_from, blend_to, len); - } else { - blend = 0.0; - } - } -} +#include "scene_forward_gi_inc.glsl" #endif //USE_FORWARD_GI @@ -1735,8 +460,6 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal #ifndef MODE_RENDER_DEPTH -#ifndef LOW_END_MODE - vec4 volumetric_fog_process(vec2 screen_uv, float z) { vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); if (fog_pos.z < 0.0) { @@ -1747,7 +470,6 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) { return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); } -#endif vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; @@ -1811,26 +533,6 @@ uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); } -float blur_shadow(float shadow) { - return shadow; -#if 0 - //disabling for now, will investigate later - float interp_shadow = shadow; - if (gl_HelperInvocation) { - interp_shadow = -4.0; // technically anything below -4 will do but just to make sure - } - - uvec2 fc2 = uvec2(gl_FragCoord.xy); - interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5); - interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5); - - if (interp_shadow >= 0.0) { - shadow = interp_shadow; - } - return shadow; -#endif -} - #endif //!MODE_RENDER DEPTH void main() { @@ -1928,11 +630,7 @@ void main() { #endif // ALPHA_ANTIALIASING_EDGE_USED { - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ +#CODE : FRAGMENT } #ifdef LIGHT_TRANSMITTANCE_USED @@ -2019,7 +717,6 @@ FRAGMENT_SHADER_CODE fog = fog_process(vertex); } -#ifndef LOW_END_MODE if (scene_data.volumetric_fog_enabled) { vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z); if (scene_data.fog_enabled) { @@ -2037,7 +734,6 @@ FRAGMENT_SHADER_CODE fog = volumetric_fog; } } -#endif //!LOW_END_MODE #endif //!CUSTOM_FOG_USED uint fog_rg = packHalf2x16(fog.rg); @@ -2377,7 +1073,7 @@ FRAGMENT_SHADER_CODE specular_light = spec_accum.rgb; ambient_light = amb_accum.rgb; } -#elif !defined(LOW_END_MODE) +#else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers @@ -2412,13 +1108,11 @@ FRAGMENT_SHADER_CODE } #endif -#ifndef LOW_END_MODE if (scene_data.ssao_enabled) { float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; ao = min(ao, ssao); ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); } -#endif //LOW_END_MODE { // process reflections @@ -2533,6 +1227,10 @@ FRAGMENT_SHADER_CODE continue; //not masked } + if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } + float shadow = 1.0; #ifdef USE_SOFT_SHADOWS @@ -2982,6 +1680,10 @@ FRAGMENT_SHADER_CODE continue; //not masked } + if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } + float shadow = light_process_omni_shadow(light_index, vertex, view); shadow = blur_shadow(shadow); @@ -3055,6 +1757,10 @@ FRAGMENT_SHADER_CODE continue; //not masked } + if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } + float shadow = light_process_spot_shadow(light_index, vertex, view); shadow = blur_shadow(shadow); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index d78890fa9e..ca75d6300e 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -3,7 +3,7 @@ #define MAX_GI_PROBES 8 -#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) +#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) #extension GL_KHR_shader_subgroup_ballot : enable #extension GL_KHR_shader_subgroup_arithmetic : enable @@ -13,6 +13,7 @@ #endif #include "cluster_data_inc.glsl" +#include "decal_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) #ifndef NORMAL_USED @@ -28,7 +29,11 @@ layout(push_constant, binding = 0, std430) uniform DrawCall { } draw_call; -/* Set 0 Scene data that never changes, ever */ +#define SDFGI_MAX_CASCADES 8 + +/* Set 0: Base Pass (never changes) */ + +#include "light_data_inc.glsl" #define SAMPLER_NEAREST_CLAMP 0 #define SAMPLER_LINEAR_CLAMP 1 @@ -43,10 +48,6 @@ draw_call; #define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 -#define SDFGI_MAX_CASCADES 8 - -/* Set 1: Base Pass (never changes) */ - layout(set = 0, binding = 1) uniform sampler material_samplers[12]; layout(set = 0, binding = 2) uniform sampler shadow_sampler; @@ -61,12 +62,11 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler; #define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) #define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) #define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) -#define INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT 16 +#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16 //3 bits of stride -#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 +#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF -#define INSTANCE_FLAGS_SKELETON (1 << 19) -#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20) +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24) layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { LightData data[]; @@ -78,7 +78,7 @@ layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { } spot_lights; -layout(set = 0, binding = 5) buffer restrict readonly ReflectionProbeData { +layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData { ReflectionData data[]; } reflections; @@ -122,8 +122,6 @@ layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableDat } global_variables; -#ifndef LOW_END_MODE - struct SDFGIProbeCascadeData { vec3 position; float to_probe; @@ -159,9 +157,7 @@ layout(set = 0, binding = 13, std140) uniform SDFGI { } sdfgi; -#endif //LOW_END_MODE - -/* Set 2: Render Pass (changes per render pass) */ +/* Set 1: Render Pass (changes per render pass) */ layout(set = 1, binding = 0, std140) uniform SceneData { mat4 projection_matrix; @@ -245,7 +241,6 @@ layout(set = 1, binding = 0, std140) uniform SceneData { bool pancake_shadows; } - scene_data; struct InstanceData { @@ -280,9 +275,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; -#ifndef LOW_END_MOD layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; -#endif layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer { uint data[]; @@ -306,8 +299,6 @@ layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid; layout(set = 1, binding = 9) uniform texture2D depth_buffer; layout(set = 1, binding = 10) uniform texture2D color_buffer; -#ifndef LOW_END_MODE - layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer; layout(set = 1, binding = 12) uniform texture2D ao_buffer; layout(set = 1, binding = 13) uniform texture2D ambient_buffer; @@ -338,8 +329,6 @@ gi_probes; layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; -#endif // LOW_END_MODE - #endif /* Set 2 Skeleton & Instancing (can change per item) */ diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl new file mode 100644 index 0000000000..b41f16cbe7 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl @@ -0,0 +1,242 @@ +// Functions related to gi/sdfgi for our forward renderer + +//standard voxel cone trace +vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { + float dist = p_bias; + vec4 color = vec4(0.0); + + while (dist < max_distance && color.a < 0.95) { + float diameter = max(1.0, 2.0 * tan_half_angle * dist); + vec3 uvw_pos = (pos + dist * direction) * cell_size; + float half_diameter = diameter * 0.5; + //check if outside, then break + if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) { + break; + } + vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter)); + float a = (1.0 - color.a); + color += a * scolor; + dist += half_diameter; + } + + return color; +} + +vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { + float dist = p_bias; + vec4 color = vec4(0.0); + float radius = max(0.5, tan_half_angle * dist); + float lod_level = log2(radius * 2.0); + + while (dist < max_distance && color.a < 0.95) { + vec3 uvw_pos = (pos + dist * direction) * cell_size; + + //check if outside, then break + if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) { + break; + } + vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level); + lod_level += 1.0; + + float a = (1.0 - color.a); + scolor *= a; + color += scolor; + dist += radius; + radius = max(0.5, tan_half_angle * dist); + } + + return color; +} + +void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) { + position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz; + ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz); + normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz); + + position += normal * gi_probes.data[index].normal_bias; + + //this causes corrupted pixels, i have no idea why.. + if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) { + return; + } + + vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0); + float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); + //float blend=1.0; + + float max_distance = length(gi_probes.data[index].bounds); + vec3 cell_size = 1.0 / gi_probes.data[index].bounds; + + //radiance + +#define MAX_CONE_DIRS 4 + + vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( + vec3(0.707107, 0.0, 0.707107), + vec3(0.0, 0.707107, 0.707107), + vec3(-0.707107, 0.0, 0.707107), + vec3(0.0, -0.707107, 0.707107)); + + float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); + float cone_angle_tan = 0.98269; + + vec3 light = vec3(0.0); + + for (int i = 0; i < MAX_CONE_DIRS; i++) { + vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz); + + vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias); + + if (gi_probes.data[index].blend_ambient) { + cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95)); + } + + light += cone_weights[i] * cone_light.rgb; + } + + light *= gi_probes.data[index].dynamic_range; + out_diff += vec4(light * blend, blend); + + //irradiance + vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias); + if (gi_probes.data[index].blend_ambient) { + irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95)); + } + irr_light.rgb *= gi_probes.data[index].dynamic_range; + //irr_light=vec3(0.0); + + out_spec += vec4(irr_light.rgb * blend, blend); +} + +vec2 octahedron_wrap(vec2 v) { + vec2 signVal; + signVal.x = v.x >= 0.0 ? 1.0 : -1.0; + signVal.y = v.y >= 0.0 ? 1.0 : -1.0; + return (1.0 - abs(v.yx)) * signVal; +} + +vec2 octahedron_encode(vec3 n) { + // https://twitter.com/Stubbesaurus/status/937994790553227264 + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy); + n.xy = n.xy * 0.5 + 0.5; + return n.xy; +} + +void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) { + cascade_pos += cam_normal * sdfgi.normal_bias; + + vec3 base_pos = floor(cascade_pos); + //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal; + ivec3 probe_base_pos = ivec3(base_pos); + + vec4 diffuse_accum = vec4(0.0); + vec3 specular_accum; + + ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade)); + tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; + tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1); + + vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; + + vec3 specular_posf; + + if (use_specular) { + specular_accum = vec3(0.0); + specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; + } + + vec4 light_accum = vec4(0.0); + float weight_accum = 0.0; + + for (uint j = 0; j < 8; j++) { + ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); + ivec3 probe_posi = probe_base_pos; + probe_posi += offset; + + // Compute weight + + vec3 probe_pos = vec3(probe_posi); + vec3 probe_to_pos = cascade_pos - probe_pos; + vec3 probe_dir = normalize(-probe_to_pos); + + vec3 trilinear = vec3(1.0) - abs(probe_to_pos); + float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir)); + + // Compute lightprobe occlusion + + if (sdfgi.use_occlusion) { + ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); + vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); + + vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; + occ_pos.z += float(cascade); + if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures + occ_pos.x += 1.0; + } + + occ_pos *= sdfgi.occlusion_renormalize; + float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask); + + weight *= max(occlusion, 0.01); + } + + // Compute lightprobe texture position + + vec3 diffuse; + vec3 pos_uvw = diffuse_posf; + pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; + pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; + diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb; + + diffuse_accum += vec4(diffuse * weight, weight); + + if (use_specular) { + vec3 specular = vec3(0.0); + vec3 pos_uvw = specular_posf; + pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; + pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; + if (roughness < 0.99) { + specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb; + } + if (roughness > 0.5) { + specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0); + } + + specular_accum += specular * weight; + } + } + + if (diffuse_accum.a > 0.0) { + diffuse_accum.rgb /= diffuse_accum.a; + } + + diffuse_light = diffuse_accum.rgb; + + if (use_specular) { + if (diffuse_accum.a > 0.0) { + specular_accum /= diffuse_accum.a; + } + + specular_light = specular_accum; + } + + { + //process blend + float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5; + float blend_to = blend_from + 2.0; + + vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe; + + float len = length(inner_pos); + + inner_pos = abs(normalize(inner_pos)); + len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + if (len >= blend_from) { + blend = smoothstep(blend_from, blend_to, len); + } else { + blend = 0.0; + } + } +} diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl new file mode 100644 index 0000000000..32a86cb166 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -0,0 +1,1023 @@ +// Functions related to lighting + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5 * alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m * cos_theta_m; + // float sin2 = (1.0 - cos2); + // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha * alpha; + float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; + return alpha2 / (M_PI * d * d); +} + +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float r_x = cos_phi / alpha_x; + float r_y = sin_phi / alpha_y; + float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); +} + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) { + if (a >= 1.0) + return 1.0 / M_PI; + float a2 = a * a; + float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); +} + +void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, + float transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 B, vec3 T, float anisotropy, +#endif +#ifdef USE_SOFT_SHADOWS + float A, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + +#if defined(LIGHT_CODE_USED) + // light is written by the light shader + + vec3 normal = N; + vec3 light = L; + vec3 view = V; + +#CODE : LIGHT + +#else + +#ifdef USE_SOFT_SHADOWS + float NdotL = min(A + dot(N, L), 1.0); +#else + float NdotL = dot(N, L); +#endif + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(NdotV, 0.0); + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); +#else + float cNdotH = clamp(dot(N, H), 0.0, 1.0); +#endif +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); +#else + float cLdotH = clamp(dot(L, H), 0.0, 1.0); +#endif +#endif + + float metallic = unpackUnorm4x8(orms).z; + if (metallic < 1.0) { + float roughness = unpackUnorm4x8(orms).y; + +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif + +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); +#elif defined(DIFFUSE_TOON) + + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); + +#elif defined(DIFFUSE_BURLEY) + + { + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; + */ + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + diffuse_light += light_color * diffuse_brdf_NL * attenuation; + +#if defined(LIGHT_BACKLIGHT_USED) + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; +#endif + +#if defined(LIGHT_RIM_USED) + float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; +#endif + +#ifdef LIGHT_TRANSMITTANCE_USED + +#ifdef SSS_MODE_SKIN + + { + float scale = 8.25 / transmittance_depth; + float d = scale * abs(transmittance_z); + float dd = -d * d; + vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + + diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); + } +#else + + if (transmittance_depth > 0.0) { + float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0); + + fade = pow(max(0.0, 1.0 - fade), transmittance_curve); + fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); + + diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; + } + +#endif //SSS_MODE_SKIN + +#endif //LIGHT_TRANSMITTANCE_USED + } + + float roughness = unpackUnorm4x8(orms).y; + if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely + + // D + +#if defined(SPECULAR_BLINN) + + //normalized blinn + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess) * cNdotL; + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float intensity = blinn; + + specular_light += light_color * intensity * attenuation * specular_amount; + +#elif defined(SPECULAR_PHONG) + + vec3 R = normalize(-reflect(L, N)); + float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + + specular_light += light_color * intensity * attenuation * specular_amount; + +#elif defined(SPECULAR_TOON) + + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection + +#elif defined(SPECULAR_DISABLED) + // none.. + +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + +#if defined(LIGHT_ANISOTROPY_USED) + + float alpha_ggx = roughness * roughness; + float aspect = sqrt(1.0 - anisotropy * 0.9); + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); + float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + +#else + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); +#endif + // F + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); + + vec3 specular_brdf_NL = cNdotL * D * F * G; + + specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; +#endif + +#if defined(LIGHT_CLEARCOAT_USED) + +#if !defined(SPECULAR_SCHLICK_GGX) + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; +#endif + } + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); +#endif + +#endif //defined(LIGHT_CODE_USED) +} + +#ifndef USE_NO_SHADOWS + +// Interleaved Gradient Noise +// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare +float quick_hash(vec2 pos) { + const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); + return fract(magic.z * fract(dot(pos, magic.xy))); +} + +float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { + vec2 pos = coord.xy; + float depth = coord.z; + + //if only one sample is taken, take it from the center + if (scene_data.directional_soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0)); + } + + return avg * (1.0 / float(scene_data.directional_soft_shadow_samples)); +} + +float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { + vec2 pos = coord.xy; + float depth = coord.z; + + //if only one sample is taken, take it from the center + if (scene_data.soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0)); + } + + return avg * (1.0 / float(scene_data.soft_shadow_samples)); +} + +float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { + //find blocker + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; + float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; + if (d < pssm_coord.z) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (pssm_coord.z - blocker_average) / blocker_average; + tex_scale *= penumbra; + + float s = 0.0; + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; + s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); + } + + return s / float(scene_data.directional_penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + return 1.0; + } +} + +#endif //USE_NO_SHADOWS + +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + +float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { +#ifndef USE_NO_SHADOWS + if (omni_lights.data[idx].shadow_enabled) { + // there is a shadowmap + + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + + vec4 v = vec4(vertex, 1.0); + + vec4 splane = (omni_lights.data[idx].shadow_matrix * v); + float shadow_len = length(splane.xyz); //need to remember shadow len from here + + { + vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius; + nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); + v.xyz += nofs; + splane = (omni_lights.data[idx].shadow_matrix * v); + } + + float shadow; + +#ifdef USE_SOFT_SHADOWS + if (omni_lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + vec3 normal = normalize(splane.xyz); + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(v0, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + float z_norm = shadow_len * omni_lights.data[idx].inv_radius; + + tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; + bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; + + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; + + pos = normalize(pos); + vec4 uv_rect = omni_lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + tangent *= penumbra; + bitangent *= penumbra; + + z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; + + shadow = 0.0; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; + + pos = normalize(pos); + vec4 uv_rect = omni_lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + } else { +#endif + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; + + if (splane.z >= 0.0) { + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; + + } else { + splane.z = 1.0 - splane.z; + } + + splane.xy /= splane.z; + + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already + shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); +#ifdef USE_SOFT_SHADOWS + } +#endif + + return shadow; + } +#endif + + return 1.0; +} + +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); + float light_attenuation = omni_attenuation; + vec3 color = omni_lights.data[idx].color; + +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; + + if (omni_lights.data[idx].size > 0.0) { + float t = omni_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; //no transmittance by default + transmittance_color.a *= light_attenuation; + { + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; + + //redo shadowmapping, but shrink the model a bit to avoid arctifacts + vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); + + shadow_len = length(splane.xyz); + splane = normalize(splane.xyz); + + if (splane.z >= 0.0) { + splane.z += 1.0; + + } else { + splane.z = 1.0 - splane.z; + } + + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already + + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius; + } +#endif + +#if 0 + + if (omni_lights.data[idx].projector_rect != vec4(0.0)) { + vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + local_v = normalize(local_v); + + vec4 atlas_rect = omni_lights.data[idx].projector_rect; + + if (local_v.z >= 0.0) { + local_v.z += 1.0; + atlas_rect.y += atlas_rect.w; + + } else { + local_v.z = 1.0 - local_v.z; + } + + local_v.xy /= local_v.z; + local_v.xy = local_v.xy * 0.5 + 0.5; + vec2 proj_uv = local_v.xy * atlas_rect.zw; + + vec2 proj_uv_ddx; + vec2 proj_uv_ddy; + { + vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; + local_v_ddx = normalize(local_v_ddx); + + if (local_v_ddx.z >= 0.0) { + local_v_ddx.z += 1.0; + } else { + local_v_ddx.z = 1.0 - local_v_ddx.z; + } + + local_v_ddx.xy /= local_v_ddx.z; + local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; + + proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; + + vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; + local_v_ddy = normalize(local_v_ddy); + + if (local_v_ddy.z >= 0.0) { + local_v_ddy.z += 1.0; + } else { + local_v_ddy.z = 1.0 - local_v_ddy.z; + } + + local_v_ddy.xy /= local_v_ddy.z; + local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + + proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; + } + + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); + } +#endif + + light_attenuation *= shadow; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + rim * omni_attenuation, rim_tint, rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOWS + size_A, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, + specular_light); +} + +float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { +#ifndef USE_NO_SHADOWS + if (spot_lights.data[idx].shadow_enabled) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec3 spot_dir = spot_lights.data[idx].direction; + //there is a shadowmap + vec4 v = vec4(vertex, 1.0); + + v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias; + + float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius; + + float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale; + normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z + v.xyz += normal_bias; + + //adjust with bias + z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; + + float shadow; + + vec4 splane = (spot_lights.data[idx].shadow_matrix * v); + splane /= splane.w; + +#ifdef USE_SOFT_SHADOWS + if (spot_lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; + + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale; + vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + uv_size *= penumbra; + + shadow = 0.0; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + + } else { +#endif + //hard shadow + vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); + + shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); +#ifdef USE_SOFT_SHADOWS + } +#endif + + return shadow; + } + +#endif //USE_NO_SHADOWS + + return 1.0; +} + +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, + inout vec3 specular_light) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); + vec3 spot_dir = spot_lights.data[idx].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); + float light_attenuation = spot_attenuation; + vec3 color = spot_lights.data[idx].color; + float specular_amount = spot_lights.data[idx].specular_amount; + +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; + + if (spot_lights.data[idx].size > 0.0) { + float t = spot_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif + + /* + if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) { + //use projector texture + } + */ + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + transmittance_color.a *= light_attenuation; + { + splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); + splane /= splane.w; + splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; + + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + //reconstruct depth + shadow_z /= spot_lights.data[idx].inv_radius; + //distance to light plane + float z = dot(spot_dir, -light_rel_vec); + transmittance_z = z - shadow_z; + } +#endif //LIGHT_TRANSMITTANCE_USED + + light_attenuation *= shadow; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + rim * spot_attenuation, rim_tint, rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOW + size_A, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); +} + +void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) { + vec3 box_extents = reflections.data[ref_index].box_extents; + vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + return; + } + + vec3 ref_vec = normalize(reflect(vertex, normal)); + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + //make blend more rounded + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + if (reflections.data[ref_index].intensity > 0.0) { // compute reflection + + vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; + + if (reflections.data[ref_index].box_project) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections.data[ref_index].box_offset; + } + + vec4 reflection; + + reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; + + if (reflections.data[ref_index].exterior) { + reflection.rgb = mix(specular_light, reflection.rgb, blend); + } + + reflection.rgb *= reflections.data[ref_index].intensity; //intensity + reflection.a = blend; + reflection.rgb *= reflection.a; + + reflection_accum += reflection; + } + + switch (reflections.data[ref_index].ambient_mode) { + case REFLECTION_AMBIENT_DISABLED: { + //do nothing + } break; + case REFLECTION_AMBIENT_ENVIRONMENT: { + //do nothing + vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; + + vec4 ambient_out; + + ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; + ambient_out.a = blend; + if (reflections.data[ref_index].exterior) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } break; + case REFLECTION_AMBIENT_COLOR: { + vec4 ambient_out; + ambient_out.a = blend; + ambient_out.rgb = reflections.data[ref_index].ambient; + if (reflections.data[ref_index].exterior) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } break; + } +} + +float blur_shadow(float shadow) { + return shadow; +#if 0 + //disabling for now, will investigate later + float interp_shadow = shadow; + if (gl_HelperInvocation) { + interp_shadow = -4.0; // technically anything below -4 will do but just to make sure + } + + uvec2 fc2 = uvec2(gl_FragCoord.xy); + interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5); + interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5); + + if (interp_shadow >= 0.0) { + shadow = interp_shadow; + } + return shadow; +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl new file mode 100644 index 0000000000..b38b8d803d --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -0,0 +1,1476 @@ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +/* Include our forward mobile UBOs definitions etc. */ +#include "scene_forward_mobile_inc.glsl" + +/* INPUT ATTRIBS */ + +layout(location = 0) in vec3 vertex_attrib; + +//only for pure render depth when normal is not used + +#ifdef NORMAL_USED +layout(location = 1) in vec3 normal_attrib; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 2) in vec4 tangent_attrib; +#endif + +#if defined(COLOR_USED) +layout(location = 3) in vec4 color_attrib; +#endif + +#ifdef UV_USED +layout(location = 4) in vec2 uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) +layout(location = 5) in vec2 uv2_attrib; +#endif // MODE_RENDER_MATERIAL + +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; +#endif + +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; +#endif + +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; +#endif + +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; +#endif + +#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS) +layout(location = 10) in uvec4 bone_attrib; +#endif + +#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS) +layout(location = 11) in vec4 weight_attrib; +#endif + +/* Varyings */ + +layout(location = 0) out vec3 vertex_interp; + +#ifdef NORMAL_USED +layout(location = 1) out vec3 normal_interp; +#endif + +#if defined(COLOR_USED) +layout(location = 2) out vec4 color_interp; +#endif + +#ifdef UV_USED +layout(location = 3) out vec2 uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +layout(location = 4) out vec2 uv2_interp; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 5) out vec3 tangent_interp; +layout(location = 6) out vec3 binormal_interp; +#endif + +#ifdef MATERIAL_UNIFORMS_USED +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ + +#MATERIAL_UNIFORMS + +} material; +#endif + +#ifdef MODE_DUAL_PARABOLOID + +layout(location = 8) out float dp_clip; + +#endif + +invariant gl_Position; + +#GLOBALS + +void main() { + vec4 instance_custom = vec4(0.0); +#if defined(COLOR_USED) + color_interp = color_attrib; +#endif + + bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH); + + mat4 world_matrix = draw_call.transform; + + mat3 world_normal_matrix; + if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + world_normal_matrix = inverse(mat3(world_matrix)); + } else { + world_normal_matrix = mat3(world_matrix); + } + + if (is_multimesh) { + //multimesh, instances are for it + + mat4 matrix; + +#ifdef USE_PARTICLE_TRAILS + uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; + uint stride = 3 + 1 + 1; //particles always uses this format + + uint offset = trail_size * stride * gl_InstanceIndex; + +#ifdef COLOR_USED + vec4 pcolor; +#endif + { + uint boffset = offset + bone_attrib.x * stride; + matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x; +#ifdef COLOR_USED + pcolor = transforms.data[boffset + 3] * weight_attrib.x; +#endif + } + if (weight_attrib.y > 0.001) { + uint boffset = offset + bone_attrib.y * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y; +#ifdef COLOR_USED + pcolor += transforms.data[boffset + 3] * weight_attrib.y; +#endif + } + if (weight_attrib.z > 0.001) { + uint boffset = offset + bone_attrib.z * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z; +#ifdef COLOR_USED + pcolor += transforms.data[boffset + 3] * weight_attrib.z; +#endif + } + if (weight_attrib.w > 0.001) { + uint boffset = offset + bone_attrib.w * stride; + matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w; +#ifdef COLOR_USED + pcolor += transforms.data[boffset + 3] * weight_attrib.w; +#endif + } + + instance_custom = transforms.data[offset + 4]; + +#ifdef COLOR_USED + color_interp *= pcolor; +#endif + +#else + uint stride = 0; + { + //TODO implement a small lookup table for the stride + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + stride += 2; + } else { + stride += 3; + } + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + stride += 1; + } + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + stride += 1; + } + } + + uint offset = stride * gl_InstanceIndex; + + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + offset += 2; + } else { + matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], transforms.data[offset + 2], vec4(0.0, 0.0, 0.0, 1.0)); + offset += 3; + } + + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { +#ifdef COLOR_USED + color_interp *= transforms.data[offset]; +#endif + offset += 1; + } + + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + instance_custom = transforms.data[offset]; + } + +#endif + //transpose + matrix = transpose(matrix); + world_matrix = world_matrix * matrix; + world_normal_matrix = world_normal_matrix * mat3(matrix); + } + + vec3 vertex = vertex_attrib; +#ifdef NORMAL_USED + vec3 normal = normal_attrib * 2.0 - 1.0; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; + float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec3 binormal = normalize(cross(normal, tangent) * binormalf); +#endif + +#ifdef UV_USED + uv_interp = uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + uv2_interp = uv2_attrib; +#endif + +#ifdef OVERRIDE_POSITION + vec4 position; +#endif + + mat4 projection_matrix = scene_data.projection_matrix; + +//using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + + vertex = (world_matrix * vec4(vertex, 1.0)).xyz; + + normal = world_normal_matrix * normal; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + tangent = world_normal_matrix * tangent; + binormal = world_normal_matrix * binormal; + +#endif +#endif + + float roughness = 1.0; + + mat4 modelview = scene_data.inv_camera_matrix * world_matrix; + mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix; + + { +#CODE : VERTEX + } + + /* output */ + +// using local coordinates (default) +#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) + + vertex = (modelview * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED + normal = modelview_normal * normal; +#endif + +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + binormal = modelview_normal * binormal; + tangent = modelview_normal * tangent; +#endif + +//using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + + vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz; + normal = mat3(scene_data.inverse_normal_matrix) * normal; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal; + tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent; +#endif +#endif + + vertex_interp = vertex; +#ifdef NORMAL_USED + normal_interp = normal; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + tangent_interp = tangent; + binormal_interp = binormal; +#endif + +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_DUAL_PARABOLOID + + vertex_interp.z *= scene_data.dual_paraboloid_side; + + dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + vec3 vtx = vertex_interp; + float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy /= 1.0 - vtx.z; + vtx.z = (distance / scene_data.z_far); + vtx.z = vtx.z * 2.0 - 1.0; + vertex_interp = vtx; + +#endif + +#endif //MODE_RENDER_DEPTH + +#ifdef OVERRIDE_POSITION + gl_Position = position; +#else + gl_Position = projection_matrix * vec4(vertex_interp, 1.0); +#endif // OVERRIDE_POSITION + +#ifdef MODE_RENDER_DEPTH + if (scene_data.pancake_shadows) { + if (gl_Position.z <= 0.00001) { + gl_Position.z = 0.00001; + } + } +#endif // MODE_RENDER_DEPTH +#ifdef MODE_RENDER_MATERIAL + if (scene_data.material_uv2_mode) { + vec2 uv_offset = draw_call.lightmap_uv_scale.xy; // we are abusing lightmap_uv_scale here, we shouldn't have a lightmap during a depth pass... + gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0; + gl_Position.z = 0.00001; + gl_Position.w = 1.0; + } +#endif // MODE_RENDER_MATERIAL +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +/* Include our forward mobile UBOs definitions etc. */ +#include "scene_forward_mobile_inc.glsl" + +/* Varyings */ + +layout(location = 0) in vec3 vertex_interp; + +#ifdef NORMAL_USED +layout(location = 1) in vec3 normal_interp; +#endif + +#if defined(COLOR_USED) +layout(location = 2) in vec4 color_interp; +#endif + +#ifdef UV_USED +layout(location = 3) in vec2 uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +layout(location = 4) in vec2 uv2_interp; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 5) in vec3 tangent_interp; +layout(location = 6) in vec3 binormal_interp; +#endif + +#ifdef MODE_DUAL_PARABOLOID + +layout(location = 8) in float dp_clip; + +#endif + +//defines to keep compatibility with vertex + +#define world_matrix draw_call.transform +#define projection_matrix scene_data.projection_matrix + +#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) +//both required for transmittance to be enabled +#define LIGHT_TRANSMITTANCE_USED +#endif + +#ifdef MATERIAL_UNIFORMS_USED +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ + +#MATERIAL_UNIFORMS + +} material; +#endif + +#GLOBALS + +/* clang-format on */ + +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + +layout(location = 0) out vec4 albedo_output_buffer; +layout(location = 1) out vec4 normal_output_buffer; +layout(location = 2) out vec4 orm_output_buffer; +layout(location = 3) out vec4 emission_output_buffer; +layout(location = 4) out float depth_output_buffer; + +#endif // MODE_RENDER_MATERIAL + +#else // RENDER DEPTH + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness +layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) +#else + +layout(location = 0) out vec4 frag_color; +#endif // MODE_MULTIPLE_RENDER_TARGETS + +#endif // RENDER DEPTH + +#include "scene_forward_aa_inc.glsl" + +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#include "scene_forward_lights_inc.glsl" + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#ifndef MODE_RENDER_DEPTH + +/* + Only supporting normal fog here. +*/ + +vec4 fog_process(vec3 vertex) { + vec3 fog_color = scene_data.fog_light_color; + + if (scene_data.fog_aerial_perspective > 0.0) { + vec3 sky_fog_color = vec3(0.0); + vec3 cube_view = scene_data.radiance_inverse_xform * vertex; + // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred + float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + float lod, blend; + blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); + sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb; + sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend); +#else + sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); + } + + if (scene_data.fog_sun_scatter > 0.001) { + vec4 sun_scatter = vec4(0.0); + float sun_total = 0.0; + vec3 view = normalize(vertex); + + for (uint i = 0; i < scene_data.directional_light_count; i++) { + vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy; + float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0); + fog_color += light_color * light_amount * scene_data.fog_sun_scatter; + } + } + + float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density)); + + if (abs(scene_data.fog_height_density) > 0.001) { + float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; + + float y_dist = scene_data.fog_height - y; + + float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0); + + fog_amount = max(vfog_amount, fog_amount); + } + + return vec4(fog_color, fog_amount); +} + +#endif //!MODE_RENDER DEPTH + +void main() { +#ifdef MODE_DUAL_PARABOLOID + + if (dp_clip > 0.0) + discard; +#endif + + //lay out everything, whathever is unused is optimized away anyway + vec3 vertex = vertex_interp; + vec3 view = -normalize(vertex_interp); + vec3 albedo = vec3(1.0); + vec3 backlight = vec3(0.0); + vec4 transmittance_color = vec4(0.0); + float transmittance_depth = 0.0; + float transmittance_curve = 1.0; + float transmittance_boost = 0.0; + float metallic = 0.0; + float specular = 0.5; + vec3 emission = vec3(0.0); + float roughness = 1.0; + float rim = 0.0; + float rim_tint = 0.0; + float clearcoat = 0.0; + float clearcoat_gloss = 0.0; + float anisotropy = 0.0; + vec2 anisotropy_flow = vec2(1.0, 0.0); + vec4 fog = vec4(0.0); +#if defined(CUSTOM_RADIANCE_USED) + vec4 custom_radiance = vec4(0.0); +#endif +#if defined(CUSTOM_IRRADIANCE_USED) + vec4 custom_irradiance = vec4(0.0); +#endif + + float ao = 1.0; + float ao_light_affect = 0.0; + + float alpha = 1.0; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 binormal = normalize(binormal_interp); + vec3 tangent = normalize(tangent_interp); +#else + vec3 binormal = vec3(0.0); + vec3 tangent = vec3(0.0); +#endif + +#ifdef NORMAL_USED + vec3 normal = normalize(normal_interp); + +#if defined(DO_SIDE_CHECK) + if (!gl_FrontFacing) { + normal = -normal; + } +#endif + +#endif //NORMAL_USED + +#ifdef UV_USED + vec2 uv = uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + vec2 uv2 = uv2_interp; +#endif + +#if defined(COLOR_USED) + vec4 color = color_interp; +#endif + +#if defined(NORMAL_MAP_USED) + + vec3 normal_map = vec3(0.5); +#endif + + float normal_map_depth = 1.0; + + vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center + + float sss_strength = 0.0; + +#ifdef ALPHA_SCISSOR_USED + float alpha_scissor_threshold = 1.0; +#endif // ALPHA_SCISSOR_USED + +#ifdef ALPHA_HASH_USED + float alpha_hash_scale = 1.0; +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + float alpha_antialiasing_edge = 0.0; + vec2 alpha_texture_coordinate = vec2(0.0, 0.0); +#endif // ALPHA_ANTIALIASING_EDGE_USED + + { +#CODE : FRAGMENT + } + +#ifdef LIGHT_TRANSMITTANCE_USED +#ifdef SSS_MODE_SKIN + transmittance_color.a = sss_strength; +#else + transmittance_color.a *= sss_strength; +#endif +#endif + +#ifndef USE_SHADOW_TO_OPACITY + +#ifdef ALPHA_SCISSOR_USED + if (alpha < alpha_scissor_threshold) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +// alpha hash can be used in unison with alpha antialiasing +#ifdef ALPHA_HASH_USED + if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) { + discard; + } +#endif // ALPHA_HASH_USED + +// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) + alpha = 1.0; +#endif + +#ifdef ALPHA_ANTIALIASING_EDGE_USED +// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather +#ifdef ALPHA_SCISSOR_USED + alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0); +#endif + alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge); +#endif // ALPHA_ANTIALIASING_EDGE_USED + +#ifdef USE_OPAQUE_PREPASS + if (alpha < opaque_prepass_threshold) { + discard; + } +#endif // USE_OPAQUE_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + +#ifdef NORMAL_MAP_USED + + normal_map.xy = normal_map.xy * 2.0 - 1.0; + normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + + normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth)); + +#endif + +#ifdef LIGHT_ANISOTROPY_USED + + if (anisotropy > 0.01) { + //rotation matrix + mat3 rot = mat3(tangent, binormal, normal); + //make local to space + tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0)); + binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0)); + } + +#endif + +#ifdef ENABLE_CLIP_ALPHA + if (albedo.a < 0.99) { + //used for doublepass and shadowmapping + discard; + } +#endif + + /////////////////////// FOG ////////////////////// +#ifndef MODE_RENDER_DEPTH + +#ifndef CUSTOM_FOG_USED + // fog must be processed as early as possible and then packed. + // to maximize VGPR usage + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + + if (scene_data.fog_enabled) { + fog = fog_process(vertex); + } + +#endif //!CUSTOM_FOG_USED + + uint fog_rg = packHalf2x16(fog.rg); + uint fog_ba = packHalf2x16(fog.ba); + +#endif //!MODE_RENDER_DEPTH + + /////////////////////// DECALS //////////////////////////////// + +#ifndef MODE_RENDER_DEPTH + + vec3 vertex_ddx = dFdx(vertex); + vec3 vertex_ddy = dFdy(vertex); + + { //Decals + // must implement + + uint decal_indices = draw_call.decals.x; + for (uint i = 0; i < 8; i++) { + uint decal_index = decal_indices & 0xFF; + if (i == 4) { + decal_indices = draw_call.decals.y; + } else { + decal_indices = decal_indices >> 8; + } + + if (decal_index == 0xFF) { + break; + } + + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + continue; //out of decal + } + + //we need ddx/ddy for mipmaps, so simulate them + vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; + vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + + float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + + if (decals.data[decal_index].normal_fade > 0.0) { + fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); + } + + if (decals.data[decal_index].albedo_rect != vec4(0.0)) { + //has albedo + vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + decal_albedo *= decals.data[decal_index].modulate; + decal_albedo.a *= fade; + albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); + + if (decals.data[decal_index].normal_rect != vec4(0.0)) { + vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; + decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software + decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); + //convert to view space, use xzy because y is up + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; + + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + } + + if (decals.data[decal_index].orm_rect != vec4(0.0)) { + vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; + ao = mix(ao, decal_orm.r, decal_albedo.a); + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } + } + + if (decals.data[decal_index].emission_rect != vec4(0.0)) { + //emission is additive, so its independent from albedo + emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + } + } + } //Decals +#endif //!MODE_RENDER_DEPTH + + /////////////////////// LIGHTING ////////////////////////////// + +#ifdef NORMAL_USED + if (scene_data.roughness_limiter_enabled) { + //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf + float roughness2 = roughness * roughness; + vec3 dndu = dFdx(normal), dndv = dFdx(normal); + float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); + float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect + float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); + roughness = sqrt(filteredRoughness2); + } +#endif // NORMAL_USED + //apply energy conservation + + vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 diffuse_light = vec3(0.0, 0.0, 0.0); + vec3 ambient_light = vec3(0.0, 0.0, 0.0); + +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + + if (scene_data.use_reflection_cubemap) { + vec3 ref_vec = reflect(-view, normal); + ref_vec = scene_data.radiance_inverse_xform * ref_vec; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + + float lod, blend; + blend = modf(roughness * MAX_ROUGHNESS_LOD, lod); + specular_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; + specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); + +#else // USE_RADIANCE_CUBEMAP_ARRAY + specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; + +#endif //USE_RADIANCE_CUBEMAP_ARRAY + specular_light *= scene_data.ambient_light_color_energy.a; + } + +#if defined(CUSTOM_RADIANCE_USED) + specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); +#endif // CUSTOM_RADIANCE_USED + +#ifndef USE_LIGHTMAP + //lightmap overrides everything + if (scene_data.use_ambient_light) { + ambient_light = scene_data.ambient_light_color_energy.rgb; + + if (scene_data.use_ambient_cubemap) { + vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; +#else + vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + + ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix); + } + } +#endif // !USE_LIGHTMAP + +#if defined(CUSTOM_IRRADIANCE_USED) + ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); +#endif // CUSTOM_IRRADIANCE_USED + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + + //radiance + +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#ifdef USE_LIGHTMAP + + //lightmap + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture + uint index = draw_call.gi_offset; + + vec3 wnormal = mat3(scene_data.camera_matrix) * normal; + const float c1 = 0.429043; + const float c2 = 0.511664; + const float c3 = 0.743125; + const float c4 = 0.886227; + const float c5 = 0.247708; + ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) + + c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + + c4 * lightmap_captures.data[index].sh[0].rgb - + c5 * lightmap_captures.data[index].sh[6].rgb + + 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + + 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + + 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + + 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + + 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + + 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); + + } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap + bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); + uint ofs = draw_call.gi_offset & 0xFFFF; + vec3 uvw; + uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy; + uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF); + + if (uses_sh) { + uvw.z *= 4.0; //SH textures use 4 times more data + vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb; + vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb; + vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb; + vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb; + + uint idx = draw_call.gi_offset >> 20; + vec3 n = normalize(lightmaps.data[idx].normal_xform * normal); + + ambient_light += lm_light_l0 * 0.282095f; + ambient_light += lm_light_l1n1 * 0.32573 * n.y; + ambient_light += lm_light_l1_0 * 0.32573 * n.z; + ambient_light += lm_light_l1p1 * 0.32573 * n.x; + if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick + vec3 r = reflect(normalize(-vertex), normal); + specular_light += lm_light_l1n1 * 0.32573 * r.y; + specular_light += lm_light_l1_0 * 0.32573 * r.z; + specular_light += lm_light_l1p1 * 0.32573 * r.x; + } + + } else { + ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb; + } + } + + // No GI nor non low end mode... + +#endif // USE_LIGHTMAP + + // skipping ssao, do we remove ssao totally? + + { //Reflection probes + vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); + vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); + + uint reflection_indices = draw_call.reflection_probes.x; + for (uint i = 0; i < 8; i++) { + uint reflection_index = reflection_indices & 0xFF; + if (i == 4) { + reflection_indices = draw_call.reflection_probes.y; + } else { + reflection_indices = reflection_indices >> 8; + } + + if (reflection_index == 0xFF) { + break; + } + + reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + } + + if (reflection_accum.a > 0.0) { + specular_light = reflection_accum.rgb / reflection_accum.a; + } + } //Reflection probes + + // finalize ambient light here + ambient_light *= albedo.rgb; + ambient_light *= ao; + + // convert ao to direct light ao + ao = mix(1.0, ao, ao_light_affect); + + //this saves some VGPRs + vec3 f0 = F0(metallic, specular, albedo); + + { +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment, GI, and reflection probes are added + // Environment brdf approximation (Lazarov 2013) + // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float ndotv = clamp(dot(normal, view), 0.0, 1.0); + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + + specular_light *= env.x * f0 + env.y; +#endif + } + +#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#if !defined(MODE_RENDER_DEPTH) + //this saves some VGPRs + uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular)); +#endif + +// LIGHTING +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + + { //directional light + + // Do shadow and lighting in two passes to reduce register pressure + uint shadow0 = 0; + uint shadow1 = 0; + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { + continue; //not masked + } + + float shadow = 1.0; + + // Directional light shadow code is basically the same as forward clustered at this point in time minus `LIGHT_TRANSMITTANCE_USED` support. + // Not sure if there is a reason to change this seeing directional lights are part of our global data + // Should think about whether we may want to move this code into an include file or function?? + +#ifdef USE_SOFT_SHADOWS + //version with soft shadows, more expensive + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + vec4 pssm_coord; + vec3 shadow_color = vec3(0.0); + vec3 light_dir = directional_lights.data[i].direction; + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.x; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color1.rgb; + + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.y; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color2.rgb; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.z; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color3.rgb; + + } else { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.w; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color4.rgb; + } + + if (directional_lights.data[i].blend_splits) { + vec3 shadow_color_blend = vec3(0.0); + float pssm_blend; + float shadow2; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.y; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + shadow_color_blend = directional_lights.data[i].shadow_color2.rgb; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.z; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + + shadow_color_blend = directional_lights.data[i].shadow_color3.rgb; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.w; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + shadow_color_blend = directional_lights.data[i].shadow_color4.rgb; + } else { + pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) + } + + pssm_blend = sqrt(pssm_blend); + + shadow = mix(shadow, shadow2, pssm_blend); + shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend); + } + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance + +#undef BIAS_FUNC + } +#else + // Soft shadow disabled version + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + vec4 pssm_coord; + vec3 light_dir = directional_lights.data[i].direction; + vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + + } else { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + } + + pssm_coord /= pssm_coord.w; + + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + + if (directional_lights.data[i].blend_splits) { + float pssm_blend; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + } else { + pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) + } + + pssm_coord /= pssm_coord.w; + + float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + shadow = mix(shadow, shadow2, pssm_blend); + } + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance + +#undef BIAS_FUNC + } +#endif + + if (i < 4) { + shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8); + } else { + shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8); + } + } + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { + continue; //not masked + } + + // We're not doing light transmittence + + float shadow = 1.0; + + if (i < 4) { + shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; + } else { + shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; + } + + blur_shadow(shadow); + + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +/* not supported here +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, +#endif +*/ +#ifdef LIGHT_RIM_USED + rim, rim_tint, albedo, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOW + directional_lights.data[i].size, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, + specular_light); + } + } //directional light + + { //omni lights + uint light_indices = draw_call.omni_lights.x; + for (uint i = 0; i < 8; i++) { + uint light_index = light_indices & 0xFF; + if (i == 4) { + light_indices = draw_call.omni_lights.y; + } else { + light_indices = light_indices >> 8; + } + + if (light_index == 0xFF) { + break; + } + + float shadow = light_process_omni_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +/* +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, +#endif +*/ +#ifdef LIGHT_RIM_USED + rim, + rim_tint, + albedo, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + tangent, binormal, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); + } + } //omni lights + + { //spot lights + + uint light_indices = draw_call.spot_lights.x; + for (uint i = 0; i < 8; i++) { + uint light_index = light_indices & 0xFF; + if (i == 4) { + light_indices = draw_call.spot_lights.y; + } else { + light_indices = light_indices >> 8; + } + + if (light_index == 0xFF) { + break; + } + + float shadow = light_process_spot_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +/* +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, +#endif +*/ +#ifdef LIGHT_RIM_USED + rim, + rim_tint, + albedo, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + tangent, binormal, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); + } + } //spot lights + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_OPAQUE_PREPASS + + if (alpha < opaque_prepass_threshold) { + discard; + } + +#endif // USE_OPAQUE_PREPASS + +#endif // USE_SHADOW_TO_OPACITY + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + + albedo_output_buffer.rgb = albedo; + albedo_output_buffer.a = alpha; + + normal_output_buffer.rgb = normal * 0.5 + 0.5; + normal_output_buffer.a = 0.0; + depth_output_buffer.r = -vertex.z; + + orm_output_buffer.r = ao; + orm_output_buffer.g = roughness; + orm_output_buffer.b = metallic; + orm_output_buffer.a = sss_strength; + + emission_output_buffer.rgb = emission; + emission_output_buffer.a = 0.0; +#endif // MODE_RENDER_MATERIAL + +#else // MODE_RENDER_DEPTH + + // multiply by albedo + diffuse_light *= albedo; // ambient must be multiplied by albedo at the end + + // apply direct light AO + ao = unpackUnorm4x8(orms).x; + specular_light *= ao; + diffuse_light *= ao; + + // apply metallic + metallic = unpackUnorm4x8(orms).z; + diffuse_light *= 1.0 - metallic; + ambient_light *= 1.0 - metallic; + + //restore fog + fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +#ifdef MODE_UNSHADED + diffuse_buffer = vec4(albedo.rgb, 0.0); + specular_buffer = vec4(0.0); + +#else // MODE_UNSHADED + +#ifdef SSS_MODE_SKIN + sss_strength = -sss_strength; +#endif // SSS_MODE_SKIN + diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); + specular_buffer = vec4(specular_light, metallic); +#endif // MODE_UNSHADED + + diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); + specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); + +#else //MODE_MULTIPLE_RENDER_TARGETS + +#ifdef MODE_UNSHADED + frag_color = vec4(albedo, alpha); +#else // MODE_UNSHADED + frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); + //frag_color = vec4(1.0); +#endif // MODE_UNSHADED + + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + +#endif //MODE_MULTIPLE_RENDER_TARGETS + +#endif //MODE_RENDER_DEPTH +} diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl new file mode 100644 index 0000000000..0156b58574 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -0,0 +1,220 @@ +#define M_PI 3.14159265359 + +#include "decal_data_inc.glsl" + +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#ifndef NORMAL_USED +#define NORMAL_USED +#endif +#endif + +/* don't exceed 128 bytes!! */ +/* put instance data into our push content, not a array */ +layout(push_constant, binding = 0, std430) uniform DrawCall { + mat4 transform; // 64 - 64 + uint flags; // 04 - 68 + uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72 + uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76 + uint layer_mask; // 04 - 80 + vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed + + uvec2 reflection_probes; // 08 - 104 + uvec2 omni_lights; // 08 - 112 + uvec2 spot_lights; // 08 - 120 + uvec2 decals; // 08 - 128 +} +draw_call; + +/* Set 0: Base Pass (never changes) */ + +#include "light_data_inc.glsl" + +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + +layout(set = 0, binding = 1) uniform sampler material_samplers[12]; + +layout(set = 0, binding = 2) uniform sampler shadow_sampler; + +#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) +#define INSTANCE_FLAGS_USE_SDFGI (1 << 7) +#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) +#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) +#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) +#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11) +#define INSTANCE_FLAGS_MULTIMESH (1 << 12) +#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) +#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) +#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) +#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16 +//3 bits of stride +#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF + +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24) + +layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { + LightData data[]; +} +omni_lights; + +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { + LightData data[]; +} +spot_lights; + +layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData { + ReflectionData data[]; +} +reflections; + +layout(set = 0, binding = 6, std140) uniform DirectionalLights { + DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} +directional_lights; + +#define LIGHTMAP_FLAG_USE_DIRECTION 1 +#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2 + +struct Lightmap { + mat3 normal_xform; +}; + +layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps { + Lightmap data[]; +} +lightmaps; + +struct LightmapCapture { + vec4 sh[9]; +}; + +layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures { + LightmapCapture data[]; +} +lightmap_captures; + +layout(set = 0, binding = 9) uniform texture2D decal_atlas; +layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb; + +layout(set = 0, binding = 11, std430) restrict readonly buffer Decals { + DecalData data[]; +} +decals; + +layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + +/* Set 1: Render Pass (changes per render pass) */ + +layout(set = 1, binding = 0, std140) uniform SceneData { + mat4 projection_matrix; + mat4 inv_projection_matrix; + + mat4 camera_matrix; + mat4 inv_camera_matrix; + + vec2 viewport_size; + vec2 screen_pixel_size; + + //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + vec4 directional_penumbra_shadow_kernel[32]; + vec4 directional_soft_shadow_kernel[32]; + vec4 penumbra_shadow_kernel[32]; + vec4 soft_shadow_kernel[32]; + + uint directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; + + vec4 ambient_light_color_energy; + + float ambient_color_sky_mix; + bool use_ambient_light; + bool use_ambient_cubemap; + bool use_reflection_cubemap; + + mat3 radiance_inverse_xform; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + uint directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + bool ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + bool roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uvec2 roughness_limiter_pad; + + vec4 ao_color; + + bool fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + vec3 fog_light_color; + float fog_sun_scatter; + + float fog_aerial_perspective; + bool material_uv2_mode; + + float time; + float reflection_multiplier; // one normally, zero when rendering reflections + + bool pancake_shadows; + uint pad1; + uint pad2; + uint pad3; +} +scene_data; + +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + +layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; + +#else + +layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; + +#endif + +layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; + +layout(set = 1, binding = 4) uniform texture2D shadow_atlas; + +layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; + +// this needs to change to providing just the lightmap we're using.. +layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; + +layout(set = 1, binding = 9) uniform texture2D depth_buffer; +layout(set = 1, binding = 10) uniform texture2D color_buffer; + +/* Set 2 Skeleton & Instancing (can change per item) */ + +layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { + vec4 data[]; +} +transforms; + +/* Set 3 User Material */ diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl index 06dc4b13de..78e0a85341 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl index a5afe74cb2..62d1cffb0a 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl index 218605a962..7e06516d90 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl index e4c3f3a84b..8b58796962 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl index 08da283dad..0eacbc5363 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define MAX_CASCADES 8 @@ -153,7 +153,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) out vec4 frag_color; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl index dc7238abed..99db35bb34 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl deleted file mode 100644 index 69d8824d8a..0000000000 --- a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl +++ /dev/null @@ -1,182 +0,0 @@ -/* clang-format off */ -[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = OCT_RES, local_size_y = OCT_RES, local_size_z = 1) in; - -/* clang-format on */ - -#define MAX_CASCADES 8 - -layout(rgba16f, set = 0, binding = 1) uniform restrict image2DArray irradiance_texture; -layout(rg16f, set = 0, binding = 2) uniform restrict image2DArray depth_texture; - -layout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture; -layout(rg32ui, set = 0, binding = 4) uniform restrict uimage2DArray depth_history_texture; - -struct CascadeData { - vec3 offset; //offset of (0,0,0) in world coordinates - float to_cell; // 1/bounds * grid_size -}; - -layout(set = 0, binding = 5, std140) uniform Cascades { - CascadeData data[MAX_CASCADES]; -} -cascades; - -#define DEPTH_HISTORY_BITS 24 -#define IRRADIANCE_HISTORY_BITS 16 - -layout(push_constant, binding = 0, std430) uniform Params { - vec3 grid_size; - uint max_cascades; - - uint probe_axis_size; - uint cascade; - uint history_size; - uint pad0; - - ivec3 scroll; //scroll in probes - uint pad1; -} -params; - -void main() { - ivec2 local = ivec2(gl_LocalInvocationID.xy); - ivec2 probe = ivec2(gl_WorkGroupID.xy); - - ivec3 probe_cell; - probe_cell.x = probe.x % int(params.probe_axis_size); - probe_cell.y = probe.y; - probe_cell.z = probe.x / int(params.probe_axis_size); - -#ifdef MODE_SCROLL_BEGIN - - ivec3 read_cell = probe_cell - params.scroll; - - uint src_layer = (params.history_size + 1) * params.cascade; - uint dst_layer = (params.history_size + 1) * params.max_cascades; - - for (uint i = 0; i <= params.history_size; i++) { - ivec3 write_pos = ivec3(probe * OCT_RES + local, int(i)); - - if (any(lessThan(read_pos, ivec3(0))) || any(greaterThanEqual(read_pos, ivec3(params.probe_axis_size)))) { - // nowhere to read from for scrolling, try finding the value from upper probes - -#ifdef MODE_IRRADIANCE - imageStore(irradiance_history_texture, write_pos, uvec4(0)); -#endif -#ifdef MODE_DEPTH - imageStore(depth_history_texture, write_pos, uvec4(0)); -#endif - } else { - ivec3 read_pos; - read_pos.xy = read_cell.xy; - read_pos.x += read_cell.z * params.probe_axis_size; - read_pos.xy = read_pos.xy * OCT_RES + local; - read_pos.z = int(i); - -#ifdef MODE_IRRADIANCE - uvec4 value = imageLoad(irradiance_history_texture, read_pos); - imageStore(irradiance_history_texture, write_pos, value); -#endif -#ifdef MODE_DEPTH - uvec2 value = imageLoad(depth_history_texture, read_pos); - imageStore(depth_history_texture, write_pos, value); -#endif - } - } - -#endif // MODE_SCROLL_BEGIN - -#ifdef MODE_SCROLL_END - - uint src_layer = (params.history_size + 1) * params.max_cascades; - uint dst_layer = (params.history_size + 1) * params.cascade; - - for (uint i = 0; i <= params.history_size; i++) { - ivec3 pos = ivec3(probe * OCT_RES + local, int(i)); - -#ifdef MODE_IRRADIANCE - uvec4 value = imageLoad(irradiance_history_texture, read_pos); - imageStore(irradiance_history_texture, write_pos, value); -#endif -#ifdef MODE_DEPTH - uvec2 value = imageLoad(depth_history_texture, read_pos); - imageStore(depth_history_texture, write_pos, value); -#endif - } - -#endif //MODE_SCROLL_END - -#ifdef MODE_STORE - - uint src_layer = (params.history_size + 1) * params.cascade + params.history_size; - ivec3 read_pos = ivec3(probe * OCT_RES + local, int(src_layer)); - - ivec3 write_pos = ivec3(probe * (OCT_RES + 2) + ivec2(1), int(params.cascade)); - - ivec3 copy_to[4] = ivec3[](write_pos, ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2)); - -#ifdef MODE_IRRADIANCE - uvec4 average = imageLoad(irradiance_history_texture, read_pos); - vec4 light_accum = vec4(average / params.history_size) / float(1 << IRRADIANCE_HISTORY_BITS); - -#endif -#ifdef MODE_DEPTH - uvec2 value = imageLoad(depth_history_texture, read_pos); - vec2 depth_accum = vec4(average / params.history_size) / float(1 << IRRADIANCE_HISTORY_BITS); - - float probe_cell_size = float(params.grid_size / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; - float max_depth = length(params.grid_size / cascades.data[params.max_cascades - 1].to_cell); - max_depth /= probe_cell_size; - - depth_value = (vec2(average / params.history_size) / float(1 << DEPTH_HISTORY_BITS)) * vec2(max_depth, max_depth * max_depth); - -#endif - - /* Fill the border if required */ - - if (local == ivec2(0, 0)) { - copy_to[1] = texture_pos + ivec3(OCT_RES - 1, -1, 0); - copy_to[2] = texture_pos + ivec3(-1, OCT_RES - 1, 0); - copy_to[3] = texture_pos + ivec3(OCT_RES, OCT_RES, 0); - } else if (local == ivec2(OCT_RES - 1, 0)) { - copy_to[1] = texture_pos + ivec3(0, -1, 0); - copy_to[2] = texture_pos + ivec3(OCT_RES, OCT_RES - 1, 0); - copy_to[3] = texture_pos + ivec3(-1, OCT_RES, 0); - } else if (local == ivec2(0, OCT_RES - 1)) { - copy_to[1] = texture_pos + ivec3(-1, 0, 0); - copy_to[2] = texture_pos + ivec3(OCT_RES - 1, OCT_RES, 0); - copy_to[3] = texture_pos + ivec3(OCT_RES, -1, 0); - } else if (local == ivec2(OCT_RES - 1, OCT_RES - 1)) { - copy_to[1] = texture_pos + ivec3(0, OCT_RES, 0); - copy_to[2] = texture_pos + ivec3(OCT_RES, 0, 0); - copy_to[3] = texture_pos + ivec3(-1, -1, 0); - } else if (local.y == 0) { - copy_to[1] = texture_pos + ivec3(OCT_RES - local.x - 1, local.y - 1, 0); - } else if (local.x == 0) { - copy_to[1] = texture_pos + ivec3(local.x - 1, OCT_RES - local.y - 1, 0); - } else if (local.y == OCT_RES - 1) { - copy_to[1] = texture_pos + ivec3(OCT_RES - local.x - 1, local.y + 1, 0); - } else if (local.x == OCT_RES - 1) { - copy_to[1] = texture_pos + ivec3(local.x + 1, OCT_RES - local.y - 1, 0); - } - - for (int i = 0; i < 4; i++) { - if (copy_to[i] == ivec3(-2, -2, -2)) { - continue; - } -#ifdef MODE_IRRADIANCE - imageStore(irradiance_texture, copy_to[i], light_accum); -#endif -#ifdef MODE_DEPTH - imageStore(depth_texture, copy_to[i], vec4(depth_value, 0.0, 0.0)); -#endif - } - -#endif // MODE_STORE -} diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl index 007e4c113a..bc376e9522 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl index 916c60ac89..aa4ded146f 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #ifdef MODE_JUMPFLOOD_OPTIMIZED #define GROUP_SIZE 8 diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index 680d1045cd..b831005256 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; @@ -74,6 +74,53 @@ void main() { #ifdef MODE_2D vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1])); + + if (params.has_blend_shape) { + float blend_total = 0.0; + vec2 blend_vertex = vec2(0.0); + + for (uint i = 0; i < params.blend_shape_count; i++) { + float w = blend_shape_weights.data[i]; + if (abs(w) > 0.0001) { + uint base_offset = (params.vertex_count * i + index) * params.vertex_stride; + + blend_vertex += uintBitsToFloat(uvec2(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1])) * w; + + base_offset += 2; + + blend_total += w; + } + } + + if (params.normalized_blend_shapes) { + vertex = (1.0 - blend_total) * vertex; + } + + vertex += blend_vertex; + } + + if (params.has_skeleton) { + uint skin_offset = params.skin_stride * index; + + uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + uvec2 weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + vec2 weights_01 = unpackUnorm2x16(weights.x); + vec2 weights_23 = unpackUnorm2x16(weights.y); + + mat4 m = mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + + //reverse order because its transposed + vertex = (vec4(vertex, 0.0, 1.0) * m).xy; + } #else vec3 vertex; vec3 normal; diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl index 6c985e1f5c..9924da37d5 100644 --- a/servers/rendering/renderer_rd/shaders/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/sky.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) out vec2 uv_interp; @@ -24,7 +24,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define M_PI 3.14159265359 @@ -88,13 +88,9 @@ layout(set = 0, binding = 3, std140) uniform DirectionalLights { directional_lights; -#ifdef USE_MATERIAL_UNIFORMS +#ifdef MATERIAL_UNIFORMS_USED layout(set = 1, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ - -MATERIAL_UNIFORMS - - /* clang-format on */ +#MATERIAL_UNIFORMS } material; #endif @@ -127,11 +123,7 @@ layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture; #define AT_QUARTER_RES_PASS false #endif -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ +#GLOBALS layout(location = 0) out vec4 frag_color; @@ -202,22 +194,10 @@ void main() { #endif #endif -// unused, just here to make our compiler happy, make sure we don't execute any light code the user adds in.. -#ifndef REALLYINCLUDETHIS - { - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - } -#endif { - /* clang-format off */ -FRAGMENT_SHADER_CODE +#CODE : SKY - /* clang-format on */ } frag_color.rgb = color * params.position_multiplier.w; diff --git a/servers/rendering/renderer_rd/shaders/sort.glsl b/servers/rendering/renderer_rd/shaders/sort.glsl index e5ebb9c64b..307e60dc21 100644 --- a/servers/rendering/renderer_rd/shaders/sort.glsl +++ b/servers/rendering/renderer_rd/shaders/sort.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES // Original version here: // https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11/blob/master/gpuparticles11/src/Shaders diff --git a/servers/rendering/renderer_rd/shaders/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/specular_merge.glsl index 0b8f406213..3579c35cce 100644 --- a/servers/rendering/renderer_rd/shaders/specular_merge.glsl +++ b/servers/rendering/renderer_rd/shaders/specular_merge.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) out vec2 uv_interp; @@ -17,7 +17,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) in vec2 uv_interp; diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl index 231f8f91ec..6e945edfcd 100644 --- a/servers/rendering/renderer_rd/shaders/ssao.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao.glsl @@ -21,7 +21,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES #define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl index 510a777048..d9cd2b4e85 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl @@ -21,7 +21,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl index cb2d31f70d..ee0db6a6f0 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl @@ -21,7 +21,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl index 6aa7624261..687fe1e6e2 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl @@ -21,7 +21,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl index 4fdf334aa5..0907423d5d 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl @@ -20,7 +20,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl index 88a953562f..9367b641c2 100644 --- a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl +++ b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 7de91fd541..86b4da6b08 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -2,7 +2,7 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) out vec2 uv_interp; @@ -16,7 +16,7 @@ void main() { #version 450 -VERSION_DEFINES +#VERSION_DEFINES layout(location = 0) in vec2 uv_interp; diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index e7ba8feb80..c793b6ebe1 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -2,13 +2,13 @@ #version 450 -VERSION_DEFINES +#VERSION_DEFINES /* Do not use subgroups here, seems there is not much advantage and causes glitches +#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) #extension GL_KHR_shader_subgroup_ballot: enable #extension GL_KHR_shader_subgroup_arithmetic: enable -#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) #define USE_SUBGROUPS #endif */ @@ -26,6 +26,7 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; #endif #include "cluster_data_inc.glsl" +#include "light_data_inc.glsl" #define M_PI 3.14159265359 diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index b546001843..db1e3d1377 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -49,6 +49,10 @@ public: virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0; virtual bool is_camera(RID p_camera) const = 0; + virtual RID occluder_allocate() = 0; + virtual void occluder_initialize(RID p_occluder) = 0; + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0; + virtual RID scenario_allocate() = 0; virtual void scenario_initialize(RID p_rid) = 0; @@ -69,7 +73,7 @@ public: virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; - virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; + virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0; @@ -197,8 +201,8 @@ public: virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0; - virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; - virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; virtual void update() = 0; virtual void render_probes() = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index e8155e4025..fcea8e4ffc 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -109,6 +109,20 @@ bool RendererSceneCull::is_camera(RID p_camera) const { return camera_owner.owns(p_camera); } +/* OCCLUDER API */ + +RID RendererSceneCull::occluder_allocate() { + return RendererSceneOcclusionCull::get_singleton()->occluder_allocate(); +} + +void RendererSceneCull::occluder_initialize(RID p_rid) { + RendererSceneOcclusionCull::get_singleton()->occluder_initialize(p_rid); +} + +void RendererSceneCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { + RendererSceneOcclusionCull::get_singleton()->occluder_set_mesh(p_occluder, p_vertices, p_indices); +} + /* SCENARIO API */ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { @@ -310,6 +324,8 @@ void RendererSceneCull::scenario_initialize(RID p_rid) { scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool); scenario->instance_data.set_page_pool(&instance_data_page_pool); + RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid); + scenario_owner.initialize_rid(p_rid, scenario); } @@ -497,6 +513,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { scene_render->free(gi_probe->probe_instance); } break; + case RS::INSTANCE_OCCLUDER: { + if (scenario && instance->visible) { + RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance); + } + } break; default: { } } @@ -514,6 +535,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { if (p_base.is_valid()) { instance->base_type = RSG::storage->get_base_type(p_base); + + if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) { + instance->base_type = RS::INSTANCE_OCCLUDER; + } + ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE); switch (instance->base_type) { @@ -588,6 +614,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base); } break; + case RS::INSTANCE_OCCLUDER: { + if (scenario) { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, p_base, instance->transform, instance->visible); + } + } break; default: { } } @@ -655,6 +686,11 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { gi_probe_update_list.remove(&gi_probe->update_element); } } break; + case RS::INSTANCE_OCCLUDER: { + if (instance->visible) { + RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance); + } + } break; default: { } } @@ -684,6 +720,9 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { gi_probe_update_list.add(&gi_probe->update_element); } } break; + case RS::INSTANCE_OCCLUDER: { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, instance->base, instance->transform, instance->visible); + } break; default: { } } @@ -752,7 +791,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh } } -void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { +void RendererSceneCull::instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) { Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); @@ -801,6 +840,12 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible); } + + if (instance->base_type == RS::INSTANCE_OCCLUDER) { + if (instance->scenario) { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible); + } + } } inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { @@ -998,6 +1043,18 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF } } break; + case RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING: { + instance->ignore_occlusion_culling = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->ignore_occlusion_culling) { + idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_OCCLUSION_CULLING); + } + } + } break; default: { } } @@ -1210,6 +1267,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { heightfield_particle_colliders_update_list.insert(p_instance); } RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) { + if (p_instance->scenario) { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible); + } } if (p_instance->aabb.has_no_surface()) { @@ -1337,6 +1398,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (p_instance->mesh_instance.is_valid()) { idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE; } + if (p_instance->ignore_occlusion_culling) { + idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING; + } p_instance->scenario->instance_data.push_back(idata); p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb)); @@ -1363,6 +1427,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE; pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP; + if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + pair.pair_mask |= 1 << RS::INSTANCE_PARTICLES_COLLISION; + } pair.pair_mask |= geometry_instance_pair_mask; @@ -2119,7 +2186,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons return animated_material_found; } -void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { +void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { // render to mono camera #ifndef _3D_DISABLED @@ -2164,11 +2231,14 @@ void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_ RID environment = _render_get_environment(p_camera, p_scenario); - _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); + RENDER_TIMESTAMP("Update occlusion buffer") + RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera->transform, camera_matrix, ortho, RendererThreadPool::singleton->thread_work_pool); + + _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); #endif } -void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { +void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { // render for AR/VR interface #if 0 Camera *camera = camera_owner.getornull(p_camera); @@ -2253,7 +2323,7 @@ void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_ #endif }; -void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data) { +void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, CullData *cull_data) { uint32_t cull_total = cull_data->scenario->instance_data.size(); uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); uint32_t cull_from = p_thread * cull_total / total_threads; @@ -2262,7 +2332,7 @@ void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullDat _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to); } -void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) { +void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) { uint64_t frame_number = RSG::rasterizer->get_frame_number(); float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); @@ -2271,10 +2341,14 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; + Transform inv_cam_transform = cull_data.cam_transform.inverse(); + float z_near = cull_data.camera_matrix->get_z_near(); + for (uint64_t i = p_from; i < p_to; i++) { bool mesh_visible = false; - if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum)) { + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum) && (cull_data.occlusion_buffer == nullptr || cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING || + !cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))) { InstanceData &idata = cull_data.scenario->instance_data[i]; uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; @@ -2320,7 +2394,7 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); } else if (base_type == RS::INSTANCE_LIGHTMAP) { - cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid)); } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { bool keep = true; @@ -2339,7 +2413,7 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes cull_data.cull->lock.lock(); RSG::storage->particles_request_process(idata.base_rid); cull_data.cull->lock.unlock(); - RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized()); + RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized()); //particles visible? request redraw RenderingServerDefault::redraw_request(); } @@ -2379,18 +2453,19 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes } if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { - //InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - //todo for GLES3 - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); - /*for (Set<Instance *>::Element *E = geom->dec.front(); E; E = E->next()) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; - instance_pair_buffer[idx++] = reflection_probe->instance; - if (idx==MAX_INSTANCE_PAIRS) { - break; + for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = decal->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } - }*/ - //scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, light_instances, idx); + scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); } if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) { @@ -2469,7 +2544,7 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes } } -void RendererSceneCull::_render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) { +void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) { // Note, in stereo rendering: // - p_cam_transform will be a transform in the middle of our two eyes // - p_cam_projection is a wider frustrum that encompasses both eyes @@ -2566,7 +2641,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam uint64_t cull_from = 0; uint64_t cull_to = scenario->instance_data.size(); - FrustumCullData cull_data; + CullData cull_data; //prepare for eventual thread usage cull_data.cull = &cull; @@ -2575,6 +2650,8 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam cull_data.cam_transform = p_cam_transform; cull_data.visible_layers = p_visible_layers; cull_data.render_reflection_probe = render_reflection_probe; + cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport); + cull_data.camera_matrix = &p_cam_projection; //#define DEBUG_CULL_TIME #ifdef DEBUG_CULL_TIME uint64_t time_from = OS::get_singleton()->get_ticks_usec(); @@ -2781,8 +2858,13 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam } /* PROCESS GEOMETRY AND DRAW SCENE */ + RID occluders_tex; + if (p_viewport.is_valid()) { + occluders_tex = RSG::viewport->viewport_get_occluder_debug_texture(p_viewport); + } + RENDER_TIMESTAMP("Render Scene "); - scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data); + scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data); for (uint32_t i = 0; i < max_shadows_used; i++) { render_shadow_data[i].instances.clear(); @@ -2829,7 +2911,7 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, environment = scenario->fallback_environment; } RENDER_TIMESTAMP("Render Empty Scene "); - scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); + scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif } @@ -2891,8 +2973,15 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int shadow_atlas = scenario->reflection_probe_shadow_atlas; } + RID environment; + if (scenario->environment.is_valid()) { + environment = scenario->environment; + } else { + environment = scenario->fallback_environment; + } + RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _render_scene(xform, cm, false, false, RID(), RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows); + _render_scene(xform, cm, false, false, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows); } else { //do roughness postprocess step until it believes it's done @@ -3466,8 +3555,11 @@ bool RendererSceneCull::free(RID p_rid) { scene_render->free(scenario->reflection_probe_shadow_atlas); scene_render->free(scenario->reflection_atlas); scenario_owner.free(p_rid); + RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid); memdelete(scenario); + } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) { + RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid); } else if (instance_owner.owns(p_rid)) { // delete the instance @@ -3536,6 +3628,8 @@ RendererSceneCull::RendererSceneCull() { indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances"); thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU + + dummy_occlusion_culling = memnew(RendererSceneOcclusionCull); } RendererSceneCull::~RendererSceneCull() { @@ -3554,4 +3648,8 @@ RendererSceneCull::~RendererSceneCull() { frustum_cull_result_threads[i].reset(); } frustum_cull_result_threads.clear(); + + if (dummy_occlusion_culling) { + memdelete(dummy_occlusion_culling); + } } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 32f4334288..a61b04afc8 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -45,8 +45,10 @@ #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" #include "servers/rendering/renderer_scene.h" +#include "servers/rendering/renderer_scene_occlusion_cull.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/xr/xr_interface.h" + class RendererSceneCull : public RendererScene { public: RendererSceneRender *scene_render; @@ -109,6 +111,14 @@ public: virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable); virtual bool is_camera(RID p_camera) const; + /* OCCLUDER API */ + + virtual RID occluder_allocate(); + virtual void occluder_initialize(RID p_occluder); + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); + + RendererSceneOcclusionCull *dummy_occlusion_culling; + /* SCENARIO API */ struct Instance; @@ -248,6 +258,7 @@ public: FLAG_USES_BAKED_LIGHT = (1 << 16), FLAG_USES_MESH_INSTANCE = (1 << 17), FLAG_REFLECTION_PROBE_DIRTY = (1 << 18), + FLAG_IGNORE_OCCLUSION_CULLING = (1 << 19), }; uint32_t flags = 0; @@ -346,6 +357,8 @@ public: float lod_bias; + bool ignore_occlusion_culling; + Vector<RID> materials; RS::ShadowCastingSetting cast_shadows; @@ -430,6 +443,7 @@ public: singleton->_instance_queue_update(instance, false, true); } break; case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_PARTICLES: case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: case RendererStorage::DEPENDENCY_CHANGED_DECAL: case RendererStorage::DEPENDENCY_CHANGED_LIGHT: @@ -470,6 +484,7 @@ public: lightmap = nullptr; lightmap_cull_index = 0; lod_bias = 1.0; + ignore_occlusion_culling = false; scenario = nullptr; @@ -647,6 +662,7 @@ public: _FORCE_INLINE_ bool operator()(void *p_data) { Instance *p_instance = (Instance *)p_data; + if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) { //test is more coarse in indexer p_instance->pair_check = pair_pass; @@ -840,7 +856,7 @@ public: virtual void instance_set_transform(RID p_instance, const Transform &p_transform); virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); - virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); + virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material); virtual void instance_set_visible(RID p_instance, bool p_visible); virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); @@ -921,24 +937,26 @@ public: Frustum frustum; } cull; - struct FrustumCullData { + struct CullData { Cull *cull; Scenario *scenario; RID shadow_atlas; Transform cam_transform; uint32_t visible_layers; Instance *render_reflection_probe; + const RendererSceneOcclusionCull::HZBuffer *occlusion_buffer; + const CameraMatrix *camera_matrix; }; - void _frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data); - void _frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to); + void _frustum_cull_threaded(uint32_t p_thread, CullData *cull_data); + void _frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to); bool _render_reflection_probe_step(Instance *p_instance, int p_step); - void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true); + void _render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true); void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); void update_dirty_instances(); void render_particle_colliders(); diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp new file mode 100644 index 0000000000..c491ccbe7a --- /dev/null +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -0,0 +1,192 @@ +/*************************************************************************/ +/* renderer_scene_occlusion_cull.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene_occlusion_cull.h" + +RendererSceneOcclusionCull *RendererSceneOcclusionCull::singleton = nullptr; + +const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = { + Vector3(0, 0, 0), + Vector3(0, 0, 1), + Vector3(0, 1, 0), + Vector3(0, 1, 1), + Vector3(1, 0, 0), + Vector3(1, 0, 1), + Vector3(1, 1, 0), + Vector3(1, 1, 1) +}; + +bool RendererSceneOcclusionCull::HZBuffer::is_empty() const { + return sizes.is_empty(); +} + +void RendererSceneOcclusionCull::HZBuffer::clear() { + if (sizes.is_empty()) { + return; // Already cleared + } + + data.clear(); + sizes.clear(); + mips.clear(); + + debug_data.clear(); + if (debug_image.is_valid()) { + debug_image.unref(); + } + RS::get_singleton()->free(debug_texture); +} + +void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { + if (p_size == Size2i()) { + clear(); + return; + } + + if (!sizes.is_empty() && p_size == sizes[0]) { + return; // Size didn't change + } + + int mip_count = 0; + int data_size = 0; + int w = p_size.x; + int h = p_size.y; + + while (true) { + data_size += h * w; + + w = MAX(1, w >> 1); + h = MAX(1, h >> 1); + + mip_count++; + + if (w == 1U && h == 1U) { + data_size += 1U; + mip_count++; + break; + } + } + + data.resize(data_size); + mips.resize(mip_count); + sizes.resize(mip_count); + + w = p_size.x; + h = p_size.y; + float *ptr = data.ptr(); + + for (int i = 0; i < mip_count; i++) { + sizes[i] = Size2i(w, h); + mips[i] = ptr; + + ptr = &ptr[w * h]; + w = MAX(1, w >> 1); + h = MAX(1, h >> 1); + } + + for (int i = 0; i < data_size; i++) { + data[i] = FLT_MAX; + } + + debug_data.resize(sizes[0].x * sizes[0].y); + if (debug_texture.is_valid()) { + RS::get_singleton()->free(debug_texture); + debug_texture = RID(); + } +} + +void RendererSceneOcclusionCull::HZBuffer::update_mips() { + if (sizes.is_empty()) { + return; + } + + for (uint32_t mip = 1; mip < mips.size(); mip++) { + for (int y = 0; y < sizes[mip].y; y++) { + for (int x = 0; x < sizes[mip].x; x++) { + int prev_x = x * 2; + int prev_y = y * 2; + + int prev_w = sizes[mip - 1].width; + int prev_h = sizes[mip - 1].height; + + bool odd_w = (prev_w % 2) != 0; + bool odd_h = (prev_h % 2) != 0; + +#define CHECK_OFFSET(xx, yy) max_depth = MAX(max_depth, mips[mip - 1][MIN(prev_h - 1, prev_y + (yy)) * prev_w + MIN(prev_w - 1, prev_x + (xx))]) + + float max_depth = mips[mip - 1][prev_y * sizes[mip - 1].x + prev_x]; + CHECK_OFFSET(0, 1); + CHECK_OFFSET(1, 0); + CHECK_OFFSET(1, 1); + + if (odd_w) { + CHECK_OFFSET(2, 0); + CHECK_OFFSET(2, 1); + } + + if (odd_h) { + CHECK_OFFSET(0, 2); + CHECK_OFFSET(1, 2); + } + + if (odd_w && odd_h) { + CHECK_OFFSET(2, 2); + } + + mips[mip][y * sizes[mip].x + x] = max_depth; +#undef CHECK_OFFSET + } + } + } +} + +RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() { + if (sizes.is_empty() || sizes[0] == Size2i()) { + return RID(); + } + + if (debug_image.is_null()) { + debug_image.instance(); + } + + unsigned char *ptrw = debug_data.ptrw(); + for (int i = 0; i < debug_data.size(); i++) { + ptrw[i] = MIN(mips[0][i] / debug_tex_range, 1.0) * 255; + } + + debug_image->create(sizes[0].x, sizes[0].y, false, Image::FORMAT_L8, debug_data); + + if (debug_texture.is_null()) { + debug_texture = RS::get_singleton()->texture_2d_create(debug_image); + } else { + RenderingServer::get_singleton()->texture_2d_update_immediate(debug_texture, debug_image); + } + + return debug_texture; +} diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h new file mode 100644 index 0000000000..390bbaa64b --- /dev/null +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -0,0 +1,201 @@ +/*************************************************************************/ +/* renderer_scene_occlusion_cull.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERER_SCENE_OCCLUSION_CULL_H +#define RENDERER_SCENE_OCCLUSION_CULL_H + +#include "core/math/camera_matrix.h" +#include "core/templates/local_vector.h" +#include "servers/rendering_server.h" + +class RendererSceneOcclusionCull { +protected: + static RendererSceneOcclusionCull *singleton; + +public: + class HZBuffer { + protected: + static const Vector3 corners[8]; + + LocalVector<float> data; + LocalVector<Size2i> sizes; + LocalVector<float *> mips; + + RID debug_texture; + Ref<Image> debug_image; + PackedByteArray debug_data; + float debug_tex_range = 0.0f; + + public: + bool is_empty() const; + virtual void clear(); + virtual void resize(const Size2i &p_size); + + void update_mips(); + + _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const { + if (is_empty()) { + return false; + } + + Vector3 closest_point = Vector3(CLAMP(p_cam_position.x, p_bounds[0], p_bounds[3]), CLAMP(p_cam_position.y, p_bounds[1], p_bounds[4]), CLAMP(p_cam_position.z, p_bounds[2], p_bounds[5])); + + if (closest_point == p_cam_position) { + return false; + } + + Vector3 closest_point_view = p_cam_inv_transform.xform(closest_point); + if (closest_point_view.z > -p_near) { + return false; + } + + float min_depth; + if (p_cam_projection.is_orthogonal()) { + min_depth = (-closest_point_view.z) - p_near; + } else { + float r = -p_near / closest_point_view.z; + Vector3 closest_point_proj = Vector3(closest_point_view.x * r, closest_point_view.y * r, -p_near); + min_depth = closest_point_proj.distance_to(closest_point_view); + } + + Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX); + Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN); + + for (int j = 0; j < 8; j++) { + Vector3 c = RendererSceneOcclusionCull::HZBuffer::corners[j]; + Vector3 nc = Vector3(1, 1, 1) - c; + Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z); + Vector3 view = p_cam_inv_transform.xform(corner); + + Vector3 projected = p_cam_projection.xform(view); + Vector2 normalized = Vector2(projected.x * 0.5f + 0.5f, projected.y * 0.5f + 0.5f); + rect_min = rect_min.min(normalized); + rect_max = rect_max.max(normalized); + } + + rect_max = rect_max.min(Vector2(1, 1)); + rect_min = rect_min.max(Vector2(0, 0)); + + int mip_count = mips.size(); + + Vector2 screen_diagonal = (rect_max - rect_min) * sizes[0]; + float size = MAX(screen_diagonal.x, screen_diagonal.y); + float l = Math::ceil(Math::log2(size)); + int lod = CLAMP(l, 0, mip_count - 1); + + const int max_samples = 512; + int sample_count = 0; + bool visible = true; + + for (; lod >= 0; lod--) { + int w = sizes[lod].x; + int h = sizes[lod].y; + + int minx = CLAMP(rect_min.x * w - 1, 0, w - 1); + int maxx = CLAMP(rect_max.x * w + 1, 0, w - 1); + + int miny = CLAMP(rect_min.y * h - 1, 0, h - 1); + int maxy = CLAMP(rect_max.y * h + 1, 0, h - 1); + + sample_count += (maxx - minx + 1) * (maxy - miny + 1); + + if (sample_count > max_samples) { + return false; + } + + visible = false; + for (int y = miny; y <= maxy; y++) { + for (int x = minx; x <= maxx; x++) { + float depth = mips[lod][y * w + x]; + if (depth > min_depth) { + visible = true; + break; + } + } + if (visible) { + break; + } + } + + if (!visible) { + return true; + } + } + + return !visible; + } + + RID get_debug_texture(); + + virtual ~HZBuffer(){}; + }; + + static RendererSceneOcclusionCull *get_singleton() { return singleton; } + + void _print_warining() { + WARN_PRINT_ONCE("Occlusion culling is disabled at build time."); + } + + virtual bool is_occluder(RID p_rid) { return false; } + virtual RID occluder_allocate() { return RID(); } + virtual void occluder_initialize(RID p_occluder) {} + virtual void free_occluder(RID p_occluder) { _print_warining(); } + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { _print_warining(); } + + virtual void add_scenario(RID p_scenario) {} + virtual void remove_scenario(RID p_scenario) {} + virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) { _print_warining(); } + virtual void scenario_remove_instance(RID p_scenario, RID p_instance) { _print_warining(); } + + virtual void add_buffer(RID p_buffer) { _print_warining(); } + virtual void remove_buffer(RID p_buffer) { _print_warining(); } + virtual HZBuffer *buffer_get_ptr(RID p_buffer) { + return nullptr; + } + virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) { _print_warining(); } + virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) { _print_warining(); } + virtual void buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {} + virtual RID buffer_get_debug_texture(RID p_buffer) { + _print_warining(); + return RID(); + } + + virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {} + + RendererSceneOcclusionCull() { + singleton = this; + }; + + virtual ~RendererSceneOcclusionCull() { + singleton = nullptr; + }; +}; + +#endif //RENDERER_SCENE_OCCLUSION_CULL_H diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 1dea3580b6..3f28fac549 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -216,7 +216,7 @@ public: uint32_t positional_light_count; }; - virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0; + virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0; virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0; @@ -241,8 +241,6 @@ public: virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; - virtual bool is_low_end() const = 0; - virtual void update() = 0; virtual ~RendererSceneRender() {} }; diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index 22cf6acb19..cc4ff5d55e 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -43,6 +43,7 @@ public: DEPENDENCY_CHANGED_MESH, DEPENDENCY_CHANGED_MULTIMESH, DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES, + DEPENDENCY_CHANGED_PARTICLES, DEPENDENCY_CHANGED_DECAL, DEPENDENCY_CHANGED_SKELETON_DATA, DEPENDENCY_CHANGED_SKELETON_BONES, @@ -483,6 +484,7 @@ public: virtual RID particles_allocate() = 0; virtual void particles_initialize(RID p_rid) = 0; + virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) = 0; virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0; virtual bool particles_get_emitting(RID p_particles) = 0; @@ -498,8 +500,15 @@ public: virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; + virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0; virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0; + + virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) = 0; + + virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length) = 0; + virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0; + virtual void particles_restart(RID p_particles) = 0; virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0; @@ -520,7 +529,7 @@ public: virtual int particles_get_draw_passes(RID p_particles) const = 0; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; - virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0; + virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) = 0; virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0; virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index a5d5033c18..f7be6c6c60 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -79,11 +79,26 @@ void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { xr_interface = XRServer::get_singleton()->get_primary_interface(); } + if (p_viewport->use_occlusion_culling) { + if (p_viewport->occlusion_buffer_dirty) { + float aspect = p_viewport->size.aspect(); + int max_size = occlusion_rays_per_thread * RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + + int viewport_size = p_viewport->size.width * p_viewport->size.height; + max_size = CLAMP(max_size, viewport_size / (32 * 32), viewport_size / (2 * 2)); // At least one depth pixel for every 16x16 region. At most one depth pixel for every 2x2 region. + + float height = Math::sqrt(max_size / aspect); + Size2i new_size = Size2i(height * aspect, height); + RendererSceneOcclusionCull::get_singleton()->buffer_set_size(p_viewport->self, new_size); + p_viewport->occlusion_buffer_dirty = false; + } + } + float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width); if (p_viewport->use_xr && xr_interface.is_valid()) { - RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); + RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); } else { - RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); + RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); } RENDER_TIMESTAMP("<End Rendering 3D Scene"); } @@ -647,6 +662,8 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding); } } + + viewport->occlusion_buffer_dirty = true; } void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { @@ -655,6 +672,7 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { if (p_active) { ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active + viewport->occlusion_buffer_dirty = true; active_viewports.push_back(viewport); } else { active_viewports.erase(viewport); @@ -739,6 +757,16 @@ RID RendererViewport::viewport_get_texture(RID p_viewport) const { return RSG::storage->render_target_get_texture(viewport->render_target); } +RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const { + const Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND_V(!viewport, RID()); + + if (viewport->use_occlusion_culling && viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_OCCLUDERS) { + return RendererSceneOcclusionCull::get_singleton()->buffer_get_debug_texture(p_viewport); + } + return RID(); +} + void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -772,6 +800,9 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { ERR_FAIL_COND(!viewport); viewport->scenario = p_scenario; + if (viewport->use_occlusion_culling) { + RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario); + } } void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { @@ -888,6 +919,41 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb } } +void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + if (viewport->use_occlusion_culling == p_use_occlusion_culling) { + return; + } + viewport->use_occlusion_culling = p_use_occlusion_culling; + + if (viewport->use_occlusion_culling) { + RendererSceneOcclusionCull::get_singleton()->add_buffer(p_viewport); + RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, viewport->scenario); + } else { + RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_viewport); + } + + viewport->occlusion_buffer_dirty = true; +} + +void RendererViewport::viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) { + if (occlusion_rays_per_thread == p_rays_per_thread) { + return; + } + + occlusion_rays_per_thread = p_rays_per_thread; + + for (int i = 0; i < active_viewports.size(); i++) { + active_viewports[i]->occlusion_buffer_dirty = true; + } +} + +void RendererViewport::viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) { + RendererSceneOcclusionCull::get_singleton()->set_build_quality(p_quality); +} + void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -985,6 +1051,10 @@ bool RendererViewport::free(RID p_rid) { viewport_set_scenario(p_rid, RID()); active_viewports.erase(viewport); + if (viewport->use_occlusion_culling) { + RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid); + } + viewport_owner.free(p_rid); memdelete(viewport); @@ -1026,4 +1096,5 @@ void RendererViewport::call_set_use_vsync(bool p_enable) { } RendererViewport::RendererViewport() { + occlusion_rays_per_thread = GLOBAL_GET("rendering/occlusion_culling/occlusion_rays_per_thread"); } diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index f5ed543e8d..5c372e8c9a 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -31,9 +31,9 @@ #ifndef VISUALSERVERVIEWPORT_H #define VISUALSERVERVIEWPORT_H +#include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" -#include "renderer_compositor.h" #include "servers/rendering_server.h" #include "servers/xr/xr_interface.h" @@ -61,6 +61,9 @@ public: RS::ViewportScreenSpaceAA screen_space_aa; bool use_debanding; + bool use_occlusion_culling; + bool occlusion_buffer_dirty; + DisplayServer::WindowID viewport_to_screen; Rect2 viewport_to_screen_rect; bool viewport_render_direct_to_screen; @@ -143,6 +146,8 @@ public: msaa = RS::VIEWPORT_MSAA_DISABLED; screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; use_debanding = false; + use_occlusion_culling = false; + occlusion_buffer_dirty = true; snap_2d_transforms_to_pixel = false; snap_2d_vertices_to_pixel = false; @@ -185,6 +190,10 @@ private: void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye); void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO); + int occlusion_rays_per_thread = 512; + + void _resize_occlusion_culling_buffer(const Size2i &p_size); + public: RID viewport_allocate(); void viewport_initialize(RID p_rid); @@ -204,6 +213,7 @@ public: void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode); RID viewport_get_texture(RID p_viewport) const; + RID viewport_get_occluder_debug_texture(RID p_viewport) const; void viewport_set_hide_scenario(RID p_viewport, bool p_hide); void viewport_set_hide_canvas(RID p_viewport, bool p_hide); @@ -225,7 +235,9 @@ public: void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa); void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode); void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding); - + void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling); + void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread); + void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality); void viewport_set_lod_threshold(RID p_viewport, float p_pixels); virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 27a9353e4e..e6ad001807 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -59,7 +59,7 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>()); - return compile_function(p_stage, p_source_code, p_language, r_error); + return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities); } RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) { diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 9fbf58d131..d86c44a206 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -51,6 +51,13 @@ class RDPipelineColorBlendState; class RenderingDevice : public Object { GDCLASS(RenderingDevice, Object) public: + enum DeviceFamily { + DEVICE_UNKNOWN, + DEVICE_OPENGL, + DEVICE_VULKAN, + DEVICE_DIRECTX + }; + enum ShaderStage { SHADER_STAGE_VERTEX, SHADER_STAGE_FRAGMENT, @@ -70,7 +77,33 @@ public: SHADER_LANGUAGE_HLSL }; - typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error); + enum SubgroupOperations { + SUBGROUP_BASIC_BIT = 1, + SUBGROUP_VOTE_BIT = 2, + SUBGROUP_ARITHMETIC_BIT = 4, + SUBGROUP_BALLOT_BIT = 8, + SUBGROUP_SHUFFLE_BIT = 16, + SUBGROUP_SHUFFLE_RELATIVE_BIT = 32, + SUBGROUP_CLUSTERED_BIT = 64, + SUBGROUP_QUAD_BIT = 128, + }; + + struct Capabilities { + // main device info + DeviceFamily device_family = DEVICE_UNKNOWN; + uint32_t version_major = 1.0; + uint32_t version_minor = 0.0; + + // subgroup capabilities + uint32_t subgroup_size = 0; + uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc. + uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations + + // features + bool supports_multiview = false; // If true this device supports multiview options + }; + + typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities); typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language); private: @@ -82,6 +115,8 @@ private: protected: static void _bind_methods(); + Capabilities device_capabilities; + public: //base numeric ID for all types enum { @@ -597,6 +632,8 @@ public: /**** SHADER ****/ /****************/ + const Capabilities *get_device_capabilities() const { return &device_capabilities; }; + virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true); static void shader_set_compile_function(ShaderCompileFunction p_function); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index e82d5cc3f8..bf47d497b6 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -478,6 +478,7 @@ public: FUNCRIDSPLIT(particles) + FUNC2(particles_set_mode, RID, ParticlesMode) FUNC2(particles_set_emitting, RID, bool) FUNC1R(bool, particles_get_emitting, RID) FUNC2(particles_set_amount, RID, int) @@ -491,14 +492,20 @@ public: FUNC2(particles_set_use_local_coordinates, RID, bool) FUNC2(particles_set_process_material, RID, RID) FUNC2(particles_set_fixed_fps, RID, int) + FUNC2(particles_set_interpolate, RID, bool) FUNC2(particles_set_fractional_delta, RID, bool) FUNC1R(bool, particles_is_inactive, RID) + FUNC3(particles_set_trails, RID, bool, float) + FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform> &) + FUNC1(particles_request_process, RID) FUNC1(particles_restart, RID) FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t) FUNC2(particles_set_subemitter, RID, RID) FUNC2(particles_set_collision_base_size, RID, float) + FUNC2(particles_set_transform_align, RID, RS::ParticlesTransformAlign) + FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder) FUNC2(particles_set_draw_passes, RID, int) @@ -540,6 +547,10 @@ public: FUNC2(camera_set_camera_effects, RID, RID) FUNC2(camera_set_use_vertical_aspect, RID, bool) + /* OCCLUDER */ + FUNCRIDSPLIT(occluder) + FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &); + #undef server_name #undef ServerName //from now on, calls forwarded to this singleton @@ -590,6 +601,9 @@ public: FUNC2(viewport_set_msaa, RID, ViewportMSAA) FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) FUNC2(viewport_set_use_debanding, RID, bool) + FUNC2(viewport_set_use_occlusion_culling, RID, bool) + FUNC1(viewport_set_occlusion_rays_per_thread, int) + FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality) FUNC2(viewport_set_lod_threshold, RID, float) FUNC2R(int, viewport_get_render_info, RID, ViewportRenderInfo) @@ -703,7 +717,7 @@ public: FUNC2(instance_set_transform, RID, const Transform &) FUNC2(instance_attach_object_instance_id, RID, ObjectID) FUNC3(instance_set_blend_shape_weight, RID, int, float) - FUNC3(instance_set_surface_material, RID, int, RID) + FUNC3(instance_set_surface_override_material, RID, int, RID) FUNC2(instance_set_visible, RID, bool) FUNC2(instance_set_custom_aabb, RID, AABB) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index df1a7d58d0..a81306b97d 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -2969,6 +2969,20 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { } } +bool ShaderLanguage::is_control_flow_keyword(String p_keyword) { + return p_keyword == "break" || + p_keyword == "case" || + p_keyword == "continue" || + p_keyword == "default" || + p_keyword == "do" || + p_keyword == "else" || + p_keyword == "for" || + p_keyword == "if" || + p_keyword == "return" || + p_keyword == "switch" || + p_keyword == "while"; +} + void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) { Set<String> kws; @@ -3109,20 +3123,20 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St } switch (p_varying.stage) { case ShaderNode::Varying::STAGE_UNKNOWN: // first assign - if (current_function == String("vertex")) { + if (current_function == varying_function_names.vertex) { p_varying.stage = ShaderNode::Varying::STAGE_VERTEX; - } else if (current_function == String("fragment")) { + } else if (current_function == varying_function_names.fragment) { p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT; } break; case ShaderNode::Varying::STAGE_VERTEX: - if (current_function == String("fragment")) { + if (current_function == varying_function_names.fragment) { *r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'."); return false; } break; case ShaderNode::Varying::STAGE_FRAGMENT: - if (current_function == String("vertex")) { + if (current_function == varying_function_names.vertex) { *r_message = RTR("Varyings which assigned in 'fragment' function may not be reassigned in 'vertex' or 'light'."); return false; } @@ -3139,25 +3153,25 @@ bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, Str *r_message = RTR("Varying must be assigned before using!"); return false; case ShaderNode::Varying::STAGE_VERTEX: - if (current_function == String("fragment")) { + if (current_function == varying_function_names.fragment) { p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT; - } else if (current_function == String("light")) { + } else if (current_function == varying_function_names.light) { p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT; } break; case ShaderNode::Varying::STAGE_FRAGMENT: - if (current_function == String("light")) { + if (current_function == varying_function_names.light) { p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; } break; case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT: - if (current_function == String("light")) { + if (current_function == varying_function_names.light) { *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); return false; } break; case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT: - if (current_function == String("fragment")) { + if (current_function == varying_function_names.fragment) { *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); return false; } @@ -3168,6 +3182,36 @@ bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, Str return true; } +bool ShaderLanguage::_check_node_constness(const Node *p_node) const { + switch (p_node->type) { + case Node::TYPE_OPERATOR: { + OperatorNode *op_node = (OperatorNode *)p_node; + for (int i = (1 ? op_node->op == OP_CALL : 0); i < op_node->arguments.size(); i++) { + if (!_check_node_constness(op_node->arguments[i])) { + return false; + } + } + } break; + case Node::TYPE_CONSTANT: + break; + case Node::TYPE_VARIABLE: { + VariableNode *varn = (VariableNode *)p_node; + if (!varn->is_const) { + return false; + } + } break; + case Node::TYPE_ARRAY: { + ArrayNode *arrn = (ArrayNode *)p_node; + if (!arrn->is_const) { + return false; + } + } break; + default: + return false; + } + return true; +} + bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) { if (p_node->type == Node::TYPE_OPERATOR) { OperatorNode *op = static_cast<OperatorNode *>(p_node); @@ -3956,8 +4000,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons ERR_FAIL_COND_V(!expr, nullptr); /* OK now see what's NEXT to the operator.. */ - /* OK now see what's NEXT to the operator.. */ - /* OK now see what's NEXT to the operator.. */ while (true) { TkPos pos2 = _get_tkpos(); @@ -4735,7 +4777,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons ERR_FAIL_COND_V(next_op == -1, nullptr); // OK! create operator.. - // OK! create operator.. if (is_unary) { int expr_pos = next_op; while (expression[expr_pos].is_op) { @@ -5387,8 +5428,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { - _set_error("Expected constant expression after '='"); - return ERR_PARSE_ERROR; + OperatorNode *op = ((OperatorNode *)n); + for (int i = 1; i < op->arguments.size(); i++) { + if (!_check_node_constness(op->arguments[i])) { + _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='"); + return ERR_PARSE_ERROR; + } + } } decl.initializer = n; @@ -5847,7 +5893,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun //check return type BlockNode *b = p_block; - if (b && b->parent_function && (b->parent_function->name == "vertex" || b->parent_function->name == "fragment" || b->parent_function->name == "light")) { + if (b && b->parent_function && p_function_info.main_function) { _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name)); return ERR_PARSE_ERROR; } @@ -6825,7 +6871,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } else { _set_tkpos(pos2); - Node *n = _parse_and_reduce_expression(NULL, FunctionInfo()); + Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo()); if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { _set_error("Expected single integer constant > 0"); return ERR_PARSE_ERROR; @@ -6906,7 +6952,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization while (true) { - Node *n = _parse_and_reduce_expression(NULL, FunctionInfo()); + Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo()); if (!n) { return ERR_PARSE_ERROR; } @@ -6932,10 +6978,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct decl.initializer.push_back(n); break; } else { - if (curly) + if (curly) { _set_error("Expected '}' or ','"); - else + } else { _set_error("Expected ')' or ','"); + } return ERR_PARSE_ERROR; } } @@ -6961,12 +7008,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct constant.initializer = static_cast<ConstantNode *>(expr); } else { //variable created with assignment! must parse an expression - Node *expr = _parse_and_reduce_expression(NULL, FunctionInfo()); - if (!expr) + Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo()); + if (!expr) { return ERR_PARSE_ERROR; + } if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) { - _set_error("Expected constant expression after '='"); - return ERR_PARSE_ERROR; + OperatorNode *op = ((OperatorNode *)expr); + for (int i = 1; i < op->arguments.size(); i++) { + if (!_check_node_constness(op->arguments[i])) { + _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='"); + return ERR_PARSE_ERROR; + } + } } constant.initializer = static_cast<ConstantNode *>(expr); @@ -7244,26 +7297,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) { - if (p_functions.has("vertex")) { - if (p_functions["vertex"].built_ins.has(p_name)) { - return true; - } - } - if (p_functions.has("fragment")) { - if (p_functions["fragment"].built_ins.has(p_name)) { - return true; - } - } - if (p_functions.has("light")) { - if (p_functions["light"].built_ins.has(p_name)) { - return true; - } - } - if (p_functions.has("compute")) { - if (p_functions["compute"].built_ins.has(p_name)) { + for (Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) { + if (E->get().built_ins.has(p_name)) { return true; } } + return false; } @@ -7397,11 +7436,12 @@ String ShaderLanguage::get_shader_type(const String &p_code) { return String(); } -Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) { +Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) { clear(); code = p_code; global_var_get_type_func = p_global_variable_type_func; + varying_function_names = p_varying_function_names; nodes = nullptr; @@ -7414,10 +7454,11 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi return OK; } -Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) { +Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) { clear(); code = p_code; + varying_function_names = p_varying_function_names; nodes = nullptr; global_var_get_type_func = p_global_variable_type_func; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 14594b039c..e00f4dce19 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -331,6 +331,17 @@ public: MAX_INSTANCE_UNIFORM_INDICES = 16 }; + struct VaryingFunctionNames { + StringName fragment; + StringName vertex; + StringName light; + VaryingFunctionNames() { + fragment = "fragment"; + vertex = "vertex"; + light = "light"; + } + }; + struct Node { Node *next = nullptr; @@ -737,6 +748,7 @@ public: static uint32_t get_type_size(DataType p_type); static void get_keyword_list(List<String> *r_keywords); + static bool is_control_flow_keyword(String p_keyword); static void get_builtin_funcs(List<String> *r_keywords); struct BuiltInInfo { @@ -769,7 +781,8 @@ public: Map<StringName, BuiltInInfo> built_ins; Map<StringName, StageFunctionInfo> stage_functions; - bool can_discard; + bool can_discard = false; + bool main_function = false; }; static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name); @@ -796,6 +809,8 @@ private: StringName current_function; bool last_const = false; + VaryingFunctionNames varying_function_names; + TkPos _get_tkpos() { TkPos tkp; tkp.char_idx = char_idx; @@ -877,6 +892,7 @@ private: bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin); bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message); + bool _check_node_constness(const Node *p_node) const; Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info); Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size); @@ -898,8 +914,8 @@ public: void clear(); static String get_shader_type(const String &p_code); - Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func); - Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint); + Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func); + Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint); String get_error_text(); int get_error_line(); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index e99b8504bb..0bf68b9e0f 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -74,6 +74,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].main_function = true; //builtins shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; @@ -139,6 +140,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RADIANCE"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["IRRADIANCE"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].can_discard = true; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].main_function = true; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR_THRESHOLD"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_HASH_SCALE"] = ShaderLanguage::TYPE_FLOAT; @@ -171,6 +173,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true; + shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true; //order used puts first enum mode (default) first shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mix"); @@ -216,6 +219,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting"); + shader_modes[RS::SHADER_SPATIAL].modes.push_back("particle_trails"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage_and_one"); @@ -236,6 +240,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].main_function = true; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2; @@ -257,6 +262,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true; { ShaderLanguage::StageFunctionInfo func; @@ -294,6 +300,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].main_function = true; shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform"); @@ -310,34 +317,50 @@ ShaderTypes::ShaderTypes() { /************ PARTICLES **************************/ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLIDED"] = constt(ShaderLanguage::TYPE_BOOL); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_PARTICLES].functions["compute"].can_discard = false; + + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["start"].main_function = true; + + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLIDED"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_PARTICLES].functions["process"].main_function = true; { ShaderLanguage::StageFunctionInfo emit_vertex_func; @@ -347,7 +370,7 @@ ShaderTypes::ShaderTypes() { emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4)); emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT)); emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit - shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_subparticle"] = emit_vertex_func; + shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func; } shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale"); @@ -384,14 +407,15 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_COLOR"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_SIZE"] = constt(ShaderLanguage::TYPE_FLOAT); - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4); - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4); - shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SKY].functions["sky"].main_function = true; shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass"); shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass"); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 809343114c..49990407e3 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -349,7 +349,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float vector[2] = { src[i].x, src[i].y }; - copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2); + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2); if (i == 0) { aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size @@ -374,7 +374,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float vector[3] = { src[i].x, src[i].y, src[i].z }; - copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); if (i == 0) { aabb = AABB(src[i], SMALL_VEC3); @@ -403,7 +403,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; - copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } } break; @@ -422,9 +422,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 3.0), 0, 3) << 30; + value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 1023.0), 0, 1023) << 30; - copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } } break; @@ -442,7 +442,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint color16[1] = Math::make_half_float(src[i].g); color16[2] = Math::make_half_float(src[i].b); color16[3] = Math::make_half_float(src[i].a); - copymem(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8); + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8); } } break; case RS::ARRAY_TEX_UV: { @@ -457,7 +457,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float uv[2] = { src[i].x, src[i].y }; - copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); } } break; @@ -472,8 +472,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; - copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2); + float uv[2] = { src[i].x, src[i].y }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); } } break; case RS::ARRAY_CUSTOM0: @@ -495,7 +495,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const uint8_t *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4); + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4); } } break; @@ -510,7 +510,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const uint8_t *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8); + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8); } } break; case ARRAY_CUSTOM_R_FLOAT: @@ -528,7 +528,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const float *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s); + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s); } } break; default: { @@ -554,7 +554,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535); } - copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); + memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } } @@ -578,7 +578,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint max_bone = MAX(data[j], max_bone); } - copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); + memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } } break; @@ -600,11 +600,11 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint if (p_vertex_array_len < (1 << 16)) { uint16_t v = src[i]; - copymem(&iw[i * 2], &v, 2); + memcpy(&iw[i * 2], &v, 2); } else { uint32_t v = src[i]; - copymem(&iw[i * 4], &v, 4); + memcpy(&iw[i * 4], &v, 4); } } } break; @@ -858,8 +858,10 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa case Variant::PACKED_VECTOR2_ARRAY: { Vector<Vector2> v2 = p_arrays[i]; array_len = v2.size(); + format |= ARRAY_FLAG_USE_2D_VERTICES; } break; case Variant::PACKED_VECTOR3_ARRAY: { + ERR_FAIL_COND_V(p_compress_format & ARRAY_FLAG_USE_2D_VERTICES, ERR_INVALID_PARAMETER); Vector<Vector3> v3 = p_arrays[i]; array_len = v3.size(); } break; @@ -1172,7 +1174,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t for (int j = 0; j < p_vertex_len; j++) { const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]]; - copymem(&w[j * s], v, s); + memcpy(&w[j * s], v, s); } ret[i] = arr; @@ -1189,7 +1191,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t for (int j = 0; j < p_vertex_len; j++) { const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; - copymem(&w[j * s], v, s * sizeof(float)); + memcpy(&w[j * s], v, s * sizeof(float)); } ret[i] = arr; @@ -1594,7 +1596,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("gi_probe_set_compress", "probe", "enable"), &RenderingServer::gi_probe_set_compress); ClassDB::bind_method(D_METHOD("gi_probe_is_compressed", "probe"), &RenderingServer::gi_probe_is_compressed); #endif -/* + /* ClassDB::bind_method(D_METHOD("lightmap_create()"), &RenderingServer::lightmap_capture_create); ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &RenderingServer::lightmap_capture_set_bounds); ClassDB::bind_method(D_METHOD("lightmap_capture_get_bounds", "capture"), &RenderingServer::lightmap_capture_get_bounds); @@ -1607,6 +1609,10 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &RenderingServer::lightmap_capture_set_energy); ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &RenderingServer::lightmap_capture_get_energy); */ + + ClassDB::bind_method(D_METHOD("occluder_create"), &RenderingServer::occluder_create); + ClassDB::bind_method(D_METHOD("occluder_set_mesh"), &RenderingServer::occluder_set_mesh); + #endif ClassDB::bind_method(D_METHOD("particles_create"), &RenderingServer::particles_create); ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting); @@ -1667,6 +1673,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); + ClassDB::bind_method(D_METHOD("viewport_set_use_occlusion_culling", "viewport", "enable"), &RenderingServer::viewport_set_use_occlusion_culling); + ClassDB::bind_method(D_METHOD("viewport_set_occlusion_rays_per_thread", "rays_per_thread"), &RenderingServer::viewport_set_occlusion_rays_per_thread); + ClassDB::bind_method(D_METHOD("viewport_set_occlusion_culling_build_quality", "quality"), &RenderingServer::viewport_set_occlusion_culling_build_quality); ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info); ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw); @@ -1694,6 +1703,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create); ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &RenderingServer::scenario_set_debug); ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &RenderingServer::scenario_set_environment); + ClassDB::bind_method(D_METHOD("scenario_set_camera_effects", "scenario", "effects"), &RenderingServer::scenario_set_camera_effects); ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment); #ifndef _3D_DISABLED @@ -1706,7 +1716,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform); ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id); ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight); - ClassDB::bind_method(D_METHOD("instance_set_surface_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_material); + ClassDB::bind_method(D_METHOD("instance_set_surface_override_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_override_material); ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible); // ClassDB::bind_method(D_METHOD("instance_set_use_lightmap", "instance", "lightmap_instance", "lightmap"), &RenderingServer::instance_set_use_lightmap); ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb); @@ -2024,6 +2034,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI_PROBES); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_BUFFER); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS); BIND_ENUM_CONSTANT(SKY_MODE_QUALITY); BIND_ENUM_CONSTANT(SKY_MODE_REALTIME); @@ -2093,6 +2104,10 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(SCENARIO_DEBUG_OVERDRAW); BIND_ENUM_CONSTANT(SCENARIO_DEBUG_SHADELESS); + BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW); + BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM); + BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH); + BIND_ENUM_CONSTANT(INSTANCE_NONE); BIND_ENUM_CONSTANT(INSTANCE_MESH); BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH); @@ -2104,12 +2119,14 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(INSTANCE_DECAL); BIND_ENUM_CONSTANT(INSTANCE_GI_PROBE); BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP); + BIND_ENUM_CONSTANT(INSTANCE_OCCLUDER); BIND_ENUM_CONSTANT(INSTANCE_MAX); BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK); BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT); BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_DYNAMIC_GI); BIND_ENUM_CONSTANT(INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE); + BIND_ENUM_CONSTANT(INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING); BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF); @@ -2282,8 +2299,12 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048); - GLOBAL_DEF("rendering/driver/rd_renderer/use_low_end_renderer", false); - GLOBAL_DEF("rendering/driver/rd_renderer/use_low_end_renderer.mobile", true); + GLOBAL_DEF_RST("rendering/vulkan/rendering/back_end", 0); + GLOBAL_DEF_RST("rendering/vulkan/rendering/back_end.mobile", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/vulkan/rendering/back_end", + PropertyInfo(Variant::INT, + "rendering/vulkan/rendering/back_end", + PROPERTY_HINT_ENUM, "ForwardClustered,ForwardMobile")); GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8); GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true); @@ -2340,6 +2361,10 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01")); + GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512); + GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/occlusion_culling/bvh_build_quality", PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High")); + GLOBAL_DEF("rendering/environment/glow/upscale_mode", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)")); GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 6a8bb83ec1..0c1a010f73 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -618,6 +618,12 @@ public: virtual RID particles_create() = 0; + enum ParticlesMode { + PARTICLES_MODE_2D, + PARTICLES_MODE_3D + }; + virtual void particles_set_mode(RID p_particles, ParticlesMode p_mode) = 0; + virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0; virtual bool particles_get_emitting(RID p_particles) = 0; virtual void particles_set_amount(RID p_particles, int p_amount) = 0; @@ -631,8 +637,22 @@ public: virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; + virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0; virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0; + + enum ParticlesTransformAlign { + PARTICLES_TRANSFORM_ALIGN_DISABLED, + PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD, + PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY, + PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY, + }; + + virtual void particles_set_transform_align(RID p_particles, ParticlesTransformAlign p_transform_align) = 0; + + virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length_sec) = 0; + virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0; + virtual bool particles_is_inactive(RID p_particles) = 0; virtual void particles_request_process(RID p_particles) = 0; virtual void particles_restart(RID p_particles) = 0; @@ -713,6 +733,11 @@ public: virtual void camera_set_camera_effects(RID p_camera, RID p_camera_effects) = 0; virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0; + /* OCCLUDER API */ + + virtual RID occluder_create() = 0; + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0; + /* VIEWPORT TARGET API */ enum CanvasItemTextureFilter { @@ -826,6 +851,17 @@ public: virtual void viewport_set_lod_threshold(RID p_viewport, float p_pixels) = 0; + virtual void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_debanding) = 0; + virtual void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) = 0; + + enum ViewportOcclusionCullingBuildQuality { + VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW = 0, + VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM = 1, + VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH = 2, + }; + + virtual void viewport_set_occlusion_culling_build_quality(ViewportOcclusionCullingBuildQuality p_quality) = 0; + enum ViewportRenderInfo { VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME, VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME, @@ -862,6 +898,7 @@ public: VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS, VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS, VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES, + VIEWPORT_DEBUG_DRAW_OCCLUDERS, }; virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0; @@ -1109,6 +1146,7 @@ public: INSTANCE_DECAL, INSTANCE_GI_PROBE, INSTANCE_LIGHTMAP, + INSTANCE_OCCLUDER, INSTANCE_MAX, INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES) @@ -1124,7 +1162,7 @@ public: virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; - virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; + virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0; @@ -1147,6 +1185,7 @@ public: INSTANCE_FLAG_USE_BAKED_LIGHT, INSTANCE_FLAG_USE_DYNAMIC_GI, INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, + INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, INSTANCE_FLAG_MAX }; @@ -1505,6 +1544,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA); VARIANT_ENUM_CAST(RenderingServer::ViewportScreenSpaceAA); VARIANT_ENUM_CAST(RenderingServer::ViewportRenderInfo); VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw); +VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality); VARIANT_ENUM_CAST(RenderingServer::SkyMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG); VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index d6d3c11cfb..8b03565291 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -291,6 +291,8 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size); ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box); + ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::_font_get_glyph_contours); + /* Shaped text buffer interface */ ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL)); @@ -403,6 +405,11 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM); BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE); BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA); + + /* FT Contour Point Types */ + BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_ON); + BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CONIC); + BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CUBIC); } Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) }; @@ -1212,6 +1219,21 @@ RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String return create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size); } +Dictionary TextServer::_font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index) const { + Vector<Vector3> points; + Vector<int32_t> contours; + bool orientation; + bool ok = font_get_glyph_contours(p_font, p_size, p_index, points, contours, orientation); + Dictionary out; + + if (ok) { + out["points"] = points; + out["contours"] = contours; + out["orientation"] = orientation; + } + return out; +} + void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { Vector<Vector2i> overrides; for (int i = 0; i < p_override.size(); i++) { diff --git a/servers/text_server.h b/servers/text_server.h index e1429da1d1..7fcfb91151 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -99,6 +99,12 @@ public: FEATURE_USE_SUPPORT_DATA = 1 << 7 }; + enum ContourPointTag { + CONTOUR_CURVE_TAG_ON = 0x01, + CONTOUR_CURVE_TAG_OFF_CONIC = 0x00, + CONTOUR_CURVE_TAG_OFF_CUBIC = 0x02 + }; + struct Glyph { int start = -1; // Start offset in the source string. int end = -1; // End offset in the source string. @@ -286,6 +292,8 @@ public: virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0; virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0; + virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const = 0; + virtual float font_get_oversampling() const = 0; virtual void font_set_oversampling(float p_oversampling) = 0; @@ -372,6 +380,8 @@ public: /* GDScript wrappers */ RID _create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16); + Dictionary _font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index) const; + Array _shaped_text_get_glyphs(RID p_shaped) const; Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const; @@ -454,5 +464,6 @@ VARIANT_ENUM_CAST(TextServer::LineBreakFlag); VARIANT_ENUM_CAST(TextServer::GraphemeFlag); VARIANT_ENUM_CAST(TextServer::Hinting); VARIANT_ENUM_CAST(TextServer::Feature); +VARIANT_ENUM_CAST(TextServer::ContourPointTag); #endif // TEXT_SERVER_H diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 420d818342..a5c6459471 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -43,8 +43,8 @@ This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking. */ -class XRPositionalTracker : public Object { - GDCLASS(XRPositionalTracker, Object); +class XRPositionalTracker : public Reference { + GDCLASS(XRPositionalTracker, Reference); _THREAD_SAFE_CLASS_ public: diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 2acc2e398c..5678071857 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -48,12 +48,17 @@ void XRServer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale"); + ClassDB::bind_method(D_METHOD("add_interface", "interface"), &XRServer::add_interface); + ClassDB::bind_method(D_METHOD("clear_primary_interface_if", "interface"), &XRServer::clear_primary_interface_if); ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count); + ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &XRServer::remove_interface); ClassDB::bind_method(D_METHOD("get_interface", "idx"), &XRServer::get_interface); ClassDB::bind_method(D_METHOD("get_interfaces"), &XRServer::get_interfaces); ClassDB::bind_method(D_METHOD("find_interface", "name"), &XRServer::find_interface); ClassDB::bind_method(D_METHOD("get_tracker_count"), &XRServer::get_tracker_count); ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &XRServer::get_tracker); + ClassDB::bind_method(D_METHOD("add_tracker", "tracker"), &XRServer::add_tracker); + ClassDB::bind_method(D_METHOD("remove_tracker", "tracker"), &XRServer::remove_tracker); ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface); ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface); @@ -260,15 +265,15 @@ int XRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) { return tracker_id; }; -void XRServer::add_tracker(XRPositionalTracker *p_tracker) { - ERR_FAIL_NULL(p_tracker); +void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) { + ERR_FAIL_COND(p_tracker.is_null()); trackers.push_back(p_tracker); emit_signal("tracker_added", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); }; -void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { - ERR_FAIL_NULL(p_tracker); +void XRServer::remove_tracker(Ref<XRPositionalTracker> p_tracker) { + ERR_FAIL_COND(p_tracker.is_null()); int idx = -1; for (int i = 0; i < trackers.size(); i++) { @@ -288,14 +293,14 @@ int XRServer::get_tracker_count() const { return trackers.size(); }; -XRPositionalTracker *XRServer::get_tracker(int p_index) const { - ERR_FAIL_INDEX_V(p_index, trackers.size(), nullptr); +Ref<XRPositionalTracker> XRServer::get_tracker(int p_index) const { + ERR_FAIL_INDEX_V(p_index, trackers.size(), Ref<XRPositionalTracker>()); return trackers[p_index]; }; -XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const { - ERR_FAIL_COND_V(p_tracker_id == 0, nullptr); +Ref<XRPositionalTracker> XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const { + ERR_FAIL_COND_V(p_tracker_id == 0, Ref<XRPositionalTracker>()); for (int i = 0; i < trackers.size(); i++) { if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { @@ -303,7 +308,7 @@ XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, i }; }; - return nullptr; + return Ref<XRPositionalTracker>(); }; Ref<XRInterface> XRServer::get_primary_interface() const { @@ -311,6 +316,7 @@ Ref<XRInterface> XRServer::get_primary_interface() const { }; void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) { + ERR_FAIL_COND(p_primary_interface.is_null()); primary_interface = p_primary_interface; print_verbose("XR: Primary interface set to: " + primary_interface->get_name()); diff --git a/servers/xr_server.h b/servers/xr_server.h index d3972be838..46243d7fd0 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -77,7 +77,7 @@ public: private: Vector<Ref<XRInterface>> interfaces; - Vector<XRPositionalTracker *> trackers; + Vector<Ref<XRPositionalTracker>> trackers; Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ @@ -167,11 +167,11 @@ public: */ bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const; int get_free_tracker_id_for_type(TrackerType p_tracker_type); - void add_tracker(XRPositionalTracker *p_tracker); - void remove_tracker(XRPositionalTracker *p_tracker); + void add_tracker(Ref<XRPositionalTracker> p_tracker); + void remove_tracker(Ref<XRPositionalTracker> p_tracker); int get_tracker_count() const; - XRPositionalTracker *get_tracker(int p_index) const; - XRPositionalTracker *find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const; + Ref<XRPositionalTracker> get_tracker(int p_index) const; + Ref<XRPositionalTracker> find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const; uint64_t get_last_process_usec(); uint64_t get_last_commit_usec(); |