summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/audio/effects/audio_effect_capture.cpp2
-rw-r--r--servers/audio/effects/audio_effect_chorus.cpp2
-rw-r--r--servers/camera/camera_feed.cpp10
-rw-r--r--servers/camera/camera_feed.h6
-rw-r--r--servers/camera_server.cpp2
-rw-r--r--servers/navigation_server_2d.cpp43
-rw-r--r--servers/navigation_server_2d.h15
-rw-r--r--servers/navigation_server_3d.cpp11
-rw-r--r--servers/navigation_server_3d.h15
-rw-r--r--servers/physics_2d/area_2d_sw.cpp8
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp43
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp19
-rw-r--r--servers/physics_2d/joints_2d_sw.h12
-rw-r--r--servers/physics_2d/space_2d_sw.cpp26
-rw-r--r--servers/physics_3d/area_3d_sw.cpp8
-rw-r--r--servers/physics_3d/body_3d_sw.cpp32
-rw-r--r--servers/physics_3d/body_3d_sw.h6
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp332
-rw-r--r--servers/physics_3d/body_pair_3d_sw.h85
-rw-r--r--servers/physics_3d/collision_object_3d_sw.h7
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp222
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp158
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.h6
-rw-r--r--servers/physics_3d/gjk_epa.cpp99
-rw-r--r--servers/physics_3d/gjk_epa.h2
-rw-r--r--servers/physics_3d/joints_3d_sw.h9
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp284
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h81
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h15
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp105
-rw-r--r--servers/physics_3d/shape_3d_sw.h28
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp1221
-rw-r--r--servers/physics_3d/soft_body_3d_sw.h247
-rw-r--r--servers/physics_3d/space_3d_sw.cpp74
-rw-r--r--servers/physics_3d/space_3d_sw.h6
-rw-r--r--servers/physics_3d/step_3d_sw.cpp33
-rw-r--r--servers/physics_server_3d.cpp5
-rw-r--r--servers/physics_server_3d.h26
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp12
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp126
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_environment_rd.h155
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp3403
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.h668
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp (renamed from servers/rendering/renderer_rd/renderer_scene_render_forward.cpp)273
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h (renamed from servers/rendering/renderer_rd/renderer_scene_render_forward.h)49
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp5115
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h990
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp1491
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.h292
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/SCsub55
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward.glsl)4
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl)2
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl2
-rw-r--r--servers/rendering/renderer_storage.h2
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h35
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h4
-rw-r--r--servers/rendering/shader_language.cpp33
-rw-r--r--servers/rendering_server.h2
-rw-r--r--servers/text_server.cpp27
-rw-r--r--servers/text_server.h28
-rw-r--r--servers/xr/xr_positional_tracker.h4
-rw-r--r--servers/xr_server.cpp24
-rw-r--r--servers/xr_server.h10
70 files changed, 9609 insertions, 6517 deletions
diff --git a/servers/audio/effects/audio_effect_capture.cpp b/servers/audio/effects/audio_effect_capture.cpp
index 37e4122e50..78837c7531 100644
--- a/servers/audio/effects/audio_effect_capture.cpp
+++ b/servers/audio/effects/audio_effect_capture.cpp
@@ -91,8 +91,6 @@ Ref<AudioEffectInstance> AudioEffectCapture::instance() {
}
void AudioEffectCapture::set_buffer_length(float p_buffer_length_seconds) {
- ERR_FAIL_COND(buffer_initialized);
-
buffer_length_seconds = p_buffer_length_seconds;
}
diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp
index 76a995eb37..eb2268aa2e 100644
--- a/servers/audio/effects/audio_effect_chorus.cpp
+++ b/servers/audio/effects/audio_effect_chorus.cpp
@@ -309,7 +309,7 @@ void AudioEffectChorus::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_dry", "amount"), &AudioEffectChorus::set_dry);
ClassDB::bind_method(D_METHOD("get_dry"), &AudioEffectChorus::get_dry);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "voice_count", PROPERTY_HINT_RANGE, "1,4,1"), "set_voice_count", "get_voice_count");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "voice_count", PROPERTY_HINT_RANGE, "1,4,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_voice_count", "get_voice_count");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dry", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dry", "get_dry");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wet", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_wet", "get_wet");
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index be812cf62d..eab4c61591 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -184,9 +184,10 @@ CameraFeed::~CameraFeed() {
#endif
}
-void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
+void CameraFeed::set_RGB_img(const Ref<Image> &p_rgb_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_rgb_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
@@ -207,9 +208,10 @@ void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
#endif
}
-void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
+void CameraFeed::set_YCbCr_img(const Ref<Image> &p_ycbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_ycbcr_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
@@ -230,9 +232,11 @@ void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
#endif
}
-void CameraFeed::set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img) {
+void CameraFeed::set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_y_img.is_null());
+ ERR_FAIL_COND(p_cbcr_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index fc02af4249..eb4ef155bc 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -100,9 +100,9 @@ public:
virtual ~CameraFeed();
FeedDataType get_datatype() const;
- void set_RGB_img(Ref<Image> p_rgb_img);
- void set_YCbCr_img(Ref<Image> p_ycbcr_img);
- void set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img);
+ void set_RGB_img(const Ref<Image> &p_rgb_img);
+ void set_YCbCr_img(const Ref<Image> &p_ycbcr_img);
+ void set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img);
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
void allocate_texture(int p_width, int p_height, Image::Format p_format, RenderingServer::TextureType p_texture_type, FeedDataType p_data_type);
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/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index df348d2add..9e32bc209b 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -80,6 +80,18 @@ NavigationServer2D *NavigationServer2D::singleton = nullptr;
return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3)); \
}
+#define FORWARD_5_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4))); \
+ }
+
+#define FORWARD_5_C(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4)); \
+ }
+
static RID rid_to_rid(const RID d) {
return d;
}
@@ -92,6 +104,10 @@ static int int_to_int(const int d) {
return d;
}
+static uint32_t uint32_to_uint32(const uint32_t d) {
+ return d;
+}
+
static real_t real_to_real(const real_t d) {
return d;
}
@@ -116,7 +132,8 @@ static Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) {
static Transform trf2_to_trf3(const Transform2D &d) {
Vector3 o(v2_to_v3(d.get_origin()));
Basis b;
- b.rotate(Vector3(0, 1, 0), d.get_rotation());
+ b.rotate(Vector3(0, -1, 0), d.get_rotation());
+ b.scale(v2_to_v3(d.get_scale()));
return Transform(b, o);
}
@@ -140,6 +157,10 @@ static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
}
}
+void NavigationServer2D::_emit_map_changed(RID p_map) {
+ emit_signal("map_changed", p_map);
+}
+
void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create);
ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active);
@@ -148,14 +169,19 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer2D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer2D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer2D::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize"), &NavigationServer2D::map_get_path);
+ ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "layers"), &NavigationServer2D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer2D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer2D::map_get_closest_point_owner);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer2D::region_set_map);
+ ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer2D::region_set_layers);
+ ClassDB::bind_method(D_METHOD("region_get_layers", "region"), &NavigationServer2D::region_get_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &NavigationServer2D::region_set_navpoly);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
@@ -171,10 +197,14 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &NavigationServer2D::agent_set_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("free", "object"), &NavigationServer2D::free);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
}
NavigationServer2D::NavigationServer2D() {
singleton = this;
+ ERR_FAIL_COND_MSG(!NavigationServer3D::get_singleton(), "The Navigation3D singleton should be initialized before the 2D one.");
+ NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed));
}
NavigationServer2D::~NavigationServer2D() {
@@ -193,20 +223,25 @@ real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid);
void FORWARD_2_C(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
-Vector<Vector2> FORWARD_4_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool);
+Vector<Vector2> FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_0_C(region_create);
void FORWARD_2_C(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
-
+void FORWARD_2_C(region_set_layers, RID, p_region, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
+uint32_t FORWARD_1_C(region_get_layers, RID, p_region, rid_to_rid);
void FORWARD_2_C(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3);
void NavigationServer2D::region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const {
NavigationServer3D::get_singleton()->region_set_navmesh(p_region, poly_to_mesh(p_nav_mesh));
}
+int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+
RID NavigationServer2D::agent_create() const {
RID agent = NavigationServer3D::get_singleton()->agent_create();
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, true);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 7be5a74cb3..d56c719839 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -45,12 +45,14 @@ class NavigationServer2D : public Object {
static NavigationServer2D *singleton;
+ void _emit_map_changed(RID p_map);
+
protected:
static void _bind_methods();
public:
/// Thread safe, can be used across many threads.
- static const NavigationServer2D *get_singleton() { return singleton; }
+ static NavigationServer2D *get_singleton() { return singleton; }
/// MUST be used in single thread!
static NavigationServer2D *get_singleton_mut() { return singleton; }
@@ -77,7 +79,7 @@ public:
virtual real_t map_get_edge_connection_margin(RID p_map) const;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector<Vector2> map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize) const;
+ virtual Vector<Vector2> map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const;
@@ -88,12 +90,21 @@ public:
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const;
+ /// Set the region's layers
+ virtual void region_set_layers(RID p_region, uint32_t p_layers) const;
+ virtual uint32_t region_get_layers(RID p_region) const;
+
/// Set the global transformation of this region.
virtual void region_set_transform(RID p_region, Transform2D p_transform) const;
/// Set the navigation poly of this region.
virtual void region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const;
+ /// Get a list of a region's connection to other regions.
+ virtual int region_get_connections_count(RID p_region) const;
+ virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
+ virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+
/// Creates the agent.
virtual RID agent_create() const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 0e5ae82b0d..b0047a250a 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -46,7 +46,7 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer3D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer3D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer3D::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize"), &NavigationServer3D::map_get_path);
+ ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "layers"), &NavigationServer3D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point_to_segment", "map", "start", "end", "use_collision"), &NavigationServer3D::map_get_closest_point_to_segment, DEFVAL(false));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer3D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_normal", "map", "to_point"), &NavigationServer3D::map_get_closest_point_normal);
@@ -54,9 +54,14 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer3D::region_set_map);
+ ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer3D::region_set_layers);
+ ClassDB::bind_method(D_METHOD("region_get_layers", "region"), &NavigationServer3D::region_get_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer3D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer3D::region_set_navmesh);
ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer3D::region_bake_navmesh);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer3D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
@@ -75,9 +80,11 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &NavigationServer3D::set_active);
ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
}
-const NavigationServer3D *NavigationServer3D::get_singleton() {
+NavigationServer3D *NavigationServer3D::get_singleton() {
return singleton;
}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 3761c3871a..420f9c9c18 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -55,7 +55,7 @@ protected:
public:
/// Thread safe, can be used across many threads.
- static const NavigationServer3D *get_singleton();
+ static NavigationServer3D *get_singleton();
/// MUST be used in single thread!
static NavigationServer3D *get_singleton_mut();
@@ -88,7 +88,7 @@ public:
virtual real_t map_get_edge_connection_margin(RID p_map) const = 0;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize) const = 0;
+ virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigable_layers = 1) const = 0;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const = 0;
virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const = 0;
@@ -101,15 +101,24 @@ public:
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const = 0;
+ /// Set the region's layers
+ virtual void region_set_layers(RID p_region, uint32_t p_layers) const = 0;
+ virtual uint32_t region_get_layers(RID p_region) const = 0;
+
/// Set the global transformation of this region.
virtual void region_set_transform(RID p_region, Transform p_transform) const = 0;
/// Set the navigation mesh of this region.
virtual void region_set_navmesh(RID p_region, Ref<NavigationMesh> p_nav_mesh) const = 0;
- /// Bake the navigation mesh
+ /// Bake the navigation mesh.
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0;
+ /// Get a list of a region's connection to other regions.
+ virtual int region_get_connections_count(RID p_region) const = 0;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
+
/// Creates the agent.
virtual RID agent_create() const = 0;
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/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index feced36a2b..da70ac7d4b 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -221,11 +221,21 @@ real_t combine_friction(Body2DSW *A, Body2DSW *B) {
bool BodyPair2DSW::setup(real_t p_step) {
//cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+ 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)) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
+ }
+
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
@@ -350,51 +360,44 @@ bool BodyPair2DSW::setup(real_t p_step) {
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);
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0 || !c.reused) {
- c.active = false;
continue;
}
- c.active = true;
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
#endif
- int gather_A = A->can_report_contacts();
- int gather_B = B->can_report_contacts();
c.rA = global_A;
c.rB = global_B - offset_B;
- if (gather_A | gather_B) {
- //Vector2 crB( -B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x );
-
- global_A += offset_A;
- global_B += offset_A;
+ if (A->can_report_contacts()) {
+ Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
+ A->add_contact(global_A + offset_A, -c.normal, depth, shape_A, global_B + offset_A, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
+ }
- if (gather_A) {
- Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
- A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
- }
- if (gather_B) {
- Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
- B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
- }
+ if (B->can_report_contacts()) {
+ Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
+ B->add_contact(global_B + offset_A, c.normal, depth, shape_B, global_A + offset_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
}
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
- c.active = false;
+ if (report_contacts_only) {
collided = false;
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);
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index f503868ba5..c7b556deba 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -205,15 +205,6 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p
}
}
-PinJoint2DSW::~PinJoint2DSW() {
- if (A) {
- A->remove_constraint(this, 0);
- }
- if (B) {
- B->remove_constraint(this, 1);
- }
-}
-
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
@@ -346,11 +337,6 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
B->add_constraint(this, 1);
}
-GrooveJoint2DSW::~GrooveJoint2DSW() {
- A->remove_constraint(this, 0);
- B->remove_constraint(this, 1);
-}
-
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
@@ -442,8 +428,3 @@ DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Ve
A->add_constraint(this, 0);
B->add_constraint(this, 1);
}
-
-DampedSpringJoint2DSW::~DampedSpringJoint2DSW() {
- A->remove_constraint(this, 0);
- B->remove_constraint(this, 1);
-}
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h
index 6050dc2775..628de972ae 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/joints_2d_sw.h
@@ -60,6 +60,15 @@ public:
bias = 0;
max_force = max_bias = 3.40282e+38;
};
+
+ virtual ~Joint2DSW() {
+ for (int i = 0; i < get_body_count(); i++) {
+ Body2DSW *body = get_body_ptr()[i];
+ if (body) {
+ body->remove_constraint(this, i);
+ }
+ }
+ };
};
class PinJoint2DSW : public Joint2DSW {
@@ -90,7 +99,6 @@ public:
real_t get_param(PhysicsServer2D::PinJointParam p_param) const;
PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = nullptr);
- ~PinJoint2DSW();
};
class GrooveJoint2DSW : public Joint2DSW {
@@ -124,7 +132,6 @@ public:
virtual void solve(real_t p_step);
GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b);
- ~GrooveJoint2DSW();
};
class DampedSpringJoint2DSW : public Joint2DSW {
@@ -160,7 +167,6 @@ public:
real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const;
DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b);
- ~DampedSpringJoint2DSW();
};
#endif // JOINTS_2D_SW_H
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 9cbc01d1d3..4f12248c3e 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -84,6 +84,10 @@ int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, S
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
Shape2DSW *shape = col_obj->get_shape(shape_idx);
Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point);
@@ -229,6 +233,10 @@ int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Trans
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_margin)) {
continue;
}
@@ -272,6 +280,10 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
//test initial overlap, does it collide if going all the way?
if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) {
@@ -346,12 +358,17 @@ bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D &
}
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
cbk.valid_dir = Vector2();
cbk.valid_depth = 0;
@@ -436,12 +453,17 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh
}
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
rcd.valid_dir = Vector2();
rcd.object = col_obj;
rcd.shape = shape_idx;
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/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 82356e77ef..64ba0cb09d 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -51,18 +51,18 @@ void Body3DSW::_update_transform_dependant() {
}
void Body3DSW::update_inertias() {
- //update shapes and motions
+ // Update shapes and motions.
switch (mode) {
case PhysicsServer3D::BODY_MODE_RIGID: {
- //update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
+ // Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
real_t total_area = 0;
for (int i = 0; i < get_shape_count(); i++) {
total_area += get_shape_area(i);
}
- // We have to recompute the center of mass
+ // We have to recompute the center of mass.
center_of_mass_local.zero();
for (int i = 0; i < get_shape_count(); i++) {
@@ -70,21 +70,24 @@ void Body3DSW::update_inertias() {
real_t mass = area * this->mass / total_area;
- // NOTE: we assume that the shape origin is also its center of mass
+ // NOTE: we assume that the shape origin is also its center of mass.
center_of_mass_local += mass * get_shape_transform(i).origin;
}
center_of_mass_local /= mass;
- // Recompute the inertia tensor
+ // Recompute the inertia tensor.
Basis inertia_tensor;
inertia_tensor.set_zero();
+ bool inertia_set = false;
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
continue;
}
+ inertia_set = true;
+
const Shape3DSW *shape = get_shape(i);
real_t area = get_shape_area(i);
@@ -102,7 +105,12 @@ void Body3DSW::update_inertias() {
inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
}
- // Compute the principal axes of inertia
+ // Set the inertia to a valid value when there are no valid shapes.
+ if (!inertia_set) {
+ inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0));
+ }
+
+ // Compute the principal axes of inertia.
principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
_inv_inertia = inertia_tensor.get_main_diagonal().inverse();
@@ -493,20 +501,18 @@ void Body3DSW::integrate_forces(real_t p_step) {
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
//compute motion, angular and etc. velocities from prev transform
- linear_velocity = (new_transform.origin - get_transform().origin) / p_step;
+ motion = new_transform.origin - get_transform().origin;
+ do_motion = true;
+ linear_velocity = motion / p_step;
//compute a FAKE angular velocity, not so easy
- Basis rot = new_transform.basis.orthonormalized().transposed() * get_transform().basis.orthonormalized();
+ Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed();
Vector3 axis;
real_t angle;
rot.get_axis_angle(axis, angle);
axis.normalize();
- angular_velocity = axis.normalized() * (angle / p_step);
-
- motion = new_transform.origin - get_transform().origin;
- do_motion = true;
-
+ angular_velocity = axis * (angle / p_step);
} else {
if (!omit_force_integration && !first_integration) {
//overridden by direct state query
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 8e21003a5f..e87ff2364b 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -290,10 +290,10 @@ public:
void update_inertias();
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
- _FORCE_INLINE_ Vector3 get_inv_inertia() const { return _inv_inertia; }
- _FORCE_INLINE_ Basis get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
+ _FORCE_INLINE_ const Vector3 &get_inv_inertia() const { return _inv_inertia; }
+ _FORCE_INLINE_ const Basis &get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
- _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
+ _FORCE_INLINE_ const Vector3 &get_gravity() const { return gravity; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock);
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
index 6012ff1522..36114c0c91 100644
--- a/servers/physics_3d/body_pair_3d_sw.cpp
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -49,12 +49,12 @@
#define MIN_VELOCITY 0.0001
#define MAX_BIAS_ROTATION (Math_PI / 8)
-void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
BodyPair3DSW *pair = (BodyPair3DSW *)p_userdata;
- pair->contact_added_callback(p_point_A, p_point_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
}
-void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
// check if we already have the contact
//Vector3 local_A = A->get_inv_transform().xform(p_point_A);
@@ -73,6 +73,8 @@ void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector
contact.acc_bias_impulse = 0;
contact.acc_bias_impulse_center_of_mass = 0;
contact.acc_tangent_impulse = Vector3();
+ contact.index_A = p_index_A;
+ contact.index_B = p_index_B;
contact.local_A = local_A;
contact.local_B = local_B;
contact.normal = (p_point_A - p_point_B).normalized();
@@ -211,11 +213,21 @@ real_t combine_friction(Body3DSW *A, Body3DSW *B) {
bool BodyPair3DSW::setup(real_t p_step) {
//cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+ 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)) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
+ }
+
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
@@ -279,12 +291,9 @@ bool BodyPair3DSW::setup(real_t p_step) {
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0) {
- c.active = false;
continue;
}
- c.active = true;
-
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
@@ -308,6 +317,11 @@ bool BodyPair3DSW::setup(real_t p_step) {
B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crB);
}
+ if (report_contacts_only) {
+ collided = false;
+ continue;
+ }
+
c.active = true;
// Precompute normal mass, tangent mass, and bias.
@@ -456,7 +470,7 @@ void BodyPair3DSW::solve(real_t p_step) {
}
BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B) :
- Constraint3DSW(_arr, 2) {
+ BodyContact3DSW(_arr, 2) {
A = p_A;
B = p_B;
shape_A = p_shape_A;
@@ -472,3 +486,305 @@ BodyPair3DSW::~BodyPair3DSW() {
A->remove_constraint(this);
B->remove_constraint(this);
}
+
+void BodySoftBodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ BodySoftBodyPair3DSW *pair = (BodySoftBodyPair3DSW *)p_userdata;
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+}
+
+void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+ Vector3 local_A = body->get_inv_transform().xform(p_point_A);
+ Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B);
+
+ Contact contact;
+ contact.index_A = p_index_A;
+ contact.index_B = p_index_B;
+ contact.acc_normal_impulse = 0;
+ contact.acc_bias_impulse = 0;
+ contact.acc_bias_impulse_center_of_mass = 0;
+ contact.acc_tangent_impulse = Vector3();
+ contact.local_A = local_A;
+ contact.local_B = local_B;
+ contact.normal = (p_point_A - p_point_B).normalized();
+ contact.mass_normal = 0;
+
+ // Attempt to determine if the contact will be reused.
+ real_t contact_recycle_radius = space->get_contact_recycle_radius();
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ if (c.index_B == p_index_B) {
+ if (c.local_A.distance_squared_to(local_A) < (contact_recycle_radius * contact_recycle_radius) &&
+ c.local_B.distance_squared_to(local_B) < (contact_recycle_radius * contact_recycle_radius)) {
+ contact.acc_normal_impulse = c.acc_normal_impulse;
+ contact.acc_bias_impulse = c.acc_bias_impulse;
+ contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass;
+ contact.acc_tangent_impulse = c.acc_tangent_impulse;
+ }
+ c = contact;
+ return;
+ }
+ }
+
+ contacts.push_back(contact);
+}
+
+void BodySoftBodyPair3DSW::validate_contacts() {
+ // Make sure to erase contacts that are no longer valid.
+ const Transform &transform_A = body->get_transform();
+
+ real_t contact_max_separation = space->get_contact_max_separation();
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+
+ Vector3 global_A = transform_A.xform(c.local_A);
+ Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
+
+ if (depth < -contact_max_separation || (global_B + c.normal * depth - global_A).length() > contact_max_separation) {
+ // Contact no longer needed, remove.
+ if ((contact_index + 1) < contact_count) {
+ // Swap with the last one.
+ SWAP(c, contacts[contact_count - 1]);
+ }
+
+ contact_index--;
+ contact_count--;
+ }
+ }
+
+ contacts.resize(contact_count);
+}
+
+bool BodySoftBodyPair3DSW::setup(real_t p_step) {
+ 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;
+ }
+
+ if (body->is_shape_set_as_disabled(body_shape)) {
+ collided = false;
+ return false;
+ }
+
+ const Transform &xform_Au = body->get_transform();
+ Transform xform_A = xform_Au * body->get_shape_transform(body_shape);
+
+ Transform xform_Bu = soft_body->get_transform();
+ Transform xform_B = xform_Bu * soft_body->get_shape_transform(0);
+
+ validate_contacts();
+
+ 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;
+
+ real_t max_penetration = space->get_contact_max_allowed_penetration();
+
+ real_t bias = (real_t)0.3;
+ if (shape_A_ptr->get_custom_bias()) {
+ bias = shape_A_ptr->get_custom_bias();
+ }
+
+ real_t inv_dt = 1.0 / 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];
+ c.active = false;
+
+ real_t node_inv_mass = soft_body->get_node_inv_mass(c.index_B);
+ if (node_inv_mass == 0.0) {
+ continue;
+ }
+
+ Vector3 global_A = xform_Au.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);
+
+ if (depth <= 0) {
+ continue;
+ }
+
+ c.active = true;
+
+#ifdef DEBUG_ENABLED
+
+ if (space->is_debugging_contacts()) {
+ space->add_debug_contact(global_A);
+ space->add_debug_contact(global_B);
+ }
+#endif
+
+ c.rA = global_A - xform_Au.origin - body->get_center_of_mass();
+ c.rB = global_B;
+
+ if (body->can_report_contacts()) {
+ Vector3 crA = body->get_angular_velocity().cross(c.rA) + body->get_linear_velocity();
+ 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) {
+ body->set_active(true);
+ }
+
+ // Precompute normal mass, tangent mass, and bias.
+ Vector3 inertia_A = body->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
+ real_t kNormal = body->get_inv_mass() + node_inv_mass;
+ kNormal += c.normal.dot(inertia_A.cross(c.rA));
+ c.mass_normal = 1.0f / kNormal;
+
+ c.bias = -bias * inv_dt * MIN(0.0f, -depth + max_penetration);
+ 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);
+ soft_body->apply_node_impulse(c.index_B, j_vec);
+ c.acc_bias_impulse = 0;
+ c.acc_bias_impulse_center_of_mass = 0;
+
+ c.bounce = body->get_bounce();
+
+ if (c.bounce) {
+ Vector3 crA = body->get_angular_velocity().cross(c.rA);
+ Vector3 dv = soft_body->get_node_velocity(c.index_B) - body->get_linear_velocity() - crA;
+
+ // Normal impulse.
+ c.bounce = c.bounce * dv.dot(c.normal);
+ }
+ }
+
+ return true;
+}
+
+void BodySoftBodyPair3DSW::solve(real_t p_step) {
+ if (!collided) {
+ return;
+ }
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ if (!c.active) {
+ continue;
+ }
+
+ c.active = false;
+
+ // Bias impulse.
+ Vector3 crbA = body->get_biased_angular_velocity().cross(c.rA);
+ Vector3 dbv = soft_body->get_node_biased_velocity(c.index_B) - body->get_biased_linear_velocity() - crbA;
+
+ real_t vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn = (-vbn + c.bias) * c.mass_normal;
+ real_t jbnOld = c.acc_bias_impulse;
+ c.acc_bias_impulse = MAX(jbnOld + jbn, 0.0f);
+
+ 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);
+ soft_body->apply_node_bias_impulse(c.index_B, jb);
+
+ crbA = body->get_biased_angular_velocity().cross(c.rA);
+ dbv = soft_body->get_node_biased_velocity(c.index_B) - body->get_biased_linear_velocity() - crbA;
+
+ vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn_com = (-vbn + c.bias) / (body->get_inv_mass() + soft_body->get_node_inv_mass(c.index_B));
+ real_t jbnOld_com = c.acc_bias_impulse_center_of_mass;
+ c.acc_bias_impulse_center_of_mass = MAX(jbnOld_com + jbn_com, 0.0f);
+
+ 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);
+ }
+
+ c.active = true;
+ }
+
+ Vector3 crA = body->get_angular_velocity().cross(c.rA);
+ Vector3 dv = soft_body->get_node_velocity(c.index_B) - body->get_linear_velocity() - crA;
+
+ // Normal impulse.
+ real_t vn = dv.dot(c.normal);
+
+ if (Math::abs(vn) > MIN_VELOCITY) {
+ real_t jn = -(c.bounce + vn) * c.mass_normal;
+ real_t jnOld = c.acc_normal_impulse;
+ c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
+
+ Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
+
+ body->apply_impulse(c.rA + body->get_center_of_mass(), -j);
+ soft_body->apply_node_impulse(c.index_B, j);
+
+ c.active = true;
+ }
+
+ // Friction impulse.
+ real_t friction = body->get_friction();
+
+ Vector3 lvA = body->get_linear_velocity() + body->get_angular_velocity().cross(c.rA);
+ Vector3 lvB = soft_body->get_node_velocity(c.index_B);
+ Vector3 dtv = lvB - lvA;
+
+ real_t tn = c.normal.dot(dtv);
+
+ // Tangential velocity.
+ Vector3 tv = dtv - c.normal * tn;
+ real_t tvl = tv.length();
+
+ if (tvl > MIN_VELOCITY) {
+ tv /= tvl;
+
+ Vector3 temp1 = body->get_inv_inertia_tensor().xform(c.rA.cross(tv));
+
+ real_t t = -tvl /
+ (body->get_inv_mass() + soft_body->get_node_inv_mass(c.index_B) + tv.dot(temp1.cross(c.rA)));
+
+ Vector3 jt = t * tv;
+
+ Vector3 jtOld = c.acc_tangent_impulse;
+ c.acc_tangent_impulse += jt;
+
+ real_t fi_len = c.acc_tangent_impulse.length();
+ real_t jtMax = c.acc_normal_impulse * friction;
+
+ if (fi_len > CMP_EPSILON && fi_len > jtMax) {
+ c.acc_tangent_impulse *= jtMax / fi_len;
+ }
+
+ jt = c.acc_tangent_impulse - jtOld;
+
+ body->apply_impulse(c.rA + body->get_center_of_mass(), -jt);
+ soft_body->apply_node_impulse(c.index_B, jt);
+
+ c.active = true;
+ }
+ }
+}
+
+BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) {
+ body = p_A;
+ soft_body = p_B;
+ body_shape = p_shape_A;
+ space = p_A->get_space();
+ body->add_constraint(this, 0);
+ soft_body->add_constraint(this);
+}
+
+BodySoftBodyPair3DSW::~BodySoftBodyPair3DSW() {
+ body->remove_constraint(this);
+ soft_body->remove_constraint(this);
+}
diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h
index 4d049eafdc..74dddfa6aa 100644
--- a/servers/physics_3d/body_pair_3d_sw.h
+++ b/servers/physics_3d/body_pair_3d_sw.h
@@ -28,32 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BODY_PAIR_SW_H
-#define BODY_PAIR_SW_H
+#ifndef BODY_PAIR_3D_SW_H
+#define BODY_PAIR_3D_SW_H
#include "body_3d_sw.h"
#include "constraint_3d_sw.h"
+#include "core/templates/local_vector.h"
+#include "soft_body_3d_sw.h"
-class BodyPair3DSW : public Constraint3DSW {
- enum {
- MAX_CONTACTS = 4
- };
-
- union {
- struct {
- Body3DSW *A;
- Body3DSW *B;
- };
-
- Body3DSW *_arr[2];
- };
-
- int shape_A;
- int shape_B;
-
+class BodyContact3DSW : public Constraint3DSW {
+protected:
struct Contact {
Vector3 position;
Vector3 normal;
+ int index_A, index_B;
Vector3 local_A, local_B;
real_t acc_normal_impulse; // accumulated normal impulse (Pn)
Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
@@ -68,22 +56,45 @@ class BodyPair3DSW : public Constraint3DSW {
Vector3 rA, rB; // Offset in world orientation with respect to center of mass
};
+ Vector3 sep_axis;
+ bool collided;
+
+ Space3DSW *space;
+
+ BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
+ Constraint3DSW(p_body_ptr, p_body_count) {
+ }
+};
+
+class BodyPair3DSW : public BodyContact3DSW {
+ enum {
+ MAX_CONTACTS = 4
+ };
+
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ int shape_A;
+ int shape_B;
+
Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection
- Vector3 sep_axis;
Contact contacts[MAX_CONTACTS];
int contact_count;
- bool collided;
- static void _contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ 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);
- void contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B);
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
void validate_contacts();
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);
- Space3DSW *space;
-
public:
bool setup(real_t p_step);
void solve(real_t p_step);
@@ -92,4 +103,26 @@ public:
~BodyPair3DSW();
};
-#endif // BODY_PAIR__SW_H
+class BodySoftBodyPair3DSW : public BodyContact3DSW {
+ Body3DSW *body;
+ SoftBody3DSW *soft_body;
+
+ int body_shape;
+
+ LocalVector<Contact> contacts;
+
+ 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);
+
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
+
+ void validate_contacts();
+
+public:
+ bool setup(real_t p_step);
+ void solve(real_t p_step);
+
+ BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B);
+ ~BodySoftBodyPair3DSW();
+};
+
+#endif // BODY_PAIR_3D_SW_H
diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h
index 3847b81381..85221b7746 100644
--- a/servers/physics_3d/collision_object_3d_sw.h
+++ b/servers/physics_3d/collision_object_3d_sw.h
@@ -48,7 +48,8 @@ class CollisionObject3DSW : public ShapeOwner3DSW {
public:
enum Type {
TYPE_AREA,
- TYPE_BODY
+ TYPE_BODY,
+ TYPE_SOFT_BODY,
};
private:
@@ -129,8 +130,8 @@ public:
_FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const { return shapes[p_index].aabb_cache; }
_FORCE_INLINE_ real_t get_shape_area(int p_index) const { return shapes[p_index].area_cache; }
- _FORCE_INLINE_ Transform get_transform() const { return transform; }
- _FORCE_INLINE_ Transform get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ const Transform &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform &get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space3DSW *get_space() const { return space; }
_FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
index f507cacdc3..9d5448dbfa 100644
--- a/servers/physics_3d/collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -74,9 +74,9 @@ struct _CollectorCallback {
_FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
if (swap) {
- callback(p_point_B, p_point_A, userdata);
+ callback(p_point_B, 0, p_point_A, 0, userdata);
} else {
- callback(p_point_A, p_point_B, userdata);
+ callback(p_point_A, 0, p_point_B, 0, userdata);
}
}
};
@@ -626,7 +626,7 @@ public:
}
}
- _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
+ _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis, bool p_directional = false) {
Vector3 axis = p_axis;
if (Math::abs(axis.x) < CMP_EPSILON &&
@@ -662,7 +662,12 @@ public:
//use the smallest depth
if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0
- min_B = -min_B;
+ if (p_directional) {
+ min_B = max_B;
+ axis = -axis;
+ } else {
+ min_B = -min_B;
+ }
}
if (max_B < min_B) {
@@ -680,7 +685,7 @@ public:
return true;
}
- static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+ static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata;
Vector3 axis = (p_point_B - p_point_A);
real_t depth = axis.length();
@@ -845,7 +850,7 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t
//capsule sphere 1, sphere
- Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis;
@@ -1006,23 +1011,31 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// edges and points of B
for (int i = 0; i < 3; i++) {
Vector3 n1 = vertex[i] - p_transform_a.origin;
+ if (n1.dot(normal) < 0.0) {
+ n1 *= -1.0;
+ }
- if (!separator.test_axis(n1.normalized())) {
+ if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
return;
}
Vector3 n2 = vertex[(i + 1) % 3] - vertex[i];
Vector3 axis = n1.cross(n2).cross(n2).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1148,7 +1161,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran
}
}
- Vector3 cyl_axis = p_transform_b.basis.get_axis(2).normalized();
+ Vector3 cyl_axis = p_transform_b.basis.get_axis(1).normalized();
// edges of A, capsule cylinder
@@ -1193,7 +1206,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran
// capsule balls, edges of A
for (int i = 0; i < 2; i++) {
- Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 sphere_pos = p_transform_b.origin + ((i == 0) ? capsule_axis : -capsule_axis);
@@ -1467,15 +1480,20 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// faces of A
for (int i = 0; i < 3; i++) {
Vector3 axis = p_transform_a.basis.get_axis(i).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1486,9 +1504,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
Vector3 e = vertex[i] - vertex[(i + 1) % 3];
for (int j = 0; j < 3; j++) {
- Vector3 axis = p_transform_a.basis.get_axis(j);
+ Vector3 axis = e.cross(p_transform_a.basis.get_axis(j)).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(e.cross(axis).normalized())) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1508,8 +1529,11 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
(cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
Vector3 axis_ab = support_a - vertex[v];
+ if (axis_ab.dot(normal) < 0.0) {
+ axis_ab *= -1.0;
+ }
- if (!separator.test_axis(axis_ab.normalized())) {
+ if (!separator.test_axis(axis_ab.normalized(), !face_B->backface_collision)) {
return;
}
@@ -1519,7 +1543,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
//a ->b
Vector3 axis_a = p_transform_a.basis.get_axis(i);
- if (!separator.test_axis(axis_ab.cross(axis_a).cross(axis_a).normalized())) {
+ Vector3 axis = axis_ab.cross(axis_a).cross(axis_a).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1544,7 +1573,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
Vector3 n = (p2 - p1);
- if (!separator.test_axis((point - p2).cross(n).cross(n).normalized())) {
+ Vector3 axis = (point - p2).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1569,8 +1603,8 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_
// some values
- Vector3 capsule_A_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5);
- Vector3 capsule_B_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+ Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_B_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis;
Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis;
@@ -1627,10 +1661,55 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p
SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ // Cylinder B end caps.
+ Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1).normalized();
+ if (!separator.test_axis(cylinder_B_axis)) {
+ return;
+ }
+
+ // Cylinder edge against capsule balls.
+
+ Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1);
+
+ Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis * (capsule_A->get_height() * 0.5);
+
+ if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_1).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_2).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ // Cylinder edge against capsule edge.
+
+ Vector3 center_diff = p_transform_b.origin - p_transform_a.origin;
+
+ if (!separator.test_axis(capsule_A_axis.cross(center_diff).cross(capsule_A_axis).normalized())) {
+ return;
+ }
+
+ if (!separator.test_axis(cylinder_B_axis.cross(center_diff).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ real_t proj = capsule_A_axis.cross(cylinder_B_axis).cross(cylinder_B_axis).dot(capsule_A_axis);
+ if (Math::is_zero_approx(proj)) {
+ // Parallel capsule and cylinder axes, handle with specific axes only.
+ // Note: GJKEPA with no margin can lead to degenerate cases in this situation.
+ separator.generate_contacts();
+ return;
+ }
+
CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points;
// Fallback to generic algorithm to find the best separating axis.
- if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) {
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
return;
}
@@ -1670,7 +1749,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf
for (int i = 0; i < edge_count; i++) {
// cylinder
Vector3 edge_axis = p_transform_b.basis.xform(vertices[edges[i].a]) - p_transform_b.basis.xform(vertices[edges[i].b]);
- Vector3 axis = edge_axis.cross(p_transform_a.basis.get_axis(2)).normalized();
+ Vector3 axis = edge_axis.cross(p_transform_a.basis.get_axis(1)).normalized();
if (!separator.test_axis(axis)) {
return;
@@ -1682,7 +1761,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf
for (int i = 0; i < 2; i++) {
// edges of B, capsule cylinder
- Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
Vector3 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis);
@@ -1714,24 +1793,35 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// edges of B, capsule cylinder
- Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
for (int i = 0; i < 3; i++) {
// edge-cylinder
Vector3 edge_axis = vertex[i] - vertex[(i + 1) % 3];
+
Vector3 axis = edge_axis.cross(capsule_axis).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
- if (!separator.test_axis((p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized())) {
+ Vector3 dir_axis = (p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized();
+ if (dir_axis.dot(normal) < 0.0) {
+ dir_axis *= -1.0;
+ }
+
+ if (!separator.test_axis(dir_axis, !face_B->backface_collision)) {
return;
}
@@ -1740,16 +1830,22 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
Vector3 sphere_pos = p_transform_a.origin + ((j == 0) ? capsule_axis : -capsule_axis);
Vector3 n1 = sphere_pos - vertex[i];
+ if (n1.dot(normal) < 0.0) {
+ n1 *= -1.0;
+ }
- if (!separator.test_axis(n1.normalized())) {
+ if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
return;
}
Vector3 n2 = edge_axis;
axis = n1.cross(n2).cross(n2);
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis.normalized())) {
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -1805,7 +1901,7 @@ static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &
CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points;
// Fallback to generic algorithm to find the best separating axis.
- if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) {
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
return;
}
@@ -1822,7 +1918,7 @@ static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Trans
CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin>::test_contact_points;
// Fallback to generic algorithm to find the best separating axis.
- if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) {
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
return;
}
@@ -1846,18 +1942,21 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
p_transform_b.xform(face_B->vertex[2]),
};
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
// Face B normal.
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
Vector3 cyl_axis = p_transform_a.basis.get_axis(1).normalized();
+ if (cyl_axis.dot(normal) < 0.0) {
+ cyl_axis *= -1.0;
+ }
// Cylinder end caps.
- {
- if (!separator.test_axis(cyl_axis)) {
- return;
- }
+ if (!separator.test_axis(cyl_axis, !face_B->backface_collision)) {
+ return;
}
// Edges of B, cylinder lateral surface.
@@ -1868,7 +1967,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
continue;
}
- if (!separator.test_axis(axis.normalized())) {
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -1877,8 +1980,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
for (int i = 0; i < 3; i++) {
const Vector3 &point = vertex[i];
Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1911,8 +2017,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
// Axis is orthogonal both to tangent and edge direction.
Vector3 axis = tangent.cross(edge_dir);
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis.normalized())) {
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -2052,7 +2161,9 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
@@ -2060,8 +2171,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int i = 0; i < face_count; i++) {
//Vector3 axis = p_transform_a.xform( faces[i].plane ).normal;
Vector3 axis = p_transform_a.basis.xform(faces[i].plane.normal).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2074,8 +2188,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
Vector3 axis = e1.cross(e2).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2087,7 +2204,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
Vector3 va = p_transform_a.xform(vertices[i]);
for (int j = 0; j < 3; j++) {
- if (!separator.test_axis((va - vertex[j]).normalized())) {
+ Vector3 axis = (va - vertex[j]).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2102,7 +2224,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int j = 0; j < 3; j++) {
Vector3 e3 = vertex[j];
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+ Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2116,7 +2243,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int j = 0; j < vertex_count; j++) {
Vector3 e3 = p_transform_a.xform(vertices[j]);
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+ Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
index fd9ea00d92..f655c4626c 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -30,6 +30,7 @@
#include "collision_solver_3d_sw.h"
#include "collision_solver_3d_sat.h"
+#include "soft_body_3d_sw.h"
#include "gjk_epa.h"
@@ -78,9 +79,9 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(supports[i], support_A, p_userdata);
+ p_result_callback(supports[i], 0, support_A, 0, p_userdata);
} else {
- p_result_callback(support_A, supports[i], p_userdata);
+ p_result_callback(support_A, 0, supports[i], 0, p_userdata);
}
}
}
@@ -113,14 +114,148 @@ bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(support_B, support_A, p_userdata);
+ p_result_callback(support_B, 0, support_A, 0, p_userdata);
} else {
- p_result_callback(support_A, support_B, p_userdata);
+ p_result_callback(support_A, 0, support_B, 0, p_userdata);
}
}
return true;
}
+struct _SoftBodyContactCollisionInfo {
+ int node_index = 0;
+ CollisionSolver3DSW::CallbackResult result_callback = nullptr;
+ void *userdata = nullptr;
+ bool swap_result = false;
+ int contact_count = 0;
+};
+
+void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ _SoftBodyContactCollisionInfo &cinfo = *(_SoftBodyContactCollisionInfo *)(p_userdata);
+
+ ++cinfo.contact_count;
+
+ if (cinfo.swap_result) {
+ cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata);
+ } else {
+ cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata);
+ }
+}
+
+struct _SoftBodyQueryInfo {
+ SoftBody3DSW *soft_body = nullptr;
+ const Shape3DSW *shape_A = nullptr;
+ const Shape3DSW *shape_B = nullptr;
+ Transform transform_A;
+ Transform node_transform;
+ _SoftBodyContactCollisionInfo contact_info;
+#ifdef DEBUG_ENABLED
+ int node_query_count = 0;
+ int convex_query_count = 0;
+#endif
+};
+
+bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void *p_userdata) {
+ _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
+
+ Vector3 node_position = query_cinfo.soft_body->get_node_position(p_node_index);
+
+ Transform transform_B;
+ transform_B.origin = query_cinfo.node_transform.xform(node_position);
+
+ query_cinfo.contact_info.node_index = p_node_index;
+ solve_static(query_cinfo.shape_A, query_cinfo.transform_A, query_cinfo.shape_B, transform_B, soft_body_contact_callback, &query_cinfo.contact_info);
+
+#ifdef DEBUG_ENABLED
+ ++query_cinfo.node_query_count;
+#endif
+
+ // Continue with the query.
+ return false;
+}
+
+void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex) {
+ _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
+
+ query_cinfo.shape_A = p_convex;
+
+ // Calculate AABB for internal soft body query (in world space).
+ AABB shape_aabb;
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis;
+ axis[i] = 1.0;
+
+ real_t smin, smax;
+ p_convex->project_range(axis, query_cinfo.transform_A, smin, smax);
+
+ shape_aabb.position[i] = smin;
+ shape_aabb.size[i] = smax - smin;
+ }
+
+ shape_aabb.grow_by(query_cinfo.soft_body->get_collision_margin());
+
+ query_cinfo.soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+
+#ifdef DEBUG_ENABLED
+ ++query_cinfo.convex_query_count;
+#endif
+}
+
+bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+ const SoftBodyShape3DSW *soft_body_shape_B = static_cast<const SoftBodyShape3DSW *>(p_shape_B);
+
+ SoftBody3DSW *soft_body = soft_body_shape_B->get_soft_body();
+ const Transform &world_to_local = soft_body->get_inv_transform();
+
+ const real_t collision_margin = soft_body->get_collision_margin();
+
+ SphereShape3DSW sphere_shape;
+ sphere_shape.set_data(collision_margin);
+
+ _SoftBodyQueryInfo query_cinfo;
+ query_cinfo.contact_info.result_callback = p_result_callback;
+ query_cinfo.contact_info.userdata = p_userdata;
+ query_cinfo.contact_info.swap_result = p_swap_result;
+ query_cinfo.soft_body = soft_body;
+ query_cinfo.node_transform = p_transform_B * world_to_local;
+ query_cinfo.shape_A = p_shape_A;
+ query_cinfo.transform_A = p_transform_A;
+ query_cinfo.shape_B = &sphere_shape;
+
+ if (p_shape_A->is_concave()) {
+ // In case of concave shape, query convex shapes first.
+ const ConcaveShape3DSW *concave_shape_A = static_cast<const ConcaveShape3DSW *>(p_shape_A);
+
+ AABB soft_body_aabb = soft_body->get_bounds();
+ soft_body_aabb.grow_by(collision_margin);
+
+ // Calculate AABB for internal concave shape query (in local space).
+ AABB local_aabb;
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis(p_transform_A.basis.get_axis(i));
+ real_t axis_scale = 1.0 / axis.length();
+
+ real_t smin = soft_body_aabb.position[i];
+ real_t smax = smin + soft_body_aabb.size[i];
+
+ smin *= axis_scale;
+ smax *= axis_scale;
+
+ local_aabb.position[i] = smin;
+ local_aabb.size[i] = smax - smin;
+ }
+
+ concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo);
+ } else {
+ AABB shape_aabb = p_transform_A.xform(p_shape_A->get_aabb());
+ shape_aabb.grow_by(collision_margin);
+
+ soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+ }
+
+ return (query_cinfo.contact_info.contact_count > 0);
+}
+
struct _ConcaveCollisionInfo {
const Transform *transform_A;
const Shape3DSW *shape_A;
@@ -215,6 +350,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
if (type_B == PhysicsServer3D::SHAPE_RAY) {
return false;
}
+ if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ return false;
+ }
if (swap) {
return solve_static_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
@@ -233,6 +371,18 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
return solve_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
+ } else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ // Soft Body / Soft Body not supported.
+ return false;
+ }
+
+ if (swap) {
+ return solve_soft_body(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ } else {
+ return solve_soft_body(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ }
+
} else if (concave_B) {
if (concave_A) {
return false;
diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h
index 81d87e9773..34ac2c6d3f 100644
--- a/servers/physics_3d/collision_solver_3d_sw.h
+++ b/servers/physics_3d/collision_solver_3d_sw.h
@@ -35,12 +35,16 @@
class CollisionSolver3DSW {
public:
- typedef void (*CallbackResult)(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
private:
+ static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata);
+ static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex);
static void concave_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_ray(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_concave(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
static void concave_distance_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B);
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index aa7c11eec5..1a8c7f704f 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -110,26 +110,60 @@ struct MinkowskiDiff {
Transform transform_A;
Transform transform_B;
+ real_t margin_A = 0.0;
+ real_t margin_B = 0.0;
+
+ Vector3 (*get_support)(const Shape3DSW*, const Vector3&, real_t);
+
+ void Initialize(const Shape3DSW* shape0, const Transform& wtrs0, const real_t margin0,
+ const Shape3DSW* shape1, const Transform& wtrs1, const real_t margin1) {
+ m_shapes[0] = shape0;
+ m_shapes[1] = shape1;
+ transform_A = wtrs0;
+ transform_B = wtrs1;
+ margin_A = margin0;
+ margin_B = margin1;
+
+ if ((margin0 > 0.0) || (margin1 > 0.0)) {
+ get_support = get_support_with_margin;
+ } else {
+ get_support = get_support_without_margin;
+ }
+ }
+
+ static Vector3 get_support_without_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) {
+ return p_shape->get_support(p_dir.normalized());
+ }
+
+ static Vector3 get_support_with_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) {
+ Vector3 local_dir_norm = p_dir;
+ if (local_dir_norm.length_squared() < CMP_EPSILON2) {
+ local_dir_norm = Vector3(-1.0, -1.0, -1.0);
+ }
+ local_dir_norm.normalize();
+
+ return p_shape->get_support(local_dir_norm) + p_margin * local_dir_norm;
+ }
+
// i wonder how this could be sped up... if it can
- _FORCE_INLINE_ Vector3 Support0 ( const Vector3& d ) const {
- return transform_A.xform( m_shapes[0]->get_support( transform_A.basis.xform_inv(d).normalized() ) );
+ _FORCE_INLINE_ Vector3 Support0(const Vector3& d) const {
+ return transform_A.xform(get_support(m_shapes[0], transform_A.basis.xform_inv(d), margin_A));
}
- _FORCE_INLINE_ Vector3 Support1 ( const Vector3& d ) const {
- return transform_B.xform( m_shapes[1]->get_support( transform_B.basis.xform_inv(d).normalized() ) );
+ _FORCE_INLINE_ Vector3 Support1(const Vector3& d) const {
+ return transform_B.xform(get_support(m_shapes[1], transform_B.basis.xform_inv(d), margin_B));
}
- _FORCE_INLINE_ Vector3 Support ( const Vector3& d ) const {
- return ( Support0 ( d )-Support1 ( -d ) );
+ _FORCE_INLINE_ Vector3 Support (const Vector3& d) const {
+ return (Support0(d) - Support1(-d));
}
- _FORCE_INLINE_ Vector3 Support ( const Vector3& d,U index ) const
- {
- if ( index ) {
- return ( Support1 ( d ) );
+ _FORCE_INLINE_ Vector3 Support(const Vector3& d, U index) const {
+ if (index) {
+ return Support1(d);
} else {
- return ( Support0 ( d ) );
-}
+ return Support0(d);
+ }
}
};
@@ -828,22 +862,17 @@ struct GJK
};
//
- static void Initialize( const Shape3DSW* shape0,const Transform& wtrs0,
- const Shape3DSW* shape1,const Transform& wtrs1,
+ static void Initialize( const Shape3DSW* shape0, const Transform& wtrs0, real_t margin0,
+ const Shape3DSW* shape1, const Transform& wtrs1, real_t margin1,
sResults& results,
- tShape& shape,
- bool withmargins)
+ tShape& shape)
{
/* Results */
- results.witnesses[0] =
- results.witnesses[1] = Vector3(0,0,0);
+ results.witnesses[0] = Vector3(0,0,0);
+ results.witnesses[1] = Vector3(0,0,0);
results.status = sResults::Separated;
/* Shape */
- shape.m_shapes[0] = shape0;
- shape.m_shapes[1] = shape1;
- shape.transform_A = wtrs0;
- shape.transform_B = wtrs1;
-
+ shape.Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1);
}
@@ -857,13 +886,15 @@ struct GJK
//
bool Distance( const Shape3DSW* shape0,
const Transform& wtrs0,
- const Shape3DSW* shape1,
+ real_t margin0,
+ const Shape3DSW* shape1,
const Transform& wtrs1,
+ real_t margin1,
const Vector3& guess,
sResults& results)
{
tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);
if(gjk_status==GJK::eStatus::Valid)
@@ -896,14 +927,16 @@ bool Distance( const Shape3DSW* shape0,
//
bool Penetration( const Shape3DSW* shape0,
const Transform& wtrs0,
- const Shape3DSW* shape1,
+ real_t margin0,
+ const Shape3DSW* shape1,
const Transform& wtrs1,
- const Vector3& guess,
+ real_t margin1,
+ const Vector3& guess,
sResults& results
)
{
tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
switch(gjk_status)
@@ -963,7 +996,7 @@ bool Penetration( const Shape3DSW* shape0,
bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) {
GjkEpa2::sResults res;
- if (GjkEpa2::Distance(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_transform_B.origin - p_transform_A.origin, res)) {
+ if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) {
r_result_A = res.witnesses[0];
r_result_B = res.witnesses[1];
return true;
@@ -972,15 +1005,15 @@ bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_t
return false;
}
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap) {
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) {
GjkEpa2::sResults res;
- if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_transform_B.origin - p_transform_A.origin, res)) {
+ if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) {
if (p_result_callback) {
if (p_swap) {
- p_result_callback(res.witnesses[1], res.witnesses[0], p_userdata);
+ p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, p_userdata);
} else {
- p_result_callback(res.witnesses[0], res.witnesses[1], p_userdata);
+ p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata);
}
}
return true;
diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h
index be3ba4e664..a7e2e1719e 100644
--- a/servers/physics_3d/gjk_epa.h
+++ b/servers/physics_3d/gjk_epa.h
@@ -34,7 +34,7 @@
#include "collision_solver_3d_sw.h"
#include "shape_3d_sw.h"
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false);
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0);
bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
#endif
diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h
index 1fe573c69e..225a71aca9 100644
--- a/servers/physics_3d/joints_3d_sw.h
+++ b/servers/physics_3d/joints_3d_sw.h
@@ -49,6 +49,15 @@ public:
_FORCE_INLINE_ Joint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
Constraint3DSW(p_body_ptr, p_body_count) {
}
+
+ virtual ~Joint3DSW() {
+ for (int i = 0; i < get_body_count(); i++) {
+ Body3DSW *body = get_body_ptr()[i];
+ if (body) {
+ body->remove_constraint(this);
+ }
+ }
+ }
};
#endif // JOINTS_SW_H
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index 735e9094d2..3d0063b0fa 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -611,9 +611,18 @@ uint32_t PhysicsServer3DSW::body_get_collision_mask(RID p_body) const {
void PhysicsServer3DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
Body3DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
+ if (body) {
+ body->set_instance_id(p_id);
+ return;
+ }
+
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ if (soft_body) {
+ soft_body->set_instance_id(p_id);
+ return;
+ }
- body->set_instance_id(p_id);
+ ERR_FAIL_MSG("Invalid ID.");
};
ObjectID PhysicsServer3DSW::body_get_object_instance_id(RID p_body) const {
@@ -893,6 +902,266 @@ PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
return direct_state;
}
+/* SOFT BODY */
+
+RID PhysicsServer3DSW::soft_body_create() {
+ SoftBody3DSW *soft_body = memnew(SoftBody3DSW);
+ RID rid = soft_body_owner.make_rid(soft_body);
+ soft_body->set_self(rid);
+ return rid;
+}
+
+void PhysicsServer3DSW::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->update_rendering_server(p_rendering_server_handler);
+}
+
+void PhysicsServer3DSW::soft_body_set_space(RID p_body, RID p_space) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ Space3DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (soft_body->get_space() == space) {
+ return;
+ }
+
+ soft_body->set_space(space);
+}
+
+RID PhysicsServer3DSW::soft_body_get_space(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, RID());
+
+ Space3DSW *space = soft_body->get_space();
+ if (!space) {
+ return RID();
+ }
+ return space->get_self();
+}
+
+void PhysicsServer3DSW::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_collision_layer(p_layer);
+}
+
+uint32_t PhysicsServer3DSW::soft_body_get_collision_layer(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0);
+
+ return soft_body->get_collision_layer();
+}
+
+void PhysicsServer3DSW::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_collision_mask(p_mask);
+}
+
+uint32_t PhysicsServer3DSW::soft_body_get_collision_mask(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0);
+
+ return soft_body->get_collision_mask();
+}
+
+void PhysicsServer3DSW::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->add_exception(p_body_b);
+}
+
+void PhysicsServer3DSW::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->remove_exception(p_body_b);
+}
+
+void PhysicsServer3DSW::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ for (int i = 0; i < soft_body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(soft_body->get_exceptions()[i]);
+ }
+}
+
+void PhysicsServer3DSW::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_state(p_state, p_variant);
+}
+
+Variant PhysicsServer3DSW::soft_body_get_state(RID p_body, BodyState p_state) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, Variant());
+
+ return soft_body->get_state(p_state);
+}
+
+void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_state(BODY_STATE_TRANSFORM, p_transform);
+}
+
+void PhysicsServer3DSW::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_ray_pickable(p_enable);
+}
+
+void PhysicsServer3DSW::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_iteration_count(p_simulation_precision);
+}
+
+int PhysicsServer3DSW::soft_body_get_simulation_precision(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_iteration_count();
+}
+
+void PhysicsServer3DSW::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_total_mass(p_total_mass);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_total_mass(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_total_mass();
+}
+
+void PhysicsServer3DSW::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_linear_stiffness(p_stiffness);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_linear_stiffness(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_linear_stiffness();
+}
+
+void PhysicsServer3DSW::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_pressure_coefficient(p_pressure_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_pressure_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_pressure_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_damping_coefficient(p_damping_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_damping_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_damping_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_drag_coefficient(p_drag_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_drag_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_drag_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_mesh(p_mesh);
+}
+
+AABB PhysicsServer3DSW::soft_body_get_bounds(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, AABB());
+
+ return soft_body->get_bounds();
+}
+
+void PhysicsServer3DSW::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_vertex_position(p_point_index, p_global_position);
+}
+
+Vector3 PhysicsServer3DSW::soft_body_get_point_global_position(RID p_body, int p_point_index) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, Vector3());
+
+ return soft_body->get_vertex_position(p_point_index);
+}
+
+void PhysicsServer3DSW::soft_body_remove_all_pinned_points(RID p_body) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->unpin_all_vertices();
+}
+
+void PhysicsServer3DSW::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ if (p_pin) {
+ soft_body->pin_vertex(p_point_index);
+ } else {
+ soft_body->unpin_vertex(p_point_index);
+ }
+}
+
+bool PhysicsServer3DSW::soft_body_is_point_pinned(RID p_body, int p_point_index) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, false);
+
+ return soft_body->is_vertex_pinned(p_point_index);
+}
+
/* JOINT API */
RID PhysicsServer3DSW::joint_create() {
@@ -1278,7 +1547,13 @@ void PhysicsServer3DSW::free(RID p_rid) {
body_owner.free(p_rid);
memdelete(body);
+ } else if (soft_body_owner.owns(p_rid)) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_rid);
+
+ soft_body->set_space(nullptr);
+ soft_body_owner.free(p_rid);
+ memdelete(soft_body);
} else if (area_owner.owns(p_rid)) {
Area3DSW *area = area_owner.getornull(p_rid);
@@ -1312,9 +1587,6 @@ void PhysicsServer3DSW::free(RID p_rid) {
} else if (joint_owner.owns(p_rid)) {
Joint3DSW *joint = joint_owner.getornull(p_rid);
- for (int i = 0; i < joint->get_body_count(); i++) {
- joint->get_body_ptr()[i]->remove_constraint(joint);
- }
joint_owner.free(p_rid);
memdelete(joint);
@@ -1447,7 +1719,7 @@ void PhysicsServer3DSW::_update_shapes() {
}
}
-void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
CollCbkData *cbk = (CollCbkData *)p_userdata;
if (cbk->max == 0) {
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index afda161fa8..f92652bfad 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -63,6 +63,7 @@ class PhysicsServer3DSW : public PhysicsServer3D {
mutable RID_PtrOwner<Space3DSW, true> space_owner;
mutable RID_PtrOwner<Area3DSW, true> area_owner;
mutable RID_PtrOwner<Body3DSW, true> body_owner;
+ mutable RID_PtrOwner<SoftBody3DSW, true> soft_body_owner;
mutable RID_PtrOwner<Joint3DSW, true> joint_owner;
//void _clear_query(QuerySW *p_query);
@@ -79,7 +80,7 @@ public:
Vector3 *ptr;
};
- static void _shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
virtual RID plane_shape_create() override;
virtual RID ray_shape_create() override;
@@ -252,68 +253,58 @@ public:
/* SOFT BODY */
- virtual RID soft_body_create() override { return RID(); }
+ virtual RID soft_body_create() override;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) override {}
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) override;
- virtual void soft_body_set_space(RID p_body, RID p_space) override {}
- virtual RID soft_body_get_space(RID p_body) const override { return RID(); }
+ virtual void soft_body_set_space(RID p_body, RID p_space) override;
+ virtual RID soft_body_get_space(RID p_body) const override;
- virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override {}
- virtual uint32_t soft_body_get_collision_layer(RID p_body) const override { return 0; }
+ virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override;
+ virtual uint32_t soft_body_get_collision_layer(RID p_body) const override;
- virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override {}
- virtual uint32_t soft_body_get_collision_mask(RID p_body) const override { return 0; }
+ virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override;
+ virtual uint32_t soft_body_get_collision_mask(RID p_body) const override;
- virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override {}
- virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override {}
- virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {}
+ virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override;
+ virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override;
+ virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override;
- virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override {}
- virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override { return Variant(); }
+ virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
+ virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override;
- virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override {}
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const override { return Vector3(); }
+ virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
- virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override {}
+ virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override {}
- virtual int soft_body_get_simulation_precision(RID p_body) const override { return 0; }
+ virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override;
+ virtual int soft_body_get_simulation_precision(RID p_body) const override;
- virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override {}
- virtual real_t soft_body_get_total_mass(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override;
+ virtual real_t soft_body_get_total_mass(RID p_body) const override;
- virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_linear_stiffness(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override;
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) const override;
- virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_angular_stiffness(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override;
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override;
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_volume_stiffness(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override;
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) const override;
- virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override {}
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override;
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) const override;
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) override {}
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override;
- virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override {}
- virtual real_t soft_body_get_damping_coefficient(RID p_body) const override { return 0.; }
+ virtual AABB soft_body_get_bounds(RID p_body) const override;
- virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override {}
- virtual real_t soft_body_get_drag_coefficient(RID p_body) const override { return 0.; }
+ virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override;
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override;
- virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override {}
-
- virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override {}
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override { return Vector3(); }
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const override { return Vector3(); }
-
- virtual void soft_body_remove_all_pinned_points(RID p_body) override {}
- virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override {}
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override { return false; }
+ virtual void soft_body_remove_all_pinned_points(RID p_body) override;
+ virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override;
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override;
/* JOINT API */
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index f60e1332d5..49ae60db92 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -273,7 +273,7 @@ public:
FUNCRID(soft_body)
- FUNC2(soft_body_update_rendering_server, RID, class SoftBodyRenderingServerHandler *)
+ FUNC2(soft_body_update_rendering_server, RID, class RenderingServerHandler *)
FUNC2(soft_body_set_space, RID, RID)
FUNC1RC(RID, soft_body_get_space, RID)
@@ -294,7 +294,6 @@ public:
FUNC2RC(Variant, soft_body_get_state, RID, BodyState);
FUNC2(soft_body_set_transform, RID, const Transform &);
- FUNC2RC(Vector3, soft_body_get_vertex_position, RID, int);
FUNC2(soft_body_set_simulation_precision, RID, int);
FUNC1RC(int, soft_body_get_simulation_precision, RID);
@@ -305,18 +304,9 @@ public:
FUNC2(soft_body_set_linear_stiffness, RID, real_t);
FUNC1RC(real_t, soft_body_get_linear_stiffness, RID);
- FUNC2(soft_body_set_angular_stiffness, RID, real_t);
- FUNC1RC(real_t, soft_body_get_angular_stiffness, RID);
-
- FUNC2(soft_body_set_volume_stiffness, RID, real_t);
- FUNC1RC(real_t, soft_body_get_volume_stiffness, RID);
-
FUNC2(soft_body_set_pressure_coefficient, RID, real_t);
FUNC1RC(real_t, soft_body_get_pressure_coefficient, RID);
- FUNC2(soft_body_set_pose_matching_coefficient, RID, real_t);
- FUNC1RC(real_t, soft_body_get_pose_matching_coefficient, RID);
-
FUNC2(soft_body_set_damping_coefficient, RID, real_t);
FUNC1RC(real_t, soft_body_get_damping_coefficient, RID);
@@ -325,9 +315,10 @@ public:
FUNC2(soft_body_set_mesh, RID, const REF &);
+ FUNC1RC(AABB, soft_body_get_bounds, RID);
+
FUNC3(soft_body_move_point, RID, int, const Vector3 &);
FUNC2RC(Vector3, soft_body_get_point_global_position, RID, int);
- FUNC2RC(Vector3, soft_body_get_point_offset, RID, int);
FUNC1(soft_body_remove_all_pinned_points, RID);
FUNC3(soft_body_pin_point, RID, int, bool);
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index 5bac4f19b9..bf0946a0e2 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -491,10 +491,10 @@ BoxShape3DSW::BoxShape3DSW() {
void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
Vector3 n = p_transform.basis.xform_inv(p_normal).normalized();
- real_t h = (n.z > 0) ? height : -height;
+ real_t h = (n.y > 0) ? height : -height;
n *= radius;
- n.z += h * 0.5;
+ n.y += h * 0.5;
r_max = p_normal.dot(p_transform.xform(n));
r_min = p_normal.dot(p_transform.xform(-n));
@@ -503,36 +503,36 @@ void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p
Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const {
Vector3 n = p_normal;
- real_t h = (n.z > 0) ? height : -height;
+ real_t h = (n.y > 0) ? height : -height;
n *= radius;
- n.z += h * 0.5;
+ n.y += h * 0.5;
return n;
}
void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
Vector3 n = p_normal;
- real_t d = n.z;
+ real_t d = n.y;
if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
// make it flat
- n.z = 0.0;
+ n.y = 0.0;
n.normalize();
n *= radius;
r_amount = 2;
r_type = FEATURE_EDGE;
r_supports[0] = n;
- r_supports[0].z += height * 0.5;
+ r_supports[0].y += height * 0.5;
r_supports[1] = n;
- r_supports[1].z -= height * 0.5;
+ r_supports[1].y -= height * 0.5;
} else {
real_t h = (d > 0) ? height : -height;
n *= radius;
- n.z += h * 0.5;
+ n.y += h * 0.5;
r_amount = 1;
r_type = FEATURE_POINT;
*r_supports = n;
@@ -551,7 +551,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
// test against cylinder and spheres :-|
- collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn);
+ collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn, 1);
if (collided) {
real_t d = norm.dot(auxres);
@@ -563,7 +563,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
}
- collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * 0.5), radius, &auxres, &auxn);
+ collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * 0.5, 0), radius, &auxres, &auxn);
if (collided) {
real_t d = norm.dot(auxres);
@@ -575,7 +575,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
}
- collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * -0.5), radius, &auxres, &auxn);
+ collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * -0.5, 0), radius, &auxres, &auxn);
if (collided) {
real_t d = norm.dot(auxres);
@@ -596,19 +596,19 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
bool CapsuleShape3DSW::intersect_point(const Vector3 &p_point) const {
- if (Math::abs(p_point.z) < height * 0.5) {
- return Vector3(p_point.x, p_point.y, 0).length() < radius;
+ if (Math::abs(p_point.y) < height * 0.5) {
+ return Vector3(p_point.x, 0, p_point.z).length() < radius;
} else {
Vector3 p = p_point;
- p.z = Math::abs(p.z) - height * 0.5;
+ p.y = Math::abs(p.y) - height * 0.5;
return p.length() < radius;
}
}
Vector3 CapsuleShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
Vector3 s[2] = {
- Vector3(0, 0, -height * 0.5),
- Vector3(0, 0, height * 0.5),
+ Vector3(0, -height * 0.5, 0),
+ Vector3(0, height * 0.5, 0),
};
Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s);
@@ -627,13 +627,13 @@ Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void CapsuleShape3DSW::_setup(real_t p_height, real_t p_radius) {
height = p_height;
radius = p_radius;
- configure(AABB(Vector3(-radius, -radius, -height * 0.5 - radius), Vector3(radius * 2, radius * 2, height + radius * 2.0)));
+ configure(AABB(Vector3(-radius, -height * 0.5 - radius, -radius), Vector3(radius * 2, height + radius * 2.0, radius * 2)));
}
void CapsuleShape3DSW::set_data(const Variant &p_data) {
@@ -807,7 +807,7 @@ Vector3 CylinderShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void CylinderShape3DSW::_setup(real_t p_height, real_t p_radius) {
@@ -1064,7 +1064,7 @@ Vector3 ConvexPolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) {
@@ -1134,7 +1134,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_
Vector3 n = p_normal;
/** TEST FACE AS SUPPORT **/
- if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+ if (Math::abs(normal.dot(n)) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
r_amount = 3;
r_type = FEATURE_FACE;
for (int i = 0; i < 3; i++) {
@@ -1187,7 +1187,11 @@ bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_e
if (c) {
r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
if (r_normal.dot(p_end - p_begin) > 0) {
- r_normal = -r_normal;
+ if (backface_collision) {
+ r_normal = -r_normal;
+ } else {
+ c = false;
+ }
}
}
@@ -1285,30 +1289,24 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par
}
if (bvh->face_index >= 0) {
- Vector3 res;
- Vector3 vertices[3] = {
- p_params->vertices[p_params->faces[bvh->face_index].indices[0]],
- p_params->vertices[p_params->faces[bvh->face_index].indices[1]],
- p_params->vertices[p_params->faces[bvh->face_index].indices[2]]
- };
+ const Face *f = &p_params->faces[bvh->face_index];
+ FaceShape3DSW *face = p_params->face;
+ face->normal = f->normal;
+ face->vertex[0] = p_params->vertices[f->indices[0]];
+ face->vertex[1] = p_params->vertices[f->indices[1]];
+ face->vertex[2] = p_params->vertices[f->indices[2]];
- if (Geometry3D::segment_intersects_triangle(
- p_params->from,
- p_params->to,
- vertices[0],
- vertices[1],
- vertices[2],
- &res)) {
+ Vector3 res;
+ Vector3 normal;
+ if (face->intersect_segment(p_params->from, p_params->to, res, normal)) {
real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
- //TODO, seems segmen/triangle intersection is broken :(
- if (d > 0 && d < p_params->min_d) {
+ if ((d > 0) && (d < p_params->min_d)) {
p_params->min_d = d;
p_params->result = res;
- p_params->normal = Plane(vertices[0], vertices[1], vertices[2]).normal;
+ p_params->normal = normal;
p_params->collisions++;
}
}
-
} else {
if (bvh->left >= 0) {
_cull_segment(bvh->left, p_params);
@@ -1329,17 +1327,20 @@ bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Ve
const Vector3 *vr = vertices.ptr();
const BVH *br = bvh.ptr();
+ FaceShape3DSW face;
+ face.backface_collision = backface_collision;
+
_SegmentCullParams params;
params.from = p_begin;
params.to = p_end;
- params.collisions = 0;
params.dir = (p_end - p_begin).normalized();
params.faces = fr;
params.vertices = vr;
params.bvh = br;
- params.min_d = 1e20;
+ params.face = &face;
+
// cull
_cull_segment(0, &params);
@@ -1401,6 +1402,7 @@ void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback
const BVH *br = bvh.ptr();
FaceShape3DSW face; // use this to send in the callback
+ face.backface_collision = backface_collision;
_CullParams params;
params.aabb = local_aabb;
@@ -1422,7 +1424,7 @@ Vector3 ConcavePolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
struct _VolumeSW_BVH_Element {
@@ -1532,7 +1534,7 @@ void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_ar
memdelete(p_bvh_tree);
}
-void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
+void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) {
int src_face_count = p_faces.size();
if (src_face_count == 0) {
configure(AABB());
@@ -1587,15 +1589,24 @@ void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
int idx = 0;
_fill_bvh(bvh_tree, bvh_arrayw2, idx);
+ backface_collision = p_backface_collision;
+
configure(_aabb); // this type of shape has no margin
}
void ConcavePolygonShape3DSW::set_data(const Variant &p_data) {
- _setup(p_data);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("faces"));
+
+ _setup(d["faces"], d["backface_collision"]);
}
Variant ConcavePolygonShape3DSW::get_data() const {
- return get_faces();
+ Dictionary d;
+ d["faces"] = get_faces();
+ d["backface_collision"] = backface_collision;
+
+ return d;
}
ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {
@@ -1651,7 +1662,7 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (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) {
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index cafe978abb..988e76c699 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -334,34 +334,37 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
struct _CullParams {
AABB aabb;
- Callback callback;
- void *userdata;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
- FaceShape3DSW *face;
+ Callback callback = nullptr;
+ void *userdata = nullptr;
+ const Face *faces = nullptr;
+ const Vector3 *vertices = nullptr;
+ const BVH *bvh = nullptr;
+ FaceShape3DSW *face = nullptr;
};
struct _SegmentCullParams {
Vector3 from;
Vector3 to;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
Vector3 dir;
+ const Face *faces = nullptr;
+ const Vector3 *vertices = nullptr;
+ const BVH *bvh = nullptr;
+ FaceShape3DSW *face = nullptr;
Vector3 result;
Vector3 normal;
- real_t min_d;
- int collisions;
+ real_t min_d = 1e20;
+ int collisions = 0;
};
+ bool backface_collision = false;
+
void _cull_segment(int p_idx, _SegmentCullParams *p_params) const;
void _cull(int p_idx, _CullParams *p_params) const;
void _fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx);
- void _setup(Vector<Vector3> p_faces);
+ void _setup(const Vector<Vector3> &p_faces, bool p_backface_collision);
public:
Vector<Vector3> get_faces() const;
@@ -424,6 +427,7 @@ public:
struct FaceShape3DSW : public Shape3DSW {
Vector3 normal; //cache
Vector3 vertex[3];
+ bool backface_collision = false;
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
new file mode 100644
index 0000000000..f63a470cbe
--- /dev/null
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -0,0 +1,1221 @@
+/*************************************************************************/
+/* soft_body_3d_sw.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 "soft_body_3d_sw.h"
+#include "space_3d_sw.h"
+
+#include "core/math/geometry_3d.h"
+#include "core/templates/map.h"
+
+// Based on Bullet soft body.
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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.
+*/
+///btSoftBody implementation by Nathanael Presson
+
+SoftBody3DSW::SoftBody3DSW() :
+ CollisionObject3DSW(TYPE_SOFT_BODY),
+ active_list(this) {
+ _set_static(false);
+}
+
+void SoftBody3DSW::_shapes_changed() {
+}
+
+void SoftBody3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().inverse());
+
+ apply_nodes_transform(get_transform());
+
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+ // Not supported.
+ ERR_FAIL_MSG("Linear velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ ERR_FAIL_MSG("Angular velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
+ } break;
+ }
+}
+
+Variant SoftBody3DSW::get_state(PhysicsServer3D::BodyState p_state) const {
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+ return get_transform();
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+ ERR_FAIL_V_MSG(Vector3(), "Linear velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ ERR_FAIL_V_MSG(Vector3(), "Angular velocity is not supported for Soft bodies.");
+ return Vector3();
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
+ } break;
+ }
+
+ return Variant();
+}
+
+void SoftBody3DSW::set_space(Space3DSW *p_space) {
+ if (get_space()) {
+ get_space()->soft_body_remove_from_active_list(&active_list);
+
+ deinitialize_shape();
+ }
+
+ _set_space(p_space);
+
+ if (get_space()) {
+ get_space()->soft_body_add_to_active_list(&active_list);
+
+ if (bounds != AABB()) {
+ initialize_shape(true);
+ }
+ }
+}
+
+void SoftBody3DSW::set_mesh(const Ref<Mesh> &p_mesh) {
+ destroy();
+
+ soft_mesh = p_mesh;
+
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ Array arrays = soft_mesh->surface_get_arrays(0);
+ ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & RS::ARRAY_FORMAT_INDEX));
+
+ bool success = create_from_trimesh(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
+ if (!success) {
+ destroy();
+ soft_mesh = Ref<Mesh>();
+ }
+}
+
+void SoftBody3DSW::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ const uint32_t vertex_count = map_visual_to_physics.size();
+ for (uint32_t i = 0; i < vertex_count; ++i) {
+ const uint32_t node_index = map_visual_to_physics[i];
+ const Node &node = nodes[node_index];
+ const Vector3 &vertex_position = node.x;
+ const Vector3 &vertex_normal = node.n;
+
+ p_rendering_server_handler->set_vertex(i, &vertex_position);
+ p_rendering_server_handler->set_normal(i, &vertex_normal);
+ }
+
+ p_rendering_server_handler->set_aabb(bounds);
+}
+
+void SoftBody3DSW::update_normals() {
+ uint32_t i, ni;
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ nodes[i].n = Vector3();
+ }
+
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ Face &face = faces[i];
+ const Vector3 n = vec3_cross(face.n[0]->x - face.n[2]->x, face.n[0]->x - face.n[1]->x);
+ face.n[0]->n += n;
+ face.n[1]->n += n;
+ face.n[2]->n += n;
+ face.normal = n;
+ face.normal.normalize();
+ }
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ real_t len = node.n.length();
+ if (len > CMP_EPSILON) {
+ node.n /= len;
+ }
+ }
+}
+
+void SoftBody3DSW::update_bounds() {
+ AABB prev_bounds = bounds;
+ prev_bounds.grow_by(collision_margin);
+
+ bounds = AABB();
+
+ const uint32_t nodes_count = nodes.size();
+ if (nodes_count == 0) {
+ deinitialize_shape();
+ return;
+ }
+
+ bool first = true;
+ bool moved = false;
+ for (uint32_t node_index = 0; node_index < nodes_count; ++node_index) {
+ const Node &node = nodes[node_index];
+ if (!prev_bounds.has_point(node.x)) {
+ moved = true;
+ }
+ if (first) {
+ bounds.position = node.x;
+ first = false;
+ } else {
+ bounds.expand_to(node.x);
+ }
+ }
+
+ if (get_space()) {
+ initialize_shape(moved);
+ }
+}
+
+void SoftBody3DSW::update_constants() {
+ reset_link_rest_lengths();
+ update_link_constants();
+ update_area();
+}
+
+void SoftBody3DSW::update_area() {
+ int i, ni;
+
+ // Face area.
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ Face &face = faces[i];
+
+ const Vector3 &x0 = face.n[0]->x;
+ const Vector3 &x1 = face.n[1]->x;
+ const Vector3 &x2 = face.n[2]->x;
+
+ const Vector3 a = x1 - x0;
+ const Vector3 b = x2 - x0;
+ const Vector3 cr = vec3_cross(a, b);
+ face.ra = cr.length();
+ }
+
+ // Node area.
+ LocalVector<int> counts;
+ counts.resize(nodes.size());
+ memset(counts.ptr(), 0, counts.size() * sizeof(int));
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ nodes[i].area = 0.0;
+ }
+
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ const Face &face = faces[i];
+ for (int j = 0; j < 3; ++j) {
+ const int index = (int)(face.n[j] - &nodes[0]);
+ counts[index]++;
+ face.n[j]->area += Math::abs(face.ra);
+ }
+ }
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ if (counts[i] > 0) {
+ nodes[i].area /= (real_t)counts[i];
+ } else {
+ nodes[i].area = 0.0;
+ }
+ }
+}
+
+void SoftBody3DSW::reset_link_rest_lengths() {
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.rl = (link.n[0]->x - link.n[1]->x).length();
+ link.c1 = link.rl * link.rl;
+ }
+}
+
+void SoftBody3DSW::update_link_constants() {
+ real_t inv_linear_stiffness = 1.0 / linear_stiffness;
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.c0 = (link.n[0]->im + link.n[1]->im) * inv_linear_stiffness;
+ }
+}
+
+void SoftBody3DSW::apply_nodes_transform(const Transform &p_transform) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ uint32_t node_count = nodes.size();
+ Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
+ for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
+ Node &node = nodes[node_index];
+
+ node.x = p_transform.xform(node.x);
+ node.q = node.x;
+ node.v = Vector3();
+ node.bv = Vector3();
+
+ AABB node_aabb(node.x, leaf_size);
+ node_tree.update(node.leaf, node_aabb);
+ }
+
+ face_tree.clear();
+
+ update_normals();
+ update_bounds();
+ update_constants();
+}
+
+Vector3 SoftBody3DSW::get_vertex_position(int p_index) const {
+ if (soft_mesh.is_null()) {
+ return Vector3();
+ }
+
+ ERR_FAIL_INDEX_V(p_index, (int)map_visual_to_physics.size(), Vector3());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3());
+ return nodes[node_index].x;
+}
+
+void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.q = node.x;
+ node.x = p_position;
+}
+
+void SoftBody3DSW::pin_vertex(int p_index) {
+ if (is_vertex_pinned(p_index)) {
+ return;
+ }
+
+ pinned_vertices.push_back(p_index);
+
+ if (!soft_mesh.is_null()) {
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.im = 0.0;
+ }
+}
+
+void SoftBody3DSW::unpin_vertex(int p_index) {
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ if (p_index == pinned_vertices[i]) {
+ pinned_vertices.remove(i);
+
+ if (!soft_mesh.is_null()) {
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ real_t inv_node_mass = nodes.size() * inv_total_mass;
+
+ Node &node = nodes[node_index];
+ node.im = inv_node_mass;
+ }
+
+ return;
+ }
+ }
+}
+
+void SoftBody3DSW::unpin_all_vertices() {
+ if (!soft_mesh.is_null()) {
+ real_t inv_node_mass = nodes.size() * inv_total_mass;
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ uint32_t vertex_index = pinned_vertices[i];
+
+ ERR_CONTINUE(vertex_index >= map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[vertex_index];
+
+ ERR_CONTINUE(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.im = inv_node_mass;
+ }
+ }
+
+ pinned_vertices.clear();
+}
+
+bool SoftBody3DSW::is_vertex_pinned(int p_index) const {
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ if (p_index == pinned_vertices[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint32_t SoftBody3DSW::get_node_count() const {
+ return nodes.size();
+}
+
+real_t SoftBody3DSW::get_node_inv_mass(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), 0.0);
+ return nodes[p_node_index].im;
+}
+
+Vector3 SoftBody3DSW::get_node_position(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].x;
+}
+
+Vector3 SoftBody3DSW::get_node_velocity(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].v;
+}
+
+Vector3 SoftBody3DSW::get_node_biased_velocity(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].bv;
+}
+
+void SoftBody3DSW::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND(p_node_index >= nodes.size());
+ Node &node = nodes[p_node_index];
+ node.v += p_impulse * node.im;
+}
+
+void SoftBody3DSW::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND(p_node_index >= nodes.size());
+ Node &node = nodes[p_node_index];
+ node.bv += p_impulse * node.im;
+}
+
+uint32_t SoftBody3DSW::get_face_count() const {
+ return faces.size();
+}
+
+void SoftBody3DSW::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const {
+ ERR_FAIL_COND(p_face_index >= faces.size());
+ const Face &face = faces[p_face_index];
+ r_point_1 = face.n[0]->x;
+ r_point_2 = face.n[1]->x;
+ r_point_3 = face.n[2]->x;
+}
+
+Vector3 SoftBody3DSW::get_face_normal(uint32_t p_face_index) const {
+ ERR_FAIL_COND_V(p_face_index >= faces.size(), Vector3());
+ return faces[p_face_index].normal;
+}
+
+bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) {
+ uint32_t node_count = 0;
+ LocalVector<Vector3> vertices;
+ const int visual_vertex_count(p_vertices.size());
+
+ LocalVector<int> triangles;
+ const uint32_t triangle_count(p_indices.size() / 3);
+ triangles.resize(triangle_count * 3);
+
+ // Merge all overlapping vertices and create a map of physical vertices to visual vertices.
+ {
+ // Process vertices.
+ {
+ uint32_t vertex_count = 0;
+ Map<Vector3, uint32_t> unique_vertices;
+
+ vertices.resize(visual_vertex_count);
+ map_visual_to_physics.resize(visual_vertex_count);
+
+ for (int visual_vertex_index = 0; visual_vertex_index < visual_vertex_count; ++visual_vertex_index) {
+ const Vector3 &vertex = p_vertices[visual_vertex_index];
+
+ Map<Vector3, uint32_t>::Element *e = unique_vertices.find(vertex);
+ uint32_t vertex_id;
+ if (e) {
+ // Already existing.
+ vertex_id = e->value();
+ } else {
+ // Create new one.
+ vertex_id = vertex_count++;
+ unique_vertices[vertex] = vertex_id;
+ vertices[vertex_id] = vertex;
+ }
+
+ map_visual_to_physics[visual_vertex_index] = vertex_id;
+ }
+
+ vertices.resize(vertex_count);
+ }
+
+ // Process triangles.
+ {
+ for (uint32_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) {
+ for (int i = 0; i < 3; ++i) {
+ int visual_index = 3 * triangle_index + i;
+ int physics_index = map_visual_to_physics[p_indices[visual_index]];
+ triangles[visual_index] = physics_index;
+ node_count = MAX((int)node_count, physics_index);
+ }
+ }
+ }
+ }
+
+ ++node_count;
+
+ // Create nodes from vertices.
+ nodes.resize(node_count);
+ real_t inv_node_mass = node_count * inv_total_mass;
+ Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
+ for (uint32_t i = 0; i < node_count; ++i) {
+ Node &node = nodes[i];
+ node.s = vertices[i];
+ node.x = node.s;
+ node.q = node.s;
+ node.im = inv_node_mass;
+
+ AABB node_aabb(node.x, leaf_size);
+ node.leaf = node_tree.insert(node_aabb, &node);
+
+ node.index = i;
+ }
+
+ // Create links and faces from triangles.
+ LocalVector<bool> chks;
+ chks.resize(node_count * node_count);
+ memset(chks.ptr(), 0, chks.size() * sizeof(bool));
+
+ for (uint32_t i = 0; i < triangle_count * 3; i += 3) {
+ const int idx[] = { triangles[i], triangles[i + 1], triangles[i + 2] };
+
+ for (int j = 2, k = 0; k < 3; j = k++) {
+ int chk = idx[k] * node_count + idx[j];
+ if (!chks[chk]) {
+ chks[chk] = true;
+ int inv_chk = idx[j] * node_count + idx[k];
+ chks[inv_chk] = true;
+
+ append_link(idx[j], idx[k]);
+ }
+ }
+
+ append_face(idx[0], idx[1], idx[2]);
+ }
+
+ // Set pinned nodes.
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ int pinned_vertex = pinned_vertices[i];
+
+ ERR_CONTINUE(pinned_vertex >= visual_vertex_count);
+ uint32_t node_index = map_visual_to_physics[pinned_vertex];
+
+ ERR_CONTINUE(node_index >= node_count);
+ Node &node = nodes[node_index];
+ node.im = 0.0;
+ }
+
+ generate_bending_constraints(2);
+ reoptimize_link_order();
+
+ update_constants();
+ update_normals();
+ update_bounds();
+
+ return true;
+}
+
+void SoftBody3DSW::generate_bending_constraints(int p_distance) {
+ uint32_t i, j;
+
+ if (p_distance > 1) {
+ // Build graph.
+ const uint32_t n = nodes.size();
+ const unsigned inf = (~(unsigned)0) >> 1;
+ const uint32_t adj_size = n * n;
+ unsigned *adj = memnew_arr(unsigned, adj_size);
+
+#define IDX(_x_, _y_) ((_y_)*n + (_x_))
+ for (j = 0; j < n; ++j) {
+ for (i = 0; i < n; ++i) {
+ int idx_ij = j * n + i;
+ int idx_ji = i * n + j;
+ if (i != j) {
+ adj[idx_ij] = adj[idx_ji] = inf;
+ } else {
+ adj[idx_ij] = adj[idx_ji] = 0;
+ }
+ }
+ }
+ for (i = 0; i < links.size(); ++i) {
+ const int ia = (int)(links[i].n[0] - &nodes[0]);
+ const int ib = (int)(links[i].n[1] - &nodes[0]);
+ int idx = ib * n + ia;
+ int idx_inv = ia * n + ib;
+ adj[idx] = 1;
+ adj[idx_inv] = 1;
+ }
+
+ // Special optimized case for distance == 2.
+ if (p_distance == 2) {
+ LocalVector<LocalVector<int>> node_links;
+
+ // Build node links.
+ node_links.resize(nodes.size());
+
+ for (i = 0; i < links.size(); ++i) {
+ const int ia = (int)(links[i].n[0] - &nodes[0]);
+ const int ib = (int)(links[i].n[1] - &nodes[0]);
+ if (node_links[ia].find(ib) == -1) {
+ node_links[ia].push_back(ib);
+ }
+
+ if (node_links[ib].find(ia) == -1) {
+ node_links[ib].push_back(ia);
+ }
+ }
+ for (uint32_t ii = 0; ii < node_links.size(); ii++) {
+ for (uint32_t jj = 0; jj < node_links[ii].size(); jj++) {
+ int k = node_links[ii][jj];
+ for (uint32_t kk = 0; kk < node_links[k].size(); kk++) {
+ int l = node_links[k][kk];
+ if ((int)ii != l) {
+ int idx_ik = k * n + ii;
+ int idx_kj = l * n + k;
+ const unsigned sum = adj[idx_ik] + adj[idx_kj];
+ ERR_FAIL_COND(sum != 2);
+ int idx_ij = l * n + ii;
+ if (adj[idx_ij] > sum) {
+ int idx_ji = l * n + ii;
+ adj[idx_ij] = adj[idx_ji] = sum;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // Generic Floyd's algorithm.
+ for (uint32_t k = 0; k < n; ++k) {
+ for (j = 0; j < n; ++j) {
+ for (i = j + 1; i < n; ++i) {
+ int idx_ik = k * n + i;
+ int idx_kj = j * n + k;
+ const unsigned sum = adj[idx_ik] + adj[idx_kj];
+ int idx_ij = j * n + i;
+ if (adj[idx_ij] > sum) {
+ int idx_ji = j * n + i;
+ adj[idx_ij] = adj[idx_ji] = sum;
+ }
+ }
+ }
+ }
+ }
+
+ // Build links.
+ for (j = 0; j < n; ++j) {
+ for (i = j + 1; i < n; ++i) {
+ int idx_ij = j * n + i;
+ if (adj[idx_ij] == (unsigned)p_distance) {
+ append_link(i, j);
+ }
+ }
+ }
+ memdelete_arr(adj);
+ }
+}
+
+//===================================================================
+//
+//
+// This function takes in a list of interdependent Links and tries
+// to maximize the distance between calculation
+// of dependent links. This increases the amount of parallelism that can
+// be exploited by out-of-order instruction processors with large but
+// (inevitably) finite instruction windows.
+//
+//===================================================================
+
+// A small structure to track lists of dependent link calculations.
+class LinkDeps {
+public:
+ int value; // A link calculation that is dependent on this one
+ // Positive values = "input A" while negative values = "input B"
+ LinkDeps *next; // Next dependence in the list
+};
+typedef LinkDeps *LinkDepsPtr;
+
+void SoftBody3DSW::reoptimize_link_order() {
+ const int reop_not_dependent = -1;
+ const int reop_node_complete = -2;
+
+ uint32_t i, link_count = links.size(), node_count = nodes.size();
+ Link *lr;
+ int ar, br;
+ Node *node0 = &(nodes[0]);
+ Node *node1 = &(nodes[1]);
+ LinkDepsPtr link_dep;
+ int ready_list_head, ready_list_tail, link_num, link_dep_frees, dep_link;
+
+ // Allocate temporary buffers.
+ int *node_written_at = memnew_arr(int, node_count + 1); // What link calculation produced this node's current values?
+ int *link_dep_A = memnew_arr(int, link_count); // Link calculation input is dependent upon prior calculation #N
+ int *link_dep_B = memnew_arr(int, link_count);
+ int *ready_list = memnew_arr(int, link_count); // List of ready-to-process link calculations (# of links, maximum)
+ LinkDeps *link_dep_free_list = memnew_arr(LinkDeps, 2 * link_count); // Dependent-on-me list elements (2x# of links, maximum)
+ LinkDepsPtr *link_dep_list_starts = memnew_arr(LinkDepsPtr, link_count); // Start nodes of dependent-on-me lists, one for each link
+
+ // Copy the original, unsorted links to a side buffer.
+ Link *link_buffer = memnew_arr(Link, link_count);
+ memcpy(link_buffer, &(links[0]), sizeof(Link) * link_count);
+
+ // Clear out the node setup and ready list.
+ for (i = 0; i < node_count + 1; i++) {
+ node_written_at[i] = reop_not_dependent;
+ }
+ for (i = 0; i < link_count; i++) {
+ link_dep_list_starts[i] = nullptr;
+ }
+ ready_list_head = ready_list_tail = link_dep_frees = 0;
+
+ // Initial link analysis to set up data structures.
+ for (i = 0; i < link_count; i++) {
+ // Note which prior link calculations we are dependent upon & build up dependence lists.
+ lr = &(links[i]);
+ ar = (lr->n[0] - node0) / (node1 - node0);
+ br = (lr->n[1] - node0) / (node1 - node0);
+ if (node_written_at[ar] > reop_not_dependent) {
+ link_dep_A[i] = node_written_at[ar];
+ link_dep = &link_dep_free_list[link_dep_frees++];
+ link_dep->value = i;
+ link_dep->next = link_dep_list_starts[node_written_at[ar]];
+ link_dep_list_starts[node_written_at[ar]] = link_dep;
+ } else {
+ link_dep_A[i] = reop_not_dependent;
+ }
+ if (node_written_at[br] > reop_not_dependent) {
+ link_dep_B[i] = node_written_at[br];
+ link_dep = &link_dep_free_list[link_dep_frees++];
+ link_dep->value = -(int)(i + 1);
+ link_dep->next = link_dep_list_starts[node_written_at[br]];
+ link_dep_list_starts[node_written_at[br]] = link_dep;
+ } else {
+ link_dep_B[i] = reop_not_dependent;
+ }
+
+ // Add this link to the initial ready list, if it is not dependent on any other links.
+ if ((link_dep_A[i] == reop_not_dependent) && (link_dep_B[i] == reop_not_dependent)) {
+ ready_list[ready_list_tail++] = i;
+ link_dep_A[i] = link_dep_B[i] = reop_node_complete; // Probably not needed now.
+ }
+
+ // Update the nodes to mark which ones are calculated by this link.
+ node_written_at[ar] = node_written_at[br] = i;
+ }
+
+ // Process the ready list and create the sorted list of links:
+ // -- By treating the ready list as a queue, we maximize the distance between any
+ // inter-dependent node calculations.
+ // -- All other (non-related) nodes in the ready list will automatically be inserted
+ // in between each set of inter-dependent link calculations by this loop.
+ i = 0;
+ while (ready_list_head != ready_list_tail) {
+ // Use ready list to select the next link to process.
+ link_num = ready_list[ready_list_head++];
+ // Copy the next-to-calculate link back into the original link array.
+ links[i++] = link_buffer[link_num];
+
+ // Free up any link inputs that are dependent on this one.
+ link_dep = link_dep_list_starts[link_num];
+ while (link_dep) {
+ dep_link = link_dep->value;
+ if (dep_link >= 0) {
+ link_dep_A[dep_link] = reop_not_dependent;
+ } else {
+ dep_link = -dep_link - 1;
+ link_dep_B[dep_link] = reop_not_dependent;
+ }
+ // Add this dependent link calculation to the ready list if *both* inputs are clear.
+ if ((link_dep_A[dep_link] == reop_not_dependent) && (link_dep_B[dep_link] == reop_not_dependent)) {
+ ready_list[ready_list_tail++] = dep_link;
+ link_dep_A[dep_link] = link_dep_B[dep_link] = reop_node_complete; // Probably not needed now.
+ }
+ link_dep = link_dep->next;
+ }
+ }
+
+ // Delete the temporary buffers.
+ memdelete_arr(node_written_at);
+ memdelete_arr(link_dep_A);
+ memdelete_arr(link_dep_B);
+ memdelete_arr(ready_list);
+ memdelete_arr(link_dep_free_list);
+ memdelete_arr(link_dep_list_starts);
+ memdelete_arr(link_buffer);
+}
+
+void SoftBody3DSW::append_link(uint32_t p_node1, uint32_t p_node2) {
+ if (p_node1 == p_node2) {
+ return;
+ }
+
+ Node *node1 = &nodes[p_node1];
+ Node *node2 = &nodes[p_node2];
+
+ Link link;
+ link.n[0] = node1;
+ link.n[1] = node2;
+ link.rl = (node1->x - node2->x).length();
+
+ links.push_back(link);
+}
+
+void SoftBody3DSW::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) {
+ if (p_node1 == p_node2) {
+ return;
+ }
+ if (p_node1 == p_node3) {
+ return;
+ }
+ if (p_node2 == p_node3) {
+ return;
+ }
+
+ Node *node1 = &nodes[p_node1];
+ Node *node2 = &nodes[p_node2];
+ Node *node3 = &nodes[p_node3];
+
+ Face face;
+ face.n[0] = node1;
+ face.n[1] = node2;
+ face.n[2] = node3;
+
+ face.index = faces.size();
+
+ faces.push_back(face);
+}
+
+void SoftBody3DSW::set_iteration_count(int p_val) {
+ iteration_count = p_val;
+}
+
+void SoftBody3DSW::set_total_mass(real_t p_val) {
+ ERR_FAIL_COND(p_val < 0.0);
+
+ inv_total_mass = 1.0 / p_val;
+ real_t mass_factor = total_mass * inv_total_mass;
+ total_mass = p_val;
+
+ uint32_t node_count = nodes.size();
+ for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
+ Node &node = nodes[node_index];
+ node.im *= mass_factor;
+ }
+
+ update_constants();
+}
+
+void SoftBody3DSW::set_collision_margin(real_t p_val) {
+ collision_margin = p_val;
+}
+
+void SoftBody3DSW::set_linear_stiffness(real_t p_val) {
+ linear_stiffness = p_val;
+}
+
+void SoftBody3DSW::set_pressure_coefficient(real_t p_val) {
+ pressure_coefficient = p_val;
+}
+
+void SoftBody3DSW::set_damping_coefficient(real_t p_val) {
+ damping_coefficient = p_val;
+}
+
+void SoftBody3DSW::set_drag_coefficient(real_t p_val) {
+ drag_coefficient = p_val;
+}
+
+void SoftBody3DSW::add_velocity(const Vector3 &p_velocity) {
+ for (uint32_t i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ if (node.im > 0) {
+ node.v += p_velocity;
+ }
+ }
+}
+
+void SoftBody3DSW::apply_forces() {
+ if (pressure_coefficient < CMP_EPSILON) {
+ return;
+ }
+
+ if (nodes.is_empty()) {
+ return;
+ }
+
+ uint32_t i, ni;
+
+ // Calculate volume.
+ real_t volume = 0.0;
+ const Vector3 &org = nodes[0].x;
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ const Face &face = faces[i];
+ volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org));
+ }
+ volume /= 6.0;
+
+ // Apply per node forces.
+ real_t ivolumetp = 1.0 / Math::abs(volume) * pressure_coefficient;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ if (node.im > 0) {
+ node.f += node.n * (node.area * ivolumetp);
+ }
+ }
+}
+
+void SoftBody3DSW::predict_motion(real_t p_delta) {
+ const real_t inv_delta = 1.0 / p_delta;
+
+ ERR_FAIL_COND(!get_space());
+
+ Area3DSW *def_area = get_space()->get_default_area();
+ ERR_FAIL_COND(!def_area);
+
+ // Apply forces.
+ Vector3 gravity = def_area->get_gravity_vector() * def_area->get_gravity();
+ add_velocity(gravity * p_delta);
+ apply_forces();
+
+ // Avoid soft body from 'exploding' so use some upper threshold of maximum motion
+ // that a node can travel per frame.
+ const real_t max_displacement = 1000.0;
+ real_t clamp_delta_v = max_displacement * inv_delta;
+
+ // Integrate.
+ uint32_t i, ni;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ node.q = node.x;
+ Vector3 delta_v = node.f * node.im * p_delta;
+ for (int c = 0; c < 3; c++) {
+ delta_v[c] = CLAMP(delta_v[c], -clamp_delta_v, clamp_delta_v);
+ }
+ node.v += delta_v;
+ node.x += node.v * p_delta;
+ node.f = Vector3();
+ }
+
+ // Bounds and tree update.
+ update_bounds();
+
+ // Node tree update.
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ const Node &node = nodes[i];
+
+ AABB node_aabb(node.x, Vector3());
+ node_aabb.expand_to(node.x + node.v * p_delta);
+ node_aabb.grow_by(collision_margin);
+
+ node_tree.update(node.leaf, node_aabb);
+ }
+
+ // Face tree update.
+ if (!face_tree.is_empty()) {
+ update_face_tree(p_delta);
+ }
+
+ // Optimize node tree.
+ node_tree.optimize_incremental(1);
+ face_tree.optimize_incremental(1);
+}
+
+void SoftBody3DSW::solve_constraints(real_t p_delta) {
+ const real_t inv_delta = 1.0 / p_delta;
+
+ uint32_t i, ni;
+
+ for (i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.c3 = link.n[1]->q - link.n[0]->q;
+ link.c2 = 1 / (link.c3.length_squared() * link.c0);
+ }
+
+ // Solve velocities.
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ node.x = node.q + node.v * p_delta;
+ }
+
+ // Solve positions.
+ for (int isolve = 0; isolve < iteration_count; ++isolve) {
+ const real_t ti = isolve / (real_t)iteration_count;
+ solve_links(1.0, ti);
+ }
+ const real_t vc = (1.0 - damping_coefficient) * inv_delta;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+
+ node.x += node.bv * p_delta;
+ node.bv = Vector3();
+
+ node.v = (node.x - node.q) * vc;
+
+ node.q = node.x;
+ }
+
+ update_normals();
+}
+
+void SoftBody3DSW::solve_links(real_t kst, real_t ti) {
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ if (link.c0 > 0) {
+ Node &node_a = *link.n[0];
+ Node &node_b = *link.n[1];
+ const Vector3 del = node_b.x - node_a.x;
+ const real_t len = del.length_squared();
+ if (link.c1 + len > CMP_EPSILON) {
+ const real_t k = ((link.c1 - len) / (link.c0 * (link.c1 + len))) * kst;
+ node_a.x -= del * (k * node_a.im);
+ node_b.x += del * (k * node_b.im);
+ }
+ }
+ }
+}
+
+struct AABBQueryResult {
+ const SoftBody3DSW *soft_body = nullptr;
+ void *userdata = nullptr;
+ SoftBody3DSW::QueryResultCallback result_callback = nullptr;
+
+ _FORCE_INLINE_ bool operator()(void *p_data) {
+ return result_callback(soft_body->get_node_index(p_data), userdata);
+ };
+};
+
+void SoftBody3DSW::query_aabb(const AABB &p_aabb, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) {
+ AABBQueryResult query_result;
+ query_result.soft_body = this;
+ query_result.result_callback = p_result_callback;
+ query_result.userdata = p_userdata;
+
+ node_tree.aabb_query(p_aabb, query_result);
+}
+
+struct RayQueryResult {
+ const SoftBody3DSW *soft_body = nullptr;
+ void *userdata = nullptr;
+ SoftBody3DSW::QueryResultCallback result_callback = nullptr;
+
+ _FORCE_INLINE_ bool operator()(void *p_data) {
+ return result_callback(soft_body->get_face_index(p_data), userdata);
+ };
+};
+
+void SoftBody3DSW::query_ray(const Vector3 &p_from, const Vector3 &p_to, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) {
+ if (face_tree.is_empty()) {
+ initialize_face_tree();
+ }
+
+ RayQueryResult query_result;
+ query_result.soft_body = this;
+ query_result.result_callback = p_result_callback;
+ query_result.userdata = p_userdata;
+
+ face_tree.ray_query(p_from, p_to, query_result);
+}
+
+void SoftBody3DSW::initialize_face_tree() {
+ face_tree.clear();
+ for (uint32_t i = 0; i < faces.size(); ++i) {
+ Face &face = faces[i];
+
+ AABB face_aabb;
+
+ face_aabb.position = face.n[0]->x;
+ face_aabb.expand_to(face.n[1]->x);
+ face_aabb.expand_to(face.n[2]->x);
+
+ face_aabb.grow_by(collision_margin);
+
+ face.leaf = face_tree.insert(face_aabb, &face);
+ }
+}
+
+void SoftBody3DSW::update_face_tree(real_t p_delta) {
+ for (uint32_t i = 0; i < faces.size(); ++i) {
+ const Face &face = faces[i];
+
+ AABB face_aabb;
+
+ const Node *node0 = face.n[0];
+ face_aabb.position = node0->x;
+ face_aabb.expand_to(node0->x + node0->v * p_delta);
+
+ const Node *node1 = face.n[1];
+ face_aabb.expand_to(node1->x);
+ face_aabb.expand_to(node1->x + node1->v * p_delta);
+
+ const Node *node2 = face.n[2];
+ face_aabb.expand_to(node2->x);
+ face_aabb.expand_to(node2->x + node2->v * p_delta);
+
+ face_aabb.grow_by(collision_margin);
+
+ face_tree.update(face.leaf, face_aabb);
+ }
+}
+
+void SoftBody3DSW::initialize_shape(bool p_force_move) {
+ if (get_shape_count() == 0) {
+ SoftBodyShape3DSW *soft_body_shape = memnew(SoftBodyShape3DSW(this));
+ add_shape(soft_body_shape);
+ } else if (p_force_move) {
+ SoftBodyShape3DSW *soft_body_shape = static_cast<SoftBodyShape3DSW *>(get_shape(0));
+ soft_body_shape->update_bounds();
+ }
+}
+
+void SoftBody3DSW::deinitialize_shape() {
+ if (get_shape_count() > 0) {
+ Shape3DSW *shape = get_shape(0);
+ remove_shape(shape);
+ memdelete(shape);
+ }
+}
+
+void SoftBody3DSW::destroy() {
+ map_visual_to_physics.clear();
+
+ node_tree.clear();
+ face_tree.clear();
+
+ nodes.clear();
+ links.clear();
+ faces.clear();
+
+ bounds = AABB();
+ deinitialize_shape();
+}
+
+void SoftBodyShape3DSW::update_bounds() {
+ ERR_FAIL_COND(!soft_body);
+
+ AABB collision_aabb = soft_body->get_bounds();
+ collision_aabb.grow_by(soft_body->get_collision_margin());
+ configure(collision_aabb);
+}
+
+SoftBodyShape3DSW::SoftBodyShape3DSW(SoftBody3DSW *p_soft_body) {
+ soft_body = p_soft_body;
+ update_bounds();
+}
+
+struct _SoftBodyIntersectSegmentInfo {
+ const SoftBody3DSW *soft_body = nullptr;
+ Vector3 from;
+ Vector3 dir;
+ Vector3 hit_position;
+ uint32_t hit_face_index = -1;
+ real_t hit_dist_sq = Math_INF;
+
+ static bool process_hit(uint32_t p_face_index, void *p_userdata) {
+ _SoftBodyIntersectSegmentInfo &query_info = *(_SoftBodyIntersectSegmentInfo *)(p_userdata);
+
+ Vector3 points[3];
+ query_info.soft_body->get_face_points(p_face_index, points[0], points[1], points[2]);
+
+ Vector3 result;
+ if (Geometry3D::ray_intersects_triangle(query_info.from, query_info.dir, points[0], points[1], points[2], &result)) {
+ real_t dist_sq = query_info.from.distance_squared_to(result);
+ if (dist_sq < query_info.hit_dist_sq) {
+ query_info.hit_dist_sq = dist_sq;
+ query_info.hit_position = result;
+ query_info.hit_face_index = p_face_index;
+ }
+ }
+
+ // Continue with the query.
+ return false;
+ }
+};
+
+bool SoftBodyShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+ _SoftBodyIntersectSegmentInfo query_info;
+ query_info.soft_body = soft_body;
+ query_info.from = p_begin;
+ query_info.dir = (p_end - p_begin).normalized();
+
+ soft_body->query_ray(p_begin, p_end, _SoftBodyIntersectSegmentInfo::process_hit, &query_info);
+
+ if (query_info.hit_dist_sq != Math_INF) {
+ r_result = query_info.hit_position;
+ r_normal = soft_body->get_face_normal(query_info.hit_face_index);
+ return true;
+ }
+
+ return false;
+}
+
+bool SoftBodyShape3DSW::intersect_point(const Vector3 &p_point) const {
+ return false;
+}
+
+Vector3 SoftBodyShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+ ERR_FAIL_V_MSG(Vector3(), "Get closest point is not supported for soft bodies.");
+}
diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h
new file mode 100644
index 0000000000..6c0451ff45
--- /dev/null
+++ b/servers/physics_3d/soft_body_3d_sw.h
@@ -0,0 +1,247 @@
+/*************************************************************************/
+/* soft_body_3d_sw.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 SOFT_BODY_3D_SW_H
+#define SOFT_BODY_3D_SW_H
+
+#include "collision_object_3d_sw.h"
+
+#include "core/math/aabb.h"
+#include "core/math/dynamic_bvh.h"
+#include "core/math/vector3.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/set.h"
+#include "core/templates/vset.h"
+#include "scene/resources/mesh.h"
+
+class Constraint3DSW;
+
+class SoftBody3DSW : public CollisionObject3DSW {
+ Ref<Mesh> soft_mesh;
+
+ struct Node {
+ Vector3 s; // Source position
+ Vector3 x; // Position
+ Vector3 q; // Previous step position/Test position
+ Vector3 f; // Force accumulator
+ Vector3 v; // Velocity
+ Vector3 bv; // Biased Velocity
+ Vector3 n; // Normal
+ real_t area = 0.0; // Area
+ real_t im = 0.0; // 1/mass
+ DynamicBVH::ID leaf; // Leaf data
+ uint32_t index = 0;
+ };
+
+ struct Link {
+ Vector3 c3; // gradient
+ Node *n[2] = { nullptr, nullptr }; // Node pointers
+ real_t rl = 0.0; // Rest length
+ real_t c0 = 0.0; // (ima+imb)*kLST
+ real_t c1 = 0.0; // rl^2
+ real_t c2 = 0.0; // |gradient|^2/c0
+ };
+
+ struct Face {
+ Node *n[3] = { nullptr, nullptr, nullptr }; // Node pointers
+ Vector3 normal; // Normal
+ real_t ra = 0.0; // Rest area
+ DynamicBVH::ID leaf; // Leaf data
+ uint32_t index = 0;
+ };
+
+ LocalVector<Node> nodes;
+ LocalVector<Link> links;
+ LocalVector<Face> faces;
+
+ DynamicBVH node_tree;
+ DynamicBVH face_tree;
+
+ LocalVector<uint32_t> map_visual_to_physics;
+
+ AABB bounds;
+
+ real_t collision_margin = 0.05;
+
+ real_t total_mass = 1.0;
+ real_t inv_total_mass = 1.0;
+
+ int iteration_count = 5;
+ real_t linear_stiffness = 0.5; // [0,1]
+ real_t pressure_coefficient = 0.0; // [-inf,+inf]
+ real_t damping_coefficient = 0.01; // [0,1]
+ real_t drag_coefficient = 0.0; // [0,1]
+ LocalVector<int> pinned_vertices;
+
+ SelfList<SoftBody3DSW> active_list;
+
+ Set<Constraint3DSW *> constraints;
+
+ VSet<RID> exceptions;
+
+public:
+ SoftBody3DSW();
+
+ const AABB &get_bounds() const { return bounds; }
+
+ void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer3D::BodyState p_state) const;
+
+ _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint) { constraints.insert(p_constraint); }
+ _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraints.erase(p_constraint); }
+ _FORCE_INLINE_ const Set<Constraint3DSW *> &get_constraints() const { return constraints; }
+ _FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
+
+ _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); }
+ _FORCE_INLINE_ void remove_exception(const RID &p_exception) { exceptions.erase(p_exception); }
+ _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; }
+
+ virtual void set_space(Space3DSW *p_space);
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+
+ void update_rendering_server(RenderingServerHandler *p_rendering_server_handler);
+
+ Vector3 get_vertex_position(int p_index) const;
+ void set_vertex_position(int p_index, const Vector3 &p_position);
+
+ void pin_vertex(int p_index);
+ void unpin_vertex(int p_index);
+ void unpin_all_vertices();
+ bool is_vertex_pinned(int p_index) const;
+
+ uint32_t get_node_count() const;
+ real_t get_node_inv_mass(uint32_t p_node_index) const;
+ Vector3 get_node_position(uint32_t p_node_index) const;
+ Vector3 get_node_velocity(uint32_t p_node_index) const;
+ Vector3 get_node_biased_velocity(uint32_t p_node_index) const;
+ void apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+ void apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+
+ uint32_t get_face_count() const;
+ void get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const;
+ Vector3 get_face_normal(uint32_t p_face_index) const;
+
+ void set_iteration_count(int p_val);
+ _FORCE_INLINE_ real_t get_iteration_count() const { return iteration_count; }
+
+ void set_total_mass(real_t p_val);
+ _FORCE_INLINE_ real_t get_total_mass() const { return total_mass; }
+ _FORCE_INLINE_ real_t get_total_inv_mass() const { return inv_total_mass; }
+
+ void set_collision_margin(real_t p_val);
+ _FORCE_INLINE_ real_t get_collision_margin() const { return collision_margin; }
+
+ void set_linear_stiffness(real_t p_val);
+ _FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; }
+
+ void set_pressure_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
+
+ void set_damping_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
+
+ void set_drag_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; }
+
+ void predict_motion(real_t p_delta);
+ void solve_constraints(real_t p_delta);
+
+ _FORCE_INLINE_ uint32_t get_node_index(void *p_node) const { return ((Node *)p_node)->index; }
+ _FORCE_INLINE_ uint32_t get_face_index(void *p_face) const { return ((Face *)p_face)->index; }
+
+ // Return true to stop the query.
+ // p_index is the node index for AABB query, face index for Ray query.
+ typedef bool (*QueryResultCallback)(uint32_t p_index, void *p_userdata);
+
+ void query_aabb(const AABB &p_aabb, QueryResultCallback p_result_callback, void *p_userdata);
+ void query_ray(const Vector3 &p_from, const Vector3 &p_to, QueryResultCallback p_result_callback, void *p_userdata);
+
+protected:
+ virtual void _shapes_changed();
+
+private:
+ void update_normals();
+ void update_bounds();
+ void update_constants();
+ void update_area();
+ void reset_link_rest_lengths();
+ void update_link_constants();
+
+ void apply_nodes_transform(const Transform &p_transform);
+
+ void add_velocity(const Vector3 &p_velocity);
+
+ void apply_forces();
+
+ bool create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices);
+ void generate_bending_constraints(int p_distance);
+ void reoptimize_link_order();
+ void append_link(uint32_t p_node1, uint32_t p_node2);
+ void append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3);
+
+ void solve_links(real_t kst, real_t ti);
+
+ void initialize_face_tree();
+ void update_face_tree(real_t p_delta);
+
+ void initialize_shape(bool p_force_move = true);
+ void deinitialize_shape();
+
+ void destroy();
+};
+
+class SoftBodyShape3DSW : public Shape3DSW {
+ SoftBody3DSW *soft_body = nullptr;
+
+public:
+ SoftBody3DSW *get_soft_body() const { return soft_body; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; }
+ virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; }
+ virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
+
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
+ virtual bool intersect_point(const Vector3 &p_point) const;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const { return Vector3(); }
+
+ virtual void set_data(const Variant &p_data) {}
+ virtual Variant get_data() const { return Variant(); }
+
+ void update_bounds();
+
+ SoftBodyShape3DSW(SoftBody3DSW *p_soft_body);
+ ~SoftBodyShape3DSW() {}
+};
+
+#endif // SOFT_BODY_3D_SW_H
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index dd5754b9ac..2df824b320 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -47,6 +47,10 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint
return false;
}
+ if (p_object->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY && !p_collide_with_bodies) {
+ return false;
+ }
+
return true;
}
@@ -210,6 +214,10 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
if (!CollisionSolver3DSW::solve_static(shape, p_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_margin, 0)) {
continue;
}
@@ -265,6 +273,10 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
Vector3 point_A, point_B;
Vector3 sep_axis = p_motion.normalized();
@@ -324,7 +336,8 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
best_first = false;
if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(col_obj);
- r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - closest_B);
+ Vector3 rel_vec = closest_B - (body->get_transform().origin + body->get_center_of_mass());
+ r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
}
}
@@ -365,12 +378,17 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_
}
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
if (CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) {
collided = true;
}
@@ -394,7 +412,7 @@ struct _RestCallbackData {
real_t min_allowed_depth;
};
-static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
_RestCallbackData *rd = (_RestCallbackData *)p_userdata;
Vector3 contact_rel = p_point_B - p_point_A;
@@ -435,12 +453,17 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap
}
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
rcd.object = col_obj;
rcd.shape = shape_idx;
bool sc = CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
@@ -460,8 +483,8 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap
r_info->rid = rcd.best_object->get_self();
if (rcd.best_object->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
- r_info->linear_velocity = body->get_linear_velocity() +
- (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
+ Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
+ r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
} else {
r_info->linear_velocity = Vector3();
@@ -526,6 +549,8 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
keep = false;
} else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_AREA) {
keep = false;
+ } else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ keep = false;
} else if ((static_cast<Body3DSW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0) {
keep = false;
} else if (static_cast<Body3DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
@@ -666,10 +691,8 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra
//result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
Body3DSW *body = (Body3DSW *)col_obj;
-
- Vector3 rel_vec = b - body->get_transform().get_origin();
- //result.collider_velocity = Vector3(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - rel_vec); // * mPos);
+ Vector3 rel_vec = b - (body->get_transform().origin + body->get_center_of_mass());
+ result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
}
}
@@ -991,9 +1014,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
//r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
- //Vector3 rel_vec = r_result->collision_point - body->get_transform().get_origin();
- // r_result->collider_velocity = Vector3(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
+
+ Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
+ r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
r_result->motion = safe * p_motion;
r_result->remainder = p_motion - safe * p_motion;
@@ -1036,14 +1059,23 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll
Area3DSW *area_b = static_cast<Area3DSW *>(B);
Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A));
return area2_pair;
+ } else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ // Area/Soft Body, not supported.
} else {
Body3DSW *body = static_cast<Body3DSW *>(B);
AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A));
return area_pair;
}
+ } else if (type_A == CollisionObject3DSW::TYPE_BODY) {
+ if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ BodySoftBodyPair3DSW *soft_pair = memnew(BodySoftBodyPair3DSW((Body3DSW *)A, p_subindex_A, (SoftBody3DSW *)B));
+ return soft_pair;
+ } else {
+ BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
+ return b;
+ }
} else {
- BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
- return b;
+ // Soft Body/Soft Body, not supported.
}
return nullptr;
@@ -1126,6 +1158,18 @@ const SelfList<Area3DSW>::List &Space3DSW::get_moved_area_list() const {
return area_moved_list;
}
+const SelfList<SoftBody3DSW>::List &Space3DSW::get_active_soft_body_list() const {
+ return active_soft_body_list;
+}
+
+void Space3DSW::soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body) {
+ active_soft_body_list.add(p_soft_body);
+}
+
+void Space3DSW::soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body) {
+ active_soft_body_list.remove(p_soft_body);
+}
+
void Space3DSW::call_queries() {
while (state_query_list.first()) {
Body3DSW *b = state_query_list.first()->self();
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index eed3d86a72..3a8f452e54 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -40,6 +40,7 @@
#include "core/config/project_settings.h"
#include "core/templates/hash_map.h"
#include "core/typedefs.h"
+#include "soft_body_3d_sw.h"
class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D {
GDCLASS(PhysicsDirectSpaceState3DSW, PhysicsDirectSpaceState3D);
@@ -82,6 +83,7 @@ private:
SelfList<Body3DSW>::List state_query_list;
SelfList<Area3DSW>::List monitor_query_list;
SelfList<Area3DSW>::List area_moved_list;
+ SelfList<SoftBody3DSW>::List active_soft_body_list;
static void *_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self);
static void _broadphase_unpair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_self);
@@ -145,6 +147,10 @@ public:
void area_remove_from_moved_list(SelfList<Area3DSW> *p_area);
const SelfList<Area3DSW>::List &get_moved_area_list() const;
+ const SelfList<SoftBody3DSW>::List &get_active_soft_body_list() const;
+ void soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body);
+ void soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body);
+
BroadPhase3DSW *get_broadphase();
void add_object(CollisionObject3DSW *p_object);
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
index d9370de6a3..9a73e11562 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -146,6 +146,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
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();
+
/* INTEGRATE FORCES */
uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
@@ -160,6 +162,15 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
active_count++;
}
+ /* UPDATE SOFT BODY MOTION */
+
+ const SelfList<SoftBody3DSW> *sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->predict_motion(p_delta);
+ sb = sb->next();
+ active_count++;
+ }
+
p_space->set_active_objects(active_count);
{ //profile
@@ -214,6 +225,20 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
}
+ 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;
+ }
+ sb = sb->next();
+ }
+
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
@@ -272,6 +297,14 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
}
}
+ /* UPDATE SOFT BODY CONSTRAINTS */
+
+ sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->solve_constraints(p_delta);
+ sb = sb->next();
+ }
+
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index af25029f04..586845de99 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -556,6 +556,10 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);
+ /* SOFT BODY API */
+
+ ClassDB::bind_method(D_METHOD("soft_body_get_bounds", "body"), &PhysicsServer3D::soft_body_get_bounds);
+
/* JOINT API */
ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer3D::joint_create);
@@ -693,6 +697,7 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP);
+ BIND_ENUM_CONSTANT(SHAPE_SOFT_BODY);
BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index e16857192c..69f5c1c0ad 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -216,6 +216,15 @@ public:
PhysicsShapeQueryResult3D();
};
+class RenderingServerHandler {
+public:
+ virtual void set_vertex(int p_vertex_id, const void *p_vector3) = 0;
+ virtual void set_normal(int p_vertex_id, const void *p_vector3) = 0;
+ virtual void set_aabb(const AABB &p_aabb) = 0;
+
+ virtual ~RenderingServerHandler() {}
+};
+
class PhysicsServer3D : public Object {
GDCLASS(PhysicsServer3D, Object);
@@ -237,6 +246,7 @@ public:
SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
SHAPE_CONCAVE_POLYGON, ///< vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
SHAPE_HEIGHTMAP, ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"
+ SHAPE_SOFT_BODY, ///< Used internally, can't be created from the physics server.
SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
};
@@ -522,13 +532,15 @@ public:
virtual RID soft_body_create() = 0;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) = 0;
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) = 0;
virtual void soft_body_set_space(RID p_body, RID p_space) = 0;
virtual RID soft_body_get_space(RID p_body) const = 0;
virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) = 0;
+ virtual AABB soft_body_get_bounds(RID p_body) const = 0;
+
virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
virtual uint32_t soft_body_get_collision_layer(RID p_body) const = 0;
@@ -543,7 +555,6 @@ public:
virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const = 0;
virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) = 0;
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const = 0;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0;
@@ -556,18 +567,9 @@ public:
virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) = 0;
virtual real_t soft_body_get_linear_stiffness(RID p_body) const = 0;
- virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_angular_stiffness(RID p_body) const = 0;
-
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_volume_stiffness(RID p_body) const = 0;
-
virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) = 0;
virtual real_t soft_body_get_pressure_coefficient(RID p_body) const = 0;
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) = 0;
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) const = 0;
-
virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) = 0;
virtual real_t soft_body_get_damping_coefficient(RID p_body) const = 0;
@@ -577,8 +579,6 @@ public:
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0;
virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const = 0;
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const = 0;
-
virtual void soft_body_remove_all_pinned_points(RID p_body) = 0;
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0;
virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const = 0;
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index e34bc9acb8..7f3fc2f8f4 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -148,6 +148,8 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
} else {
ci->final_clip_rect = global_rect;
}
+ ci->final_clip_rect.position = ci->final_clip_rect.position.round();
+ ci->final_clip_rect.size = ci->final_clip_rect.size.round();
ci->final_clip_owner = ci;
} else {
@@ -525,11 +527,11 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
ERR_FAIL_COND(!line);
if (p_width > 1.001) {
- Vector2 t = (p_from - p_to).orthogonal().normalized();
- line->points[0] = p_from + t * p_width;
- line->points[1] = p_from - t * p_width;
- line->points[2] = p_to - t * p_width;
- line->points[3] = p_to + t * p_width;
+ Vector2 t = (p_from - p_to).orthogonal().normalized() * p_width * 0.5;
+ line->points[0] = p_from + t;
+ line->points[1] = p_from - t;
+ line->points[2] = p_to - t;
+ line->points[3] = p_to + t;
line->point_count = 4;
} else {
line->point_count = 2;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index be2552bd32..d5ac05d1d1 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -175,5 +175,5 @@ RendererCompositorRD::RendererCompositorRD() {
storage = memnew(RendererStorageRD);
canvas = memnew(RendererCanvasRenderRD(storage));
- scene = memnew(RendererSceneRenderForward(storage));
+ scene = memnew(RendererSceneRenderForwardClustered(storage));
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index cb85fc79e0..67a843452b 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -35,14 +35,14 @@
#include "core/templates/thread_work_pool.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
-#include "servers/rendering/renderer_rd/renderer_scene_render_forward.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 {
protected:
RendererCanvasRenderRD *canvas;
RendererStorageRD *storage;
- RendererSceneRenderForward *scene;
+ RendererSceneRenderRD *scene;
RID copy_viewports_rd_shader;
RID copy_viewports_rd_pipeline;
diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
new file mode 100644
index 0000000000..d631cb4bac
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* renderer_scene_environment_rd.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 "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+
+uint64_t RendererSceneEnvironmentRD::auto_exposure_counter = 2;
+
+void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
+ ambient_light = p_color;
+ ambient_source = p_ambient;
+ ambient_light_energy = p_energy;
+ ambient_sky_contribution = p_sky_contribution;
+ reflection_source = p_reflection_source;
+ ao_color = p_ao_color;
+}
+
+void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
+ exposure = p_exposure;
+ tone_mapper = p_tone_mapper;
+ if (!auto_exposure && p_auto_exposure) {
+ auto_exposure_version = ++auto_exposure_counter;
+ }
+ auto_exposure = p_auto_exposure;
+ white = p_white;
+ min_luminance = p_min_luminance;
+ max_luminance = p_max_luminance;
+ auto_exp_speed = p_auto_exp_speed;
+ auto_exp_scale = p_auto_exp_scale;
+}
+
+void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {
+ ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7");
+ glow_enabled = p_enable;
+ glow_levels = p_levels;
+ glow_intensity = p_intensity;
+ glow_strength = p_strength;
+ glow_mix = p_mix;
+ glow_bloom = p_bloom_threshold;
+ glow_blend_mode = p_blend_mode;
+ glow_hdr_bleed_threshold = p_hdr_bleed_threshold;
+ glow_hdr_bleed_scale = p_hdr_bleed_scale;
+ glow_hdr_luminance_cap = p_hdr_luminance_cap;
+}
+
+void RendererSceneEnvironmentRD::set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
+ sdfgi_enabled = p_enable;
+ sdfgi_cascades = p_cascades;
+ sdfgi_min_cell_size = p_min_cell_size;
+ sdfgi_use_occlusion = p_use_occlusion;
+ sdfgi_bounce_feedback = p_bounce_feedback;
+ sdfgi_read_sky_light = p_read_sky;
+ sdfgi_energy = p_energy;
+ sdfgi_normal_bias = p_normal_bias;
+ sdfgi_probe_bias = p_probe_bias;
+ sdfgi_y_scale = p_y_scale;
+}
+
+void RendererSceneEnvironmentRD::set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
+ fog_enabled = p_enable;
+ fog_light_color = p_light_color;
+ fog_light_energy = p_light_energy;
+ fog_sun_scatter = p_sun_scatter;
+ fog_density = p_density;
+ fog_height = p_height;
+ fog_height_density = p_height_density;
+ fog_aerial_perspective = p_fog_aerial_perspective;
+}
+
+void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
+ volumetric_fog_enabled = p_enable;
+ volumetric_fog_density = p_density;
+ volumetric_fog_light = p_light;
+ volumetric_fog_light_energy = p_light_energy;
+ volumetric_fog_length = p_length;
+ volumetric_fog_detail_spread = p_detail_spread;
+ volumetric_fog_gi_inject = p_gi_inject;
+ volumetric_fog_temporal_reprojection = p_temporal_reprojection;
+ volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
+}
+
+void RendererSceneEnvironmentRD::set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
+ ssr_enabled = p_enable;
+ ssr_max_steps = p_max_steps;
+ ssr_fade_in = p_fade_int;
+ ssr_fade_out = p_fade_out;
+ ssr_depth_tolerance = p_depth_tolerance;
+}
+
+void RendererSceneEnvironmentRD::set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) {
+ ssao_enabled = p_enable;
+ ssao_radius = p_radius;
+ ssao_intensity = p_intensity;
+ ssao_power = p_power;
+ ssao_detail = p_detail;
+ ssao_horizon = p_horizon;
+ ssao_sharpness = p_sharpness;
+ ssao_direct_light_affect = p_light_affect;
+ ssao_ao_channel_affect = p_ao_channel_affect;
+}
diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
new file mode 100644
index 0000000000..992c4bf471
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
@@ -0,0 +1,155 @@
+/*************************************************************************/
+/* renderer_scene_environment_rd.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_ENVIRONMENT_RD_H
+#define RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H
+
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_device.h"
+
+class RendererSceneEnvironmentRD {
+private:
+ static uint64_t auto_exposure_counter;
+
+public:
+ // BG
+ RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR;
+ RID sky;
+ float sky_custom_fov = 0.0;
+ Basis sky_orientation;
+ Color bg_color;
+ float bg_energy = 1.0;
+ int canvas_max_layer = 0;
+ RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG;
+ Color ambient_light;
+ float ambient_light_energy = 1.0;
+ float ambient_sky_contribution = 1.0;
+ RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG;
+ Color ao_color;
+
+ /// Tonemap
+
+ RS::EnvironmentToneMapper tone_mapper;
+ float exposure = 1.0;
+ float white = 1.0;
+ bool auto_exposure = false;
+ float min_luminance = 0.2;
+ float max_luminance = 8.0;
+ float auto_exp_speed = 0.2;
+ float auto_exp_scale = 0.5;
+ uint64_t auto_exposure_version = 0;
+
+ // Fog
+ bool fog_enabled = false;
+ Color fog_light_color = Color(0.5, 0.6, 0.7);
+ float fog_light_energy = 1.0;
+ float fog_sun_scatter = 0.0;
+ float fog_density = 0.001;
+ float fog_height = 0.0;
+ float fog_height_density = 0.0; //can be negative to invert effect
+ float fog_aerial_perspective = 0.0;
+
+ /// Volumetric Fog
+ ///
+ bool volumetric_fog_enabled = false;
+ float volumetric_fog_density = 0.01;
+ Color volumetric_fog_light = Color(0, 0, 0);
+ float volumetric_fog_light_energy = 0.0;
+ float volumetric_fog_length = 64.0;
+ float volumetric_fog_detail_spread = 2.0;
+ float volumetric_fog_gi_inject = 0.0;
+ bool volumetric_fog_temporal_reprojection = true;
+ float volumetric_fog_temporal_reprojection_amount = 0.9;
+
+ /// Glow
+
+ bool glow_enabled = false;
+ Vector<float> glow_levels;
+ float glow_intensity = 0.8;
+ float glow_strength = 1.0;
+ float glow_bloom = 0.0;
+ float glow_mix = 0.01;
+ RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT;
+ float glow_hdr_bleed_threshold = 1.0;
+ float glow_hdr_luminance_cap = 12.0;
+ float glow_hdr_bleed_scale = 2.0;
+
+ /// SSAO
+
+ bool ssao_enabled = false;
+ float ssao_radius = 1.0;
+ float ssao_intensity = 2.0;
+ float ssao_power = 1.5;
+ float ssao_detail = 0.5;
+ float ssao_horizon = 0.06;
+ float ssao_sharpness = 0.98;
+ float ssao_direct_light_affect = 0.0;
+ float ssao_ao_channel_affect = 0.0;
+
+ /// SSR
+ ///
+ bool ssr_enabled = false;
+ int ssr_max_steps = 64;
+ float ssr_fade_in = 0.15;
+ float ssr_fade_out = 2.0;
+ float ssr_depth_tolerance = 0.2;
+
+ /// SDFGI
+ bool sdfgi_enabled = false;
+ RS::EnvironmentSDFGICascades sdfgi_cascades;
+ float sdfgi_min_cell_size = 0.2;
+ bool sdfgi_use_occlusion = false;
+ float sdfgi_bounce_feedback = 0.0;
+ bool sdfgi_read_sky_light = false;
+ float sdfgi_energy = 1.0;
+ float sdfgi_normal_bias = 1.1;
+ float sdfgi_probe_bias = 1.1;
+ RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED;
+
+ /// Adjustments
+
+ bool adjustments_enabled = false;
+ float adjustments_brightness = 1.0f;
+ float adjustments_contrast = 1.0f;
+ float adjustments_saturation = 1.0f;
+ bool use_1d_color_correction = false;
+ RID color_correction = RID();
+
+ void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color);
+ void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
+ void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
+ void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
+ void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective);
+ void set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount);
+ void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
+ void set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect);
+};
+
+#endif /* !RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
new file mode 100644
index 0000000000..4e4e553605
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -0,0 +1,3403 @@
+/*************************************************************************/
+/* renderer_scene_gi_rd.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_gi_rd.h"
+
+#include "core/config/project_settings.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/rendering_server_default.h"
+
+const Vector3i RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
+
+////////////////////////////////////////////////////////////////////////////////
+// SDFGI
+
+void RendererSceneGIRD::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi) {
+ storage = p_gi->storage;
+ gi = p_gi;
+ cascade_mode = p_env->sdfgi_cascades;
+ min_cell_size = p_env->sdfgi_min_cell_size;
+ uses_occlusion = p_env->sdfgi_use_occlusion;
+ y_scale_mode = p_env->sdfgi_y_scale;
+ static const float y_scale[3] = { 1.0, 1.5, 2.0 };
+ y_mult = y_scale[y_scale_mode];
+ static const int cascasde_size[3] = { 4, 6, 8 };
+ cascades.resize(cascasde_size[cascade_mode]);
+ probe_axis_count = SDFGI::PROBE_DIVISOR + 1;
+ solid_cell_ratio = gi->sdfgi_solid_cell_ratio;
+ solid_cell_count = uint32_t(float(cascade_size * cascade_size * cascade_size) * solid_cell_ratio);
+
+ float base_cell_size = min_cell_size;
+
+ RD::TextureFormat tf_sdf;
+ tf_sdf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf_sdf.width = cascade_size; // Always 64x64
+ tf_sdf.height = cascade_size;
+ tf_sdf.depth = cascade_size;
+ tf_sdf.texture_type = RD::TEXTURE_TYPE_3D;
+ tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+
+ {
+ RD::TextureFormat tf_render = tf_sdf;
+ tf_render.format = RD::DATA_FORMAT_R16_UINT;
+ render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ tf_render.format = RD::DATA_FORMAT_R32_UINT;
+ render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+
+ tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize
+
+ for (int i = 0; i < 8; i++) {
+ render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ }
+
+ tf_render.format = RD::DATA_FORMAT_R32_UINT;
+ render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+
+ tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT;
+ render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+
+ tf_render.width /= 2;
+ tf_render.height /= 2;
+ tf_render.depth /= 2;
+
+ render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ }
+
+ RD::TextureFormat tf_occlusion = tf_sdf;
+ tf_occlusion.format = RD::DATA_FORMAT_R16_UINT;
+ tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
+ tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
+ tf_occlusion.depth *= cascades.size(); //use depth for occlusion slices
+ tf_occlusion.width *= 2; //use width for the other half
+
+ RD::TextureFormat tf_light = tf_sdf;
+ tf_light.format = RD::DATA_FORMAT_R32_UINT;
+ tf_light.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
+ tf_light.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
+
+ RD::TextureFormat tf_aniso0 = tf_sdf;
+ tf_aniso0.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ RD::TextureFormat tf_aniso1 = tf_sdf;
+ tf_aniso1.format = RD::DATA_FORMAT_R8G8_UNORM;
+
+ int passes = nearest_shift(cascade_size) - 1;
+
+ //store lightprobe SH
+ RD::TextureFormat tf_probes;
+ tf_probes.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf_probes.width = probe_axis_count * probe_axis_count;
+ tf_probes.height = probe_axis_count * SDFGI::SH_SIZE;
+ tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+
+ history_size = p_requested_history_size;
+
+ RD::TextureFormat tf_probe_history = tf_probes;
+ tf_probe_history.format = RD::DATA_FORMAT_R16G16B16A16_SINT; //signed integer because SH are signed
+ tf_probe_history.array_layers = history_size;
+
+ RD::TextureFormat tf_probe_average = tf_probes;
+ tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed
+ tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D;
+
+ lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
+ lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
+
+ {
+ //octahedral lightprobes
+ RD::TextureFormat tf_octprobes = tf_probes;
+ tf_octprobes.array_layers = cascades.size() * 2;
+ tf_octprobes.format = RD::DATA_FORMAT_R32_UINT; //pack well with RGBE
+ tf_octprobes.width = probe_axis_count * probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
+ tf_octprobes.height = probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
+ tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
+ tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
+ //lightprobe texture is an octahedral texture
+
+ lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView());
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+ lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, lightprobe_data);
+
+ //texture handling ambient data, to integrate with volumetric foc
+ RD::TextureFormat tf_ambient = tf_probes;
+ tf_ambient.array_layers = cascades.size();
+ tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE
+ tf_ambient.width = probe_axis_count * probe_axis_count;
+ tf_ambient.height = probe_axis_count;
+ tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ //lightprobe texture is an octahedral texture
+ ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
+ }
+
+ cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
+
+ occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView());
+ {
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16;
+ occlusion_texture = RD::get_singleton()->texture_create_shared(tv, occlusion_data);
+ }
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+
+ /* 3D Textures */
+
+ cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView());
+
+ cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView());
+
+ cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView());
+ cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView());
+
+ {
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+ cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data);
+
+ RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ }
+
+ cascade.cell_size = base_cell_size;
+ Vector3 world_position = p_world_position;
+ world_position.y *= y_mult;
+ int32_t probe_cells = cascade_size / SDFGI::PROBE_DIVISOR;
+ Vector3 probe_size = Vector3(1, 1, 1) * cascade.cell_size * probe_cells;
+ Vector3i probe_pos = Vector3i((world_position / probe_size + Vector3(0.5, 0.5, 0.5)).floor());
+ cascade.position = probe_pos * probe_cells;
+
+ cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
+
+ base_cell_size *= 2.0;
+
+ /* Probe History */
+
+ cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
+ RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work
+
+ cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
+ RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work
+
+ /* Buffers */
+
+ cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * solid_cell_count);
+ cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
+ cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS));
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ for (int j = 0; j < 8; j++) {
+ u.ids.push_back(render_occlusion[j]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 4;
+ u.ids.push_back(render_emission);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(render_emission_aniso);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(render_geom_facing);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(cascade.sdf_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(occlusion_data);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 10;
+ u.ids.push_back(cascade.solid_cell_dispatch_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 11;
+ u.ids.push_back(cascade.solid_cell_buffer);
+ uniforms.push_back(u);
+ }
+
+ cascade.sdf_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_STORE), 0);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_geom_facing);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(render_emission);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 4;
+ u.ids.push_back(render_emission_aniso);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 5;
+ u.ids.push_back(cascade.solid_cell_dispatch_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 6;
+ u.ids.push_back(cascade.solid_cell_buffer);
+ uniforms.push_back(u);
+ }
+
+ cascade.scroll_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_SCROLL), 0);
+ }
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ for (int j = 0; j < 8; j++) {
+ u.ids.push_back(render_occlusion[j]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(occlusion_data);
+ uniforms.push_back(u);
+ }
+
+ cascade.scroll_occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION), 0);
+ }
+ }
+
+ //direct light
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cascade.solid_cell_dispatch_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cascade.solid_cell_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(cascade.light_data);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(cascade.light_aniso_0_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(cascade.light_aniso_1_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cascade.lights_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(lightprobe_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(occlusion_texture);
+ uniforms.push_back(u);
+ }
+
+ cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.direct_light.version_get_shader(gi->sdfgi_shader.direct_light_shader, 0), 0);
+ }
+
+ //preprocess initialize uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf[0]);
+ uniforms.push_back(u);
+ }
+
+ sdf_initialize_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE), 0);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf_half[0]);
+ uniforms.push_back(u);
+ }
+
+ sdf_initialize_half_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF), 0);
+ }
+
+ //jump flood uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_sdf[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf[1]);
+ uniforms.push_back(u);
+ }
+
+ jump_flood_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
+ jump_flood_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ }
+ //jump flood half uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_sdf_half[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf_half[1]);
+ uniforms.push_back(u);
+ }
+
+ jump_flood_half_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
+ jump_flood_half_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ }
+
+ //upscale half size sdf
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass
+ uniforms.push_back(u);
+ }
+
+ upscale_jfa_uniform_set_index = (passes & 1) ? 0 : 1;
+ sdf_upscale_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE), 0);
+ }
+
+ //occlusion uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ for (int i = 0; i < 8; i++) {
+ u.ids.push_back(render_occlusion[i]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(render_geom_facing);
+ uniforms.push_back(u);
+ }
+
+ occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_OCCLUSION), 0);
+ }
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ //integrate uniform
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].light_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].light_aniso_0_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].light_aniso_1_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 6;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 7;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(lightprobe_data);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 9;
+ u.ids.push_back(cascades[i].lightprobe_history_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 10;
+ u.ids.push_back(cascades[i].lightprobe_average_tex);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(lightprobe_history_scroll);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(lightprobe_average_scroll);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 13;
+ RID parent_average;
+ if (i < cascades.size() - 1) {
+ parent_average = cascades[i + 1].lightprobe_average_tex;
+ } else {
+ parent_average = cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used
+ }
+ u.ids.push_back(parent_average);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 14;
+ u.ids.push_back(ambient_texture);
+ uniforms.push_back(u);
+ }
+
+ cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.integrate.version_get_shader(gi->sdfgi_shader.integrate_shader, 0), 0);
+ }
+
+ bounce_feedback = p_env->sdfgi_bounce_feedback;
+ energy = p_env->sdfgi_energy;
+ normal_bias = p_env->sdfgi_normal_bias;
+ probe_bias = p_env->sdfgi_probe_bias;
+ reads_sky = p_env->sdfgi_read_sky_light;
+}
+
+void RendererSceneGIRD::SDFGI::erase() {
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ const SDFGI::Cascade &c = cascades[i];
+ RD::get_singleton()->free(c.light_data);
+ RD::get_singleton()->free(c.light_aniso_0_tex);
+ RD::get_singleton()->free(c.light_aniso_1_tex);
+ RD::get_singleton()->free(c.sdf_tex);
+ RD::get_singleton()->free(c.solid_cell_dispatch_buffer);
+ RD::get_singleton()->free(c.solid_cell_buffer);
+ RD::get_singleton()->free(c.lightprobe_history_tex);
+ RD::get_singleton()->free(c.lightprobe_average_tex);
+ RD::get_singleton()->free(c.lights_buffer);
+ }
+
+ RD::get_singleton()->free(render_albedo);
+ RD::get_singleton()->free(render_emission);
+ RD::get_singleton()->free(render_emission_aniso);
+
+ RD::get_singleton()->free(render_sdf[0]);
+ RD::get_singleton()->free(render_sdf[1]);
+
+ RD::get_singleton()->free(render_sdf_half[0]);
+ RD::get_singleton()->free(render_sdf_half[1]);
+
+ for (int i = 0; i < 8; i++) {
+ RD::get_singleton()->free(render_occlusion[i]);
+ }
+
+ RD::get_singleton()->free(render_geom_facing);
+
+ RD::get_singleton()->free(lightprobe_data);
+ RD::get_singleton()->free(lightprobe_history_scroll);
+ RD::get_singleton()->free(occlusion_data);
+ RD::get_singleton()->free(ambient_texture);
+
+ RD::get_singleton()->free(cascades_ubo);
+}
+
+void RendererSceneGIRD::SDFGI::update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position) {
+ bounce_feedback = p_env->sdfgi_bounce_feedback;
+ energy = p_env->sdfgi_energy;
+ normal_bias = p_env->sdfgi_normal_bias;
+ probe_bias = p_env->sdfgi_probe_bias;
+ reads_sky = p_env->sdfgi_read_sky_light;
+
+ int32_t drag_margin = (cascade_size / SDFGI::PROBE_DIVISOR) / 2;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+ cascade.dirty_regions = Vector3i();
+
+ Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(cascade_size / SDFGI::PROBE_DIVISOR) * 0.5;
+ probe_half_size = Vector3(0, 0, 0);
+
+ Vector3 world_position = p_world_position;
+ world_position.y *= y_mult;
+ Vector3i pos_in_cascade = Vector3i((world_position + probe_half_size) / cascade.cell_size);
+
+ for (int j = 0; j < 3; j++) {
+ if (pos_in_cascade[j] < cascade.position[j]) {
+ while (pos_in_cascade[j] < (cascade.position[j] - drag_margin)) {
+ cascade.position[j] -= drag_margin * 2;
+ cascade.dirty_regions[j] += drag_margin * 2;
+ }
+ } else if (pos_in_cascade[j] > cascade.position[j]) {
+ while (pos_in_cascade[j] > (cascade.position[j] + drag_margin)) {
+ cascade.position[j] += drag_margin * 2;
+ cascade.dirty_regions[j] -= drag_margin * 2;
+ }
+ }
+
+ if (cascade.dirty_regions[j] == 0) {
+ continue; // not dirty
+ } else if (uint32_t(ABS(cascade.dirty_regions[j])) >= cascade_size) {
+ //moved too much, just redraw everything (make all dirty)
+ cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
+ break;
+ }
+ }
+
+ if (cascade.dirty_regions != Vector3i() && cascade.dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ //see how much the total dirty volume represents from the total volume
+ uint32_t total_volume = cascade_size * cascade_size * cascade_size;
+ uint32_t safe_volume = 1;
+ for (int j = 0; j < 3; j++) {
+ safe_volume *= cascade_size - ABS(cascade.dirty_regions[j]);
+ }
+ uint32_t dirty_volume = total_volume - safe_volume;
+ if (dirty_volume > (safe_volume / 2)) {
+ //more than half the volume is dirty, make all dirty so its only rendered once
+ cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
+ }
+ }
+ }
+}
+
+void RendererSceneGIRD::SDFGI::update_light() {
+ RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light");
+
+ /* Update dynamic light */
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_DYNAMIC]);
+
+ SDFGIShader::DirectLightPushConstant push_constant;
+
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.bounce_feedback = bounce_feedback;
+ push_constant.y_mult = y_mult;
+ push_constant.use_occlusion = uses_occlusion;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+ push_constant.light_count = cascade_dynamic_light_count[i];
+ push_constant.cascade = i;
+
+ if (cascades[i].all_dynamic_lights_dirty || gi->sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) {
+ push_constant.process_offset = 0;
+ push_constant.process_increment = 1;
+ } else {
+ static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = {
+ 1, 2, 4, 8, 16
+ };
+
+ uint32_t frames_to_update = frames_to_update_table[gi->sdfgi_frames_to_update_light];
+
+ push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update;
+ push_constant.process_increment = frames_to_update;
+ }
+ cascades[i].all_dynamic_lights_dirty = false;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::DirectLightPushConstant));
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0);
+ }
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneGIRD::SDFGI::update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky) {
+ RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes");
+
+ SDFGIShader::IntegratePushConstant push_constant;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.history_index = render_pass % history_size;
+ push_constant.history_size = history_size;
+ static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
+ push_constant.ray_count = ray_count[gi->sdfgi_ray_count];
+ push_constant.ray_bias = probe_bias;
+ push_constant.image_size[0] = probe_axis_count * probe_axis_count;
+ push_constant.image_size[1] = probe_axis_count;
+ push_constant.store_ambient_texture = p_env->volumetric_fog_enabled;
+
+ RID sky_uniform_set = gi->sdfgi_shader.integrate_default_sky_uniform_set;
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_DISABLED;
+ push_constant.y_mult = y_mult;
+
+ if (reads_sky && p_env) {
+ push_constant.sky_energy = p_env->bg_energy;
+
+ if (p_env->background == RS::ENV_BG_CLEAR_COLOR) {
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_COLOR;
+ Color c = storage->get_default_clear_color().to_linear();
+ push_constant.sky_color[0] = c.r;
+ push_constant.sky_color[1] = c.g;
+ push_constant.sky_color[2] = c.b;
+ } else if (p_env->background == RS::ENV_BG_COLOR) {
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_COLOR;
+ Color c = p_env->bg_color;
+ push_constant.sky_color[0] = c.r;
+ push_constant.sky_color[1] = c.g;
+ push_constant.sky_color[2] = c.b;
+
+ } else if (p_env->background == RS::ENV_BG_SKY) {
+ if (p_sky && p_sky->radiance.is_valid()) {
+ if (integrate_sky_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(integrate_sky_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(p_sky->radiance);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ integrate_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.integrate.version_get_shader(gi->sdfgi_shader.integrate_shader, 0), 1);
+ }
+ sky_uniform_set = integrate_sky_uniform_set;
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_SKY;
+ }
+ }
+ }
+
+ render_pass++;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_PROCESS]);
+
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ push_constant.cascade = i;
+ push_constant.world_offset[0] = cascades[i].position.x / probe_divisor;
+ push_constant.world_offset[1] = cascades[i].position.y / probe_divisor;
+ push_constant.world_offset[2] = cascades[i].position.z / probe_divisor;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[i].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
+ }
+
+ //end later after raster to avoid barriering on layout changes
+ //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneGIRD::SDFGI::store_probes() {
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes");
+
+ SDFGIShader::IntegratePushConstant push_constant;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.history_index = render_pass % history_size;
+ push_constant.history_size = history_size;
+ static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
+ push_constant.ray_count = ray_count[gi->sdfgi_ray_count];
+ push_constant.ray_bias = probe_bias;
+ push_constant.image_size[0] = probe_axis_count * probe_axis_count;
+ push_constant.image_size[1] = probe_axis_count;
+ push_constant.store_ambient_texture = false;
+
+ push_constant.sky_mode = 0;
+ push_constant.y_mult = y_mult;
+
+ // Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces
+ RENDER_TIMESTAMP("Average Probes");
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE]);
+
+ //convert to octahedral to store
+ push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+ push_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ push_constant.cascade = i;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[i].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
+ }
+
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+int RendererSceneGIRD::SDFGI::get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const {
+ int dirty_count = 0;
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ const SDFGI::Cascade &c = cascades[i];
+
+ if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) {
+ if (dirty_count == p_region) {
+ r_local_offset = Vector3i();
+ r_local_size = Vector3i(1, 1, 1) * cascade_size;
+
+ r_bounds.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + c.position)) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+ r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+ return i;
+ }
+ dirty_count++;
+ } else {
+ for (int j = 0; j < 3; j++) {
+ if (c.dirty_regions[j] != 0) {
+ if (dirty_count == p_region) {
+ Vector3i from = Vector3i(0, 0, 0);
+ Vector3i to = Vector3i(1, 1, 1) * cascade_size;
+
+ if (c.dirty_regions[j] > 0) {
+ //fill from the beginning
+ to[j] = c.dirty_regions[j];
+ } else {
+ //fill from the end
+ from[j] = to[j] + c.dirty_regions[j];
+ }
+
+ for (int k = 0; k < j; k++) {
+ // "chip" away previous regions to avoid re-voxelizing the same thing
+ if (c.dirty_regions[k] > 0) {
+ from[k] += c.dirty_regions[k];
+ } else if (c.dirty_regions[k] < 0) {
+ to[k] += c.dirty_regions[k];
+ }
+ }
+
+ r_local_offset = from;
+ r_local_size = to - from;
+
+ r_bounds.position = Vector3(from + Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + c.position) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+ r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+
+ return i;
+ }
+
+ dirty_count++;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+void RendererSceneGIRD::SDFGI::update_cascades() {
+ //update cascades
+ SDFGI::Cascade::UBO cascade_data[SDFGI::MAX_CASCADES];
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[i].position)) * cascades[i].cell_size;
+
+ cascade_data[i].offset[0] = pos.x;
+ cascade_data[i].offset[1] = pos.y;
+ cascade_data[i].offset[2] = pos.z;
+ cascade_data[i].to_cell = 1.0 / cascades[i].cell_size;
+ cascade_data[i].probe_offset[0] = cascades[i].position.x / probe_divisor;
+ cascade_data[i].probe_offset[1] = cascades[i].position.y / probe_divisor;
+ cascade_data[i].probe_offset[2] = cascades[i].position.z / probe_divisor;
+ cascade_data[i].pad = 0;
+ }
+
+ RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
+}
+
+void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) {
+ if (!debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].light_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].light_aniso_0_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].light_aniso_1_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(occlusion_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(p_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(lightprobe_texture);
+ uniforms.push_back(u);
+ }
+ debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.debug_shader_version, 0);
+ }
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.debug_pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set, 0);
+
+ SDFGIShader::DebugPushConstant push_constant;
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.screen_size[0] = p_width;
+ push_constant.screen_size[1] = p_height;
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.use_occlusion = uses_occlusion;
+ push_constant.y_mult = y_mult;
+
+ Vector2 vp_half = p_projection.get_viewport_half_extents();
+ push_constant.cam_extent[0] = vp_half.x;
+ push_constant.cam_extent[1] = vp_half.y;
+ push_constant.cam_extent[2] = -p_projection.get_z_near();
+
+ push_constant.cam_transform[0] = p_transform.basis.elements[0][0];
+ push_constant.cam_transform[1] = p_transform.basis.elements[1][0];
+ push_constant.cam_transform[2] = p_transform.basis.elements[2][0];
+ push_constant.cam_transform[3] = 0;
+ push_constant.cam_transform[4] = p_transform.basis.elements[0][1];
+ push_constant.cam_transform[5] = p_transform.basis.elements[1][1];
+ push_constant.cam_transform[6] = p_transform.basis.elements[2][1];
+ push_constant.cam_transform[7] = 0;
+ push_constant.cam_transform[8] = p_transform.basis.elements[0][2];
+ push_constant.cam_transform[9] = p_transform.basis.elements[1][2];
+ push_constant.cam_transform[10] = p_transform.basis.elements[2][2];
+ push_constant.cam_transform[11] = 0;
+ push_constant.cam_transform[12] = p_transform.origin.x;
+ push_constant.cam_transform[13] = p_transform.origin.y;
+ push_constant.cam_transform[14] = p_transform.origin.z;
+ push_constant.cam_transform[15] = 1;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::DebugPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_width, p_height, 1);
+ RD::get_singleton()->compute_list_end();
+
+ Size2 rtsize = storage->render_target_get_size(p_render_target);
+ storage->get_effects()->copy_to_fb_rect(p_texture, storage->render_target_get_rd_framebuffer(p_render_target), Rect2(Vector2(), rtsize), true);
+}
+
+void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) {
+ SDFGIShader::DebugProbesPushConstant push_constant;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ push_constant.projection[i * 4 + j] = p_camera_with_transform.matrix[i][j];
+ }
+ }
+
+ //gen spheres from strips
+ uint32_t band_points = 16;
+ push_constant.band_power = 4;
+ push_constant.sections_in_band = ((band_points / 2) - 1);
+ push_constant.band_mask = band_points - 2;
+ push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band);
+ push_constant.y_mult = y_mult;
+
+ uint32_t total_points = push_constant.sections_in_band * band_points;
+ uint32_t total_probes = probe_axis_count * probe_axis_count * probe_axis_count;
+
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.cascade = 0;
+
+ push_constant.probe_axis_size = probe_axis_count;
+
+ if (!debug_probes_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_probes_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(lightprobe_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(occlusion_texture);
+ uniforms.push_back(u);
+ }
+
+ debug_probes_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.debug_probes.version_get_shader(gi->sdfgi_shader.debug_probes_shader, 0), 0);
+ }
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, gi->sdfgi_shader.debug_probes_pipeline[SDFGIShader::PROBE_DEBUG_PROBES].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, debug_probes_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDFGIShader::DebugProbesPushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points);
+
+ if (gi->sdfgi_debug_probe_dir != Vector3()) {
+ print_line("CLICK DEBUG ME?");
+ uint32_t cascade = 0;
+ Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[cascade].position)) * cascades[cascade].cell_size * Vector3(1.0, 1.0 / y_mult, 1.0);
+ Vector3 probe_size = cascades[cascade].cell_size * (cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / y_mult, 1.0);
+ Vector3 ray_from = gi->sdfgi_debug_probe_pos;
+ Vector3 ray_to = gi->sdfgi_debug_probe_pos + gi->sdfgi_debug_probe_dir * cascades[cascade].cell_size * Math::sqrt(3.0) * cascade_size;
+ float sphere_radius = 0.2;
+ float closest_dist = 1e20;
+ gi->sdfgi_debug_probe_enabled = false;
+
+ Vector3i probe_from = cascades[cascade].position / (cascade_size / SDFGI::PROBE_DIVISOR);
+ for (int i = 0; i < (SDFGI::PROBE_DIVISOR + 1); i++) {
+ for (int j = 0; j < (SDFGI::PROBE_DIVISOR + 1); j++) {
+ for (int k = 0; k < (SDFGI::PROBE_DIVISOR + 1); k++) {
+ Vector3 pos = offset + probe_size * Vector3(i, j, k);
+ Vector3 res;
+ if (Geometry3D::segment_intersects_sphere(ray_from, ray_to, pos, sphere_radius, &res)) {
+ float d = ray_from.distance_to(res);
+ if (d < closest_dist) {
+ closest_dist = d;
+ gi->sdfgi_debug_probe_enabled = true;
+ gi->sdfgi_debug_probe_index = probe_from + Vector3i(i, j, k);
+ }
+ }
+ }
+ }
+ }
+
+ if (gi->sdfgi_debug_probe_enabled) {
+ print_line("found: " + gi->sdfgi_debug_probe_index);
+ } else {
+ print_line("no found");
+ }
+ gi->sdfgi_debug_probe_dir = Vector3();
+ }
+
+ if (gi->sdfgi_debug_probe_enabled) {
+ uint32_t cascade = 0;
+ uint32_t probe_cells = (cascade_size / SDFGI::PROBE_DIVISOR);
+ Vector3i probe_from = cascades[cascade].position / probe_cells;
+ Vector3i ofs = gi->sdfgi_debug_probe_index - probe_from;
+ if (ofs.x < 0 || ofs.y < 0 || ofs.z < 0) {
+ return;
+ }
+ if (ofs.x > SDFGI::PROBE_DIVISOR || ofs.y > SDFGI::PROBE_DIVISOR || ofs.z > SDFGI::PROBE_DIVISOR) {
+ return;
+ }
+
+ uint32_t mult = (SDFGI::PROBE_DIVISOR + 1);
+ uint32_t index = ofs.z * mult * mult + ofs.y * mult + ofs.x;
+
+ push_constant.probe_debug_index = index;
+
+ uint32_t cell_count = probe_cells * 2 * probe_cells * 2 * probe_cells * 2;
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, gi->sdfgi_shader.debug_probes_pipeline[SDFGIShader::PROBE_DEBUG_VISIBILITY].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, debug_probes_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDFGIShader::DebugProbesPushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, total_points);
+ }
+}
+
+void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render) {
+ /* Update general SDFGI Buffer */
+
+ SDFGIData sdfgi_data;
+
+ sdfgi_data.grid_size[0] = cascade_size;
+ sdfgi_data.grid_size[1] = cascade_size;
+ sdfgi_data.grid_size[2] = cascade_size;
+
+ sdfgi_data.max_cascades = cascades.size();
+ sdfgi_data.probe_axis_size = probe_axis_count;
+ sdfgi_data.cascade_probe_size[0] = sdfgi_data.probe_axis_size - 1; //float version for performance
+ sdfgi_data.cascade_probe_size[1] = sdfgi_data.probe_axis_size - 1;
+ sdfgi_data.cascade_probe_size[2] = sdfgi_data.probe_axis_size - 1;
+
+ float csize = cascade_size;
+ sdfgi_data.probe_to_uvw = 1.0 / float(sdfgi_data.cascade_probe_size[0]);
+ sdfgi_data.use_occlusion = uses_occlusion;
+ //sdfgi_data.energy = energy;
+
+ sdfgi_data.y_mult = y_mult;
+
+ float cascade_voxel_size = (csize / sdfgi_data.cascade_probe_size[0]);
+ float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size;
+ sdfgi_data.occlusion_clamp[0] = occlusion_clamp;
+ sdfgi_data.occlusion_clamp[1] = occlusion_clamp;
+ sdfgi_data.occlusion_clamp[2] = occlusion_clamp;
+ sdfgi_data.normal_bias = (normal_bias / csize) * sdfgi_data.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;
+
+ uint32_t oct_size = SDFGI::LIGHTPROBE_OCT_SIZE;
+
+ sdfgi_data.lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size * sdfgi_data.probe_axis_size);
+ sdfgi_data.lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size);
+ sdfgi_data.lightprobe_tex_pixel_size[2] = 1.0;
+
+ sdfgi_data.energy = energy;
+
+ sdfgi_data.lightprobe_uv_offset[0] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[0];
+ sdfgi_data.lightprobe_uv_offset[1] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[1];
+ sdfgi_data.lightprobe_uv_offset[2] = float((oct_size + 2) * sdfgi_data.probe_axis_size) * sdfgi_data.lightprobe_tex_pixel_size[0];
+
+ sdfgi_data.occlusion_renormalize[0] = 0.5;
+ sdfgi_data.occlusion_renormalize[1] = 1.0;
+ sdfgi_data.occlusion_renormalize[2] = 1.0 / float(sdfgi_data.max_cascades);
+
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+
+ for (uint32_t i = 0; i < sdfgi_data.max_cascades; i++) {
+ SDFGIData::ProbeCascadeData &c = sdfgi_data.cascades[i];
+ Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[i].position)) * cascades[i].cell_size;
+ Vector3 cam_origin = p_transform.origin;
+ cam_origin.y *= y_mult;
+ pos -= cam_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 / (float(cascade_size) * cascades[i].cell_size / float(probe_axis_count - 1));
+
+ Vector3i probe_ofs = cascades[i].position / probe_divisor;
+ c.probe_world_offset[0] = probe_ofs.x;
+ c.probe_world_offset[1] = probe_ofs.y;
+ c.probe_world_offset[2] = probe_ofs.z;
+
+ c.to_cell = 1.0 / cascades[i].cell_size;
+ }
+
+ RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE);
+
+ /* Update dynamic lights in SDFGI cascades */
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+
+ SDFGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];
+ uint32_t idx = 0;
+ for (uint32_t j = 0; j < (uint32_t)p_scene_render->render_state.sdfgi_update_data->directional_lights->size(); j++) {
+ if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
+ break;
+ }
+
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j));
+ ERR_CONTINUE(!li);
+
+ if (storage->light_directional_is_sky_only(li->light)) {
+ continue;
+ }
+
+ Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
+ dir.y *= y_mult;
+ dir.normalize();
+ lights[idx].direction[0] = dir.x;
+ lights[idx].direction[1] = dir.y;
+ lights[idx].direction[2] = dir.z;
+ Color color = storage->light_get_color(li->light);
+ color = color.to_linear();
+ lights[idx].color[0] = color.r;
+ lights[idx].color[1] = color.g;
+ lights[idx].color[2] = color.b;
+ lights[idx].type = RS::LIGHT_DIRECTIONAL;
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].has_shadow = storage->light_has_shadow(li->light);
+
+ idx++;
+ }
+
+ AABB cascade_aabb;
+ cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascade.position)) * cascade.cell_size;
+ cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cascade.cell_size;
+
+ for (uint32_t j = 0; j < p_scene_render->render_state.sdfgi_update_data->positional_light_count; j++) {
+ if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
+ break;
+ }
+
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]);
+ ERR_CONTINUE(!li);
+
+ uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
+ if (i > max_sdfgi_cascade) {
+ continue;
+ }
+
+ if (!cascade_aabb.intersects(li->aabb)) {
+ continue;
+ }
+
+ Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
+ //faster to not do this here
+ //dir.y *= y_mult;
+ //dir.normalize();
+ lights[idx].direction[0] = dir.x;
+ lights[idx].direction[1] = dir.y;
+ lights[idx].direction[2] = dir.z;
+ Vector3 pos = li->transform.origin;
+ pos.y *= y_mult;
+ lights[idx].position[0] = pos.x;
+ lights[idx].position[1] = pos.y;
+ lights[idx].position[2] = pos.z;
+ Color color = storage->light_get_color(li->light);
+ color = color.to_linear();
+ lights[idx].color[0] = color.r;
+ lights[idx].color[1] = color.g;
+ lights[idx].color[2] = color.b;
+ lights[idx].type = storage->light_get_type(li->light);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].has_shadow = storage->light_has_shadow(li->light);
+ lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
+ lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
+ lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE);
+ }
+
+ cascade_dynamic_light_count[i] = idx;
+ }
+}
+
+void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render) {
+ //print_line("rendering region " + itos(p_region));
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
+ AABB bounds;
+ Vector3i from;
+ Vector3i size;
+
+ int cascade_prev = get_pending_region_data(p_region - 1, from, size, bounds);
+ int cascade_next = get_pending_region_data(p_region + 1, from, size, bounds);
+ int cascade = get_pending_region_data(p_region, from, size, bounds);
+ ERR_FAIL_COND(cascade < 0);
+
+ if (cascade_prev != cascade) {
+ //initialize render
+ RD::get_singleton()->texture_clear(render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ }
+
+ //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size));
+ p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing);
+
+ if (cascade_next != cascade) {
+ RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
+
+ RENDER_TIMESTAMP(">SDFGI Update SDF");
+ //done rendering! must update SDF
+ //clear dispatch indirect data
+
+ SDFGIShader::PreprocessPushConstant push_constant;
+ zeromem(&push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+
+ RENDER_TIMESTAMP("Scroll SDF");
+
+ //scroll
+ if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ //for scroll
+ Vector3i dirty = cascades[cascade].dirty_regions;
+ push_constant.scroll[0] = dirty.x;
+ push_constant.scroll[1] = dirty.y;
+ push_constant.scroll[2] = dirty.z;
+ } else {
+ //for no scroll
+ push_constant.scroll[0] = 0;
+ push_constant.scroll[1] = 0;
+ push_constant.scroll[2] = 0;
+ }
+
+ cascades[cascade].all_dynamic_lights_dirty = true;
+
+ push_constant.grid_size = cascade_size;
+ push_constant.cascade = cascade;
+
+ if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ //must pre scroll existing data because not all is dirty
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_uniform_set, 0);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer, 0);
+ // no barrier do all together
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_occlusion_uniform_set, 0);
+
+ Vector3i dirty = cascades[cascade].dirty_regions;
+ Vector3i groups;
+ groups.x = cascade_size - ABS(dirty.x);
+ groups.y = cascade_size - ABS(dirty.y);
+ groups.z = cascade_size - ABS(dirty.z);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z);
+
+ //no barrier, continue together
+
+ {
+ //scroll probes and their history also
+
+ SDFGIShader::IntegratePushConstant ipush_constant;
+ ipush_constant.grid_size[1] = cascade_size;
+ ipush_constant.grid_size[2] = cascade_size;
+ ipush_constant.grid_size[0] = cascade_size;
+ ipush_constant.max_cascades = cascades.size();
+ ipush_constant.probe_axis_size = probe_axis_count;
+ ipush_constant.history_index = 0;
+ ipush_constant.history_size = history_size;
+ ipush_constant.ray_count = 0;
+ ipush_constant.ray_bias = 0;
+ ipush_constant.sky_mode = 0;
+ ipush_constant.sky_energy = 0;
+ ipush_constant.sky_color[0] = 0;
+ ipush_constant.sky_color[1] = 0;
+ ipush_constant.sky_color[2] = 0;
+ ipush_constant.y_mult = y_mult;
+ ipush_constant.store_ambient_texture = false;
+
+ ipush_constant.image_size[0] = probe_axis_count * probe_axis_count;
+ ipush_constant.image_size[1] = probe_axis_count;
+
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+ ipush_constant.cascade = cascade;
+ ipush_constant.world_offset[0] = cascades[cascade].position.x / probe_divisor;
+ ipush_constant.world_offset[1] = cascades[cascade].position.y / probe_divisor;
+ ipush_constant.world_offset[2] = cascades[cascade].position.z / probe_divisor;
+
+ ipush_constant.scroll[0] = dirty.x / probe_divisor;
+ ipush_constant.scroll[1] = dirty.y / probe_divisor;
+ ipush_constant.scroll[2] = dirty.z / probe_divisor;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL_STORE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (bounce_feedback > 0.0) {
+ //multibounce requires this to be stored so direct light can read from it
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE]);
+
+ //convert to octahedral to store
+ ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+ ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
+ }
+ }
+
+ //ok finally barrier
+ RD::get_singleton()->compute_list_end();
+ }
+
+ //clear dispatch indirect data
+ uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };
+ RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data);
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ bool half_size = true; //much faster, very little difference
+ static const int optimized_jf_group_size = 8;
+
+ if (half_size) {
+ push_constant.grid_size >>= 1;
+
+ uint32_t cascade_half_size = cascade_size >> 1;
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_half_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //must start with regular jumpflood
+
+ push_constant.half_size = true;
+ {
+ RENDER_TIMESTAMP("SDFGI Jump Flood (Half Size)");
+
+ uint32_t s = cascade_half_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD]);
+
+ int jf_us = 0;
+ //start with regular jump flood for very coarse reads, as this is impossible to optimize
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_half_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+
+ if (cascade_half_size / (s / 2) >= optimized_jf_group_size) {
+ break;
+ }
+ }
+
+ RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half Size)");
+
+ //continue with optimized jump flood for smaller reads
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_half_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+ }
+ }
+
+ // restore grid size for last passes
+ push_constant.grid_size = cascade_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_upscale_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //run one pass of fullsize jumpflood to fix up half size arctifacts
+
+ push_constant.half_size = false;
+ push_constant.step_size = 1;
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[upscale_jfa_uniform_set_index], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ } else {
+ //full size jumpflood
+ RENDER_TIMESTAMP("SDFGI Jump Flood");
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ push_constant.half_size = false;
+ {
+ uint32_t s = cascade_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD]);
+
+ int jf_us = 0;
+ //start with regular jump flood for very coarse reads, as this is impossible to optimize
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+
+ if (cascade_size / (s / 2) >= optimized_jf_group_size) {
+ break;
+ }
+ }
+
+ RENDER_TIMESTAMP("SDFGI Jump Flood Optimized");
+
+ //continue with optimized jump flood for smaller reads
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+ }
+ }
+ }
+
+ RENDER_TIMESTAMP("SDFGI Occlusion");
+
+ // occlusion
+ {
+ uint32_t probe_size = cascade_size / SDFGI::PROBE_DIVISOR;
+ Vector3i probe_global_pos = cascades[cascade].position / probe_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_OCCLUSION]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, occlusion_uniform_set, 0);
+ for (int i = 0; i < 8; i++) {
+ //dispatch all at once for performance
+ Vector3i offset(i & 1, (i >> 1) & 1, (i >> 2) & 1);
+
+ if ((probe_global_pos.x & 1) != 0) {
+ offset.x = (offset.x + 1) & 1;
+ }
+ if ((probe_global_pos.y & 1) != 0) {
+ offset.y = (offset.y + 1) & 1;
+ }
+ if ((probe_global_pos.z & 1) != 0) {
+ offset.z = (offset.z + 1) & 1;
+ }
+ push_constant.probe_offset[0] = offset.x;
+ push_constant.probe_offset[1] = offset.y;
+ push_constant.probe_offset[2] = offset.z;
+ push_constant.occlusion_index = i;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+
+ Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute
+ RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z);
+ }
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ RENDER_TIMESTAMP("SDFGI Store");
+
+ // store
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_STORE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].sdf_store_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+
+ RD::get_singleton()->compute_list_end();
+
+ //clear these textures, as they will have previous garbage on next draw
+ RD::get_singleton()->texture_clear(cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+
+#if 0
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(cascades[cascade].sdf, 0);
+ Ref<Image> img;
+ img.instance();
+ for (uint32_t i = 0; i < cascade_size; i++) {
+ Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1);
+ img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr);
+ img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png");
+ }
+
+ //finalize render and update sdf
+#endif
+
+#if 0
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(render_albedo, 0);
+ Ref<Image> img;
+ img.instance();
+ for (uint32_t i = 0; i < cascade_size; i++) {
+ Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1);
+ img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr);
+ img->convert(Image::FORMAT_RGBA8);
+ img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png");
+ }
+
+ //finalize render and update sdf
+#endif
+
+ RENDER_TIMESTAMP("<SDFGI Update SDF");
+ RD::get_singleton()->draw_command_end_label();
+ }
+}
+
+void RendererSceneGIRD::SDFGI::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) {
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
+
+ RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs");
+
+ update_cascades();
+ ; //need cascades updated for this
+
+ SDFGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS];
+ uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS];
+
+ for (uint32_t i = 0; i < p_cascade_count; i++) {
+ ERR_CONTINUE(p_cascade_indices[i] >= cascades.size());
+
+ SDFGI::Cascade &cc = cascades[p_cascade_indices[i]];
+
+ { //fill light buffer
+
+ AABB cascade_aabb;
+ cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cc.position)) * cc.cell_size;
+ cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cc.cell_size;
+
+ int idx = 0;
+
+ for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) {
+ if (idx == SDFGI::MAX_STATIC_LIGHTS) {
+ break;
+ }
+
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_positional_light_cull_result[i][j]);
+ ERR_CONTINUE(!li);
+
+ uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
+ if (p_cascade_indices[i] > max_sdfgi_cascade) {
+ continue;
+ }
+
+ if (!cascade_aabb.intersects(li->aabb)) {
+ continue;
+ }
+
+ lights[idx].type = storage->light_get_type(li->light);
+
+ Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
+ if (lights[idx].type == RS::LIGHT_DIRECTIONAL) {
+ dir.y *= y_mult; //only makes sense for directional
+ dir.normalize();
+ }
+ lights[idx].direction[0] = dir.x;
+ lights[idx].direction[1] = dir.y;
+ lights[idx].direction[2] = dir.z;
+ Vector3 pos = li->transform.origin;
+ pos.y *= y_mult;
+ lights[idx].position[0] = pos.x;
+ lights[idx].position[1] = pos.y;
+ lights[idx].position[2] = pos.z;
+ Color color = storage->light_get_color(li->light);
+ color = color.to_linear();
+ lights[idx].color[0] = color.r;
+ lights[idx].color[1] = color.g;
+ lights[idx].color[2] = color.b;
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].has_shadow = storage->light_has_shadow(li->light);
+ lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
+ lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
+ lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights);
+ }
+
+ light_count[i] = idx;
+ }
+ }
+
+ /* Static Lights */
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_STATIC]);
+
+ SDFGIShader::DirectLightPushConstant dl_push_constant;
+
+ dl_push_constant.grid_size[0] = cascade_size;
+ dl_push_constant.grid_size[1] = cascade_size;
+ dl_push_constant.grid_size[2] = cascade_size;
+ dl_push_constant.max_cascades = cascades.size();
+ dl_push_constant.probe_axis_size = probe_axis_count;
+ dl_push_constant.bounce_feedback = 0.0; // this is static light, do not multibounce yet
+ dl_push_constant.y_mult = y_mult;
+ dl_push_constant.use_occlusion = uses_occlusion;
+
+ //all must be processed
+ dl_push_constant.process_offset = 0;
+ dl_push_constant.process_increment = 1;
+
+ for (uint32_t i = 0; i < p_cascade_count; i++) {
+ ERR_CONTINUE(p_cascade_indices[i] >= cascades.size());
+
+ SDFGI::Cascade &cc = cascades[p_cascade_indices[i]];
+
+ dl_push_constant.light_count = light_count[i];
+ dl_push_constant.cascade = p_cascade_indices[i];
+
+ if (dl_push_constant.light_count > 0) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDFGIShader::DirectLightPushConstant));
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0);
+ }
+ }
+
+ RD::get_singleton()->compute_list_end();
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GIProbeInstance
+
+void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ uint32_t data_version = storage->gi_probe_get_data_version(probe);
+
+ // (RE)CREATE IF NEEDED
+
+ if (last_probe_data_version != data_version) {
+ //need to re-create everything
+ if (texture.is_valid()) {
+ RD::get_singleton()->free(texture);
+ RD::get_singleton()->free(write_buffer);
+ mipmaps.clear();
+ }
+
+ for (int i = 0; i < dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(dynamic_maps[i].texture);
+ RD::get_singleton()->free(dynamic_maps[i].depth);
+ }
+
+ dynamic_maps.clear();
+
+ Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+
+ if (octree_size != Vector3i()) {
+ //can create a 3D texture
+ Vector<int> levels = storage->gi_probe_get_level_counts(probe);
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tf.width = octree_size.x;
+ tf.height = octree_size.y;
+ tf.depth = octree_size.z;
+ tf.texture_type = RD::TEXTURE_TYPE_3D;
+ tf.mipmaps = levels.size();
+
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+ texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1);
+
+ {
+ int total_elements = 0;
+ for (int i = 0; i < levels.size(); i++) {
+ total_elements += levels[i];
+ }
+
+ write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16);
+ }
+
+ for (int i = 0; i < levels.size(); i++) {
+ GIProbeInstance::Mipmap mipmap;
+ mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D);
+ mipmap.level = levels.size() - i - 1;
+ mipmap.cell_offset = 0;
+ for (uint32_t j = 0; j < mipmap.level; j++) {
+ mipmap.cell_offset += levels[j];
+ }
+ mipmap.cell_count = levels[mipmap.level];
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->gi_probe_get_octree_buffer(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 4;
+ u.ids.push_back(write_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ Vector<RD::Uniform> copy_uniforms = uniforms;
+ if (i == 0) {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(gi->gi_probe_lights_uniform);
+ copy_uniforms.push_back(u);
+ }
+
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
+
+ copy_uniforms = uniforms; //restore
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ u.ids.push_back(texture);
+ copy_uniforms.push_back(u);
+ }
+ mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
+ } else {
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(mipmap.texture);
+ uniforms.push_back(u);
+ }
+
+ mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
+
+ mipmaps.push_back(mipmap);
+ }
+
+ {
+ uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+ uint32_t oversample = nearest_power_of_2_templated(4);
+ int mipmap_index = 0;
+
+ while (mipmap_index < mipmaps.size()) {
+ GIProbeInstance::DynamicMap dmap;
+
+ if (oversample > 0) {
+ dmap.size = dynamic_map_size * (1 << oversample);
+ dmap.mipmap = -1;
+ oversample--;
+ } else {
+ dmap.size = dynamic_map_size >> mipmap_index;
+ dmap.mipmap = mipmap_index;
+ mipmap_index++;
+ }
+
+ RD::TextureFormat dtf;
+ dtf.width = dmap.size;
+ dtf.height = dmap.size;
+ dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ if (dynamic_maps.size() == 0) {
+ dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+ dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ if (dynamic_maps.size() == 0) {
+ //render depth for first one
+ dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
+ dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ }
+
+ //just use depth as-is
+ dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ if (dynamic_maps.size() == 0) {
+ dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ Vector<RID> fb;
+ fb.push_back(dmap.albedo);
+ fb.push_back(dmap.normal);
+ fb.push_back(dmap.orm);
+ fb.push_back(dmap.texture); //emission
+ fb.push_back(dmap.depth);
+ fb.push_back(dmap.fb_depth);
+
+ dmap.fb = RD::get_singleton()->framebuffer_create(fb);
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(gi->gi_probe_lights_uniform);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(dmap.albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(dmap.normal);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.orm);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 8;
+ u.ids.push_back(dmap.fb_depth);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
+ }
+ } else {
+ bool plot = dmap.mipmap >= 0;
+ bool write = dmap.mipmap < (mipmaps.size() - 1);
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(dynamic_maps[dynamic_maps.size() - 1].texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(dynamic_maps[dynamic_maps.size() - 1].depth);
+ uniforms.push_back(u);
+ }
+
+ if (write) {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ if (plot) {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(mipmaps[dmap.mipmap].texture);
+ uniforms.push_back(u);
+ }
+ }
+
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(
+ uniforms,
+ gi->giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
+ 0);
+ }
+
+ dynamic_maps.push_back(dmap);
+ }
+ }
+ }
+
+ last_probe_data_version = data_version;
+ p_update_light_instances = true; //just in case
+
+ p_scene_render->_base_uniforms_changed();
+ }
+
+ // UDPDATE TIME
+
+ if (has_dynamic_object_data) {
+ //if it has dynamic object data, it needs to be cleared
+ RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, mipmaps.size(), 0, 1);
+ }
+
+ uint32_t light_count = 0;
+
+ if (p_update_light_instances || p_dynamic_objects.size() > 0) {
+ light_count = MIN(gi->gi_probe_max_lights, (uint32_t)p_light_instances.size());
+
+ {
+ Transform to_cell = storage->gi_probe_get_to_cell_xform(probe);
+ Transform to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
+ //update lights
+
+ for (uint32_t i = 0; i < light_count; i++) {
+ GIProbeLight &l = gi->gi_probe_lights[i];
+ RID light_instance = p_light_instances[i];
+ RID light = p_scene_render->light_instance_get_base_light(light_instance);
+
+ l.type = storage->light_get_type(light);
+ if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) {
+ light_count--;
+ continue;
+ }
+
+ l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
+ l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
+ Color color = storage->light_get_color(light).to_linear();
+ l.color[0] = color.r;
+ l.color[1] = color.g;
+ l.color[2] = color.b;
+
+ l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ Transform xform = p_scene_render->light_instance_get_base_transform(light_instance);
+
+ Vector3 pos = to_probe_xform.xform(xform.origin);
+ Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
+
+ l.position[0] = pos.x;
+ l.position[1] = pos.y;
+ l.position[2] = pos.z;
+
+ l.direction[0] = dir.x;
+ l.direction[1] = dir.y;
+ l.direction[2] = dir.z;
+
+ l.has_shadow = storage->light_has_shadow(light);
+ }
+
+ RD::get_singleton()->buffer_update(gi->gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi->gi_probe_lights);
+ }
+ }
+
+ if (has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) {
+ // PROCESS MIPMAPS
+ if (mipmaps.size()) {
+ //can update mipmaps
+
+ Vector3i probe_size = storage->gi_probe_get_octree_size(probe);
+
+ GIProbePushConstant push_constant;
+
+ push_constant.limits[0] = probe_size.x;
+ push_constant.limits[1] = probe_size.y;
+ push_constant.limits[2] = probe_size.z;
+ push_constant.stack_size = mipmaps.size();
+ push_constant.emission_scale = 1.0;
+ push_constant.propagation = storage->gi_probe_get_propagation(probe);
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.light_count = light_count;
+ push_constant.aniso_strength = 0;
+
+ /* print_line("probe update to version " + itos(last_probe_version));
+ print_line("propagation " + rtos(push_constant.propagation));
+ print_line("dynrange " + rtos(push_constant.dynamic_range));
+ */
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ int passes;
+ if (p_update_light_instances) {
+ passes = storage->gi_probe_is_using_two_bounces(probe) ? 2 : 1;
+ } else {
+ passes = 1; //only re-blitting is necessary
+ }
+ int wg_size = 64;
+ int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
+
+ for (int pass = 0; pass < passes; pass++) {
+ if (p_update_light_instances) {
+ for (int i = 0; i < mipmaps.size(); i++) {
+ if (i == 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
+ } else if (i == 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
+ }
+
+ if (pass == 1 || i > 0) {
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+ }
+ if (pass == 0 || i > 0) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].uniform_set, 0);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].second_bounce_uniform_set, 0);
+ }
+
+ push_constant.cell_offset = mipmaps[i].cell_offset;
+ push_constant.cell_count = mipmaps[i].cell_count;
+
+ int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
+ while (wg_todo) {
+ int wg_count = MIN(wg_todo, wg_limit_x);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+ wg_todo -= wg_count;
+ push_constant.cell_offset += wg_count * wg_size;
+ }
+ }
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+ }
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+
+ for (int i = 0; i < mipmaps.size(); i++) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0);
+
+ push_constant.cell_offset = mipmaps[i].cell_offset;
+ push_constant.cell_count = mipmaps[i].cell_count;
+
+ int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
+ while (wg_todo) {
+ int wg_count = MIN(wg_todo, wg_limit_x);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+ wg_todo -= wg_count;
+ push_constant.cell_offset += wg_count * wg_size;
+ }
+ }
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+ }
+
+ has_dynamic_object_data = false; //clear until dynamic object data is used again
+
+ if (p_dynamic_objects.size() && dynamic_maps.size()) {
+ Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ int multiplier = dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+
+ Transform oversample_scale;
+ oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
+
+ Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(probe);
+ Transform to_world_xform = transform * to_cell.affine_inverse();
+ Transform to_probe_xform = to_world_xform.affine_inverse();
+
+ AABB probe_aabb(Vector3(), octree_size);
+
+ //this could probably be better parallelized in compute..
+ for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {
+ RendererSceneRender::GeometryInstance *instance = p_dynamic_objects[i];
+
+ //transform aabb to giprobe
+ AABB aabb = (to_probe_xform * p_scene_render->geometry_instance_get_transform(instance)).xform(p_scene_render->geometry_instance_get_aabb(instance));
+
+ //this needs to wrap to grid resolution to avoid jitter
+ //also extend margin a bit just in case
+ Vector3i begin = aabb.position - Vector3i(1, 1, 1);
+ Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
+
+ for (int j = 0; j < 3; j++) {
+ if ((end[j] - begin[j]) & 1) {
+ end[j]++; //for half extents split, it needs to be even
+ }
+ begin[j] = MAX(begin[j], 0);
+ end[j] = MIN(end[j], octree_size[j] * multiplier);
+ }
+
+ //aabb = aabb.intersection(probe_aabb); //intersect
+ aabb.position = begin;
+ aabb.size = end - begin;
+
+ //print_line("aabb: " + aabb);
+
+ for (int j = 0; j < 6; j++) {
+ //if (j != 0 && j != 3) {
+ // continue;
+ //}
+ static const Vector3 render_z[6] = {
+ Vector3(1, 0, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(-1, 0, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, -1),
+ };
+ static const Vector3 render_up[6] = {
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ };
+
+ Vector3 render_dir = render_z[j];
+ Vector3 up_dir = render_up[j];
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ Transform xform;
+ xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
+
+ Vector3 x_dir = xform.basis.get_axis(0).abs();
+ int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
+ Vector3 y_dir = xform.basis.get_axis(1).abs();
+ int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
+ Vector3 z_dir = -xform.basis.get_axis(2);
+ int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
+
+ Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
+ bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
+ bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
+ bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
+
+ CameraMatrix cm;
+ cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
+
+ if (p_scene_render->cull_argument.size() == 0) {
+ p_scene_render->cull_argument.push_back(nullptr);
+ }
+ p_scene_render->cull_argument[0] = instance;
+
+ 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));
+ push_constant.limits[0] = octree_size.x;
+ push_constant.limits[1] = octree_size.y;
+ push_constant.limits[2] = octree_size.z;
+ push_constant.light_count = p_light_instances.size();
+ push_constant.x_dir[0] = x_dir[0];
+ push_constant.x_dir[1] = x_dir[1];
+ push_constant.x_dir[2] = x_dir[2];
+ push_constant.y_dir[0] = y_dir[0];
+ push_constant.y_dir[1] = y_dir[1];
+ push_constant.y_dir[2] = y_dir[2];
+ push_constant.z_dir[0] = z_dir[0];
+ push_constant.z_dir[1] = z_dir[1];
+ push_constant.z_dir[2] = z_dir[2];
+ push_constant.z_base = xform.origin[z_axis];
+ push_constant.z_sign = (z_flip ? -1.0 : 1.0);
+ push_constant.pos_multiplier = float(1.0) / multiplier;
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.flip_x = x_flip;
+ push_constant.flip_y = y_flip;
+ push_constant.rect_pos[0] = rect.position[0];
+ push_constant.rect_pos[1] = rect.position[1];
+ push_constant.rect_size[0] = rect.size[0];
+ push_constant.rect_size[1] = rect.size[1];
+ push_constant.prev_rect_ofs[0] = 0;
+ push_constant.prev_rect_ofs[1] = 0;
+ push_constant.prev_rect_size[0] = 0;
+ push_constant.prev_rect_size[1] = 0;
+ push_constant.on_mipmap = false;
+ push_constant.propagation = storage->gi_probe_get_propagation(probe);
+ push_constant.pad[0] = 0;
+ push_constant.pad[1] = 0;
+ push_constant.pad[2] = 0;
+
+ //process lighting
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
+ //print_line("rect: " + itos(i) + ": " + rect);
+
+ for (int k = 1; k < dynamic_maps.size(); k++) {
+ // enlarge the rect if needed so all pixels fit when downscaled,
+ // this ensures downsampling is smooth and optimal because no pixels are left behind
+
+ //x
+ if (rect.position.x & 1) {
+ rect.size.x++;
+ push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
+ } else {
+ push_constant.prev_rect_ofs[0] = 0;
+ }
+ if (rect.size.x & 1) {
+ rect.size.x++;
+ }
+
+ rect.position.x >>= 1;
+ rect.size.x = MAX(1, rect.size.x >> 1);
+
+ //y
+ if (rect.position.y & 1) {
+ rect.size.y++;
+ push_constant.prev_rect_ofs[1] = 1;
+ } else {
+ push_constant.prev_rect_ofs[1] = 0;
+ }
+ if (rect.size.y & 1) {
+ rect.size.y++;
+ }
+
+ rect.position.y >>= 1;
+ rect.size.y = MAX(1, rect.size.y >> 1);
+
+ //shrink limits to ensure plot does not go outside map
+ if (dynamic_maps[k].mipmap > 0) {
+ for (int l = 0; l < 3; l++) {
+ push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
+ }
+ }
+
+ //print_line("rect: " + itos(i) + ": " + rect);
+ push_constant.rect_pos[0] = rect.position[0];
+ push_constant.rect_pos[1] = rect.position[1];
+ push_constant.prev_rect_size[0] = push_constant.rect_size[0];
+ push_constant.prev_rect_size[1] = push_constant.rect_size[1];
+ push_constant.rect_size[0] = rect.size[0];
+ push_constant.rect_size[1] = rect.size[1];
+ push_constant.on_mipmap = dynamic_maps[k].mipmap > 0;
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (dynamic_maps[k].mipmap < 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
+ } else if (k < dynamic_maps.size() - 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
+ } else {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+ }
+
+ has_dynamic_object_data = true; //clear until dynamic object data is used again
+ }
+
+ last_probe_version = storage->gi_probe_get_version(probe);
+}
+
+void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+ if (mipmaps.size() == 0) {
+ return;
+ }
+
+ CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(probe).affine_inverse());
+
+ int level = 0;
+ Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+
+ GIProbeDebugPushConstant push_constant;
+ push_constant.alpha = p_alpha;
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.cell_offset = mipmaps[level].cell_offset;
+ push_constant.level = level;
+
+ push_constant.bounds[0] = octree_size.x >> level;
+ push_constant.bounds[1] = octree_size.y >> level;
+ push_constant.bounds[2] = octree_size.z >> level;
+ push_constant.pad = 0;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ push_constant.projection[i * 4 + j] = cam_transform.matrix[i][j];
+ }
+ }
+
+ if (gi->giprobe_debug_uniform_set.is_valid()) {
+ RD::get_singleton()->free(gi->giprobe_debug_uniform_set);
+ }
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 3;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ int cell_count;
+ if (!p_emission && p_lighting && has_dynamic_object_data) {
+ cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
+ } else {
+ cell_count = mipmaps[level].cell_count;
+ }
+
+ gi->giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_debug_shader_version_shaders[0], 0);
+
+ int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR;
+ if (p_emission) {
+ giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION;
+ } else if (p_lighting) {
+ giprobe_debug_pipeline = has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT;
+ }
+ RD::get_singleton()->draw_list_bind_render_pipeline(
+ p_draw_list,
+ gi->giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->giprobe_debug_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GIRD
+
+RendererSceneGIRD::RendererSceneGIRD() {
+ sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1)));
+ sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1)));
+ sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1)));
+}
+
+RendererSceneGIRD::~RendererSceneGIRD() {
+}
+
+void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p_sky) {
+ storage = p_storage;
+
+ /* GI */
+
+ {
+ //kinda complicated to compute the amount of slots, we try to use as many as we can
+
+ gi_probe_max_lights = 32;
+
+ gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
+ gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
+ gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1));
+
+ String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
+ versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
+ versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
+ versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+
+ giprobe_shader.initialize(versions, defines);
+ giprobe_lighting_shader_version = giprobe_shader.version_create();
+ for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
+ giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
+ giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
+ }
+ }
+
+ {
+ String defines;
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_DEBUG_COLOR\n");
+ versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
+ versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
+ versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
+
+ giprobe_debug_shader.initialize(versions, defines);
+ giprobe_debug_shader_version = giprobe_debug_shader.version_create();
+ for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
+ giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
+
+ RD::PipelineRasterizationState rs;
+ rs.cull_mode = RD::POLYGON_CULL_FRONT;
+ RD::PipelineDepthStencilState ds;
+ ds.enable_depth_test = true;
+ ds.enable_depth_write = true;
+ ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+
+ giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ /* SDGFI */
+
+ {
+ Vector<String> preprocess_modes;
+ preprocess_modes.push_back("\n#define MODE_SCROLL\n");
+ preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n");
+ preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n");
+ preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n");
+ preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n");
+ preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n");
+ preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n");
+ preprocess_modes.push_back("\n#define MODE_OCCLUSION\n");
+ preprocess_modes.push_back("\n#define MODE_STORE\n");
+ String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n";
+ sdfgi_shader.preprocess.initialize(preprocess_modes, defines);
+ sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create();
+ for (int i = 0; i < SDFGIShader::PRE_PROCESS_MAX; i++) {
+ sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i));
+ }
+ }
+
+ {
+ //calculate tables
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+
+ Vector<String> direct_light_modes;
+ direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n");
+ direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n");
+ sdfgi_shader.direct_light.initialize(direct_light_modes, defines);
+ sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create();
+ for (int i = 0; i < SDFGIShader::DIRECT_LIGHT_MODE_MAX; i++) {
+ sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i));
+ }
+ }
+
+ {
+ //calculate tables
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n";
+ if (p_sky->sky_use_cubemap_array) {
+ defines += "\n#define USE_CUBEMAP_ARRAY\n";
+ }
+
+ Vector<String> integrate_modes;
+ integrate_modes.push_back("\n#define MODE_PROCESS\n");
+ integrate_modes.push_back("\n#define MODE_STORE\n");
+ integrate_modes.push_back("\n#define MODE_SCROLL\n");
+ integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n");
+ sdfgi_shader.integrate.initialize(integrate_modes, defines);
+ sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create();
+
+ for (int i = 0; i < SDFGIShader::INTEGRATE_MODE_MAX; i++) {
+ sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i));
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1);
+ }
+ }
+
+ //GK
+ {
+ //calculate tables
+ String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ Vector<String> gi_modes;
+ gi_modes.push_back("\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define USE_SDFGI\n");
+ gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
+
+ shader.initialize(gi_modes, defines);
+ shader_version = shader.version_create();
+ for (int i = 0; i < MODE_MAX; i++) {
+ pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i));
+ }
+
+ sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGIData));
+ }
+ {
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ Vector<String> debug_modes;
+ debug_modes.push_back("");
+ sdfgi_shader.debug.initialize(debug_modes, defines);
+ sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create();
+ sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0);
+ sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version);
+ }
+ {
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_PROBES\n");
+ versions.push_back("\n#define MODE_VISIBILITY\n");
+
+ sdfgi_shader.debug_probes.initialize(versions, defines);
+ sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create();
+
+ {
+ RD::PipelineRasterizationState rs;
+ rs.cull_mode = RD::POLYGON_CULL_DISABLED;
+ RD::PipelineDepthStencilState ds;
+ ds.enable_depth_test = true;
+ ds.enable_depth_write = true;
+ ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ for (int i = 0; i < SDFGIShader::PROBE_DEBUG_MAX; i++) {
+ RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i);
+ sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+ }
+ default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
+}
+
+void RendererSceneGIRD::free() {
+ RD::get_singleton()->free(default_giprobe_buffer);
+ RD::get_singleton()->free(gi_probe_lights_uniform);
+ RD::get_singleton()->free(sdfgi_ubo);
+
+ giprobe_debug_shader.version_free(giprobe_debug_shader_version);
+ giprobe_shader.version_free(giprobe_lighting_shader_version);
+ shader.version_free(shader_version);
+ sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader);
+ sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader);
+ sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader);
+ sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
+ sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
+
+ memdelete_arr(gi_probe_lights);
+}
+
+RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
+ SDFGI *sdfgi = memnew(SDFGI);
+
+ sdfgi->create(p_env, p_world_position, p_requested_history_size, this);
+
+ return sdfgi;
+}
+
+void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render) {
+ r_gi_probes_used = 0;
+
+ // feels a little dirty to use our container this way but....
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+
+ RID gi_probe_buffer = p_scene_render->render_buffers_get_gi_probe_buffer(p_render_buffers);
+
+ RD::get_singleton()->draw_command_begin_label("GIProbes Setup");
+
+ GIProbeData gi_probe_data[MAX_GIPROBES];
+
+ bool giprobes_changed = false;
+
+ Transform to_camera;
+ to_camera.origin = p_transform.origin; //only translation, make local
+
+ for (int i = 0; i < MAX_GIPROBES; i++) {
+ RID texture;
+ if (i < (int)p_gi_probes.size()) {
+ GIProbeInstance *gipi = get_probe_instance(p_gi_probes[i]);
+
+ if (gipi) {
+ texture = gipi->texture;
+ GIProbeData &gipd = gi_probe_data[i];
+
+ RID base_probe = gipi->probe;
+
+ Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
+
+ gipd.xform[0] = to_cell.basis.elements[0][0];
+ gipd.xform[1] = to_cell.basis.elements[1][0];
+ gipd.xform[2] = to_cell.basis.elements[2][0];
+ gipd.xform[3] = 0;
+ gipd.xform[4] = to_cell.basis.elements[0][1];
+ gipd.xform[5] = to_cell.basis.elements[1][1];
+ gipd.xform[6] = to_cell.basis.elements[2][1];
+ gipd.xform[7] = 0;
+ gipd.xform[8] = to_cell.basis.elements[0][2];
+ gipd.xform[9] = to_cell.basis.elements[1][2];
+ gipd.xform[10] = to_cell.basis.elements[2][2];
+ gipd.xform[11] = 0;
+ gipd.xform[12] = to_cell.origin.x;
+ gipd.xform[13] = to_cell.origin.y;
+ gipd.xform[14] = to_cell.origin.z;
+ gipd.xform[15] = 1;
+
+ Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+
+ gipd.bounds[0] = bounds.x;
+ gipd.bounds[1] = bounds.y;
+ gipd.bounds[2] = bounds.z;
+
+ gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
+ gipd.bias = storage->gi_probe_get_bias(base_probe);
+ gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
+ gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gipd.anisotropy_strength = 0;
+ gipd.ao = storage->gi_probe_get_ao(base_probe);
+ gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
+ gipd.mipmaps = gipi->mipmaps.size();
+ }
+
+ r_gi_probes_used++;
+ }
+
+ if (texture == RID()) {
+ texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+
+ if (texture != rb->gi.giprobe_textures[i]) {
+ giprobes_changed = true;
+ rb->gi.giprobe_textures[i] = texture;
+ }
+ }
+
+ if (giprobes_changed) {
+ 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();
+ 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);
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ }
+ rb->volumetric_fog->uniform_set = RID();
+ rb->volumetric_fog->uniform_set2 = RID();
+ }
+ }
+
+ if (p_gi_probes.size() > 0) {
+ RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GIProbeData) * MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render) {
+ RD::get_singleton()->draw_command_begin_label("GI Render");
+
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ 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_valid()) {
+ RD::get_singleton()->free(rb->ambient_buffer);
+ RD::get_singleton()->free(rb->reflection_buffer);
+ }
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ if (half_resolution) {
+ tf.width >>= 1;
+ tf.height >>= 1;
+ }
+ 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);
+ }
+
+ PushConstant push_constant;
+
+ push_constant.screen_size[0] = rb->width;
+ push_constant.screen_size[1] = rb->height;
+ push_constant.z_near = p_projection.get_z_near();
+ push_constant.z_far = p_projection.get_z_far();
+ push_constant.orthogonal = p_projection.is_orthogonal();
+ push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]);
+ push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
+ push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
+ push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
+ push_constant.max_giprobes = MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size());
+ push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;
+
+ bool use_sdfgi = rb->sdfgi != nullptr;
+ bool use_giprobes = push_constant.max_giprobes > 0;
+
+ if (env) {
+ push_constant.ao_color[0] = env->ao_color.r;
+ push_constant.ao_color[1] = env->ao_color.g;
+ push_constant.ao_color[2] = env->ao_color.b;
+ } else {
+ push_constant.ao_color[0] = 0;
+ push_constant.ao_color[1] = 0;
+ push_constant.ao_color[2] = 0;
+ }
+
+ push_constant.cam_rotation[0] = p_transform.basis[0][0];
+ push_constant.cam_rotation[1] = p_transform.basis[1][0];
+ push_constant.cam_rotation[2] = p_transform.basis[2][0];
+ push_constant.cam_rotation[3] = 0;
+ push_constant.cam_rotation[4] = p_transform.basis[0][1];
+ push_constant.cam_rotation[5] = p_transform.basis[1][1];
+ push_constant.cam_rotation[6] = p_transform.basis[2][1];
+ push_constant.cam_rotation[7] = 0;
+ push_constant.cam_rotation[8] = p_transform.basis[0][2];
+ push_constant.cam_rotation[9] = p_transform.basis[1][2];
+ 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)) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].light_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ if (rb->sdfgi) {
+ u.ids.push_back(rb->sdfgi->occlusion_texture);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 6;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 7;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 9;
+ u.ids.push_back(rb->ambient_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 10;
+ u.ids.push_back(rb->reflection_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 11;
+ if (rb->sdfgi) {
+ u.ids.push_back(rb->sdfgi->lightprobe_texture);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 12;
+ u.ids.push_back(rb->depth_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 13;
+ u.ids.push_back(p_normal_roughness_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 14;
+ RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 15;
+ u.ids.push_back(sdfgi_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 16;
+ u.ids.push_back(rb->gi.giprobe_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 17;
+ for (int i = 0; i < MAX_GIPROBES; i++) {
+ u.ids.push_back(rb->gi.giprobe_textures[i]);
+ }
+ uniforms.push_back(u);
+ }
+
+ 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) {
+ 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_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
+
+ if (rb->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);
+ }
+ //do barrier later to allow oeverlap
+ //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
+ RD::get_singleton()->draw_command_end_label();
+}
+
+RID RendererSceneGIRD::gi_probe_instance_create(RID p_base) {
+ GIProbeInstance gi_probe;
+ gi_probe.gi = this;
+ gi_probe.storage = storage;
+ gi_probe.probe = p_base;
+ RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+ return rid;
+}
+
+void RendererSceneGIRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->transform = p_xform;
+}
+
+bool RendererSceneGIRD::gi_probe_needs_update(RID p_probe) const {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!gi_probe, false);
+
+ return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+}
+
+void RendererSceneGIRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
+}
+
+void RendererSceneGIRD::debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
+}
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
new file mode 100644
index 0000000000..c0f3318538
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
@@ -0,0 +1,668 @@
+/*************************************************************************/
+/* renderer_scene_gi_rd.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_GI_RD_H
+#define RENDERING_SERVER_SCENE_GI_RD_H
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
+#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
+class RendererSceneRenderRD;
+
+class RendererSceneGIRD {
+private:
+ RendererStorageRD *storage;
+
+ /* GIPROBE INSTANCE */
+
+ struct GIProbeLight {
+ uint32_t type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ float color[3];
+ float cos_spot_angle;
+
+ float position[3];
+ float inv_spot_attenuation;
+
+ float direction[3];
+ uint32_t has_shadow;
+ };
+
+ struct GIProbePushConstant {
+ int32_t limits[3];
+ uint32_t stack_size;
+
+ float emission_scale;
+ float propagation;
+ float dynamic_range;
+ uint32_t light_count;
+
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ float aniso_strength;
+ uint32_t pad;
+ };
+
+ struct GIProbeDynamicPushConstant {
+ int32_t limits[3];
+ uint32_t light_count;
+ int32_t x_dir[3];
+ float z_base;
+ int32_t y_dir[3];
+ float z_sign;
+ int32_t z_dir[3];
+ float pos_multiplier;
+ uint32_t rect_pos[2];
+ uint32_t rect_size[2];
+ uint32_t prev_rect_ofs[2];
+ uint32_t prev_rect_size[2];
+ uint32_t flip_x;
+ uint32_t flip_y;
+ float dynamic_range;
+ uint32_t on_mipmap;
+ float propagation;
+ float pad[3];
+ };
+
+ GIProbeLight *gi_probe_lights;
+ uint32_t gi_probe_max_lights;
+ RID gi_probe_lights_uniform;
+
+ enum {
+ GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
+ GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
+ GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
+ GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
+ GI_PROBE_SHADER_VERSION_MAX
+ };
+
+ GiprobeShaderRD giprobe_shader;
+ RID giprobe_lighting_shader_version;
+ RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
+ RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
+
+ enum {
+ GI_PROBE_DEBUG_COLOR,
+ GI_PROBE_DEBUG_LIGHT,
+ GI_PROBE_DEBUG_EMISSION,
+ GI_PROBE_DEBUG_LIGHT_FULL,
+ GI_PROBE_DEBUG_MAX
+ };
+
+ struct GIProbeDebugPushConstant {
+ float projection[16];
+ uint32_t cell_offset;
+ float dynamic_range;
+ float alpha;
+ uint32_t level;
+ int32_t bounds[3];
+ uint32_t pad;
+ };
+
+ GiprobeDebugShaderRD giprobe_debug_shader;
+ RID giprobe_debug_shader_version;
+ RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
+ PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
+ RID giprobe_debug_uniform_set;
+
+ /* SDFGI */
+
+ struct SDFGIShader {
+ enum SDFGIPreprocessShaderVersion {
+ PRE_PROCESS_SCROLL,
+ PRE_PROCESS_SCROLL_OCCLUSION,
+ PRE_PROCESS_JUMP_FLOOD_INITIALIZE,
+ PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF,
+ PRE_PROCESS_JUMP_FLOOD,
+ PRE_PROCESS_JUMP_FLOOD_OPTIMIZED,
+ PRE_PROCESS_JUMP_FLOOD_UPSCALE,
+ PRE_PROCESS_OCCLUSION,
+ PRE_PROCESS_STORE,
+ PRE_PROCESS_MAX
+ };
+
+ struct PreprocessPushConstant {
+ int32_t scroll[3];
+ int32_t grid_size;
+
+ int32_t probe_offset[3];
+ int32_t step_size;
+
+ int32_t half_size;
+ uint32_t occlusion_index;
+ int32_t cascade;
+ uint32_t pad;
+ };
+
+ SdfgiPreprocessShaderRD preprocess;
+ RID preprocess_shader;
+ RID preprocess_pipeline[PRE_PROCESS_MAX];
+
+ struct DebugPushConstant {
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ int32_t screen_size[2];
+ uint32_t use_occlusion;
+ float y_mult;
+
+ float cam_extent[3];
+ uint32_t probe_axis_size;
+
+ float cam_transform[16];
+ };
+
+ SdfgiDebugShaderRD debug;
+ RID debug_shader;
+ RID debug_shader_version;
+ RID debug_pipeline;
+
+ enum ProbeDebugMode {
+ PROBE_DEBUG_PROBES,
+ PROBE_DEBUG_VISIBILITY,
+ PROBE_DEBUG_MAX
+ };
+
+ struct DebugProbesPushConstant {
+ float projection[16];
+
+ uint32_t band_power;
+ uint32_t sections_in_band;
+ uint32_t band_mask;
+ float section_arc;
+
+ float grid_size[3];
+ uint32_t cascade;
+
+ uint32_t pad;
+ float y_mult;
+ int32_t probe_debug_index;
+ int32_t probe_axis_size;
+ };
+
+ SdfgiDebugProbesShaderRD debug_probes;
+ RID debug_probes_shader;
+ RID debug_probes_shader_version;
+
+ PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX];
+
+ struct Light {
+ float color[3];
+ float energy;
+
+ float direction[3];
+ uint32_t has_shadow;
+
+ float position[3];
+ float attenuation;
+
+ uint32_t type;
+ float cos_spot_angle;
+ float inv_spot_attenuation;
+ float radius;
+
+ float shadow_color[4];
+ };
+
+ struct DirectLightPushConstant {
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ uint32_t cascade;
+ uint32_t light_count;
+ uint32_t process_offset;
+ uint32_t process_increment;
+
+ int32_t probe_axis_size;
+ float bounce_feedback;
+ float y_mult;
+ uint32_t use_occlusion;
+ };
+
+ enum {
+ DIRECT_LIGHT_MODE_STATIC,
+ DIRECT_LIGHT_MODE_DYNAMIC,
+ DIRECT_LIGHT_MODE_MAX
+ };
+ SdfgiDirectLightShaderRD direct_light;
+ RID direct_light_shader;
+ RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
+
+ enum {
+ INTEGRATE_MODE_PROCESS,
+ INTEGRATE_MODE_STORE,
+ INTEGRATE_MODE_SCROLL,
+ INTEGRATE_MODE_SCROLL_STORE,
+ INTEGRATE_MODE_MAX
+ };
+ struct IntegratePushConstant {
+ enum {
+ SKY_MODE_DISABLED,
+ SKY_MODE_COLOR,
+ SKY_MODE_SKY,
+ };
+
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ uint32_t probe_axis_size;
+ uint32_t cascade;
+ uint32_t history_index;
+ uint32_t history_size;
+
+ uint32_t ray_count;
+ float ray_bias;
+ int32_t image_size[2];
+
+ int32_t world_offset[3];
+ uint32_t sky_mode;
+
+ int32_t scroll[3];
+ float sky_energy;
+
+ float sky_color[3];
+ float y_mult;
+
+ uint32_t store_ambient_texture;
+ uint32_t pad[3];
+ };
+
+ SdfgiIntegrateShaderRD integrate;
+ RID integrate_shader;
+ RID integrate_pipeline[INTEGRATE_MODE_MAX];
+
+ RID integrate_default_sky_uniform_set;
+
+ } sdfgi_shader;
+
+public:
+ /* GIPROBE INSTANCE */
+
+ //@TODO GIProbeInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
+
+ struct GIProbeInstance {
+ // access to our containers
+ RendererStorageRD *storage;
+ RendererSceneGIRD *gi;
+
+ RID probe;
+ RID texture;
+ RID write_buffer;
+
+ struct Mipmap {
+ RID texture;
+ RID uniform_set;
+ RID second_bounce_uniform_set;
+ RID write_uniform_set;
+ uint32_t level;
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ };
+ Vector<Mipmap> mipmaps;
+
+ struct DynamicMap {
+ RID texture; //color normally, or emission on first pass
+ RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
+ RID depth; //actual depth buffer for the first pass, float depth for later passes
+ RID normal; //normal buffer for the first pass
+ RID albedo; //emission buffer for the first pass
+ RID orm; //orm buffer for the first pass
+ RID fb; //used for rendering, only valid on first map
+ RID uniform_set;
+ uint32_t size;
+ int mipmap; // mipmap to write to, -1 if no mipmap assigned
+ };
+
+ Vector<DynamicMap> dynamic_maps;
+
+ int slot = -1;
+ uint32_t last_probe_version = 0;
+ uint32_t last_probe_data_version = 0;
+
+ //uint64_t last_pass = 0;
+ uint32_t render_index = 0;
+
+ bool has_dynamic_object_data = false;
+
+ Transform transform;
+
+ void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+ };
+
+ mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+
+ _FORCE_INLINE_ GIProbeInstance *get_probe_instance(RID p_probe) const {
+ return gi_probe_instance_owner.getornull(p_probe);
+ };
+
+ _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+ return gi_probe->texture;
+ };
+
+ RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH;
+
+ /* SDFGI */
+
+ struct SDFGI {
+ enum {
+ MAX_CASCADES = 8,
+ CASCADE_SIZE = 128,
+ PROBE_DIVISOR = 16,
+ ANISOTROPY_SIZE = 6,
+ MAX_DYNAMIC_LIGHTS = 128,
+ MAX_STATIC_LIGHTS = 1024,
+ LIGHTPROBE_OCT_SIZE = 6,
+ SH_SIZE = 16
+ };
+
+ struct Cascade {
+ struct UBO {
+ float offset[3];
+ float to_cell;
+ int32_t probe_offset[3];
+ uint32_t pad;
+ };
+
+ //cascade blocks are full-size for volume (128^3), half size for albedo/emission
+ RID sdf_tex;
+ RID light_tex;
+ RID light_aniso_0_tex;
+ RID light_aniso_1_tex;
+
+ RID light_data;
+ RID light_aniso_0_data;
+ RID light_aniso_1_data;
+
+ struct SolidCell { // this struct is unused, but remains as reference for size
+ uint32_t position;
+ uint32_t albedo;
+ uint32_t static_light;
+ uint32_t static_light_aniso;
+ };
+
+ RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch
+ RID solid_cell_buffer;
+
+ RID lightprobe_history_tex;
+ RID lightprobe_average_tex;
+
+ float cell_size;
+ Vector3i position;
+
+ static const Vector3i DIRTY_ALL;
+ Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all.
+
+ RID sdf_store_uniform_set;
+ RID sdf_direct_light_uniform_set;
+ RID scroll_uniform_set;
+ RID scroll_occlusion_uniform_set;
+ RID integrate_uniform_set;
+ RID lights_buffer;
+
+ bool all_dynamic_lights_dirty = true;
+ };
+
+ // access to our containers
+ RendererStorageRD *storage;
+ RendererSceneGIRD *gi;
+
+ // used for rendering (voxelization)
+ RID render_albedo;
+ RID render_emission;
+ RID render_emission_aniso;
+ RID render_occlusion[8];
+ RID render_geom_facing;
+
+ RID render_sdf[2];
+ RID render_sdf_half[2];
+
+ // used for ping pong processing in cascades
+ RID sdf_initialize_uniform_set;
+ RID sdf_initialize_half_uniform_set;
+ RID jump_flood_uniform_set[2];
+ RID jump_flood_half_uniform_set[2];
+ RID sdf_upscale_uniform_set;
+ int upscale_jfa_uniform_set_index;
+ RID occlusion_uniform_set;
+
+ uint32_t cascade_size = 128;
+
+ LocalVector<Cascade> cascades;
+
+ RID lightprobe_texture;
+ RID lightprobe_data;
+ RID occlusion_texture;
+ RID occlusion_data;
+ RID ambient_texture; //integrates with volumetric fog
+
+ RID lightprobe_history_scroll; //used for scrolling lightprobes
+ RID lightprobe_average_scroll; //used for scrolling lightprobes
+
+ uint32_t history_size = 0;
+ float solid_cell_ratio = 0;
+ uint32_t solid_cell_count = 0;
+
+ RS::EnvironmentSDFGICascades cascade_mode;
+ float min_cell_size = 0;
+ uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints
+
+ RID debug_uniform_set;
+ RID debug_probes_uniform_set;
+ RID cascades_ubo;
+
+ bool uses_occlusion = false;
+ float bounce_feedback = 0.0;
+ bool reads_sky = false;
+ float energy = 1.0;
+ float normal_bias = 1.1;
+ float probe_bias = 1.1;
+ RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED;
+
+ float y_mult = 1.0;
+
+ uint32_t render_pass = 0;
+
+ int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically
+ RID integrate_sky_uniform_set;
+
+ void create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi);
+ void erase();
+ void update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position);
+ void update_light();
+ void update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky);
+ void store_probes();
+ int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const;
+ void update_cascades();
+
+ 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 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);
+ };
+
+ RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
+ RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES;
+ RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES;
+
+ float sdfgi_solid_cell_ratio = 0.25;
+ Vector3 sdfgi_debug_probe_pos;
+ Vector3 sdfgi_debug_probe_dir;
+ bool sdfgi_debug_probe_enabled = false;
+ Vector3i sdfgi_debug_probe_index;
+
+ /* SDFGI UPDATE */
+
+ int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }
+
+ /* GI */
+ enum {
+ MAX_GIPROBES = 8
+ };
+
+ // Struct for use in render buffer
+ struct RenderBuffersGI {
+ RID giprobe_textures[MAX_GIPROBES];
+ RID giprobe_buffer;
+
+ RID full_buffer;
+ RID full_dispatch;
+ RID full_mask;
+ };
+
+ struct SDFGIData {
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ uint32_t use_occlusion;
+ int32_t probe_axis_size;
+ float probe_to_uvw;
+ float normal_bias;
+
+ float lightprobe_tex_pixel_size[3];
+ float energy;
+
+ float lightprobe_uv_offset[3];
+ float y_mult;
+
+ float occlusion_clamp[3];
+ uint32_t pad3;
+
+ float occlusion_renormalize[3];
+ uint32_t pad4;
+
+ float cascade_probe_size[3];
+ uint32_t pad5;
+
+ struct ProbeCascadeData {
+ float position[3]; //offset of (0,0,0) in world coordinates
+ float to_probe; // 1/bounds * grid_size
+ int32_t probe_world_offset[3];
+ float to_cell; // 1/bounds * grid_size
+ };
+
+ ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
+ };
+
+ struct GIProbeData {
+ float xform[16];
+ float bounds[3];
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ uint32_t blend_ambient;
+ uint32_t texture_slot;
+
+ float anisotropy_strength;
+ float ao;
+ float ao_size;
+ uint32_t mipmaps;
+ };
+
+ struct PushConstant {
+ int32_t screen_size[2];
+ float z_near;
+ float z_far;
+
+ float proj_info[4];
+ float ao_color[3];
+ uint32_t max_giprobes;
+
+ uint32_t high_quality_vct;
+ uint32_t orthogonal;
+ uint32_t pad[2];
+
+ float cam_rotation[12];
+ };
+
+ RID sdfgi_ubo;
+ enum Mode {
+ MODE_GIPROBE,
+ MODE_SDFGI,
+ MODE_COMBINED,
+ MODE_HALF_RES_GIPROBE,
+ MODE_HALF_RES_SDFGI,
+ MODE_HALF_RES_COMBINED,
+ MODE_MAX
+ };
+
+ RID default_giprobe_buffer;
+
+ bool half_resolution = false;
+ GiShaderRD shader;
+ RID shader_version;
+ RID pipelines[MODE_MAX];
+
+ RendererSceneGIRD();
+ ~RendererSceneGIRD();
+
+ void init(RendererStorageRD *p_storage, RendererSceneSkyRD *p_sky);
+ void free();
+
+ SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
+
+ void setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render);
+ void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render);
+
+ RID gi_probe_instance_create(RID p_base);
+ void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
+ bool gi_probe_needs_update(RID p_probe) const;
+ void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+};
+
+#endif /* !RENDERING_SERVER_SCENE_GI_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp
index a57dee7314..7a19495f48 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene_render_forward.cpp */
+/* renderer_scene_render_forward_clustered.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "renderer_scene_render_forward.h"
+#include "renderer_scene_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 RendererSceneRenderForward::ShaderData::set_code(const String &p_code) {
+void RendererSceneRenderForwardClustered::ShaderData::set_code(const String &p_code) {
//compile
code = p_code;
@@ -123,7 +123,7 @@ void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) {
actions.uniforms = &uniforms;
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
+ RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton;
Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
@@ -257,7 +257,7 @@ void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) {
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<RendererSceneRenderForward *>(singleton)->shader.scene_shader.is_variant_enabled(k)) {
+ if (!static_cast<RendererSceneRenderForwardClustered *>(singleton)->shader.scene_shader.is_variant_enabled(k)) {
continue;
}
RD::PipelineRasterizationState raster_state;
@@ -324,7 +324,7 @@ void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void RendererSceneRenderForward::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+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 {
@@ -332,7 +332,7 @@ void RendererSceneRenderForward::ShaderData::set_default_texture_param(const Str
}
}
-void RendererSceneRenderForward::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+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()) {
@@ -354,7 +354,7 @@ void RendererSceneRenderForward::ShaderData::get_param_list(List<PropertyInfo> *
}
}
-void RendererSceneRenderForward::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+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;
@@ -369,7 +369,7 @@ void RendererSceneRenderForward::ShaderData::get_instance_param_list(List<Render
}
}
-bool RendererSceneRenderForward::ShaderData::is_param_texture(const StringName &p_param) const {
+bool RendererSceneRenderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -377,15 +377,15 @@ bool RendererSceneRenderForward::ShaderData::is_param_texture(const StringName &
return uniforms[p_param].texture_order >= 0;
}
-bool RendererSceneRenderForward::ShaderData::is_animated() const {
+bool RendererSceneRenderForwardClustered::ShaderData::is_animated() const {
return false;
}
-bool RendererSceneRenderForward::ShaderData::casts_shadows() const {
+bool RendererSceneRenderForwardClustered::ShaderData::casts_shadows() const {
return false;
}
-Variant RendererSceneRenderForward::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+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;
@@ -394,19 +394,19 @@ Variant RendererSceneRenderForward::ShaderData::get_default_parameter(const Stri
return Variant();
}
-RS::ShaderNativeSourceCode RendererSceneRenderForward::ShaderData::get_native_source_code() const {
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
+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);
}
-RendererSceneRenderForward::ShaderData::ShaderData() {
+RendererSceneRenderForwardClustered::ShaderData::ShaderData() {
valid = false;
uses_screen_texture = false;
}
-RendererSceneRenderForward::ShaderData::~ShaderData() {
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
+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()) {
@@ -414,21 +414,21 @@ RendererSceneRenderForward::ShaderData::~ShaderData() {
}
}
-RendererStorageRD::ShaderData *RendererSceneRenderForward::_create_shader_func() {
+RendererStorageRD::ShaderData *RendererSceneRenderForwardClustered::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
return shader_data;
}
-void RendererSceneRenderForward::MaterialData::set_render_priority(int p_priority) {
+void RendererSceneRenderForwardClustered::MaterialData::set_render_priority(int p_priority) {
priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
}
-void RendererSceneRenderForward::MaterialData::set_next_pass(RID p_pass) {
+void RendererSceneRenderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
next_pass = p_pass;
}
-void RendererSceneRenderForward::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
+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;
@@ -507,7 +507,7 @@ void RendererSceneRenderForward::MaterialData::update_parameters(const Map<Strin
uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);
}
-RendererSceneRenderForward::MaterialData::~MaterialData() {
+RendererSceneRenderForwardClustered::MaterialData::~MaterialData() {
if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
RD::get_singleton()->free(uniform_set);
}
@@ -517,7 +517,7 @@ RendererSceneRenderForward::MaterialData::~MaterialData() {
}
}
-RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_func(ShaderData *p_shader) {
+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;
@@ -525,11 +525,11 @@ RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_fu
return material_data;
}
-RendererSceneRenderForward::RenderBufferDataForward::~RenderBufferDataForward() {
+RendererSceneRenderForwardClustered::RenderBufferDataForward::~RenderBufferDataForward() {
clear();
}
-void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() {
+void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_specular() {
if (!specular.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
@@ -583,7 +583,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() {
}
}
-void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() {
+void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_giprobe() {
if (!giprobe_buffer.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8_UINT;
@@ -619,7 +619,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() {
}
}
-void RendererSceneRenderForward::RenderBufferDataForward::clear() {
+void RendererSceneRenderForwardClustered::RenderBufferDataForward::clear() {
if (giprobe_buffer != RID()) {
RD::get_singleton()->free(giprobe_buffer);
giprobe_buffer = RID();
@@ -673,7 +673,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::clear() {
}
}
-void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+void RendererSceneRenderForwardClustered::RenderBufferDataForward::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 +740,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_
}
}
-void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) {
+void RendererSceneRenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) {
if (rb->normal_roughness_buffer.is_valid()) {
return;
}
@@ -778,11 +778,11 @@ void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBuffer
_render_buffers_clear_uniform_set(rb);
}
-RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForward::_create_render_buffer_data() {
+RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForwardClustered::_create_render_buffer_data() {
return memnew(RenderBufferDataForward);
}
-bool RendererSceneRenderForward::free(RID p_rid) {
+bool RendererSceneRenderForwardClustered::free(RID p_rid) {
if (RendererSceneRenderRD::free(p_rid)) {
return true;
}
@@ -791,8 +791,8 @@ bool RendererSceneRenderForward::free(RID p_rid) {
/// RENDERING ///
-template <RendererSceneRenderForward::PassMode p_pass_mode>
-void RendererSceneRenderForward::_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 <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) {
RD::DrawListID draw_list = p_draw_list;
RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
@@ -961,7 +961,7 @@ void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawList
}
}
-void RendererSceneRenderForward::_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 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) {
//use template for faster performance (pass mode comparisons are inlined)
switch (p_params->pass_mode) {
@@ -998,7 +998,7 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw
}
}
-void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
+void RendererSceneRenderForwardClustered::_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 +1006,7 @@ void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread,
_render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
}
-void RendererSceneRenderForward::_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 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) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
p_params->framebuffer_format = fb_format;
@@ -1014,7 +1014,7 @@ void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters
//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, &RendererSceneRenderForward::_render_list_thread_function, p_params);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForwardClustered::_render_list_thread_function, p_params);
RD::get_singleton()->draw_list_end(p_params->barrier);
} else {
//single threaded
@@ -1024,7 +1024,7 @@ void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters
}
}
-void RendererSceneRenderForward::_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) {
+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;
//projection.flip_y(); // Vulkan and modern APIs use Y-Down
CameraMatrix correction;
@@ -1130,7 +1130,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren
//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;
- uint32_t oct_size = sdfgi_get_lightprobe_octahedron_size();
+ uint32_t oct_size = gi.sdfgi_get_lightprobe_octahedron_size();
scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size * scene_state.ubo.sdfgi_probe_axis_size);
scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size);
@@ -1274,7 +1274,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren
RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
-void RendererSceneRenderForward::_update_instance_data_buffer(RenderListType p_render_list) {
+void RendererSceneRenderForwardClustered::_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 +1287,7 @@ void RendererSceneRenderForward::_update_instance_data_buffer(RenderListType p_r
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 RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+void RendererSceneRenderForwardClustered::_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();
@@ -1298,7 +1298,7 @@ void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_lis
GeometryInstanceSurfaceDataCache *prev_surface = nullptr;
for (uint32_t i = 0; i < element_total; i++) {
GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
- GeometryInstanceForward *inst = surface->owner;
+ GeometryInstanceForwardClustered *inst = surface->owner;
SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset];
@@ -1355,7 +1355,7 @@ void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_lis
}
}
-void RendererSceneRenderForward::_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 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) {
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
scene_state.used_screen_texture = false;
@@ -1381,7 +1381,7 @@ void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list,
//fill list
for (int i = 0; i < (int)p_instances.size(); i++) {
- GeometryInstanceForward *inst = static_cast<GeometryInstanceForward *>(p_instances[i]);
+ GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>(p_instances[i]);
Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
inst->depth = near_plane.distance_to(support_min);
@@ -1549,14 +1549,14 @@ void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list,
}
}
-void RendererSceneRenderForward::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
+void RendererSceneRenderForwardClustered::_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 RendererSceneRenderForward::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+void RendererSceneRenderForwardClustered::_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,11 +1578,12 @@ void RendererSceneRenderForward::_setup_lightmaps(const PagedArray<RID> &p_light
}
}
-void RendererSceneRenderForward::_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) {
+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);
}
+ RendererSceneEnvironmentRD *env = get_environment(p_environment);
//first of all, make a new render pass
//fill up ubo
@@ -1729,7 +1730,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
clear_color.b *= bg_energy;
if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
draw_sky_fog_only = true;
- storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
}
} break;
case RS::ENV_BG_COLOR: {
@@ -1739,7 +1740,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
clear_color.b *= bg_energy;
if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
draw_sky_fog_only = true;
- storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
}
} break;
case RS::ENV_BG_SKY: {
@@ -1767,12 +1768,12 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
projection = correction * p_cam_projection;
}
- _setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size);
+ sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this);
- RID sky = environment_get_sky(p_environment);
- if (sky.is_valid()) {
- _update_sky(p_environment, projection, p_cam_transform);
- radiance_texture = sky_get_radiance_texture_rd(sky);
+ RID sky_rid = env->sky;
+ if (sky_rid.is_valid()) {
+ sky.update(env, projection, p_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;
@@ -1890,7 +1891,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
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++) {
- _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);
+ 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);
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_list_end();
@@ -1921,7 +1922,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
projection = correction * p_cam_projection;
}
RD::get_singleton()->draw_command_begin_label("Draw Sky");
- _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform);
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time);
RD::get_singleton()->draw_command_end_label();
}
@@ -1980,7 +1981,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_shadow_begin() {
+void RendererSceneRenderForwardClustered::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
_update_render_base_uniform_set();
@@ -1988,7 +1989,7 @@ void RendererSceneRenderForward::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
}
-void RendererSceneRenderForward::_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 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) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
@@ -2035,7 +2036,7 @@ void RendererSceneRenderForward::_render_shadow_append(RID p_framebuffer, const
}
}
-void RendererSceneRenderForward::_render_shadow_process() {
+void RendererSceneRenderForwardClustered::_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)
@@ -2047,7 +2048,7 @@ void RendererSceneRenderForward::_render_shadow_process() {
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_shadow_end(uint32_t p_barrier) {
+void RendererSceneRenderForwardClustered::_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++) {
@@ -2062,7 +2063,7 @@ void RendererSceneRenderForward::_render_shadow_end(uint32_t p_barrier) {
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+void RendererSceneRenderForwardClustered::_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");
@@ -2090,7 +2091,7 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb,
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_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 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) {
RENDER_TIMESTAMP("Setup Rendering Material");
RD::get_singleton()->draw_command_begin_label("Render Material");
@@ -2128,7 +2129,7 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RendererSceneRenderForwardClustered::_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");
@@ -2190,7 +2191,7 @@ void RendererSceneRenderForward::_render_uv2(const PagedArray<GeometryInstance *
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_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 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) {
RENDER_TIMESTAMP("Render SDFGI");
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
@@ -2271,14 +2272,14 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_base_uniforms_changed() {
+void RendererSceneRenderForwardClustered::_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 RendererSceneRenderForward::_update_render_base_uniform_set() {
+void RendererSceneRenderForwardClustered::_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);
@@ -2404,7 +2405,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() {
}
}
-RID RendererSceneRenderForward::_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 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) {
//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());
@@ -2514,7 +2515,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
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_probe_instance_get_texture(p_gi_probes[i]);
+ RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]);
if (!tex.is_valid()) {
tex = default_tex;
}
@@ -2654,7 +2655,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
return render_pass_uniform_sets[p_index];
}
-RID RendererSceneRenderForward::_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 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) {
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);
}
@@ -2787,30 +2788,25 @@ RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albed
return sdfgi_pass_uniform_set;
}
-void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) {
+void RendererSceneRenderForwardClustered::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) {
}
-void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) {
+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 RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) {
+RID RendererSceneRenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) {
RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
return rb->normal_roughness_buffer;
}
-RendererSceneRenderForward *RendererSceneRenderForward::singleton = nullptr;
+RendererSceneRenderForwardClustered *RendererSceneRenderForwardClustered::singleton = nullptr;
-void RendererSceneRenderForward::set_time(double p_time, double p_step) {
- time = p_time;
- RendererSceneRenderRD::set_time(p_time, p_step);
-}
-
-void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
if (ginstance->dirty_list_element.in_list()) {
return;
}
@@ -2829,7 +2825,7 @@ void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance
geometry_instance_dirty_list.add(&ginstance->dirty_list_element);
}
-void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+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) {
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,7 +2849,7 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE;
}
- if (ginstance->data->cast_double_sided_shaodows) {
+ if (ginstance->data->cast_double_sided_shadows) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
}
@@ -2925,7 +2921,7 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
sdcache->sort.priority = p_material->priority;
}
-void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+void RendererSceneRenderForwardClustered::_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;
@@ -2965,8 +2961,8 @@ void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstance
}
}
-void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
if (ginstance->data->dirty_dependencies) {
ginstance->data->dependency_tracker.update_begin();
@@ -3123,24 +3119,24 @@ void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_g
ginstance->dirty_list_element.remove_from_list();
}
-void RendererSceneRenderForward::_update_dirty_geometry_instances() {
+void RendererSceneRenderForwardClustered::_update_dirty_geometry_instances() {
while (geometry_instance_dirty_list.first()) {
_geometry_instance_update(geometry_instance_dirty_list.first()->self());
}
}
-void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
+void RendererSceneRenderForwardClustered::_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_MULTIMESH:
case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
- static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+ static_cast<RendererSceneRenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
} break;
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_tracker->userdata);
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_tracker->userdata);
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
- ginstance->instance_count = static_cast<RendererSceneRenderForward *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ ginstance->instance_count = static_cast<RendererSceneRenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
}
} break;
default: {
@@ -3148,16 +3144,16 @@ void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererS
} break;
}
}
-void RendererSceneRenderForward::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
- static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+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));
}
-RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_instance_create(RID p_base) {
+RendererSceneRender::GeometryInstance *RendererSceneRenderForwardClustered::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);
- GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc();
- ginstance->data = memnew(GeometryInstanceForward::Data);
+ GeometryInstanceForwardClustered *ginstance = geometry_instance_alloc.alloc();
+ ginstance->data = memnew(GeometryInstanceForwardClustered::Data);
ginstance->data->base = p_base;
ginstance->data->base_type = type;
@@ -3169,35 +3165,35 @@ RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_inst
return ginstance;
}
-void RendererSceneRenderForward::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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;
ginstance->mirror = p_transform.basis.determinant() < 0;
@@ -3213,33 +3209,33 @@ void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstanc
ginstance->lod_model_scale = max_scale;
}
-void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+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) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(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 RendererSceneRenderForward::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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) {
if (ginstance->lightmap_sh == nullptr) {
@@ -3255,28 +3251,28 @@ void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(Geometry
}
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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);
- ginstance->data->cast_double_sided_shaodows = p_enable;
+ ginstance->data->cast_double_sided_shadows = p_enable;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geometry_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RendererSceneRenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (ginstance->lightmap_sh != nullptr) {
geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
@@ -3291,29 +3287,29 @@ void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geom
geometry_instance_alloc.free(ginstance);
}
-uint32_t RendererSceneRenderForward::geometry_instance_get_pair_mask() {
+uint32_t RendererSceneRenderForwardClustered::geometry_instance_get_pair_mask() {
return (1 << RS::INSTANCE_GI_PROBE);
}
-void RendererSceneRenderForward::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_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
}
-void RendererSceneRenderForward::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_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
}
-void RendererSceneRenderForward::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
+void RendererSceneRenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
}
-Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance);
+Transform RendererSceneRenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, Transform());
return ginstance->transform;
}
-AABB RendererSceneRenderForward::geometry_instance_get_aabb(GeometryInstance *p_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance);
+AABB RendererSceneRenderForwardClustered::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 RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+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) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (p_gi_probe_instance_count > 0) {
ginstance->gi_probes[0] = p_gi_probe_instances[0];
@@ -3328,11 +3324,10 @@ void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(Geome
}
}
-RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) :
+RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
low_end = is_low_end();
- storage = p_storage;
/* SCENE SHADER */
@@ -3346,7 +3341,7 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor
if (is_using_radiance_cubemap_array()) {
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
- defines += "\n#define SDFGI_OCT_SIZE " + itos(sdfgi_get_lightprobe_octahedron_size()) + "\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";
{
@@ -3627,7 +3622,7 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
}
-RendererSceneRenderForward::~RendererSceneRenderForward() {
+RendererSceneRenderForwardClustered::~RendererSceneRenderForwardClustered() {
directional_shadow_atlas_set_size(0);
//clear base uniform set if still valid
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h
index af78c50fda..98e2a7efcc 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene_render_forward.h */
+/* renderer_scene_render_forward_clustered.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_H
-#define RENDERING_SERVER_SCENE_RENDER_FORWARD_H
+#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
+#define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
#include "core/templates/paged_allocator.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.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
-class RendererSceneRenderForward : public RendererSceneRenderRD {
+class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
enum {
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
@@ -79,12 +79,10 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
};
struct {
- SceneForwardShaderRD scene_shader;
+ SceneForwardClusteredShaderRD scene_shader;
ShaderCompilerRD compiler;
} shader;
- RendererStorageRD *storage;
-
/* Material */
struct ShaderData : public RendererStorageRD::ShaderData {
@@ -186,7 +184,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
RendererStorageRD::ShaderData *_create_shader_func();
static RendererStorageRD::ShaderData *_create_shader_funcs() {
- return static_cast<RendererSceneRenderForward *>(singleton)->_create_shader_func();
+ return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_shader_func();
}
struct MaterialData : public RendererStorageRD::MaterialData {
@@ -208,7 +206,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
- return static_cast<RendererSceneRenderForward *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
}
/* Framebuffer */
@@ -490,9 +488,8 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
} scene_state;
- static RendererSceneRenderForward *singleton;
+ static RendererSceneRenderForwardClustered *singleton;
- double time;
RID default_shader;
RID default_material;
RID overdraw_material_shader;
@@ -534,7 +531,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
Map<Size2i, RID> sdfgi_framebuffer_size_cache;
struct GeometryInstanceData;
- struct GeometryInstanceForward;
+ struct GeometryInstanceForwardClustered;
struct GeometryInstanceLightmapSH {
Color sh[9];
@@ -588,10 +585,10 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
ShaderData *shader_shadow = nullptr;
GeometryInstanceSurfaceDataCache *next = nullptr;
- GeometryInstanceForward *owner = nullptr;
+ GeometryInstanceForwardClustered *owner = nullptr;
};
- struct GeometryInstanceForward : public GeometryInstance {
+ struct GeometryInstanceForwardClustered : public GeometryInstance {
//used during rendering
bool mirror = false;
bool non_uniform_scale = false;
@@ -617,7 +614,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
RID lightmap_instance;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
- SelfList<GeometryInstanceForward> dirty_list_element;
+ SelfList<GeometryInstanceForwardClustered> dirty_list_element;
struct Data {
//data used less often goes into regular heap
@@ -631,7 +628,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
bool use_dynamic_gi = false;
bool use_baked_light = false;
- bool cast_double_sided_shaodows = false;
+ bool cast_double_sided_shadows = false;
bool mirror = false;
bool dirty_dependencies = false;
@@ -640,21 +637,21 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
Data *data = nullptr;
- GeometryInstanceForward() :
+ GeometryInstanceForwardClustered() :
dirty_list_element(this) {}
};
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<GeometryInstanceForward>::List geometry_instance_dirty_list;
+ SelfList<GeometryInstanceForwardClustered>::List geometry_instance_dirty_list;
- PagedAllocator<GeometryInstanceForward> geometry_instance_alloc;
+ PagedAllocator<GeometryInstanceForwardClustered> geometry_instance_alloc;
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
- void _geometry_instance_add_surface_with_material(GeometryInstanceForward *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(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
+ 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(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();
@@ -761,11 +758,9 @@ public:
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 void set_time(double p_time, double p_step);
-
virtual bool free(RID p_rid);
- RendererSceneRenderForward(RendererStorageRD *p_storage);
- ~RendererSceneRenderForward();
+ RendererSceneRenderForwardClustered(RendererStorageRD *p_storage);
+ ~RendererSceneRenderForwardClustered();
};
-#endif // RASTERIZER_SCENE_HIGHEND_RD_H
+#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 15e963f6e4..4cf296f0db 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -35,8 +35,6 @@
#include "renderer_compositor_rd.h"
#include "servers/rendering/rendering_server_default.h"
-uint64_t RendererSceneRenderRD::auto_exposure_counter = 2;
-
void get_vogel_disk(float *r_kernel, int p_sample_count) {
const float golden_angle = 2.4;
@@ -49,980 +47,42 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) {
}
}
-void RendererSceneRenderRD::_clear_reflection_data(ReflectionData &rd) {
- rd.layers.clear();
- rd.radiance_base_cubemap = RID();
- if (rd.downsampled_radiance_cubemap.is_valid()) {
- RD::get_singleton()->free(rd.downsampled_radiance_cubemap);
- }
- rd.downsampled_radiance_cubemap = RID();
- rd.downsampled_layer.mipmaps.clear();
- rd.coefficient_buffer = RID();
-}
-
-void RendererSceneRenderRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) {
- //recreate radiance and all data
-
- int mipmaps = p_mipmaps;
- uint32_t w = p_size, h = p_size;
-
- if (p_use_array) {
- int layers = p_low_quality ? 8 : roughness_layers;
-
- for (int i = 0; i < layers; i++) {
- ReflectionData::Layer layer;
- uint32_t mmw = w;
- uint32_t mmh = h;
- layer.mipmaps.resize(mipmaps);
- layer.views.resize(mipmaps);
- for (int j = 0; j < mipmaps; j++) {
- ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
- mm.size.width = mmw;
- mm.size.height = mmh;
- for (int k = 0; k < 6; k++) {
- mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j);
- Vector<RID> fbtex;
- fbtex.push_back(mm.views[k]);
- mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
- }
-
- layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP);
-
- mmw = MAX(1, mmw >> 1);
- mmh = MAX(1, mmh >> 1);
- }
-
- rd.layers.push_back(layer);
- }
-
- } else {
- mipmaps = p_low_quality ? 8 : mipmaps;
- //regular cubemap, lower quality (aliasing, less memory)
- ReflectionData::Layer layer;
- uint32_t mmw = w;
- uint32_t mmh = h;
- layer.mipmaps.resize(mipmaps);
- layer.views.resize(mipmaps);
- for (int j = 0; j < mipmaps; j++) {
- ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
- mm.size.width = mmw;
- mm.size.height = mmh;
- for (int k = 0; k < 6; k++) {
- mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j);
- Vector<RID> fbtex;
- fbtex.push_back(mm.views[k]);
- mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
- }
-
- layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP);
-
- mmw = MAX(1, mmw >> 1);
- mmh = MAX(1, mmh >> 1);
- }
-
- rd.layers.push_back(layer);
- }
-
- rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = 64; // Always 64x64
- tf.height = 64;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE;
- tf.array_layers = 6;
- tf.mipmaps = 7;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- rd.downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
- {
- uint32_t mmw = 64;
- uint32_t mmh = 64;
- rd.downsampled_layer.mipmaps.resize(7);
- for (int j = 0; j < rd.downsampled_layer.mipmaps.size(); j++) {
- ReflectionData::DownsampleLayer::Mipmap &mm = rd.downsampled_layer.mipmaps.write[j];
- mm.size.width = mmw;
- mm.size.height = mmh;
- mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
-
- mmw = MAX(1, mmw >> 1);
- mmh = MAX(1, mmh >> 1);
- }
- }
-}
-
-void RendererSceneRenderRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) {
- storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size);
-
- for (int i = 1; i < rd.downsampled_layer.mipmaps.size(); i++) {
- storage->get_effects()->cubemap_downsample(rd.downsampled_layer.mipmaps[i - 1].view, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size);
- }
-
- Vector<RID> views;
- if (p_use_arrays) {
- for (int i = 1; i < rd.layers.size(); i++) {
- views.push_back(rd.layers[i].views[0]);
- }
- } else {
- for (int i = 1; i < rd.layers[0].views.size(); i++) {
- views.push_back(rd.layers[0].views[i]);
- }
- }
-
- storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, p_use_arrays);
-}
-
-void RendererSceneRenderRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) {
- if (p_use_arrays) {
- //render directly to the layers
- storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x);
- } else {
- storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], rd.layers[0].views[p_base_layer], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[p_base_layer].size.x);
- }
-}
-
-void RendererSceneRenderRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) {
- for (int i = p_start; i < p_end; i++) {
- for (int j = 0; j < rd.layers[i].views.size() - 1; j++) {
- RID view = rd.layers[i].views[j];
- RID texture = rd.layers[i].views[j + 1];
- Size2i size = rd.layers[i].mipmaps[j + 1].size;
- storage->get_effects()->cubemap_downsample(view, texture, size);
- }
- }
-}
-
-void RendererSceneRenderRD::_sdfgi_erase(RenderBuffers *rb) {
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const SDFGI::Cascade &c = rb->sdfgi->cascades[i];
- RD::get_singleton()->free(c.light_data);
- RD::get_singleton()->free(c.light_aniso_0_tex);
- RD::get_singleton()->free(c.light_aniso_1_tex);
- RD::get_singleton()->free(c.sdf_tex);
- RD::get_singleton()->free(c.solid_cell_dispatch_buffer);
- RD::get_singleton()->free(c.solid_cell_buffer);
- RD::get_singleton()->free(c.lightprobe_history_tex);
- RD::get_singleton()->free(c.lightprobe_average_tex);
- RD::get_singleton()->free(c.lights_buffer);
- }
-
- RD::get_singleton()->free(rb->sdfgi->render_albedo);
- RD::get_singleton()->free(rb->sdfgi->render_emission);
- RD::get_singleton()->free(rb->sdfgi->render_emission_aniso);
-
- RD::get_singleton()->free(rb->sdfgi->render_sdf[0]);
- RD::get_singleton()->free(rb->sdfgi->render_sdf[1]);
-
- RD::get_singleton()->free(rb->sdfgi->render_sdf_half[0]);
- RD::get_singleton()->free(rb->sdfgi->render_sdf_half[1]);
-
- for (int i = 0; i < 8; i++) {
- RD::get_singleton()->free(rb->sdfgi->render_occlusion[i]);
- }
-
- RD::get_singleton()->free(rb->sdfgi->render_geom_facing);
-
- RD::get_singleton()->free(rb->sdfgi->lightprobe_data);
- RD::get_singleton()->free(rb->sdfgi->lightprobe_history_scroll);
- RD::get_singleton()->free(rb->sdfgi->occlusion_data);
- RD::get_singleton()->free(rb->sdfgi->ambient_texture);
-
- RD::get_singleton()->free(rb->sdfgi->cascades_ubo);
-
- memdelete(rb->sdfgi);
-
- rb->sdfgi = nullptr;
-}
-
-const Vector3i RendererSceneRenderRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
-
void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
bool needs_sdfgi = env && env->sdfgi_enabled;
if (!needs_sdfgi) {
if (rb->sdfgi != nullptr) {
//erase it
- _sdfgi_erase(rb);
+ rb->sdfgi->erase();
+ memdelete(rb->sdfgi);
+ rb->sdfgi = nullptr;
+
_render_buffers_uniform_set_changed(p_render_buffers);
}
return;
}
static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 };
- uint32_t requested_history_size = history_frames_to_converge[sdfgi_frames_to_converge];
+ uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge];
if (rb->sdfgi && (rb->sdfgi->cascade_mode != env->sdfgi_cascades || rb->sdfgi->min_cell_size != env->sdfgi_min_cell_size || requested_history_size != rb->sdfgi->history_size || rb->sdfgi->uses_occlusion != env->sdfgi_use_occlusion || rb->sdfgi->y_scale_mode != env->sdfgi_y_scale)) {
//configuration changed, erase
- _sdfgi_erase(rb);
+ rb->sdfgi->erase();
+ memdelete(rb->sdfgi);
+ rb->sdfgi = nullptr;
}
- SDFGI *sdfgi = rb->sdfgi;
+ RendererSceneGIRD::SDFGI *sdfgi = rb->sdfgi;
if (sdfgi == nullptr) {
- //re-create
- rb->sdfgi = memnew(SDFGI);
- sdfgi = rb->sdfgi;
- sdfgi->cascade_mode = env->sdfgi_cascades;
- sdfgi->min_cell_size = env->sdfgi_min_cell_size;
- sdfgi->uses_occlusion = env->sdfgi_use_occlusion;
- sdfgi->y_scale_mode = env->sdfgi_y_scale;
- static const float y_scale[3] = { 1.0, 1.5, 2.0 };
- sdfgi->y_mult = y_scale[sdfgi->y_scale_mode];
- static const int cascasde_size[3] = { 4, 6, 8 };
- sdfgi->cascades.resize(cascasde_size[sdfgi->cascade_mode]);
- sdfgi->probe_axis_count = SDFGI::PROBE_DIVISOR + 1;
- sdfgi->solid_cell_ratio = sdfgi_solid_cell_ratio;
- sdfgi->solid_cell_count = uint32_t(float(sdfgi->cascade_size * sdfgi->cascade_size * sdfgi->cascade_size) * sdfgi->solid_cell_ratio);
-
- float base_cell_size = sdfgi->min_cell_size;
-
- RD::TextureFormat tf_sdf;
- tf_sdf.format = RD::DATA_FORMAT_R8_UNORM;
- tf_sdf.width = sdfgi->cascade_size; // Always 64x64
- tf_sdf.height = sdfgi->cascade_size;
- tf_sdf.depth = sdfgi->cascade_size;
- tf_sdf.texture_type = RD::TEXTURE_TYPE_3D;
- tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
-
- {
- RD::TextureFormat tf_render = tf_sdf;
- tf_render.format = RD::DATA_FORMAT_R16_UINT;
- sdfgi->render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- tf_render.format = RD::DATA_FORMAT_R32_UINT;
- sdfgi->render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- sdfgi->render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
-
- tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize
-
- for (int i = 0; i < 8; i++) {
- sdfgi->render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- }
-
- tf_render.format = RD::DATA_FORMAT_R32_UINT;
- sdfgi->render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
-
- tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT;
- sdfgi->render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- sdfgi->render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
-
- tf_render.width /= 2;
- tf_render.height /= 2;
- tf_render.depth /= 2;
-
- sdfgi->render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- sdfgi->render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- }
-
- RD::TextureFormat tf_occlusion = tf_sdf;
- tf_occlusion.format = RD::DATA_FORMAT_R16_UINT;
- tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
- tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
- tf_occlusion.depth *= sdfgi->cascades.size(); //use depth for occlusion slices
- tf_occlusion.width *= 2; //use width for the other half
-
- RD::TextureFormat tf_light = tf_sdf;
- tf_light.format = RD::DATA_FORMAT_R32_UINT;
- tf_light.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
- tf_light.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
-
- RD::TextureFormat tf_aniso0 = tf_sdf;
- tf_aniso0.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- RD::TextureFormat tf_aniso1 = tf_sdf;
- tf_aniso1.format = RD::DATA_FORMAT_R8G8_UNORM;
-
- int passes = nearest_shift(sdfgi->cascade_size) - 1;
-
- //store lightprobe SH
- RD::TextureFormat tf_probes;
- tf_probes.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf_probes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count;
- tf_probes.height = sdfgi->probe_axis_count * SDFGI::SH_SIZE;
- tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-
- sdfgi->history_size = requested_history_size;
-
- RD::TextureFormat tf_probe_history = tf_probes;
- tf_probe_history.format = RD::DATA_FORMAT_R16G16B16A16_SINT; //signed integer because SH are signed
- tf_probe_history.array_layers = sdfgi->history_size;
-
- RD::TextureFormat tf_probe_average = tf_probes;
- tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed
- tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D;
-
- sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
- sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
-
- {
- //octahedral lightprobes
- RD::TextureFormat tf_octprobes = tf_probes;
- tf_octprobes.array_layers = sdfgi->cascades.size() * 2;
- tf_octprobes.format = RD::DATA_FORMAT_R32_UINT; //pack well with RGBE
- tf_octprobes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
- tf_octprobes.height = sdfgi->probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
- tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
- tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
- //lightprobe texture is an octahedral texture
-
- sdfgi->lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView());
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
- sdfgi->lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->lightprobe_data);
-
- //texture handling ambient data, to integrate with volumetric foc
- RD::TextureFormat tf_ambient = tf_probes;
- tf_ambient.array_layers = sdfgi->cascades.size();
- tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE
- tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count;
- tf_ambient.height = sdfgi->probe_axis_count;
- tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- //lightprobe texture is an octahedral texture
- sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
- }
-
- sdfgi->cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
-
- sdfgi->occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView());
- {
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16;
- sdfgi->occlusion_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->occlusion_data);
- }
-
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = sdfgi->cascades[i];
-
- /* 3D Textures */
-
- cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView());
-
- cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView());
-
- cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView());
- cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView());
-
- {
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
- cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data);
-
- RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- }
-
- cascade.cell_size = base_cell_size;
- Vector3 world_position = p_world_position;
- world_position.y *= sdfgi->y_mult;
- int32_t probe_cells = sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- Vector3 probe_size = Vector3(1, 1, 1) * cascade.cell_size * probe_cells;
- Vector3i probe_pos = Vector3i((world_position / probe_size + Vector3(0.5, 0.5, 0.5)).floor());
- cascade.position = probe_pos * probe_cells;
-
- cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
-
- base_cell_size *= 2.0;
-
- /* Probe History */
-
- cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
- RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work
-
- cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
- RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work
-
- /* Buffers */
-
- cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * sdfgi->solid_cell_count);
- cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
- cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS));
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- for (int j = 0; j < 8; j++) {
- u.ids.push_back(sdfgi->render_occlusion[j]);
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 4;
- u.ids.push_back(sdfgi->render_emission);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(sdfgi->render_emission_aniso);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(sdfgi->render_geom_facing);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(cascade.sdf_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(sdfgi->occlusion_data);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 10;
- u.ids.push_back(cascade.solid_cell_dispatch_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 11;
- u.ids.push_back(cascade.solid_cell_buffer);
- uniforms.push_back(u);
- }
-
- cascade.sdf_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_STORE), 0);
- }
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_geom_facing);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(sdfgi->render_emission);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 4;
- u.ids.push_back(sdfgi->render_emission_aniso);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 5;
- u.ids.push_back(cascade.solid_cell_dispatch_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 6;
- u.ids.push_back(cascade.solid_cell_buffer);
- uniforms.push_back(u);
- }
-
- cascade.scroll_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL), 0);
- }
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- for (int j = 0; j < 8; j++) {
- u.ids.push_back(sdfgi->render_occlusion[j]);
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->occlusion_data);
- uniforms.push_back(u);
- }
-
- cascade.scroll_occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION), 0);
- }
- }
-
- //direct light
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = sdfgi->cascades[i];
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cascade.solid_cell_dispatch_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cascade.solid_cell_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 5;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(cascade.light_data);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 6;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(cascade.light_aniso_0_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 7;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(cascade.light_aniso_1_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 8;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb->sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cascade.lights_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 10;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 11;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- uniforms.push_back(u);
- }
-
- cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, 0), 0);
- }
-
- //preprocess initialize uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf[0]);
- uniforms.push_back(u);
- }
-
- sdfgi->sdf_initialize_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE), 0);
- }
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf_half[0]);
- uniforms.push_back(u);
- }
-
- sdfgi->sdf_initialize_half_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF), 0);
- }
-
- //jump flood uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_sdf[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf[1]);
- uniforms.push_back(u);
- }
-
- sdfgi->jump_flood_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
- sdfgi->jump_flood_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- }
- //jump flood half uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_sdf_half[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf_half[1]);
- uniforms.push_back(u);
- }
-
- sdfgi->jump_flood_half_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
- sdfgi->jump_flood_half_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- }
-
- //upscale half size sdf
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass
- uniforms.push_back(u);
- }
-
- sdfgi->upscale_jfa_uniform_set_index = (passes & 1) ? 0 : 1;
- sdfgi->sdf_upscale_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE), 0);
- }
-
- //occlusion uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- for (int i = 0; i < 8; i++) {
- u.ids.push_back(sdfgi->render_occlusion[i]);
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(sdfgi->render_geom_facing);
- uniforms.push_back(u);
- }
-
- sdfgi->occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_OCCLUSION), 0);
- }
-
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- //integrate uniform
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].light_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].light_aniso_0_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].light_aniso_1_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 7;
- u.ids.push_back(sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(sdfgi->lightprobe_data);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 9;
- u.ids.push_back(sdfgi->cascades[i].lightprobe_history_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
- u.ids.push_back(sdfgi->cascades[i].lightprobe_average_tex);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(sdfgi->lightprobe_history_scroll);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
- u.ids.push_back(sdfgi->lightprobe_average_scroll);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 13;
- RID parent_average;
- if (i < sdfgi->cascades.size() - 1) {
- parent_average = sdfgi->cascades[i + 1].lightprobe_average_tex;
- } else {
- parent_average = sdfgi->cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used
- }
- u.ids.push_back(parent_average);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 14;
- u.ids.push_back(sdfgi->ambient_texture);
- uniforms.push_back(u);
- }
-
- sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0);
- }
-
- sdfgi->bounce_feedback = env->sdfgi_bounce_feedback;
- sdfgi->energy = env->sdfgi_energy;
- sdfgi->normal_bias = env->sdfgi_normal_bias;
- sdfgi->probe_bias = env->sdfgi_probe_bias;
- sdfgi->reads_sky = env->sdfgi_read_sky_light;
+ // re-create
+ rb->sdfgi = gi.create_sdfgi(env, p_world_position, requested_history_size);
_render_buffers_uniform_set_changed(p_render_buffers);
-
- return; //done. all levels will need to be rendered which its going to take a bit
- }
-
- //check for updates
-
- sdfgi->bounce_feedback = env->sdfgi_bounce_feedback;
- sdfgi->energy = env->sdfgi_energy;
- sdfgi->normal_bias = env->sdfgi_normal_bias;
- sdfgi->probe_bias = env->sdfgi_probe_bias;
- sdfgi->reads_sky = env->sdfgi_read_sky_light;
-
- int32_t drag_margin = (sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) / 2;
-
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = sdfgi->cascades[i];
- cascade.dirty_regions = Vector3i();
-
- Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) * 0.5;
- probe_half_size = Vector3(0, 0, 0);
-
- Vector3 world_position = p_world_position;
- world_position.y *= sdfgi->y_mult;
- Vector3i pos_in_cascade = Vector3i((world_position + probe_half_size) / cascade.cell_size);
-
- for (int j = 0; j < 3; j++) {
- if (pos_in_cascade[j] < cascade.position[j]) {
- while (pos_in_cascade[j] < (cascade.position[j] - drag_margin)) {
- cascade.position[j] -= drag_margin * 2;
- cascade.dirty_regions[j] += drag_margin * 2;
- }
- } else if (pos_in_cascade[j] > cascade.position[j]) {
- while (pos_in_cascade[j] > (cascade.position[j] + drag_margin)) {
- cascade.position[j] += drag_margin * 2;
- cascade.dirty_regions[j] -= drag_margin * 2;
- }
- }
-
- if (cascade.dirty_regions[j] == 0) {
- continue; // not dirty
- } else if (uint32_t(ABS(cascade.dirty_regions[j])) >= sdfgi->cascade_size) {
- //moved too much, just redraw everything (make all dirty)
- cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
- break;
- }
- }
-
- if (cascade.dirty_regions != Vector3i() && cascade.dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
- //see how much the total dirty volume represents from the total volume
- uint32_t total_volume = sdfgi->cascade_size * sdfgi->cascade_size * sdfgi->cascade_size;
- uint32_t safe_volume = 1;
- for (int j = 0; j < 3; j++) {
- safe_volume *= sdfgi->cascade_size - ABS(cascade.dirty_regions[j]);
- }
- uint32_t dirty_volume = total_volume - safe_volume;
- if (dirty_volume > (safe_volume / 2)) {
- //more than half the volume is dirty, make all dirty so its only rendered once
- cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
- }
- }
+ } else {
+ //check for updates
+ rb->sdfgi->update(env, p_world_position);
}
}
@@ -1037,9 +97,9 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)
int dirty_count = 0;
for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const SDFGI::Cascade &c = rb->sdfgi->cascades[i];
+ const RendererSceneGIRD::SDFGI::Cascade &c = rb->sdfgi->cascades[i];
- if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) {
+ if (c.dirty_regions == RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL) {
dirty_count++;
} else {
for (int j = 0; j < 3; j++) {
@@ -1053,72 +113,15 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)
return dirty_count;
}
-int RendererSceneRenderRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND_V(rb == nullptr, -1);
- ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1);
-
- int dirty_count = 0;
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const SDFGI::Cascade &c = rb->sdfgi->cascades[i];
-
- if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) {
- if (dirty_count == p_region) {
- r_local_offset = Vector3i();
- r_local_size = Vector3i(1, 1, 1) * rb->sdfgi->cascade_size;
-
- r_bounds.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + c.position)) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
- r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
- return i;
- }
- dirty_count++;
- } else {
- for (int j = 0; j < 3; j++) {
- if (c.dirty_regions[j] != 0) {
- if (dirty_count == p_region) {
- Vector3i from = Vector3i(0, 0, 0);
- Vector3i to = Vector3i(1, 1, 1) * rb->sdfgi->cascade_size;
-
- if (c.dirty_regions[j] > 0) {
- //fill from the beginning
- to[j] = c.dirty_regions[j];
- } else {
- //fill from the end
- from[j] = to[j] + c.dirty_regions[j];
- }
-
- for (int k = 0; k < j; k++) {
- // "chip" away previous regions to avoid re-voxelizing the same thing
- if (c.dirty_regions[k] > 0) {
- from[k] += c.dirty_regions[k];
- } else if (c.dirty_regions[k] < 0) {
- to[k] += c.dirty_regions[k];
- }
- }
-
- r_local_offset = from;
- r_local_size = to - from;
-
- r_bounds.position = Vector3(from + Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + c.position) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
- r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
-
- return i;
- }
-
- dirty_count++;
- }
- }
- }
- }
- return -1;
-}
-
AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const {
AABB bounds;
Vector3i from;
Vector3i size;
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(rb == nullptr, AABB());
+ ERR_FAIL_COND_V(rb->sdfgi == nullptr, AABB());
- int c = _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds);
+ int c = rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);
ERR_FAIL_COND_V(c == -1, AABB());
return bounds;
}
@@ -1127,1956 +130,179 @@ uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_bu
AABB bounds;
Vector3i from;
Vector3i size;
-
- return _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds);
-}
-
-void RendererSceneRenderRD::_sdfgi_update_cascades(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- //update cascades
- SDFGI::Cascade::UBO cascade_data[SDFGI::MAX_CASCADES];
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[i].position)) * rb->sdfgi->cascades[i].cell_size;
-
- cascade_data[i].offset[0] = pos.x;
- cascade_data[i].offset[1] = pos.y;
- cascade_data[i].offset[2] = pos.z;
- cascade_data[i].to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size;
- cascade_data[i].probe_offset[0] = rb->sdfgi->cascades[i].position.x / probe_divisor;
- cascade_data[i].probe_offset[1] = rb->sdfgi->cascades[i].position.y / probe_divisor;
- cascade_data[i].probe_offset[2] = rb->sdfgi->cascades[i].position.z / probe_divisor;
- cascade_data[i].pad = 0;
- }
-
- RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
-}
-
-void RendererSceneRenderRD::_sdfgi_update_light(RID p_render_buffers, RID p_environment) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light");
-
- /* Update dynamic light */
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]);
-
- SDGIShader::DirectLightPushConstant push_constant;
-
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.bounce_feedback = rb->sdfgi->bounce_feedback;
- push_constant.y_mult = rb->sdfgi->y_mult;
- push_constant.use_occlusion = rb->sdfgi->uses_occlusion;
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = rb->sdfgi->cascades[i];
- push_constant.light_count = rb->sdfgi->cascade_dynamic_light_count[i];
- push_constant.cascade = i;
-
- if (rb->sdfgi->cascades[i].all_dynamic_lights_dirty || sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) {
- push_constant.process_offset = 0;
- push_constant.process_increment = 1;
- } else {
- static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = {
- 1, 2, 4, 8, 16
- };
-
- uint32_t frames_to_update = frames_to_update_table[sdfgi_frames_to_update_light];
-
- push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update;
- push_constant.process_increment = frames_to_update;
- }
- rb->sdfgi->cascades[i].all_dynamic_lights_dirty = false;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0);
- }
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
- RD::get_singleton()->draw_command_end_label();
-}
-
-void RendererSceneRenderRD::_sdfgi_update_probes(RID p_render_buffers, RID p_environment) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes");
-
- Environment *env = environment_owner.getornull(p_environment);
-
- SDGIShader::IntegratePushConstant push_constant;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size;
- push_constant.history_size = rb->sdfgi->history_size;
- static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
- push_constant.ray_count = ray_count[sdfgi_ray_count];
- push_constant.ray_bias = rb->sdfgi->probe_bias;
- push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
- push_constant.image_size[1] = rb->sdfgi->probe_axis_count;
- push_constant.store_ambient_texture = env->volumetric_fog_enabled;
-
- RID sky_uniform_set = sdfgi_shader.integrate_default_sky_uniform_set;
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- if (rb->sdfgi->reads_sky && env) {
- push_constant.sky_energy = env->bg_energy;
-
- if (env->background == RS::ENV_BG_CLEAR_COLOR) {
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR;
- Color c = storage->get_default_clear_color().to_linear();
- push_constant.sky_color[0] = c.r;
- push_constant.sky_color[1] = c.g;
- push_constant.sky_color[2] = c.b;
- } else if (env->background == RS::ENV_BG_COLOR) {
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR;
- Color c = env->bg_color;
- push_constant.sky_color[0] = c.r;
- push_constant.sky_color[1] = c.g;
- push_constant.sky_color[2] = c.b;
-
- } else if (env->background == RS::ENV_BG_SKY) {
- Sky *sky = sky_owner.getornull(env->sky);
- if (sky && sky->radiance.is_valid()) {
- if (sky->sdfgi_integrate_sky_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(sky->sdfgi_integrate_sky_uniform_set)) {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(sky->radiance);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 1;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- sky->sdfgi_integrate_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1);
- }
- sky_uniform_set = sky->sdfgi_integrate_sky_uniform_set;
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_SKY;
- }
- }
- }
-
- rb->sdfgi->render_pass++;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_PROCESS]);
-
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- push_constant.cascade = i;
- push_constant.world_offset[0] = rb->sdfgi->cascades[i].position.x / probe_divisor;
- push_constant.world_offset[1] = rb->sdfgi->cascades[i].position.y / probe_divisor;
- push_constant.world_offset[2] = rb->sdfgi->cascades[i].position.z / probe_divisor;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1);
- }
-
- //end later after raster to avoid barriering on layout changes
- //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
-
- RD::get_singleton()->draw_command_end_label();
-}
-
-void RendererSceneRenderRD::_sdfgi_store_probes(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE);
- RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes");
-
- SDGIShader::IntegratePushConstant push_constant;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size;
- push_constant.history_size = rb->sdfgi->history_size;
- static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
- push_constant.ray_count = ray_count[sdfgi_ray_count];
- push_constant.ray_bias = rb->sdfgi->probe_bias;
- push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
- push_constant.image_size[1] = rb->sdfgi->probe_axis_count;
- push_constant.store_ambient_texture = false;
-
- push_constant.sky_mode = 0;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- // Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces
- RENDER_TIMESTAMP("Average Probes");
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]);
-
- //convert to octahedral to store
- push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
- push_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- push_constant.cascade = i;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
- }
-
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
-
- RD::get_singleton()->draw_command_end_label();
-}
-void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used) {
- r_gi_probes_used = 0;
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
-
- RD::get_singleton()->draw_command_begin_label("GIProbes Setup");
-
- RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers);
- GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES];
-
- bool giprobes_changed = false;
-
- Transform to_camera;
- to_camera.origin = p_transform.origin; //only translation, make local
-
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- RID texture;
- if (i < (int)p_gi_probes.size()) {
- GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]);
-
- if (gipi) {
- texture = gipi->texture;
- GI::GIProbeData &gipd = gi_probe_data[i];
-
- RID base_probe = gipi->probe;
-
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
-
- gipd.xform[0] = to_cell.basis.elements[0][0];
- gipd.xform[1] = to_cell.basis.elements[1][0];
- gipd.xform[2] = to_cell.basis.elements[2][0];
- gipd.xform[3] = 0;
- gipd.xform[4] = to_cell.basis.elements[0][1];
- gipd.xform[5] = to_cell.basis.elements[1][1];
- gipd.xform[6] = to_cell.basis.elements[2][1];
- gipd.xform[7] = 0;
- gipd.xform[8] = to_cell.basis.elements[0][2];
- gipd.xform[9] = to_cell.basis.elements[1][2];
- gipd.xform[10] = to_cell.basis.elements[2][2];
- gipd.xform[11] = 0;
- gipd.xform[12] = to_cell.origin.x;
- gipd.xform[13] = to_cell.origin.y;
- gipd.xform[14] = to_cell.origin.z;
- gipd.xform[15] = 1;
-
- Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
-
- gipd.bounds[0] = bounds.x;
- gipd.bounds[1] = bounds.y;
- gipd.bounds[2] = bounds.z;
-
- gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
- gipd.bias = storage->gi_probe_get_bias(base_probe);
- gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
- gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
- gipd.anisotropy_strength = 0;
- gipd.ao = storage->gi_probe_get_ao(base_probe);
- gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
- gipd.mipmaps = gipi->mipmaps.size();
- }
-
- r_gi_probes_used++;
- }
-
- if (texture == RID()) {
- texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
-
- if (texture != rb->giprobe_textures[i]) {
- giprobes_changed = true;
- rb->giprobe_textures[i] = texture;
- }
- }
-
- if (giprobes_changed) {
- 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();
- 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);
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
- }
- rb->volumetric_fog->uniform_set = RID();
- rb->volumetric_fog->uniform_set2 = RID();
- }
- }
-
- if (p_gi_probes.size() > 0) {
- RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE);
- }
-
- RD::get_singleton()->draw_command_end_label();
-}
-
-void RendererSceneRenderRD::_pre_process_gi(RID p_render_buffers, const Transform &p_transform) {
- // Do the required buffer transfers and setup before the depth-pre pass, this way GI can
- // run in parallel during depth-pre pass and shadow rendering.
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
-
- /* Update Cascades UBO */
-
- if (rb->sdfgi) {
- /* Update general SDFGI Buffer */
-
- _sdfgi_update_cascades(p_render_buffers);
-
- GI::SDFGIData sdfgi_data;
-
- sdfgi_data.grid_size[0] = rb->sdfgi->cascade_size;
- sdfgi_data.grid_size[1] = rb->sdfgi->cascade_size;
- sdfgi_data.grid_size[2] = rb->sdfgi->cascade_size;
-
- sdfgi_data.max_cascades = rb->sdfgi->cascades.size();
- sdfgi_data.probe_axis_size = rb->sdfgi->probe_axis_count;
- sdfgi_data.cascade_probe_size[0] = sdfgi_data.probe_axis_size - 1; //float version for performance
- sdfgi_data.cascade_probe_size[1] = sdfgi_data.probe_axis_size - 1;
- sdfgi_data.cascade_probe_size[2] = sdfgi_data.probe_axis_size - 1;
-
- float csize = rb->sdfgi->cascade_size;
- sdfgi_data.probe_to_uvw = 1.0 / float(sdfgi_data.cascade_probe_size[0]);
- sdfgi_data.use_occlusion = rb->sdfgi->uses_occlusion;
- //sdfgi_data.energy = rb->sdfgi->energy;
-
- sdfgi_data.y_mult = rb->sdfgi->y_mult;
-
- float cascade_voxel_size = (csize / sdfgi_data.cascade_probe_size[0]);
- float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size;
- sdfgi_data.occlusion_clamp[0] = occlusion_clamp;
- sdfgi_data.occlusion_clamp[1] = occlusion_clamp;
- sdfgi_data.occlusion_clamp[2] = occlusion_clamp;
- sdfgi_data.normal_bias = (rb->sdfgi->normal_bias / csize) * sdfgi_data.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;
-
- uint32_t oct_size = SDFGI::LIGHTPROBE_OCT_SIZE;
-
- sdfgi_data.lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size * sdfgi_data.probe_axis_size);
- sdfgi_data.lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size);
- sdfgi_data.lightprobe_tex_pixel_size[2] = 1.0;
-
- sdfgi_data.energy = rb->sdfgi->energy;
-
- sdfgi_data.lightprobe_uv_offset[0] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[0];
- sdfgi_data.lightprobe_uv_offset[1] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[1];
- sdfgi_data.lightprobe_uv_offset[2] = float((oct_size + 2) * sdfgi_data.probe_axis_size) * sdfgi_data.lightprobe_tex_pixel_size[0];
-
- sdfgi_data.occlusion_renormalize[0] = 0.5;
- sdfgi_data.occlusion_renormalize[1] = 1.0;
- sdfgi_data.occlusion_renormalize[2] = 1.0 / float(sdfgi_data.max_cascades);
-
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
-
- for (uint32_t i = 0; i < sdfgi_data.max_cascades; i++) {
- GI::SDFGIData::ProbeCascadeData &c = sdfgi_data.cascades[i];
- Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[i].position)) * rb->sdfgi->cascades[i].cell_size;
- Vector3 cam_origin = p_transform.origin;
- cam_origin.y *= rb->sdfgi->y_mult;
- pos -= cam_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 / (float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[i].cell_size / float(rb->sdfgi->probe_axis_count - 1));
-
- Vector3i probe_ofs = rb->sdfgi->cascades[i].position / probe_divisor;
- c.probe_world_offset[0] = probe_ofs.x;
- c.probe_world_offset[1] = probe_ofs.y;
- c.probe_world_offset[2] = probe_ofs.z;
-
- c.to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size;
- }
-
- RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE);
-
- /* Update dynamic lights in SDFGI cascades */
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = rb->sdfgi->cascades[i];
-
- SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];
- uint32_t idx = 0;
- for (uint32_t j = 0; j < (uint32_t)render_state.sdfgi_update_data->directional_lights->size(); j++) {
- if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
- break;
- }
-
- LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->directional_lights->get(j));
- ERR_CONTINUE(!li);
-
- if (storage->light_directional_is_sky_only(li->light)) {
- continue;
- }
-
- Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
- dir.y *= rb->sdfgi->y_mult;
- dir.normalize();
- lights[idx].direction[0] = dir.x;
- lights[idx].direction[1] = dir.y;
- lights[idx].direction[2] = dir.z;
- Color color = storage->light_get_color(li->light);
- color = color.to_linear();
- lights[idx].color[0] = color.r;
- lights[idx].color[1] = color.g;
- lights[idx].color[2] = color.b;
- lights[idx].type = RS::LIGHT_DIRECTIONAL;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
- lights[idx].has_shadow = storage->light_has_shadow(li->light);
-
- idx++;
- }
-
- AABB cascade_aabb;
- cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size;
- cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size;
-
- for (uint32_t j = 0; j < render_state.sdfgi_update_data->positional_light_count; j++) {
- if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
- break;
- }
-
- LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->positional_light_instances[j]);
- ERR_CONTINUE(!li);
-
- uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
- if (i > max_sdfgi_cascade) {
- continue;
- }
-
- if (!cascade_aabb.intersects(li->aabb)) {
- continue;
- }
-
- Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
- //faster to not do this here
- //dir.y *= rb->sdfgi->y_mult;
- //dir.normalize();
- lights[idx].direction[0] = dir.x;
- lights[idx].direction[1] = dir.y;
- lights[idx].direction[2] = dir.z;
- Vector3 pos = li->transform.origin;
- pos.y *= rb->sdfgi->y_mult;
- lights[idx].position[0] = pos.x;
- lights[idx].position[1] = pos.y;
- lights[idx].position[2] = pos.z;
- Color color = storage->light_get_color(li->light);
- color = color.to_linear();
- lights[idx].color[0] = color.r;
- lights[idx].color[1] = color.g;
- lights[idx].color[2] = color.b;
- lights[idx].type = storage->light_get_type(li->light);
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
- lights[idx].has_shadow = storage->light_has_shadow(li->light);
- lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
- lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- idx++;
- }
-
- if (idx > 0) {
- RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE);
- }
-
- rb->sdfgi->cascade_dynamic_light_count[i] = idx;
- }
- }
-}
-
-void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes) {
- RD::get_singleton()->draw_command_begin_label("GI Render");
-
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- Environment *env = environment_owner.getornull(p_environment);
-
- if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != gi.half_resolution) {
- if (rb->ambient_buffer.is_valid()) {
- RD::get_singleton()->free(rb->ambient_buffer);
- RD::get_singleton()->free(rb->reflection_buffer);
- }
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
- if (gi.half_resolution) {
- tf.width >>= 1;
- tf.height >>= 1;
- }
- 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 = gi.half_resolution;
-
- _render_buffers_uniform_set_changed(p_render_buffers);
- }
-
- GI::PushConstant push_constant;
-
- push_constant.screen_size[0] = rb->width;
- push_constant.screen_size[1] = rb->height;
- push_constant.z_near = p_projection.get_z_near();
- push_constant.z_far = p_projection.get_z_far();
- push_constant.orthogonal = p_projection.is_orthogonal();
- push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
- push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
- push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
- push_constant.max_giprobes = MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size());
- push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;
-
- bool use_sdfgi = rb->sdfgi != nullptr;
- bool use_giprobes = push_constant.max_giprobes > 0;
-
- if (env) {
- push_constant.ao_color[0] = env->ao_color.r;
- push_constant.ao_color[1] = env->ao_color.g;
- push_constant.ao_color[2] = env->ao_color.b;
- } else {
- push_constant.ao_color[0] = 0;
- push_constant.ao_color[1] = 0;
- push_constant.ao_color[2] = 0;
- }
-
- push_constant.cam_rotation[0] = p_transform.basis[0][0];
- push_constant.cam_rotation[1] = p_transform.basis[1][0];
- push_constant.cam_rotation[2] = p_transform.basis[2][0];
- push_constant.cam_rotation[3] = 0;
- push_constant.cam_rotation[4] = p_transform.basis[0][1];
- push_constant.cam_rotation[5] = p_transform.basis[1][1];
- push_constant.cam_rotation[6] = p_transform.basis[2][1];
- push_constant.cam_rotation[7] = 0;
- push_constant.cam_rotation[8] = p_transform.basis[0][2];
- push_constant.cam_rotation[9] = p_transform.basis[1][2];
- 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)) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].light_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 5;
- if (rb->sdfgi) {
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 7;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 9;
- u.ids.push_back(rb->ambient_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
- u.ids.push_back(rb->reflection_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 11;
- if (rb->sdfgi) {
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 12;
- u.ids.push_back(rb->depth_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 13;
- u.ids.push_back(p_normal_roughness_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 14;
- RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
- u.ids.push_back(buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 15;
- u.ids.push_back(gi.sdfgi_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 16;
- u.ids.push_back(rb->giprobe_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 17;
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- u.ids.push_back(rb->giprobe_textures[i]);
- }
- uniforms.push_back(u);
- }
-
- rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi.shader.version_get_shader(gi.shader_version, 0), 0);
- }
-
- GI::Mode mode;
-
- if (rb->using_half_size_gi) {
- mode = (use_sdfgi && use_giprobes) ? GI::MODE_HALF_RES_COMBINED : (use_sdfgi ? GI::MODE_HALF_RES_SDFGI : GI::MODE_HALF_RES_GIPROBE);
- } else {
- mode = (use_sdfgi && use_giprobes) ? GI::MODE_COMBINED : (use_sdfgi ? GI::MODE_SDFGI : GI::MODE_GIPROBE);
- }
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[mode]);
- 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(GI::PushConstant));
+ ERR_FAIL_COND_V(rb == nullptr, -1);
+ ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1);
- if (rb->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);
- }
- //do barrier later to allow oeverlap
- //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
- RD::get_singleton()->draw_command_end_label();
+ return rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);
}
RID RendererSceneRenderRD::sky_allocate() {
- return sky_owner.allocate_rid();
+ return sky.allocate_sky_rid();
}
void RendererSceneRenderRD::sky_initialize(RID p_rid) {
- sky_owner.initialize_rid(p_rid, Sky());
-}
-
-void RendererSceneRenderRD::_sky_invalidate(Sky *p_sky) {
- if (!p_sky->dirty) {
- p_sky->dirty = true;
- p_sky->dirty_list = dirty_sky_list;
- dirty_sky_list = p_sky;
- }
+ sky.initialize_sky_rid(p_rid);
}
void RendererSceneRenderRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
- ERR_FAIL_COND(p_radiance_size < 32 || p_radiance_size > 2048);
- if (sky->radiance_size == p_radiance_size) {
- return;
- }
- sky->radiance_size = p_radiance_size;
-
- if (sky->mode == RS::SKY_MODE_REALTIME && sky->radiance_size != 256) {
- WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
- sky->radiance_size = 256;
- }
-
- _sky_invalidate(sky);
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
+ sky.sky_set_radiance_size(p_sky, p_radiance_size);
}
void RendererSceneRenderRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
-
- if (sky->mode == p_mode) {
- return;
- }
-
- sky->mode = p_mode;
-
- if (sky->mode == RS::SKY_MODE_REALTIME && sky->radiance_size != 256) {
- WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
- sky_set_radiance_size(p_sky, 256);
- }
-
- _sky_invalidate(sky);
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
+ sky.sky_set_mode(p_sky, p_mode);
}
void RendererSceneRenderRD::sky_set_material(RID p_sky, RID p_material) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
- sky->material = p_material;
- _sky_invalidate(sky);
+ sky.sky_set_material(p_sky, p_material);
}
Ref<Image> RendererSceneRenderRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, Ref<Image>());
-
- _update_dirty_skys();
-
- if (sky->radiance.is_valid()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- tf.width = p_size.width;
- tf.height = p_size.height;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
-
- RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView());
- storage->get_effects()->copy_cubemap_to_panorama(sky->radiance, rad_tex, p_size, p_bake_irradiance ? roughness_layers : 0, sky->reflection.layers.size() > 1);
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0);
- RD::get_singleton()->free(rad_tex);
-
- Ref<Image> img;
- img.instance();
- img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
- for (int i = 0; i < p_size.width; i++) {
- for (int j = 0; j < p_size.height; j++) {
- Color c = img->get_pixel(i, j);
- c.r *= p_energy;
- c.g *= p_energy;
- c.b *= p_energy;
- img->set_pixel(i, j, c);
- }
- }
- return img;
- }
-
- return Ref<Image>();
-}
-
-void RendererSceneRenderRD::_update_dirty_skys() {
- Sky *sky = dirty_sky_list;
-
- while (sky) {
- bool texture_set_dirty = false;
- //update sky configuration if texture is missing
-
- if (sky->radiance.is_null()) {
- int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
-
- uint32_t w = sky->radiance_size, h = sky->radiance_size;
- int layers = roughness_layers;
- if (sky->mode == RS::SKY_MODE_REALTIME) {
- layers = 8;
- if (roughness_layers != 8) {
- WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections");
- }
- }
-
- if (sky_use_cubemap_array) {
- //array (higher quality, 6 times more memory)
- RD::TextureFormat tf;
- tf.array_layers = layers * 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
- tf.mipmaps = mipmaps;
- tf.width = w;
- tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-
- sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- _update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME);
-
- } else {
- //regular cubemap, lower quality (aliasing, less memory)
- RD::TextureFormat tf;
- tf.array_layers = 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE;
- tf.mipmaps = MIN(mipmaps, layers);
- tf.width = w;
- tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-
- sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- _update_reflection_data(sky->reflection, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME);
- }
- texture_set_dirty = true;
- }
-
- // Create subpass buffers if they haven't been created already
- if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tformat.width = sky->screen_size.x / 2;
- tformat.height = sky->screen_size.y / 2;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
- sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- Vector<RID> texs;
- texs.push_back(sky->half_res_pass);
- sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
- texture_set_dirty = true;
- }
-
- if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tformat.width = sky->screen_size.x / 4;
- tformat.height = sky->screen_size.y / 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
- sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- Vector<RID> texs;
- texs.push_back(sky->quarter_res_pass);
- sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
- texture_set_dirty = true;
- }
-
- if (texture_set_dirty) {
- for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) {
- if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) {
- RD::get_singleton()->free(sky->texture_uniform_sets[i]);
- sky->texture_uniform_sets[i] = RID();
- }
- }
- }
-
- sky->reflection.dirty = true;
- sky->processing_layer = 0;
-
- Sky *next = sky->dirty_list;
- sky->dirty_list = nullptr;
- sky->dirty = false;
- sky = next;
- }
-
- dirty_sky_list = nullptr;
-}
-
-RID RendererSceneRenderRD::sky_get_radiance_texture_rd(RID p_sky) const {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
-
- return sky->radiance;
-}
-
-RID RendererSceneRenderRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
-
- if (sky->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(sky->uniform_set)) {
- sky->uniform_set = RID();
- if (sky->radiance.is_valid()) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(sky->radiance);
- uniforms.push_back(u);
- }
-
- sky->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
- }
- }
-
- return sky->uniform_set;
-}
-
-RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) {
- if (p_sky->texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(p_sky->texture_uniform_sets[p_version])) {
- return p_sky->texture_uniform_sets[p_version];
- }
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- if (p_sky->radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) {
- u.ids.push_back(p_sky->radiance);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1; // half res
- if (p_sky->half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
- if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(p_sky->reflection.layers[0].views[1]);
- } else {
- u.ids.push_back(p_sky->half_res_pass);
- }
- } else {
- if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2; // quarter res
- if (p_sky->quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
- if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(p_sky->reflection.layers[0].views[2]);
- } else {
- u.ids.push_back(p_sky->quarter_res_pass);
- }
- } else {
- if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- }
- }
- uniforms.push_back(u);
- }
-
- p_sky->texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
- return p_sky->texture_uniform_sets[p_version];
-}
-
-RID RendererSceneRenderRD::sky_get_material(RID p_sky) const {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
-
- return sky->material;
-}
-
-void RendererSceneRenderRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
- ERR_FAIL_COND(!is_environment(p_environment));
-
- SkyMaterialData *material = nullptr;
-
- Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
-
- RID sky_material;
-
- RS::EnvironmentBG background = environment_get_background(p_environment);
-
- if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- ERR_FAIL_COND(!sky);
- sky_material = sky_get_material(environment_get_sky(p_environment));
-
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
- }
-
- if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
- sky_material = sky_scene_state.fog_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
-
- ERR_FAIL_COND(!material);
-
- SkyShaderData *shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
-
- Basis sky_transform = environment_get_sky_orientation(p_environment);
- sky_transform.invert();
-
- float multiplier = environment_get_bg_energy(p_environment);
- float custom_fov = environment_get_sky_custom_fov(p_environment);
- // Camera
- CameraMatrix camera;
-
- if (custom_fov) {
- float near_plane = p_projection.get_z_near();
- float far_plane = p_projection.get_z_far();
- float aspect = p_projection.get_aspect();
-
- camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
-
- } else {
- camera = p_projection;
- }
-
- sky_transform = p_transform.basis * sky_transform;
-
- if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES];
-
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_QUARTER_RES);
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
-
- if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES];
-
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_HALF_RES);
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
-
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
-
- RID texture_uniform_set;
- if (sky) {
- texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
- } else {
- texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
- }
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
-}
-
-void RendererSceneRenderRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) {
- ERR_FAIL_COND(!is_environment(p_environment));
-
- SkyMaterialData *material = nullptr;
-
- Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
-
- RID sky_material;
-
- SkyShaderData *shader_data = nullptr;
-
- RS::EnvironmentBG background = environment_get_background(p_environment);
-
- if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- ERR_FAIL_COND(!sky);
- sky_material = sky_get_material(environment_get_sky(p_environment));
-
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
-
- ERR_FAIL_COND(!material);
-
- shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
- }
-
- if (sky) {
- // Invalidate supbass buffers if screen size changes
- if (sky->screen_size != p_screen_size) {
- sky->screen_size = p_screen_size;
- sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
- sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
- if (shader_data->uses_half_res) {
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
- }
- _sky_invalidate(sky);
- }
- if (shader_data->uses_quarter_res) {
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
- }
- _sky_invalidate(sky);
- }
- }
-
- // Create new subpass buffers if necessary
- if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
- (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
- sky->radiance.is_null()) {
- _sky_invalidate(sky);
- _update_dirty_skys();
- }
-
- if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
- sky->prev_time = time;
- sky->reflection.dirty = true;
- RenderingServerDefault::redraw_request();
- }
-
- if (material != sky->prev_material) {
- sky->prev_material = material;
- sky->reflection.dirty = true;
- }
-
- if (material->uniform_set_updated) {
- material->uniform_set_updated = false;
- sky->reflection.dirty = true;
- }
-
- if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
- sky->prev_position = p_transform.origin;
- sky->reflection.dirty = true;
- }
-
- if (shader_data->uses_light) {
- // Check whether the directional_light_buffer changes
- bool light_data_dirty = false;
-
- if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
- light_data_dirty = true;
- for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
- sky_scene_state.directional_lights[i].enabled = false;
- }
- }
- if (!light_data_dirty) {
- for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
- if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
- sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
- sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
- sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
- sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
- sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
- sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
- sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
- sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
- light_data_dirty = true;
- break;
- }
- }
- }
-
- if (light_data_dirty) {
- RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights);
-
- RendererSceneRenderRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
- sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
- sky_scene_state.directional_lights = temp;
- sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
- sky->reflection.dirty = true;
- }
- }
- }
-
- //setup fog variables
- sky_scene_state.ubo.volumetric_fog_enabled = false;
- if (p_render_buffers.is_valid()) {
- if (render_buffers_has_volumetric_fog(p_render_buffers)) {
- sky_scene_state.ubo.volumetric_fog_enabled = true;
-
- float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
- if (fog_end > 0.0) {
- sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
- } else {
- sky_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
- if (fog_detail_spread > 0.0) {
- sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
- } else {
- sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
- }
- }
-
- RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
-
- if (fog_uniform_set != RID()) {
- sky_scene_state.fog_uniform_set = fog_uniform_set;
- } else {
- sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
- }
- }
-
- sky_scene_state.ubo.z_far = p_projection.get_z_far();
- sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
- sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
- sky_scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment);
- Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
- float fog_energy = environment_get_fog_light_energy(p_environment);
- sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
- sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
- sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
- sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
-
- RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
-}
-
-void RendererSceneRenderRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
- ERR_FAIL_COND(!is_environment(p_environment));
-
- Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
- ERR_FAIL_COND(!sky);
-
- RID sky_material = sky_get_material(environment_get_sky(p_environment));
-
- SkyMaterialData *material = nullptr;
-
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
-
- ERR_FAIL_COND(!material);
-
- SkyShaderData *shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
-
- float multiplier = environment_get_bg_energy(p_environment);
-
- bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
- RS::SkyMode sky_mode = sky->mode;
-
- if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
- if (shader_data->uses_time || shader_data->uses_position) {
- update_single_frame = true;
- sky_mode = RS::SKY_MODE_REALTIME;
- } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
- update_single_frame = false;
- sky_mode = RS::SKY_MODE_INCREMENTAL;
- } else {
- update_single_frame = true;
- sky_mode = RS::SKY_MODE_QUALITY;
- }
- }
-
- if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
- // On the first frame after creating sky, rebuild in single frame
- update_single_frame = true;
- sky_mode = RS::SKY_MODE_QUALITY;
- }
-
- int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size();
-
- // Update radiance cubemap
- if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
- static const Vector3 view_normals[6] = {
- Vector3(+1, 0, 0),
- Vector3(-1, 0, 0),
- Vector3(0, +1, 0),
- Vector3(0, -1, 0),
- Vector3(0, 0, +1),
- Vector3(0, 0, -1)
- };
- static const Vector3 view_up[6] = {
- Vector3(0, -1, 0),
- Vector3(0, -1, 0),
- Vector3(0, 0, +1),
- Vector3(0, 0, -1),
- Vector3(0, -1, 0),
- Vector3(0, -1, 0)
- };
-
- CameraMatrix cm;
- cm.set_perspective(90, 1, 0.01, 10.0);
- CameraMatrix correction;
- correction.set_depth_correction(true);
- cm = correction * cm;
-
- if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
- RD::DrawListID cubemap_draw_list;
-
- for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES);
-
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
- }
-
- if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
- RD::DrawListID cubemap_draw_list;
-
- for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES);
-
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
- }
-
- RD::DrawListID cubemap_draw_list;
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
-
- for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP);
-
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
-
- if (sky_mode == RS::SKY_MODE_REALTIME) {
- _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
- if (sky_use_cubemap_array) {
- _update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size());
- }
- } else {
- if (update_single_frame) {
- for (int i = 1; i < max_processing_layer; i++) {
- _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i);
- }
- if (sky_use_cubemap_array) {
- _update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size());
- }
- } else {
- if (sky_use_cubemap_array) {
- // Multi-Frame so just update the first array level
- _update_reflection_mipmaps(sky->reflection, 0, 1);
- }
- }
- sky->processing_layer = 1;
- }
-
- sky->reflection.dirty = false;
-
- } else {
- if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
- _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, sky->processing_layer);
-
- if (sky_use_cubemap_array) {
- _update_reflection_mipmaps(sky->reflection, sky->processing_layer, sky->processing_layer + 1);
- }
-
- sky->processing_layer++;
- }
- }
-}
-
-/* SKY SHADER */
-
-void RendererSceneRenderRD::SkyShaderData::set_code(const String &p_code) {
- //compile
-
- code = p_code;
- valid = false;
- ubo_size = 0;
- uniforms.clear();
-
- if (code == String()) {
- return; //just invalid, but no error
- }
-
- ShaderCompilerRD::GeneratedCode gen_code;
- ShaderCompilerRD::IdentifierActions actions;
-
- uses_time = false;
- uses_half_res = false;
- uses_quarter_res = false;
- uses_position = false;
- uses_light = false;
-
- actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
- actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
-
- actions.usage_flag_pointers["TIME"] = &uses_time;
- actions.usage_flag_pointers["POSITION"] = &uses_position;
- actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
-
- actions.uniforms = &uniforms;
-
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
-
- Error err = scene_singleton->sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
-
- if (version.is_null()) {
- version = scene_singleton->sky_shader.shader.version_create();
- }
-
-#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->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);
- ERR_FAIL_COND(!scene_singleton->sky_shader.shader.version_is_valid(version));
-
- ubo_size = gen_code.uniform_total_size;
- ubo_offsets = gen_code.uniform_offsets;
- texture_uniforms = gen_code.texture_uniforms;
-
- //update pipelines
-
- for (int i = 0; i < SKY_VERSION_MAX; i++) {
- RD::PipelineDepthStencilState depth_stencil_state;
- depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
-
- RID shader_variant = scene_singleton->sky_shader.shader.version_get_shader(version, i);
- pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
- }
-
- valid = true;
-}
-
-void RendererSceneRenderRD::SkyShaderData::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 RendererSceneRenderRD::SkyShaderData::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_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- 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 RendererSceneRenderRD::SkyShaderData::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 RendererSceneRenderRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
-bool RendererSceneRenderRD::SkyShaderData::is_animated() const {
- return false;
-}
-
-bool RendererSceneRenderRD::SkyShaderData::casts_shadows() const {
- return false;
-}
-
-Variant RendererSceneRenderRD::SkyShaderData::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 RendererSceneRenderRD::SkyShaderData::get_native_source_code() const {
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
-
- return scene_singleton->sky_shader.shader.version_get_native_source_code(version);
-}
-
-RendererSceneRenderRD::SkyShaderData::SkyShaderData() {
- valid = false;
-}
-
-RendererSceneRenderRD::SkyShaderData::~SkyShaderData() {
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
- ERR_FAIL_COND(!scene_singleton);
- //pipeline variants will clear themselves if shader is gone
- if (version.is_valid()) {
- scene_singleton->sky_shader.shader.version_free(version);
- }
-}
-
-RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_sky_shader_func() {
- SkyShaderData *shader_data = memnew(SkyShaderData);
- return shader_data;
-}
-
-void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
-
- uniform_set_updated = true;
-
- 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());
- }
-
- 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->sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
-}
-
-RendererSceneRenderRD::SkyMaterialData::~SkyMaterialData() {
- 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 *RendererSceneRenderRD::_create_sky_material_func(SkyShaderData *p_shader) {
- SkyMaterialData *material_data = memnew(SkyMaterialData);
- material_data->shader_data = p_shader;
- material_data->last_frame = false;
- //update will happen later anyway so do nothing.
- return material_data;
+ return sky.sky_bake_panorama(p_sky, p_energy, p_bake_irradiance, p_size);
}
RID RendererSceneRenderRD::environment_allocate() {
return environment_owner.allocate_rid();
}
void RendererSceneRenderRD::environment_initialize(RID p_rid) {
- environment_owner.initialize_rid(p_rid, Environment());
+ environment_owner.initialize_rid(p_rid, RendererSceneEnvironmentRD());
}
void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->background = p_bg;
}
void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky = p_sky;
}
void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky_custom_fov = p_scale;
}
void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky_orientation = p_orientation;
}
void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->bg_color = p_color;
}
void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->bg_energy = p_energy;
}
void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->canvas_max_layer = p_max_layer;
}
void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- env->ambient_light = p_color;
- env->ambient_source = p_ambient;
- env->ambient_light_energy = p_energy;
- env->ambient_sky_contribution = p_sky_contribution;
- env->reflection_source = p_reflection_source;
- env->ao_color = p_ao_color;
+ env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source, p_ao_color);
}
RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);
return env->background;
}
RID RendererSceneRenderRD::environment_get_sky(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RID());
return env->sky;
}
float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->sky_custom_fov;
}
Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Basis());
return env->sky_orientation;
}
Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->bg_color;
}
float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->bg_energy;
}
int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->canvas_max_layer;
}
Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ambient_light;
}
RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);
return env->ambient_source;
}
float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_light_energy;
}
float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_sky_contribution;
}
RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED);
return env->reflection_source;
}
Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ao_color;
}
void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- env->exposure = p_exposure;
- env->tone_mapper = p_tone_mapper;
- if (!env->auto_exposure && p_auto_exposure) {
- env->auto_exposure_version = ++auto_exposure_counter;
- }
- env->auto_exposure = p_auto_exposure;
- env->white = p_white;
- env->min_luminance = p_min_luminance;
- env->max_luminance = p_max_luminance;
- env->auto_exp_speed = p_auto_exp_speed;
- env->auto_exp_scale = p_auto_exp_scale;
+ env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale);
}
void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7");
- env->glow_enabled = p_enable;
- env->glow_levels = p_levels;
- env->glow_intensity = p_intensity;
- env->glow_strength = p_strength;
- env->glow_mix = p_mix;
- env->glow_bloom = p_bloom_threshold;
- env->glow_blend_mode = p_blend_mode;
- env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold;
- env->glow_hdr_bleed_scale = p_hdr_bleed_scale;
- env->glow_hdr_luminance_cap = p_hdr_luminance_cap;
+ env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap);
}
void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) {
@@ -3088,100 +314,76 @@ void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable)
}
void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
if (low_end) {
return;
}
- env->sdfgi_enabled = p_enable;
- env->sdfgi_cascades = p_cascades;
- env->sdfgi_min_cell_size = p_min_cell_size;
- env->sdfgi_use_occlusion = p_use_occlusion;
- env->sdfgi_bounce_feedback = p_bounce_feedback;
- env->sdfgi_read_sky_light = p_read_sky;
- env->sdfgi_energy = p_energy;
- env->sdfgi_normal_bias = p_normal_bias;
- env->sdfgi_probe_bias = p_probe_bias;
- env->sdfgi_y_scale = p_y_scale;
+ env->set_sdfgi(p_enable, p_cascades, p_min_cell_size, p_y_scale, p_use_occlusion, p_bounce_feedback, p_read_sky, p_energy, p_normal_bias, p_probe_bias);
}
void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- env->fog_enabled = p_enable;
- env->fog_light_color = p_light_color;
- env->fog_light_energy = p_light_energy;
- env->fog_sun_scatter = p_sun_scatter;
- env->fog_density = p_density;
- env->fog_height = p_height;
- env->fog_height_density = p_height_density;
- env->fog_aerial_perspective = p_fog_aerial_perspective;
+ env->set_fog(p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_fog_aerial_perspective);
}
bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->fog_enabled;
}
Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->fog_light_color;
}
float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_light_energy;
}
float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_sun_scatter;
}
float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_density;
}
float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_height;
}
float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_height_density;
}
float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_aerial_perspective;
}
void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
if (low_end) {
return;
}
- env->volumetric_fog_enabled = p_enable;
- env->volumetric_fog_density = p_density;
- env->volumetric_fog_light = p_light;
- env->volumetric_fog_light_energy = p_light_energy;
- env->volumetric_fog_length = p_length;
- env->volumetric_fog_detail_spread = p_detail_spread;
- env->volumetric_fog_gi_inject = p_gi_inject;
- env->volumetric_fog_temporal_reprojection = p_temporal_reprojection;
- env->volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
+ env->set_volumetric_fog(p_enable, p_density, p_light, p_light_energy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount);
}
void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
@@ -3194,29 +396,25 @@ void RendererSceneRenderRD::environment_set_volumetric_fog_filter_active(bool p_
}
void RendererSceneRenderRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) {
- sdfgi_ray_count = p_ray_count;
+ gi.sdfgi_ray_count = p_ray_count;
}
void RendererSceneRenderRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) {
- sdfgi_frames_to_converge = p_frames;
+ gi.sdfgi_frames_to_converge = p_frames;
}
void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) {
- sdfgi_frames_to_update_light = p_update;
+ gi.sdfgi_frames_to_update_light = p_update;
}
void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
if (low_end) {
return;
}
- env->ssr_enabled = p_enable;
- env->ssr_max_steps = p_max_steps;
- env->ssr_fade_in = p_fade_int;
- env->ssr_fade_out = p_fade_out;
- env->ssr_depth_tolerance = p_depth_tolerance;
+ env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance);
}
void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
@@ -3228,22 +426,14 @@ RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_ro
}
void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
if (low_end) {
return;
}
- env->ssao_enabled = p_enable;
- env->ssao_radius = p_radius;
- env->ssao_intensity = p_intensity;
- env->ssao_power = p_power;
- env->ssao_detail = p_detail;
- env->ssao_horizon = p_horizon;
- env->ssao_sharpness = p_sharpness;
- env->ssao_direct_light_affect = p_light_affect;
- env->ssao_ao_channel_affect = p_ao_channel_affect;
+ env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect);
}
void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
@@ -3256,30 +446,30 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual
}
bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssao_enabled;
}
float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0.0);
return env->ssao_ao_channel_affect;
}
float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0.0);
return env->ssao_direct_light_affect;
}
bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssr_enabled;
}
bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->sdfgi_enabled;
}
@@ -3289,7 +479,7 @@ bool RendererSceneRenderRD::is_environment(RID p_env) const {
}
Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Ref<Image>());
if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) {
@@ -3359,7 +549,7 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
RD::get_singleton()->free(ra->depth_buffer);
ra->depth_buffer = RID();
for (int i = 0; i < ra->reflections.size(); i++) {
- _clear_reflection_data(ra->reflections.write[i].data);
+ ra->reflections.write[i].data.clear_reflection_data();
if (ra->reflections[i].owner.is_null()) {
continue;
}
@@ -3463,7 +653,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
if (atlas->reflection.is_null()) {
- int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
+ int mipmaps = MIN(sky.roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering
{
//reflection atlas was unused, create:
@@ -3488,7 +678,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
atlas->reflections.resize(atlas->count);
for (int i = 0; i < atlas->count; i++) {
- _update_reflection_data(atlas->reflections.write[i].data, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS);
+ atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers);
for (int j = 0; j < 6; j++) {
Vector<RID> fb;
fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
@@ -3548,7 +738,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
// Using real time reflections, all roughness is done in one step
- _create_reflection_fast_filter(atlas->reflections.write[rpi->atlas_index].data, false);
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(storage, false);
rpi->rendering = false;
rpi->processing_side = 0;
rpi->processing_layer = 1;
@@ -3556,7 +746,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
}
if (rpi->processing_layer > 1) {
- _create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, 10, rpi->processing_layer);
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(storage, false, 10, rpi->processing_layer, sky.sky_ggx_samples_quality);
rpi->processing_layer++;
if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
rpi->rendering = false;
@@ -3567,7 +757,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
return false;
} else {
- _create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, rpi->processing_side, rpi->processing_layer);
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(storage, false, rpi->processing_side, rpi->processing_layer, sky.sky_ggx_samples_quality);
}
rpi->processing_side++;
@@ -4142,817 +1332,27 @@ void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, cons
/////////////////////////////////
RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) {
- GIProbeInstance gi_probe;
- gi_probe.probe = p_base;
- RID rid = gi_probe_instance_owner.make_rid(gi_probe);
- return rid;
+ return gi.gi_probe_instance_create(p_base);
}
void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->transform = p_xform;
+ gi.gi_probe_instance_set_transform_to_data(p_probe, p_xform);
}
bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!gi_probe, false);
-
if (low_end) {
return false;
}
- //return true;
- return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+ return gi.gi_probe_needs_update(p_probe);
}
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) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND(!gi_probe);
-
if (low_end) {
return;
}
- uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe);
-
- // (RE)CREATE IF NEEDED
-
- if (gi_probe->last_probe_data_version != data_version) {
- //need to re-create everything
- if (gi_probe->texture.is_valid()) {
- RD::get_singleton()->free(gi_probe->texture);
- RD::get_singleton()->free(gi_probe->write_buffer);
- gi_probe->mipmaps.clear();
- }
-
- for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
- RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
- RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
- }
-
- gi_probe->dynamic_maps.clear();
-
- Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- if (octree_size != Vector3i()) {
- //can create a 3D texture
- Vector<int> levels = storage->gi_probe_get_level_counts(gi_probe->probe);
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tf.width = octree_size.x;
- tf.height = octree_size.y;
- tf.depth = octree_size.z;
- tf.texture_type = RD::TEXTURE_TYPE_3D;
- tf.mipmaps = levels.size();
-
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
-
- gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1);
-
- {
- int total_elements = 0;
- for (int i = 0; i < levels.size(); i++) {
- total_elements += levels[i];
- }
-
- gi_probe->write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16);
- }
-
- for (int i = 0; i < levels.size(); i++) {
- GIProbeInstance::Mipmap mipmap;
- mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), gi_probe->texture, 0, i, RD::TEXTURE_SLICE_3D);
- mipmap.level = levels.size() - i - 1;
- mipmap.cell_offset = 0;
- for (uint32_t j = 0; j < mipmap.level; j++) {
- mipmap.cell_offset += levels[j];
- }
- mipmap.cell_count = levels[mipmap.level];
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 2;
- u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 4;
- u.ids.push_back(gi_probe->write_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- Vector<RD::Uniform> copy_uniforms = uniforms;
- if (i == 0) {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 3;
- u.ids.push_back(gi_probe_lights_uniform);
- copy_uniforms.push_back(u);
- }
-
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
-
- copy_uniforms = uniforms; //restore
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 5;
- u.ids.push_back(gi_probe->texture);
- copy_uniforms.push_back(u);
- }
- mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
- } else {
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
- }
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(mipmap.texture);
- uniforms.push_back(u);
- }
-
- mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
-
- gi_probe->mipmaps.push_back(mipmap);
- }
-
- {
- uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
- uint32_t oversample = nearest_power_of_2_templated(4);
- int mipmap_index = 0;
-
- while (mipmap_index < gi_probe->mipmaps.size()) {
- GIProbeInstance::DynamicMap dmap;
-
- if (oversample > 0) {
- dmap.size = dynamic_map_size * (1 << oversample);
- dmap.mipmap = -1;
- oversample--;
- } else {
- dmap.size = dynamic_map_size >> mipmap_index;
- dmap.mipmap = mipmap_index;
- mipmap_index++;
- }
-
- RD::TextureFormat dtf;
- dtf.width = dmap.size;
- dtf.height = dmap.size;
- dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
-
- if (gi_probe->dynamic_maps.size() == 0) {
- dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- }
- dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
-
- if (gi_probe->dynamic_maps.size() == 0) {
- //render depth for first one
- dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
- dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
- }
-
- //just use depth as-is
- dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
- dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
-
- if (gi_probe->dynamic_maps.size() == 0) {
- dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
- dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
- dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
-
- Vector<RID> fb;
- fb.push_back(dmap.albedo);
- fb.push_back(dmap.normal);
- fb.push_back(dmap.orm);
- fb.push_back(dmap.texture); //emission
- fb.push_back(dmap.depth);
- fb.push_back(dmap.fb_depth);
-
- dmap.fb = RD::get_singleton()->framebuffer_create(fb);
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 3;
- u.ids.push_back(gi_probe_lights_uniform);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(dmap.albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(dmap.normal);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(dmap.orm);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 8;
- u.ids.push_back(dmap.fb_depth);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(dmap.texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
- u.ids.push_back(dmap.depth);
- uniforms.push_back(u);
- }
-
- dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
- }
- } else {
- bool plot = dmap.mipmap >= 0;
- bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1);
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth);
- uniforms.push_back(u);
- }
-
- if (write) {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(dmap.texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(dmap.depth);
- uniforms.push_back(u);
- }
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- if (plot) {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
- uniforms.push_back(u);
- }
- }
-
- dmap.uniform_set = RD::get_singleton()->uniform_set_create(
- uniforms,
- giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
- 0);
- }
-
- gi_probe->dynamic_maps.push_back(dmap);
- }
- }
- }
-
- gi_probe->last_probe_data_version = data_version;
- p_update_light_instances = true; //just in case
-
- _base_uniforms_changed();
- }
-
- // UDPDATE TIME
-
- if (gi_probe->has_dynamic_object_data) {
- //if it has dynamic object data, it needs to be cleared
- RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1);
- }
-
- uint32_t light_count = 0;
-
- if (p_update_light_instances || p_dynamic_objects.size() > 0) {
- light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
-
- {
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
- Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
- //update lights
-
- for (uint32_t i = 0; i < light_count; i++) {
- GIProbeLight &l = gi_probe_lights[i];
- RID light_instance = p_light_instances[i];
- RID light = light_instance_get_base_light(light_instance);
-
- l.type = storage->light_get_type(light);
- if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) {
- light_count--;
- continue;
- }
-
- l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
- l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
- l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
- Color color = storage->light_get_color(light).to_linear();
- l.color[0] = color.r;
- l.color[1] = color.g;
- l.color[2] = color.b;
-
- l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- Transform xform = light_instance_get_base_transform(light_instance);
-
- Vector3 pos = to_probe_xform.xform(xform.origin);
- Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
-
- l.position[0] = pos.x;
- l.position[1] = pos.y;
- l.position[2] = pos.z;
-
- l.direction[0] = dir.x;
- l.direction[1] = dir.y;
- l.direction[2] = dir.z;
-
- l.has_shadow = storage->light_has_shadow(light);
- }
-
- RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights);
- }
- }
-
- if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) {
- // PROCESS MIPMAPS
- if (gi_probe->mipmaps.size()) {
- //can update mipmaps
-
- Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- GIProbePushConstant push_constant;
-
- push_constant.limits[0] = probe_size.x;
- push_constant.limits[1] = probe_size.y;
- push_constant.limits[2] = probe_size.z;
- push_constant.stack_size = gi_probe->mipmaps.size();
- push_constant.emission_scale = 1.0;
- push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.light_count = light_count;
- push_constant.aniso_strength = 0;
-
- /* print_line("probe update to version " + itos(gi_probe->last_probe_version));
- print_line("propagation " + rtos(push_constant.propagation));
- print_line("dynrange " + rtos(push_constant.dynamic_range));
- */
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- int passes;
- if (p_update_light_instances) {
- passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
- } else {
- passes = 1; //only re-blitting is necessary
- }
- int wg_size = 64;
- int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
-
- for (int pass = 0; pass < passes; pass++) {
- if (p_update_light_instances) {
- for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
- if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
- } else if (i == 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
- }
-
- if (pass == 1 || i > 0) {
- RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
- }
- if (pass == 0 || i > 0) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
- } else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
- }
-
- push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
- push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
-
- int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
- while (wg_todo) {
- int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
- wg_todo -= wg_count;
- push_constant.cell_offset += wg_count * wg_size;
- }
- }
-
- RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
- }
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
-
- for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
-
- push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
- push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
-
- int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
- while (wg_todo) {
- int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
- wg_todo -= wg_count;
- push_constant.cell_offset += wg_count * wg_size;
- }
- }
- }
-
- RD::get_singleton()->compute_list_end();
- }
- }
-
- gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again
-
- if (p_dynamic_objects.size() && gi_probe->dynamic_maps.size()) {
- Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
- int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
-
- Transform oversample_scale;
- oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
-
- Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe);
- Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse();
- Transform to_probe_xform = to_world_xform.affine_inverse();
-
- AABB probe_aabb(Vector3(), octree_size);
-
- //this could probably be better parallelized in compute..
- for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {
- GeometryInstance *instance = p_dynamic_objects[i];
-
- //transform aabb to giprobe
- AABB aabb = (to_probe_xform * geometry_instance_get_transform(instance)).xform(geometry_instance_get_aabb(instance));
-
- //this needs to wrap to grid resolution to avoid jitter
- //also extend margin a bit just in case
- Vector3i begin = aabb.position - Vector3i(1, 1, 1);
- Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
-
- for (int j = 0; j < 3; j++) {
- if ((end[j] - begin[j]) & 1) {
- end[j]++; //for half extents split, it needs to be even
- }
- begin[j] = MAX(begin[j], 0);
- end[j] = MIN(end[j], octree_size[j] * multiplier);
- }
-
- //aabb = aabb.intersection(probe_aabb); //intersect
- aabb.position = begin;
- aabb.size = end - begin;
-
- //print_line("aabb: " + aabb);
-
- for (int j = 0; j < 6; j++) {
- //if (j != 0 && j != 3) {
- // continue;
- //}
- static const Vector3 render_z[6] = {
- Vector3(1, 0, 0),
- Vector3(0, 1, 0),
- Vector3(0, 0, 1),
- Vector3(-1, 0, 0),
- Vector3(0, -1, 0),
- Vector3(0, 0, -1),
- };
- static const Vector3 render_up[6] = {
- Vector3(0, 1, 0),
- Vector3(0, 0, 1),
- Vector3(0, 1, 0),
- Vector3(0, 1, 0),
- Vector3(0, 0, 1),
- Vector3(0, 1, 0),
- };
-
- Vector3 render_dir = render_z[j];
- Vector3 up_dir = render_up[j];
-
- Vector3 center = aabb.position + aabb.size * 0.5;
- Transform xform;
- xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
-
- Vector3 x_dir = xform.basis.get_axis(0).abs();
- int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
- Vector3 y_dir = xform.basis.get_axis(1).abs();
- int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
- Vector3 z_dir = -xform.basis.get_axis(2);
- int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
-
- Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
- bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
- bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
- bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
-
- CameraMatrix cm;
- cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
-
- if (cull_argument.size() == 0) {
- cull_argument.push_back(nullptr);
- }
- cull_argument[0] = instance;
-
- _render_material(to_world_xform * xform, cm, true, cull_argument, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
-
- GIProbeDynamicPushConstant push_constant;
- zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant));
- push_constant.limits[0] = octree_size.x;
- push_constant.limits[1] = octree_size.y;
- push_constant.limits[2] = octree_size.z;
- push_constant.light_count = p_light_instances.size();
- push_constant.x_dir[0] = x_dir[0];
- push_constant.x_dir[1] = x_dir[1];
- push_constant.x_dir[2] = x_dir[2];
- push_constant.y_dir[0] = y_dir[0];
- push_constant.y_dir[1] = y_dir[1];
- push_constant.y_dir[2] = y_dir[2];
- push_constant.z_dir[0] = z_dir[0];
- push_constant.z_dir[1] = z_dir[1];
- push_constant.z_dir[2] = z_dir[2];
- push_constant.z_base = xform.origin[z_axis];
- push_constant.z_sign = (z_flip ? -1.0 : 1.0);
- push_constant.pos_multiplier = float(1.0) / multiplier;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.flip_x = x_flip;
- push_constant.flip_y = y_flip;
- push_constant.rect_pos[0] = rect.position[0];
- push_constant.rect_pos[1] = rect.position[1];
- push_constant.rect_size[0] = rect.size[0];
- push_constant.rect_size[1] = rect.size[1];
- push_constant.prev_rect_ofs[0] = 0;
- push_constant.prev_rect_ofs[1] = 0;
- push_constant.prev_rect_size[0] = 0;
- push_constant.prev_rect_size[1] = 0;
- push_constant.on_mipmap = false;
- push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
- push_constant.pad[0] = 0;
- push_constant.pad[1] = 0;
- push_constant.pad[2] = 0;
-
- //process lighting
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
- //print_line("rect: " + itos(i) + ": " + rect);
-
- for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) {
- // enlarge the rect if needed so all pixels fit when downscaled,
- // this ensures downsampling is smooth and optimal because no pixels are left behind
-
- //x
- if (rect.position.x & 1) {
- rect.size.x++;
- push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
- } else {
- push_constant.prev_rect_ofs[0] = 0;
- }
- if (rect.size.x & 1) {
- rect.size.x++;
- }
-
- rect.position.x >>= 1;
- rect.size.x = MAX(1, rect.size.x >> 1);
-
- //y
- if (rect.position.y & 1) {
- rect.size.y++;
- push_constant.prev_rect_ofs[1] = 1;
- } else {
- push_constant.prev_rect_ofs[1] = 0;
- }
- if (rect.size.y & 1) {
- rect.size.y++;
- }
-
- rect.position.y >>= 1;
- rect.size.y = MAX(1, rect.size.y >> 1);
-
- //shrink limits to ensure plot does not go outside map
- if (gi_probe->dynamic_maps[k].mipmap > 0) {
- for (int l = 0; l < 3; l++) {
- push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
- }
- }
-
- //print_line("rect: " + itos(i) + ": " + rect);
- push_constant.rect_pos[0] = rect.position[0];
- push_constant.rect_pos[1] = rect.position[1];
- push_constant.prev_rect_size[0] = push_constant.rect_size[0];
- push_constant.prev_rect_size[1] = push_constant.rect_size[1];
- push_constant.rect_size[0] = rect.size[0];
- push_constant.rect_size[1] = rect.size[1];
- push_constant.on_mipmap = gi_probe->dynamic_maps[k].mipmap > 0;
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- if (gi_probe->dynamic_maps[k].mipmap < 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
- } else if (k < gi_probe->dynamic_maps.size() - 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
- } else {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
- }
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
- }
-
- RD::get_singleton()->compute_list_end();
- }
- }
-
- gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again
- }
-
- gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
-}
-
-void RendererSceneRenderRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- if (gi_probe->mipmaps.size() == 0) {
- return;
- }
-
- CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse());
-
- int level = 0;
- Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- GIProbeDebugPushConstant push_constant;
- push_constant.alpha = p_alpha;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
- push_constant.level = level;
-
- push_constant.bounds[0] = octree_size.x >> level;
- push_constant.bounds[1] = octree_size.y >> level;
- push_constant.bounds[2] = octree_size.z >> level;
- push_constant.pad = 0;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- push_constant.projection[i * 4 + j] = transform.matrix[i][j];
- }
- }
-
- if (giprobe_debug_uniform_set.is_valid()) {
- RD::get_singleton()->free(giprobe_debug_uniform_set);
- }
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
- u.ids.push_back(gi_probe->texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 3;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- int cell_count;
- if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) {
- cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
- } else {
- cell_count = gi_probe->mipmaps[level].cell_count;
- }
-
- giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0);
-
- int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR;
- if (p_emission) {
- giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION;
- } else if (p_lighting) {
- giprobe_debug_pipeline = gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT;
- }
- RD::get_singleton()->draw_list_bind_render_pipeline(
- p_draw_list,
- giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
+ gi.gi_probe_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
}
void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) {
@@ -4963,132 +1363,7 @@ void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawLi
return; //nothing to debug
}
- SDGIShader::DebugProbesPushConstant push_constant;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- push_constant.projection[i * 4 + j] = p_camera_with_transform.matrix[i][j];
- }
- }
-
- //gen spheres from strips
- uint32_t band_points = 16;
- push_constant.band_power = 4;
- push_constant.sections_in_band = ((band_points / 2) - 1);
- push_constant.band_mask = band_points - 2;
- push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band);
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- uint32_t total_points = push_constant.sections_in_band * band_points;
- uint32_t total_probes = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
-
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.cascade = 0;
-
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
-
- if (!rb->sdfgi->debug_probes_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(rb->sdfgi->debug_probes_uniform_set)) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb->sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- uniforms.push_back(u);
- }
-
- rb->sdfgi->debug_probes_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, 0), 0);
- }
-
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_PROBES].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, rb->sdfgi->debug_probes_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points);
-
- if (sdfgi_debug_probe_dir != Vector3()) {
- print_line("CLICK DEBUG ME?");
- uint32_t cascade = 0;
- Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[cascade].position)) * rb->sdfgi->cascades[cascade].cell_size * Vector3(1.0, 1.0 / rb->sdfgi->y_mult, 1.0);
- Vector3 probe_size = rb->sdfgi->cascades[cascade].cell_size * (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / rb->sdfgi->y_mult, 1.0);
- Vector3 ray_from = sdfgi_debug_probe_pos;
- Vector3 ray_to = sdfgi_debug_probe_pos + sdfgi_debug_probe_dir * rb->sdfgi->cascades[cascade].cell_size * Math::sqrt(3.0) * rb->sdfgi->cascade_size;
- float sphere_radius = 0.2;
- float closest_dist = 1e20;
- sdfgi_debug_probe_enabled = false;
-
- Vector3i probe_from = rb->sdfgi->cascades[cascade].position / (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR);
- for (int i = 0; i < (SDFGI::PROBE_DIVISOR + 1); i++) {
- for (int j = 0; j < (SDFGI::PROBE_DIVISOR + 1); j++) {
- for (int k = 0; k < (SDFGI::PROBE_DIVISOR + 1); k++) {
- Vector3 pos = offset + probe_size * Vector3(i, j, k);
- Vector3 res;
- if (Geometry3D::segment_intersects_sphere(ray_from, ray_to, pos, sphere_radius, &res)) {
- float d = ray_from.distance_to(res);
- if (d < closest_dist) {
- closest_dist = d;
- sdfgi_debug_probe_enabled = true;
- sdfgi_debug_probe_index = probe_from + Vector3i(i, j, k);
- }
- }
- }
- }
- }
-
- if (sdfgi_debug_probe_enabled) {
- print_line("found: " + sdfgi_debug_probe_index);
- } else {
- print_line("no found");
- }
- sdfgi_debug_probe_dir = Vector3();
- }
-
- if (sdfgi_debug_probe_enabled) {
- uint32_t cascade = 0;
- uint32_t probe_cells = (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR);
- Vector3i probe_from = rb->sdfgi->cascades[cascade].position / probe_cells;
- Vector3i ofs = sdfgi_debug_probe_index - probe_from;
- if (ofs.x < 0 || ofs.y < 0 || ofs.z < 0) {
- return;
- }
- if (ofs.x > SDFGI::PROBE_DIVISOR || ofs.y > SDFGI::PROBE_DIVISOR || ofs.z > SDFGI::PROBE_DIVISOR) {
- return;
- }
-
- uint32_t mult = (SDFGI::PROBE_DIVISOR + 1);
- uint32_t index = ofs.z * mult * mult + ofs.y * mult + ofs.x;
-
- push_constant.probe_debug_index = index;
-
- uint32_t cell_count = probe_cells * 2 * probe_cells * 2 * probe_cells * 2;
-
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_VISIBILITY].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, rb->sdfgi->debug_probes_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, total_points);
- }
+ rb->sdfgi->debug_probes(p_draw_list, p_framebuffer, p_camera_with_transform);
}
////////////////////////////////
@@ -5277,7 +1552,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
return;
}
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
ERR_FAIL_COND(!env);
ERR_FAIL_COND(!env->ssr_enabled);
@@ -5322,7 +1597,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
ERR_FAIL_COND(!env);
RENDER_TIMESTAMP("Process SSAO");
@@ -5468,7 +1743,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
//glow (if enabled)
CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
@@ -5661,7 +1936,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
}
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) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->adjustments_enabled = p_enable;
@@ -5672,152 +1947,6 @@ void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable,
env->color_correction = p_color_correction;
}
-void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- if (!rb->sdfgi) {
- return; //eh
- }
-
- if (!rb->sdfgi->debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(rb->sdfgi->debug_uniform_set)) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].light_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_0_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_1_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 5;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 8;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb->sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 10;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(rb->texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 11;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- uniforms.push_back(u);
- }
- rb->sdfgi->debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.debug_shader_version, 0);
- }
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.debug_pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->debug_uniform_set, 0);
-
- SDGIShader::DebugPushConstant push_constant;
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.screen_size[0] = rb->width;
- push_constant.screen_size[1] = rb->height;
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.use_occlusion = rb->sdfgi->uses_occlusion;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- Vector2 vp_half = p_projection.get_viewport_half_extents();
- push_constant.cam_extent[0] = vp_half.x;
- push_constant.cam_extent[1] = vp_half.y;
- push_constant.cam_extent[2] = -p_projection.get_z_near();
-
- push_constant.cam_transform[0] = p_transform.basis.elements[0][0];
- push_constant.cam_transform[1] = p_transform.basis.elements[1][0];
- push_constant.cam_transform[2] = p_transform.basis.elements[2][0];
- push_constant.cam_transform[3] = 0;
- push_constant.cam_transform[4] = p_transform.basis.elements[0][1];
- push_constant.cam_transform[5] = p_transform.basis.elements[1][1];
- push_constant.cam_transform[6] = p_transform.basis.elements[2][1];
- push_constant.cam_transform[7] = 0;
- push_constant.cam_transform[8] = p_transform.basis.elements[0][2];
- push_constant.cam_transform[9] = p_transform.basis.elements[1][2];
- push_constant.cam_transform[10] = p_transform.basis.elements[2][2];
- push_constant.cam_transform[11] = 0;
- push_constant.cam_transform[12] = p_transform.origin.x;
- push_constant.cam_transform[13] = p_transform.origin.y;
- push_constant.cam_transform[14] = p_transform.origin.z;
- push_constant.cam_transform[15] = 1;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DebugPushConstant));
-
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
- RD::get_singleton()->compute_list_end();
-
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
- storage->get_effects()->copy_to_fb_rect(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), true);
-}
-
RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
@@ -5837,14 +1966,14 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {
RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
- if (rb->giprobe_buffer.is_null()) {
- rb->giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES);
+ if (rb->gi.giprobe_buffer.is_null()) {
+ rb->gi.giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::GIProbeData) * RendererSceneGIRD::MAX_GIPROBES);
}
- return rb->giprobe_buffer;
+ return rb->gi.giprobe_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() {
- return default_giprobe_buffer;
+ return gi.default_giprobe_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) {
@@ -5893,7 +2022,7 @@ Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RI
ERR_FAIL_COND_V(!rb, Vector3i());
ERR_FAIL_COND_V(!rb->sdfgi, Vector3i());
ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3i());
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
+ int32_t probe_divisor = rb->sdfgi->cascade_size / RendererSceneGIRD::SDFGI::PROBE_DIVISOR;
return rb->sdfgi->cascades[p_cascade].position / probe_divisor;
}
@@ -6142,11 +2271,11 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q
}
int RendererSceneRenderRD::get_roughness_layers() const {
- return roughness_layers;
+ return sky.roughness_layers;
}
bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
- return sky_use_cubemap_array;
+ return sky.sky_use_cubemap_array;
}
RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) {
@@ -6223,7 +2352,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
}
if (cluster.reflection_count) {
- RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ 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);
}
}
@@ -6232,7 +2361,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
r_directional_light_count = 0;
r_positional_light_count = 0;
- sky_scene_state.ubo.directional_light_count = 0;
+ sky.sky_scene_state.ubo.directional_light_count = 0;
Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized());
@@ -6252,8 +2381,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
switch (type) {
case RS::LIGHT_DIRECTIONAL: {
// Copy to SkyDirectionalLightData
- if (r_directional_light_count < sky_scene_state.max_directional_lights) {
- SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
+ if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) {
+ RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count];
Transform light_transform = li->transform;
Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
@@ -6281,7 +2410,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
angular_diameter = 0.0;
}
sky_light_data.size = angular_diameter;
- sky_scene_state.ubo.directional_light_count++;
+ sky.sky_scene_state.ubo.directional_light_count++;
}
if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) {
@@ -6816,7 +2945,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) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
float ratio = float(rb->width) / float((rb->width + rb->height) / 2);
uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
@@ -6873,7 +3002,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
uniforms.push_back(u);
}
- rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG);
}
//update volumetric fog
@@ -6984,8 +3113,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 12;
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- u.ids.push_back(rb->giprobe_textures[i]);
+ for (int i = 0; i < RendererSceneGIRD::MAX_GIPROBES; i++) {
+ u.ids.push_back(rb->gi.giprobe_textures[i]);
}
uniforms.push_back(u);
}
@@ -7224,7 +3353,14 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) {
void RendererSceneRenderRD::_post_prepass_render(bool p_use_gi) {
if (render_state.render_buffers.is_valid()) {
if (p_use_gi) {
- _sdfgi_update_probes(render_state.render_buffers, render_state.environment);
+ RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+ if (rb->sdfgi == nullptr) {
+ return;
+ }
+
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(render_state.environment);
+ rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky));
}
}
}
@@ -7241,7 +3377,13 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
// 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) {
- _sdfgi_store_probes(render_state.render_buffers);
+ RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+ if (rb->sdfgi == nullptr) {
+ return;
+ }
+
+ rb->sdfgi->store_probes();
}
render_state.cube_shadows.clear();
@@ -7308,7 +3450,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
//start GI
if (render_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);
+ 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);
}
//Do shadow rendering (in parallel with GI)
@@ -7368,6 +3510,13 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
}
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) {
+ // 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....
+ }
+
//assign render data
{
render_state.render_buffers = p_render_buffers;
@@ -7404,19 +3553,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
}
//sdfgi first
- if (p_render_buffers.is_valid()) {
+ if (rb != nullptr && rb->sdfgi != nullptr) {
for (int i = 0; i < render_state.render_sdfgi_region_count; i++) {
- _render_sdfgi_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances);
+ rb->sdfgi->render_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this);
}
if (render_state.sdfgi_update_data->update_static) {
- _render_sdfgi_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights);
+ rb->sdfgi->render_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this);
}
}
Color clear_color;
if (p_render_buffers.is_valid()) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
clear_color = storage->render_target_get_clear_request_color(rb->render_target);
} else {
clear_color = storage->get_default_clear_color();
@@ -7424,15 +3571,15 @@ 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++) {
- GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probes[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 *rb = render_buffers_owner.getornull(render_state.render_buffers);
- current_cluster_builder = rb->cluster_builder;
+ 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);
ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas);
@@ -7447,14 +3594,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
current_cluster_builder = nullptr;
}
- if (p_render_buffers.is_valid()) {
- _pre_process_gi(p_render_buffers, p_cam_transform);
+ if (rb != nullptr && rb->sdfgi != nullptr) {
+ rb->sdfgi->update_cascades();
+
+ rb->sdfgi->pre_process_gi(p_cam_transform, this);
}
render_state.gi_probe_count = 0;
- if (render_state.render_buffers.is_valid()) {
- _setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count);
- _sdfgi_update_light(render_state.render_buffers, render_state.environment);
+ 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);
+
+ rb->sdfgi->update_light();
}
render_state.depth_prepass_used = false;
@@ -7487,8 +3637,8 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
_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);
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI) {
- _sdfgi_debug_draw(p_render_buffers, p_cam_projection, p_cam_transform);
+ 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);
}
}
}
@@ -7668,366 +3818,6 @@ void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, co
_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region);
}
-void RendererSceneRenderRD::_render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) {
- //print_line("rendering region " + itos(p_region));
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
- ERR_FAIL_COND(!rb->sdfgi);
- AABB bounds;
- Vector3i from;
- Vector3i size;
-
- int cascade_prev = _sdfgi_get_pending_region_data(p_render_buffers, p_region - 1, from, size, bounds);
- int cascade_next = _sdfgi_get_pending_region_data(p_render_buffers, p_region + 1, from, size, bounds);
- int cascade = _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds);
- ERR_FAIL_COND(cascade < 0);
-
- if (cascade_prev != cascade) {
- //initialize render
- RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1);
- }
-
- //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(rb->sdfgi->cascades[cascade].cell_size));
- _render_sdfgi(p_render_buffers, from, size, bounds, p_instances, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing);
-
- if (cascade_next != cascade) {
- RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
-
- RENDER_TIMESTAMP(">SDFGI Update SDF");
- //done rendering! must update SDF
- //clear dispatch indirect data
-
- SDGIShader::PreprocessPushConstant push_constant;
- zeromem(&push_constant, sizeof(SDGIShader::PreprocessPushConstant));
-
- RENDER_TIMESTAMP("Scroll SDF");
-
- //scroll
- if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
- //for scroll
- Vector3i dirty = rb->sdfgi->cascades[cascade].dirty_regions;
- push_constant.scroll[0] = dirty.x;
- push_constant.scroll[1] = dirty.y;
- push_constant.scroll[2] = dirty.z;
- } else {
- //for no scroll
- push_constant.scroll[0] = 0;
- push_constant.scroll[1] = 0;
- push_constant.scroll[2] = 0;
- }
-
- rb->sdfgi->cascades[cascade].all_dynamic_lights_dirty = true;
-
- push_constant.grid_size = rb->sdfgi->cascade_size;
- push_constant.cascade = cascade;
-
- if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- //must pre scroll existing data because not all is dirty
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_uniform_set, 0);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0);
- // no barrier do all together
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_occlusion_uniform_set, 0);
-
- Vector3i dirty = rb->sdfgi->cascades[cascade].dirty_regions;
- Vector3i groups;
- groups.x = rb->sdfgi->cascade_size - ABS(dirty.x);
- groups.y = rb->sdfgi->cascade_size - ABS(dirty.y);
- groups.z = rb->sdfgi->cascade_size - ABS(dirty.z);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z);
-
- //no barrier, continue together
-
- {
- //scroll probes and their history also
-
- SDGIShader::IntegratePushConstant ipush_constant;
- ipush_constant.grid_size[1] = rb->sdfgi->cascade_size;
- ipush_constant.grid_size[2] = rb->sdfgi->cascade_size;
- ipush_constant.grid_size[0] = rb->sdfgi->cascade_size;
- ipush_constant.max_cascades = rb->sdfgi->cascades.size();
- ipush_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- ipush_constant.history_index = 0;
- ipush_constant.history_size = rb->sdfgi->history_size;
- ipush_constant.ray_count = 0;
- ipush_constant.ray_bias = 0;
- ipush_constant.sky_mode = 0;
- ipush_constant.sky_energy = 0;
- ipush_constant.sky_color[0] = 0;
- ipush_constant.sky_color[1] = 0;
- ipush_constant.sky_color[2] = 0;
- ipush_constant.y_mult = rb->sdfgi->y_mult;
- ipush_constant.store_ambient_texture = false;
-
- ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
- ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count;
-
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- ipush_constant.cascade = cascade;
- ipush_constant.world_offset[0] = rb->sdfgi->cascades[cascade].position.x / probe_divisor;
- ipush_constant.world_offset[1] = rb->sdfgi->cascades[cascade].position.y / probe_divisor;
- ipush_constant.world_offset[2] = rb->sdfgi->cascades[cascade].position.z / probe_divisor;
-
- ipush_constant.scroll[0] = dirty.x / probe_divisor;
- ipush_constant.scroll[1] = dirty.y / probe_divisor;
- ipush_constant.scroll[2] = dirty.z / probe_divisor;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL_STORE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- if (rb->sdfgi->bounce_feedback > 0.0) {
- //multibounce requires this to be stored so direct light can read from it
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]);
-
- //convert to octahedral to store
- ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
- ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
- }
- }
-
- //ok finally barrier
- RD::get_singleton()->compute_list_end();
- }
-
- //clear dispatch indirect data
- uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };
- RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data);
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- bool half_size = true; //much faster, very little difference
- static const int optimized_jf_group_size = 8;
-
- if (half_size) {
- push_constant.grid_size >>= 1;
-
- uint32_t cascade_half_size = rb->sdfgi->cascade_size >> 1;
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_half_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //must start with regular jumpflood
-
- push_constant.half_size = true;
- {
- RENDER_TIMESTAMP("SDFGI Jump Flood (Half Size)");
-
- uint32_t s = cascade_half_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]);
-
- int jf_us = 0;
- //start with regular jump flood for very coarse reads, as this is impossible to optimize
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
-
- if (cascade_half_size / (s / 2) >= optimized_jf_group_size) {
- break;
- }
- }
-
- RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half Size)");
-
- //continue with optimized jump flood for smaller reads
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
- }
- }
-
- // restore grid size for last passes
- push_constant.grid_size = rb->sdfgi->cascade_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_upscale_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //run one pass of fullsize jumpflood to fix up half size arctifacts
-
- push_constant.half_size = false;
- push_constant.step_size = 1;
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[rb->sdfgi->upscale_jfa_uniform_set_index], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- } else {
- //full size jumpflood
- RENDER_TIMESTAMP("SDFGI Jump Flood");
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- push_constant.half_size = false;
- {
- uint32_t s = rb->sdfgi->cascade_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]);
-
- int jf_us = 0;
- //start with regular jump flood for very coarse reads, as this is impossible to optimize
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
-
- if (rb->sdfgi->cascade_size / (s / 2) >= optimized_jf_group_size) {
- break;
- }
- }
-
- RENDER_TIMESTAMP("SDFGI Jump Flood Optimized");
-
- //continue with optimized jump flood for smaller reads
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
- }
- }
- }
-
- RENDER_TIMESTAMP("SDFGI Occlusion");
-
- // occlusion
- {
- uint32_t probe_size = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- Vector3i probe_global_pos = rb->sdfgi->cascades[cascade].position / probe_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_OCCLUSION]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->occlusion_uniform_set, 0);
- for (int i = 0; i < 8; i++) {
- //dispatch all at once for performance
- Vector3i offset(i & 1, (i >> 1) & 1, (i >> 2) & 1);
-
- if ((probe_global_pos.x & 1) != 0) {
- offset.x = (offset.x + 1) & 1;
- }
- if ((probe_global_pos.y & 1) != 0) {
- offset.y = (offset.y + 1) & 1;
- }
- if ((probe_global_pos.z & 1) != 0) {
- offset.z = (offset.z + 1) & 1;
- }
- push_constant.probe_offset[0] = offset.x;
- push_constant.probe_offset[1] = offset.y;
- push_constant.probe_offset[2] = offset.z;
- push_constant.occlusion_index = i;
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
-
- Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute
- RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z);
- }
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- }
-
- RENDER_TIMESTAMP("SDFGI Store");
-
- // store
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_STORE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].sdf_store_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
-
- RD::get_singleton()->compute_list_end();
-
- //clear these textures, as they will have previous garbage on next draw
- RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
-
-#if 0
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->cascades[cascade].sdf, 0);
- Ref<Image> img;
- img.instance();
- for (uint32_t i = 0; i < rb->sdfgi->cascade_size; i++) {
- Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1);
- img->create(rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, false, Image::FORMAT_L8, subarr);
- img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png");
- }
-
- //finalize render and update sdf
-#endif
-
-#if 0
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->render_albedo, 0);
- Ref<Image> img;
- img.instance();
- for (uint32_t i = 0; i < rb->sdfgi->cascade_size; i++) {
- Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1);
- img->create(rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, false, Image::FORMAT_RGB565, subarr);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png");
- }
-
- //finalize render and update sdf
-#endif
-
- RENDER_TIMESTAMP("<SDFGI Update SDF");
- RD::get_singleton()->draw_command_end_label();
- }
-}
-
void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider));
Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();
@@ -8045,133 +3835,15 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,
_render_particle_collider_heightfield(fb, cam_xform, cm, p_instances);
}
-void RendererSceneRenderRD::_render_sdfgi_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) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
- ERR_FAIL_COND(!rb->sdfgi);
-
- RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs");
-
- _sdfgi_update_cascades(p_render_buffers); //need cascades updated for this
-
- SDGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS];
- uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS];
-
- for (uint32_t i = 0; i < p_cascade_count; i++) {
- ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size());
-
- SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]];
-
- { //fill light buffer
-
- AABB cascade_aabb;
- cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cc.position)) * cc.cell_size;
- cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cc.cell_size;
-
- int idx = 0;
-
- for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) {
- if (idx == SDFGI::MAX_STATIC_LIGHTS) {
- break;
- }
-
- LightInstance *li = light_instance_owner.getornull(p_positional_light_cull_result[i][j]);
- ERR_CONTINUE(!li);
-
- uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
- if (p_cascade_indices[i] > max_sdfgi_cascade) {
- continue;
- }
-
- if (!cascade_aabb.intersects(li->aabb)) {
- continue;
- }
-
- lights[idx].type = storage->light_get_type(li->light);
-
- Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
- if (lights[idx].type == RS::LIGHT_DIRECTIONAL) {
- dir.y *= rb->sdfgi->y_mult; //only makes sense for directional
- dir.normalize();
- }
- lights[idx].direction[0] = dir.x;
- lights[idx].direction[1] = dir.y;
- lights[idx].direction[2] = dir.z;
- Vector3 pos = li->transform.origin;
- pos.y *= rb->sdfgi->y_mult;
- lights[idx].position[0] = pos.x;
- lights[idx].position[1] = pos.y;
- lights[idx].position[2] = pos.z;
- Color color = storage->light_get_color(li->light);
- color = color.to_linear();
- lights[idx].color[0] = color.r;
- lights[idx].color[1] = color.g;
- lights[idx].color[2] = color.b;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
- lights[idx].has_shadow = storage->light_has_shadow(li->light);
- lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
- lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- idx++;
- }
-
- if (idx > 0) {
- RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights);
- }
-
- light_count[i] = idx;
- }
- }
-
- /* Static Lights */
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]);
-
- SDGIShader::DirectLightPushConstant dl_push_constant;
-
- dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- dl_push_constant.max_cascades = rb->sdfgi->cascades.size();
- dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- dl_push_constant.bounce_feedback = 0.0; // this is static light, do not multibounce yet
- dl_push_constant.y_mult = rb->sdfgi->y_mult;
- dl_push_constant.use_occlusion = rb->sdfgi->uses_occlusion;
-
- //all must be processed
- dl_push_constant.process_offset = 0;
- dl_push_constant.process_increment = 1;
-
- for (uint32_t i = 0; i < p_cascade_count; i++) {
- ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size());
-
- SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]];
-
- dl_push_constant.light_count = light_count[i];
- dl_push_constant.cascade = p_cascade_indices[i];
-
- if (dl_push_constant.light_count > 0) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDGIShader::DirectLightPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0);
- }
- }
-
- RD::get_singleton()->compute_list_end();
-
- RD::get_singleton()->draw_command_end_label();
-}
-
bool RendererSceneRenderRD::free(RID p_rid) {
if (render_buffers_owner.owns(p_rid)) {
RenderBuffers *rb = render_buffers_owner.getornull(p_rid);
_free_render_buffer_data(rb);
memdelete(rb->data);
if (rb->sdfgi) {
- _sdfgi_erase(rb);
+ rb->sdfgi->erase();
+ memdelete(rb->sdfgi);
+ rb->sdfgi = nullptr;
}
if (rb->volumetric_fog) {
_volumetric_fog_erase(rb);
@@ -8202,8 +3874,8 @@ bool RendererSceneRenderRD::free(RID p_rid) {
decal_instance_owner.free(p_rid);
} else if (lightmap_instance_owner.owns(p_rid)) {
lightmap_instance_owner.free(p_rid);
- } else if (gi_probe_instance_owner.owns(p_rid)) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid);
+ } else if (gi.gi_probe_instance_owner.owns(p_rid)) {
+ RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_rid);
if (gi_probe->texture.is_valid()) {
RD::get_singleton()->free(gi_probe->texture);
RD::get_singleton()->free(gi_probe->write_buffer);
@@ -8214,37 +3886,10 @@ bool RendererSceneRenderRD::free(RID p_rid) {
RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
}
- gi_probe_instance_owner.free(p_rid);
- } else if (sky_owner.owns(p_rid)) {
- _update_dirty_skys();
- Sky *sky = sky_owner.getornull(p_rid);
-
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
-
- if (sky->uniform_buffer.is_valid()) {
- RD::get_singleton()->free(sky->uniform_buffer);
- sky->uniform_buffer = RID();
- }
-
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
- }
-
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
- }
-
- if (sky->material.is_valid()) {
- storage->free(sky->material);
- }
-
- sky_owner.free(p_rid);
+ gi.gi_probe_instance_owner.free(p_rid);
+ } else if (sky.sky_owner.owns(p_rid)) {
+ sky.update_dirty_skys();
+ sky.free_sky(p_rid);
} else if (light_instance_owner.owns(p_rid)) {
LightInstance *light_instance = light_instance_owner.getornull(p_rid);
@@ -8278,7 +3923,7 @@ void RendererSceneRenderRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_dr
}
void RendererSceneRenderRD::update() {
- _update_dirty_skys();
+ sky.update_dirty_skys();
}
void RendererSceneRenderRD::set_time(double p_time, double p_step) {
@@ -8404,8 +4049,8 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
}
void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) {
- sdfgi_debug_probe_pos = p_position;
- sdfgi_debug_probe_dir = p_dir;
+ gi.sdfgi_debug_probe_pos = p_position;
+ gi.sdfgi_debug_probe_dir = p_dir;
}
RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr;
@@ -8441,14 +4086,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
storage = p_storage;
singleton = this;
- roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers");
- sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
- sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections");
-
- sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1)));
- sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1)));
- sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1)));
-
directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
@@ -8460,389 +4097,14 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
low_end = true;
}
- if (!low_end) {
- //kinda complicated to compute the amount of slots, we try to use as many as we can
-
- gi_probe_max_lights = 32;
-
- gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
- gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
- gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1));
-
- String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
-
- Vector<String> versions;
- versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
- versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
- versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
- versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
-
- giprobe_shader.initialize(versions, defines);
- giprobe_lighting_shader_version = giprobe_shader.version_create();
- for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
- giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
- giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
- }
- }
-
- if (!low_end) {
- String defines;
- Vector<String> versions;
- versions.push_back("\n#define MODE_DEBUG_COLOR\n");
- versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
- versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
- versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
-
- giprobe_debug_shader.initialize(versions, defines);
- giprobe_debug_shader_version = giprobe_debug_shader.version_create();
- for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
- giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
-
- RD::PipelineRasterizationState rs;
- rs.cull_mode = RD::POLYGON_CULL_FRONT;
- RD::PipelineDepthStencilState ds;
- ds.enable_depth_test = true;
- ds.enable_depth_write = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
-
- giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
-
/* SKY SHADER */
- {
- // Start with the directional lights for the sky
- sky_scene_state.max_directional_lights = 4;
- uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData);
- sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
- sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
- sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1;
- sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
-
- String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n";
-
- // Initialize sky
- Vector<String> sky_modes;
- sky_modes.push_back(""); // Full size
- sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res
- sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res
- sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap
- sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap
- sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap
- sky_shader.shader.initialize(sky_modes, defines);
- }
-
- // register our shader funds
- storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs);
- storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs);
-
- {
- ShaderCompilerRD::DefaultIdentifierActions actions;
-
- actions.renames["COLOR"] = "color";
- actions.renames["ALPHA"] = "alpha";
- actions.renames["EYEDIR"] = "cube_normal";
- actions.renames["POSITION"] = "params.position_multiplier.xyz";
- actions.renames["SKY_COORDS"] = "panorama_coords";
- actions.renames["SCREEN_UV"] = "uv";
- actions.renames["TIME"] = "params.time";
- actions.renames["HALF_RES_COLOR"] = "half_res_color";
- actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
- actions.renames["RADIANCE"] = "radiance";
- actions.renames["FOG"] = "custom_fog";
- actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
- actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";
- actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w";
- actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz";
- actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w";
- actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
- actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz";
- actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w";
- actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz";
- actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w";
- actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
- actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz";
- actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w";
- actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz";
- actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w";
- actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
- actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz";
- actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w";
- actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz";
- actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w";
- actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
- actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
- actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
- actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
- actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
- actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
- actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
-
- actions.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 1;
- actions.texture_layout_set = 1;
- 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";
-
- sky_shader.compiler.initialize(actions);
- }
-
- {
- // default material and shader for sky shader
- sky_shader.default_shader = storage->shader_allocate();
- storage->shader_initialize(sky_shader.default_shader);
+ sky.init(storage);
- storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n");
-
- sky_shader.default_material = storage->material_allocate();
- storage->material_initialize(sky_shader.default_material);
-
- storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader);
-
- SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
- sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
-
- sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 0;
- 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.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(storage->global_variables_get_storage_buffer());
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(sky_scene_state.uniform_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(sky_scene_state.directional_light_buffer);
- uniforms.push_back(u);
- }
-
- sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
- }
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 0;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- u.ids.push_back(vfog);
- uniforms.push_back(u);
- }
-
- sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
- }
-
- {
- // Need defaults for using fog with clear color
- 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");
- sky_scene_state.fog_material = storage->material_allocate();
- storage->material_initialize(sky_scene_state.fog_material);
-
- storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- uniforms.push_back(u);
- }
-
- sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
- }
+ /* GI */
if (!low_end) {
- //SDFGI
- {
- Vector<String> preprocess_modes;
- preprocess_modes.push_back("\n#define MODE_SCROLL\n");
- preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n");
- preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n");
- preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n");
- preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n");
- preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n");
- preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n");
- preprocess_modes.push_back("\n#define MODE_OCCLUSION\n");
- preprocess_modes.push_back("\n#define MODE_STORE\n");
- String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n";
- sdfgi_shader.preprocess.initialize(preprocess_modes, defines);
- sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create();
- for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) {
- sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i));
- }
- }
-
- {
- //calculate tables
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
-
- Vector<String> direct_light_modes;
- direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n");
- direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n");
- sdfgi_shader.direct_light.initialize(direct_light_modes, defines);
- sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create();
- for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) {
- sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i));
- }
- }
-
- {
- //calculate tables
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
- defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n";
- if (sky_use_cubemap_array) {
- defines += "\n#define USE_CUBEMAP_ARRAY\n";
- }
-
- Vector<String> integrate_modes;
- integrate_modes.push_back("\n#define MODE_PROCESS\n");
- integrate_modes.push_back("\n#define MODE_STORE\n");
- integrate_modes.push_back("\n#define MODE_SCROLL\n");
- integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n");
- sdfgi_shader.integrate.initialize(integrate_modes, defines);
- sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create();
-
- for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) {
- sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i));
- }
-
- {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 1;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1);
- }
- }
- //GK
- {
- //calculate tables
- String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
- Vector<String> gi_modes;
- gi_modes.push_back("\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
-
- gi.shader.initialize(gi_modes, defines);
- gi.shader_version = gi.shader.version_create();
- for (int i = 0; i < GI::MODE_MAX; i++) {
- gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i));
- }
-
- gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData));
- }
- {
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
- Vector<String> debug_modes;
- debug_modes.push_back("");
- sdfgi_shader.debug.initialize(debug_modes, defines);
- sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create();
- sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0);
- sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version);
- }
- {
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
-
- Vector<String> versions;
- versions.push_back("\n#define MODE_PROBES\n");
- versions.push_back("\n#define MODE_VISIBILITY\n");
-
- sdfgi_shader.debug_probes.initialize(versions, defines);
- sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create();
-
- {
- RD::PipelineRasterizationState rs;
- rs.cull_mode = RD::POLYGON_CULL_DISABLED;
- RD::PipelineDepthStencilState ds;
- ds.enable_depth_test = true;
- ds.enable_depth_write = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) {
- RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i);
- sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
- }
- default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES);
+ gi.init(storage, &sky);
}
{ //decals
@@ -8935,40 +4197,27 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
RD::get_singleton()->free(E->get().cubemap);
}
- if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.uniform_set);
+ if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) {
+ RD::get_singleton()->free(sky.sky_scene_state.uniform_set);
}
if (!low_end) {
- RD::get_singleton()->free(default_giprobe_buffer);
- RD::get_singleton()->free(gi_probe_lights_uniform);
- RD::get_singleton()->free(gi.sdfgi_ubo);
-
- giprobe_debug_shader.version_free(giprobe_debug_shader_version);
- giprobe_shader.version_free(giprobe_lighting_shader_version);
- gi.shader.version_free(gi.shader_version);
- sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader);
- sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader);
- sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader);
- sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
- sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
+ gi.free();
volumetric_fog.shader.version_free(volumetric_fog.shader_version);
RD::get_singleton()->free(volumetric_fog.params_ubo);
-
- memdelete_arr(gi_probe_lights);
}
- SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
- sky_shader.shader.version_free(md->shader_data->version);
- RD::get_singleton()->free(sky_scene_state.directional_light_buffer);
- RD::get_singleton()->free(sky_scene_state.uniform_buffer);
- memdelete_arr(sky_scene_state.directional_lights);
- memdelete_arr(sky_scene_state.last_frame_directional_lights);
- storage->free(sky_shader.default_shader);
- storage->free(sky_shader.default_material);
- storage->free(sky_scene_state.fog_shader);
- storage->free(sky_scene_state.fog_material);
+ RendererSceneSkyRD::SkyMaterialData *md = (RendererSceneSkyRD::SkyMaterialData *)storage->material_get_data(sky.sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
+ sky.sky_shader.shader.version_free(md->shader_data->version);
+ RD::get_singleton()->free(sky.sky_scene_state.directional_light_buffer);
+ RD::get_singleton()->free(sky.sky_scene_state.uniform_buffer);
+ memdelete_arr(sky.sky_scene_state.directional_lights);
+ memdelete_arr(sky.sky_scene_state.last_frame_directional_lights);
+ storage->free(sky.sky_shader.default_shader);
+ storage->free(sky.sky_shader.default_material);
+ storage->free(sky.sky_scene_state.fog_shader);
+ storage->free(sky.sky_scene_state.fog_material);
memdelete_arr(directional_penumbra_shadow_kernel);
memdelete_arr(directional_soft_shadow_kernel);
memdelete_arr(penumbra_shadow_kernel);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index e4eaa93212..001cfeb74d 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -35,68 +35,22 @@
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_gi_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
-#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
class RendererSceneRenderRD : public RendererSceneRender {
+ friend RendererSceneSkyRD;
+ friend RendererSceneGIRD;
+
protected:
+ RendererStorageRD *storage;
double time;
-
- // Skys need less info from Directional Lights than the normal shaders
- struct SkyDirectionalLightData {
- float direction[3];
- float energy;
- float color[3];
- float size;
- uint32_t enabled;
- uint32_t pad[3];
- };
-
- struct SkySceneState {
- struct UBO {
- uint32_t volumetric_fog_enabled;
- float volumetric_fog_inv_length;
- float volumetric_fog_detail_spread;
-
- float fog_aerial_perspective;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- uint32_t fog_enabled;
- float fog_density;
-
- float z_far;
- uint32_t directional_light_count;
- };
-
- UBO ubo;
-
- SkyDirectionalLightData *directional_lights;
- SkyDirectionalLightData *last_frame_directional_lights;
- uint32_t max_directional_lights;
- uint32_t last_frame_directional_light_count;
- RID directional_light_buffer;
- RID uniform_set;
- RID uniform_buffer;
- RID fog_uniform_set;
- RID default_fog_uniform_set;
-
- RID fog_shader;
- RID fog_material;
- RID fog_only_texture_uniform_set;
- } sky_scene_state;
+ double time_step = 0;
struct RenderBufferData {
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
@@ -107,7 +61,6 @@ protected:
void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
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);
- void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used);
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;
@@ -121,7 +74,6 @@ protected:
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) = 0;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
- virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
RenderBufferData *render_buffers_get_data(RID p_render_buffers);
@@ -134,12 +86,6 @@ protected:
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);
- void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);
- void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
- void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
- void _pre_process_gi(RID p_render_buffers, const Transform &p_transform);
- void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes);
-
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);
@@ -150,190 +96,21 @@ protected:
// needed for a single argument calls (material and uv2)
PagedArrayPool<GeometryInstance *> cull_argument_pool;
PagedArray<GeometryInstance *> cull_argument; //need this to exist
-private:
- RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
- double time_step = 0;
- static RendererSceneRenderRD *singleton;
-
- int roughness_layers;
-
- RendererStorageRD *storage;
-
- struct ReflectionData {
- struct Layer {
- struct Mipmap {
- RID framebuffers[6];
- RID views[6];
- Size2i size;
- };
- Vector<Mipmap> mipmaps; //per-face view
- Vector<RID> views; // per-cubemap view
- };
-
- struct DownsampleLayer {
- struct Mipmap {
- RID view;
- Size2i size;
- };
- Vector<Mipmap> mipmaps;
- };
-
- RID radiance_base_cubemap; //cubemap for first layer, first cubemap
- RID downsampled_radiance_cubemap;
- DownsampleLayer downsampled_layer;
- RID coefficient_buffer;
-
- bool dirty = true;
-
- Vector<Layer> layers;
- };
-
- void _clear_reflection_data(ReflectionData &rd);
- void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality);
- void _create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays);
- void _create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer);
- void _update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end);
-
- /* Sky shader */
-
- enum SkyVersion {
- SKY_VERSION_BACKGROUND,
- SKY_VERSION_HALF_RES,
- SKY_VERSION_QUARTER_RES,
- SKY_VERSION_CUBEMAP,
- SKY_VERSION_CUBEMAP_HALF_RES,
- SKY_VERSION_CUBEMAP_QUARTER_RES,
- SKY_VERSION_MAX
- };
-
- struct SkyShader {
- SkyShaderRD shader;
- ShaderCompilerRD compiler;
-
- RID default_shader;
- RID default_material;
- RID default_shader_rd;
- } sky_shader;
-
- struct SkyShaderData : public RendererStorageRD::ShaderData {
- bool valid;
- RID version;
-
- PipelineCacheRD pipelines[SKY_VERSION_MAX];
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
- Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
-
- Vector<uint32_t> ubo_offsets;
- uint32_t ubo_size;
-
- String path;
- String code;
- Map<StringName, RID> default_texture_params;
-
- bool uses_time;
- bool uses_position;
- bool uses_half_res;
- bool uses_quarter_res;
- bool uses_light;
-
- 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;
- virtual 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;
- SkyShaderData();
- virtual ~SkyShaderData();
- };
-
- RendererStorageRD::ShaderData *_create_sky_shader_func();
- static RendererStorageRD::ShaderData *_create_sky_shader_funcs() {
- return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_shader_func();
- };
-
- struct SkyMaterialData : public RendererStorageRD::MaterialData {
- uint64_t last_frame;
- SkyShaderData *shader_data;
- RID uniform_buffer;
- RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
- bool uniform_set_updated;
-
- 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 ~SkyMaterialData();
- };
-
- RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
- static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) {
- return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader));
- };
-
- enum SkyTextureSetVersion {
- SKY_TEXTURE_SET_BACKGROUND,
- SKY_TEXTURE_SET_HALF_RES,
- SKY_TEXTURE_SET_QUARTER_RES,
- SKY_TEXTURE_SET_CUBEMAP,
- SKY_TEXTURE_SET_CUBEMAP_HALF_RES,
- SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES,
- SKY_TEXTURE_SET_MAX
- };
-
- enum SkySet {
- SKY_SET_UNIFORMS,
- SKY_SET_MATERIAL,
- SKY_SET_TEXTURES,
- SKY_SET_FOG,
- SKY_SET_MAX
- };
- /* SKY */
- struct Sky {
- RID radiance;
- RID half_res_pass;
- RID half_res_framebuffer;
- RID quarter_res_pass;
- RID quarter_res_framebuffer;
- Size2i screen_size;
+ RendererSceneGIRD gi;
+ RendererSceneSkyRD sky;
- RID texture_uniform_sets[SKY_TEXTURE_SET_MAX];
- RID uniform_set;
-
- RID material;
- RID uniform_buffer;
-
- int radiance_size = 256;
-
- RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
-
- ReflectionData reflection;
- bool dirty = false;
- int processing_layer = 0;
- Sky *dirty_list = nullptr;
-
- //State to track when radiance cubemap needs updating
- SkyMaterialData *prev_material;
- Vector3 prev_position;
- float prev_time;
-
- RID sdfgi_integrate_sky_uniform_set;
- };
-
- Sky *dirty_sky_list = nullptr;
-
- void _sky_invalidate(Sky *p_sky);
- void _update_dirty_skys();
- RID _get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version);
-
- uint32_t sky_ggx_samples_quality;
- bool sky_use_cubemap_array;
+ RendererSceneEnvironmentRD *get_environment(RID p_environment) {
+ if (p_environment.is_valid()) {
+ return environment_owner.getornull(p_environment);
+ } else {
+ return nullptr;
+ }
+ }
- mutable RID_Owner<Sky, true> sky_owner;
+private:
+ RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
+ static RendererSceneRenderRD *singleton;
/* REFLECTION ATLAS */
@@ -347,7 +124,7 @@ private:
struct Reflection {
RID owner;
- ReflectionData data;
+ RendererSceneSkyRD::ReflectionData data;
RID fbs[6];
};
@@ -397,151 +174,6 @@ private:
mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
- /* GIPROBE INSTANCE */
-
- struct GIProbeLight {
- uint32_t type;
- float energy;
- float radius;
- float attenuation;
-
- float color[3];
- float cos_spot_angle;
-
- float position[3];
- float inv_spot_attenuation;
-
- float direction[3];
- uint32_t has_shadow;
- };
-
- struct GIProbePushConstant {
- int32_t limits[3];
- uint32_t stack_size;
-
- float emission_scale;
- float propagation;
- float dynamic_range;
- uint32_t light_count;
-
- uint32_t cell_offset;
- uint32_t cell_count;
- float aniso_strength;
- uint32_t pad;
- };
-
- struct GIProbeDynamicPushConstant {
- int32_t limits[3];
- uint32_t light_count;
- int32_t x_dir[3];
- float z_base;
- int32_t y_dir[3];
- float z_sign;
- int32_t z_dir[3];
- float pos_multiplier;
- uint32_t rect_pos[2];
- uint32_t rect_size[2];
- uint32_t prev_rect_ofs[2];
- uint32_t prev_rect_size[2];
- uint32_t flip_x;
- uint32_t flip_y;
- float dynamic_range;
- uint32_t on_mipmap;
- float propagation;
- float pad[3];
- };
-
- struct GIProbeInstance {
- RID probe;
- RID texture;
- RID write_buffer;
-
- struct Mipmap {
- RID texture;
- RID uniform_set;
- RID second_bounce_uniform_set;
- RID write_uniform_set;
- uint32_t level;
- uint32_t cell_offset;
- uint32_t cell_count;
- };
- Vector<Mipmap> mipmaps;
-
- struct DynamicMap {
- RID texture; //color normally, or emission on first pass
- RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
- RID depth; //actual depth buffer for the first pass, float depth for later passes
- RID normal; //normal buffer for the first pass
- RID albedo; //emission buffer for the first pass
- RID orm; //orm buffer for the first pass
- RID fb; //used for rendering, only valid on first map
- RID uniform_set;
- uint32_t size;
- int mipmap; // mipmap to write to, -1 if no mipmap assigned
- };
-
- Vector<DynamicMap> dynamic_maps;
-
- int slot = -1;
- uint32_t last_probe_version = 0;
- uint32_t last_probe_data_version = 0;
-
- //uint64_t last_pass = 0;
- uint32_t render_index = 0;
-
- bool has_dynamic_object_data = false;
-
- Transform transform;
- };
-
- GIProbeLight *gi_probe_lights;
- uint32_t gi_probe_max_lights;
- RID gi_probe_lights_uniform;
-
- enum {
- GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
- GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
- GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
- GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
- GI_PROBE_SHADER_VERSION_MAX
- };
- GiprobeShaderRD giprobe_shader;
- RID giprobe_lighting_shader_version;
- RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
- RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
-
- mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
-
- RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH;
-
- enum {
- GI_PROBE_DEBUG_COLOR,
- GI_PROBE_DEBUG_LIGHT,
- GI_PROBE_DEBUG_EMISSION,
- GI_PROBE_DEBUG_LIGHT_FULL,
- GI_PROBE_DEBUG_MAX
- };
-
- struct GIProbeDebugPushConstant {
- float projection[16];
- uint32_t cell_offset;
- float dynamic_range;
- float alpha;
- uint32_t level;
- int32_t bounds[3];
- uint32_t pad;
- };
-
- GiprobeDebugShaderRD giprobe_debug_shader;
- RID giprobe_debug_shader_version;
- RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
- PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
- RID giprobe_debug_uniform_set;
-
/* SHADOW ATLAS */
struct ShadowShrinkStage {
@@ -690,111 +322,6 @@ private:
/* ENVIRONMENT */
- struct Environment {
- // BG
- RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR;
- RID sky;
- float sky_custom_fov = 0.0;
- Basis sky_orientation;
- Color bg_color;
- float bg_energy = 1.0;
- int canvas_max_layer = 0;
- RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG;
- Color ambient_light;
- float ambient_light_energy = 1.0;
- float ambient_sky_contribution = 1.0;
- RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG;
- Color ao_color;
-
- /// Tonemap
-
- RS::EnvironmentToneMapper tone_mapper;
- float exposure = 1.0;
- float white = 1.0;
- bool auto_exposure = false;
- float min_luminance = 0.2;
- float max_luminance = 8.0;
- float auto_exp_speed = 0.2;
- float auto_exp_scale = 0.5;
- uint64_t auto_exposure_version = 0;
-
- // Fog
- bool fog_enabled = false;
- Color fog_light_color = Color(0.5, 0.6, 0.7);
- float fog_light_energy = 1.0;
- float fog_sun_scatter = 0.0;
- float fog_density = 0.001;
- float fog_height = 0.0;
- float fog_height_density = 0.0; //can be negative to invert effect
- float fog_aerial_perspective = 0.0;
-
- /// Volumetric Fog
- ///
- bool volumetric_fog_enabled = false;
- float volumetric_fog_density = 0.01;
- Color volumetric_fog_light = Color(0, 0, 0);
- float volumetric_fog_light_energy = 0.0;
- float volumetric_fog_length = 64.0;
- float volumetric_fog_detail_spread = 2.0;
- float volumetric_fog_gi_inject = 0.0;
- bool volumetric_fog_temporal_reprojection = true;
- float volumetric_fog_temporal_reprojection_amount = 0.9;
-
- /// Glow
-
- bool glow_enabled = false;
- Vector<float> glow_levels;
- float glow_intensity = 0.8;
- float glow_strength = 1.0;
- float glow_bloom = 0.0;
- float glow_mix = 0.01;
- RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT;
- float glow_hdr_bleed_threshold = 1.0;
- float glow_hdr_luminance_cap = 12.0;
- float glow_hdr_bleed_scale = 2.0;
-
- /// SSAO
-
- bool ssao_enabled = false;
- float ssao_radius = 1.0;
- float ssao_intensity = 2.0;
- float ssao_power = 1.5;
- float ssao_detail = 0.5;
- float ssao_horizon = 0.06;
- float ssao_sharpness = 0.98;
- float ssao_direct_light_affect = 0.0;
- float ssao_ao_channel_affect = 0.0;
-
- /// SSR
- ///
- bool ssr_enabled = false;
- int ssr_max_steps = 64;
- float ssr_fade_in = 0.15;
- float ssr_fade_out = 2.0;
- float ssr_depth_tolerance = 0.2;
-
- /// SDFGI
- bool sdfgi_enabled = false;
- RS::EnvironmentSDFGICascades sdfgi_cascades;
- float sdfgi_min_cell_size = 0.2;
- bool sdfgi_use_occlusion = false;
- float sdfgi_bounce_feedback = 0.0;
- bool sdfgi_read_sky_light = false;
- float sdfgi_energy = 1.0;
- float sdfgi_normal_bias = 1.1;
- float sdfgi_probe_bias = 1.1;
- RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED;
-
- /// Adjustments
-
- bool adjustments_enabled = false;
- float adjustments_brightness = 1.0f;
- float adjustments_contrast = 1.0f;
- float adjustments_saturation = 1.0f;
- bool use_1d_color_correction = false;
- RID color_correction = RID();
- };
-
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
bool ssao_half_size = false;
bool ssao_using_half_size = false;
@@ -807,9 +334,7 @@ private:
bool glow_high_quality = false;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW;
- static uint64_t auto_exposure_counter;
-
- mutable RID_Owner<Environment, true> environment_owner;
+ mutable RID_Owner<RendererSceneEnvironmentRD, true> environment_owner;
/* CAMERA EFFECTS */
@@ -842,14 +367,9 @@ private:
ClusterBuilderSharedDataRD cluster_builder_shared;
ClusterBuilderRD *current_cluster_builder = nullptr;
- struct SDFGI;
struct VolumetricFog;
struct RenderBuffers {
- enum {
- MAX_GIPROBES = 8
- };
-
RenderBufferData *data = nullptr;
int width = 0, height = 0;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
@@ -864,7 +384,7 @@ private:
RID depth_texture; //main depth texture
RID gi_uniform_set;
- SDFGI *sdfgi = nullptr;
+ RendererSceneGIRD::SDFGI *sdfgi = nullptr;
VolumetricFog *volumetric_fog = nullptr;
ClusterBuilderRD *cluster_builder = nullptr;
@@ -906,414 +426,14 @@ private:
RID blur_radius[2];
} ssr;
- RID giprobe_textures[MAX_GIPROBES];
- RID giprobe_buffer;
-
RID ambient_buffer;
RID reflection_buffer;
bool using_half_size_gi = false;
- struct GI {
- RID full_buffer;
- RID full_dispatch;
- RID full_mask;
- } gi;
- };
-
- RID default_giprobe_buffer;
-
- /* SDFGI */
-
- struct SDFGI {
- enum {
- MAX_CASCADES = 8,
- CASCADE_SIZE = 128,
- PROBE_DIVISOR = 16,
- ANISOTROPY_SIZE = 6,
- MAX_DYNAMIC_LIGHTS = 128,
- MAX_STATIC_LIGHTS = 1024,
- LIGHTPROBE_OCT_SIZE = 6,
- SH_SIZE = 16
- };
-
- struct Cascade {
- struct UBO {
- float offset[3];
- float to_cell;
- int32_t probe_offset[3];
- uint32_t pad;
- };
-
- //cascade blocks are full-size for volume (128^3), half size for albedo/emission
- RID sdf_tex;
- RID light_tex;
- RID light_aniso_0_tex;
- RID light_aniso_1_tex;
-
- RID light_data;
- RID light_aniso_0_data;
- RID light_aniso_1_data;
-
- struct SolidCell { // this struct is unused, but remains as reference for size
- uint32_t position;
- uint32_t albedo;
- uint32_t static_light;
- uint32_t static_light_aniso;
- };
-
- RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch
- RID solid_cell_buffer;
-
- RID lightprobe_history_tex;
- RID lightprobe_average_tex;
-
- float cell_size;
- Vector3i position;
-
- static const Vector3i DIRTY_ALL;
- Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all.
-
- RID sdf_store_uniform_set;
- RID sdf_direct_light_uniform_set;
- RID scroll_uniform_set;
- RID scroll_occlusion_uniform_set;
- RID integrate_uniform_set;
- RID lights_buffer;
-
- bool all_dynamic_lights_dirty = true;
- };
-
- //used for rendering (voxelization)
- RID render_albedo;
- RID render_emission;
- RID render_emission_aniso;
- RID render_occlusion[8];
- RID render_geom_facing;
-
- RID render_sdf[2];
- RID render_sdf_half[2];
-
- //used for ping pong processing in cascades
- RID sdf_initialize_uniform_set;
- RID sdf_initialize_half_uniform_set;
- RID jump_flood_uniform_set[2];
- RID jump_flood_half_uniform_set[2];
- RID sdf_upscale_uniform_set;
- int upscale_jfa_uniform_set_index;
- RID occlusion_uniform_set;
-
- uint32_t cascade_size = 128;
-
- LocalVector<Cascade> cascades;
-
- RID lightprobe_texture;
- RID lightprobe_data;
- RID occlusion_texture;
- RID occlusion_data;
- RID ambient_texture; //integrates with volumetric fog
-
- RID lightprobe_history_scroll; //used for scrolling lightprobes
- RID lightprobe_average_scroll; //used for scrolling lightprobes
-
- uint32_t history_size = 0;
- float solid_cell_ratio = 0;
- uint32_t solid_cell_count = 0;
-
- RS::EnvironmentSDFGICascades cascade_mode;
- float min_cell_size = 0;
- uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints
-
- RID debug_uniform_set;
- RID debug_probes_uniform_set;
- RID cascades_ubo;
-
- bool uses_occlusion = false;
- float bounce_feedback = 0.0;
- bool reads_sky = false;
- float energy = 1.0;
- float normal_bias = 1.1;
- float probe_bias = 1.1;
- RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED;
-
- float y_mult = 1.0;
-
- uint32_t render_pass = 0;
-
- int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically
+ RendererSceneGIRD::RenderBuffersGI gi;
};
- void _sdfgi_update_light(RID p_render_buffers, RID p_environment);
- void _sdfgi_update_probes(RID p_render_buffers, RID p_environment);
- void _sdfgi_store_probes(RID p_render_buffers);
-
- RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
- RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES;
- RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES;
-
- float sdfgi_solid_cell_ratio = 0.25;
- Vector3 sdfgi_debug_probe_pos;
- Vector3 sdfgi_debug_probe_dir;
- bool sdfgi_debug_probe_enabled = false;
- Vector3i sdfgi_debug_probe_index;
-
- struct SDGIShader {
- enum SDFGIPreprocessShaderVersion {
- PRE_PROCESS_SCROLL,
- PRE_PROCESS_SCROLL_OCCLUSION,
- PRE_PROCESS_JUMP_FLOOD_INITIALIZE,
- PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF,
- PRE_PROCESS_JUMP_FLOOD,
- PRE_PROCESS_JUMP_FLOOD_OPTIMIZED,
- PRE_PROCESS_JUMP_FLOOD_UPSCALE,
- PRE_PROCESS_OCCLUSION,
- PRE_PROCESS_STORE,
- PRE_PROCESS_MAX
- };
-
- struct PreprocessPushConstant {
- int32_t scroll[3];
- int32_t grid_size;
-
- int32_t probe_offset[3];
- int32_t step_size;
-
- int32_t half_size;
- uint32_t occlusion_index;
- int32_t cascade;
- uint32_t pad;
- };
-
- SdfgiPreprocessShaderRD preprocess;
- RID preprocess_shader;
- RID preprocess_pipeline[PRE_PROCESS_MAX];
-
- struct DebugPushConstant {
- float grid_size[3];
- uint32_t max_cascades;
-
- int32_t screen_size[2];
- uint32_t use_occlusion;
- float y_mult;
-
- float cam_extent[3];
- uint32_t probe_axis_size;
-
- float cam_transform[16];
- };
-
- SdfgiDebugShaderRD debug;
- RID debug_shader;
- RID debug_shader_version;
- RID debug_pipeline;
-
- enum ProbeDebugMode {
- PROBE_DEBUG_PROBES,
- PROBE_DEBUG_VISIBILITY,
- PROBE_DEBUG_MAX
- };
-
- struct DebugProbesPushConstant {
- float projection[16];
-
- uint32_t band_power;
- uint32_t sections_in_band;
- uint32_t band_mask;
- float section_arc;
-
- float grid_size[3];
- uint32_t cascade;
-
- uint32_t pad;
- float y_mult;
- int32_t probe_debug_index;
- int32_t probe_axis_size;
- };
-
- SdfgiDebugProbesShaderRD debug_probes;
- RID debug_probes_shader;
- RID debug_probes_shader_version;
-
- PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX];
-
- struct Light {
- float color[3];
- float energy;
-
- float direction[3];
- uint32_t has_shadow;
-
- float position[3];
- float attenuation;
-
- uint32_t type;
- float cos_spot_angle;
- float inv_spot_attenuation;
- float radius;
-
- float shadow_color[4];
- };
-
- struct DirectLightPushConstant {
- float grid_size[3];
- uint32_t max_cascades;
-
- uint32_t cascade;
- uint32_t light_count;
- uint32_t process_offset;
- uint32_t process_increment;
-
- int32_t probe_axis_size;
- float bounce_feedback;
- float y_mult;
- uint32_t use_occlusion;
- };
-
- enum {
- DIRECT_LIGHT_MODE_STATIC,
- DIRECT_LIGHT_MODE_DYNAMIC,
- DIRECT_LIGHT_MODE_MAX
- };
- SdfgiDirectLightShaderRD direct_light;
- RID direct_light_shader;
- RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
-
- enum {
- INTEGRATE_MODE_PROCESS,
- INTEGRATE_MODE_STORE,
- INTEGRATE_MODE_SCROLL,
- INTEGRATE_MODE_SCROLL_STORE,
- INTEGRATE_MODE_MAX
- };
- struct IntegratePushConstant {
- enum {
- SKY_MODE_DISABLED,
- SKY_MODE_COLOR,
- SKY_MODE_SKY,
- };
-
- float grid_size[3];
- uint32_t max_cascades;
-
- uint32_t probe_axis_size;
- uint32_t cascade;
- uint32_t history_index;
- uint32_t history_size;
-
- uint32_t ray_count;
- float ray_bias;
- int32_t image_size[2];
-
- int32_t world_offset[3];
- uint32_t sky_mode;
-
- int32_t scroll[3];
- float sky_energy;
-
- float sky_color[3];
- float y_mult;
-
- uint32_t store_ambient_texture;
- uint32_t pad[3];
- };
-
- SdfgiIntegrateShaderRD integrate;
- RID integrate_shader;
- RID integrate_pipeline[INTEGRATE_MODE_MAX];
-
- RID integrate_default_sky_uniform_set;
-
- } sdfgi_shader;
-
- void _sdfgi_erase(RenderBuffers *rb);
- int _sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const;
- void _sdfgi_update_cascades(RID p_render_buffers);
-
/* GI */
-
- struct GI {
- struct SDFGIData {
- float grid_size[3];
- uint32_t max_cascades;
-
- uint32_t use_occlusion;
- int32_t probe_axis_size;
- float probe_to_uvw;
- float normal_bias;
-
- float lightprobe_tex_pixel_size[3];
- float energy;
-
- float lightprobe_uv_offset[3];
- float y_mult;
-
- float occlusion_clamp[3];
- uint32_t pad3;
-
- float occlusion_renormalize[3];
- uint32_t pad4;
-
- float cascade_probe_size[3];
- uint32_t pad5;
-
- struct ProbeCascadeData {
- float position[3]; //offset of (0,0,0) in world coordinates
- float to_probe; // 1/bounds * grid_size
- int32_t probe_world_offset[3];
- float to_cell; // 1/bounds * grid_size
- };
-
- ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
- };
-
- struct GIProbeData {
- float xform[16];
- float bounds[3];
- float dynamic_range;
-
- float bias;
- float normal_bias;
- uint32_t blend_ambient;
- uint32_t texture_slot;
-
- float anisotropy_strength;
- float ao;
- float ao_size;
- uint32_t mipmaps;
- };
-
- struct PushConstant {
- int32_t screen_size[2];
- float z_near;
- float z_far;
-
- float proj_info[4];
- float ao_color[3];
- uint32_t max_giprobes;
-
- uint32_t high_quality_vct;
- uint32_t orthogonal;
- uint32_t pad[2];
-
- float cam_rotation[12];
- };
-
- RID sdfgi_ubo;
- enum Mode {
- MODE_GIPROBE,
- MODE_SDFGI,
- MODE_COMBINED,
- MODE_HALF_RES_GIPROBE,
- MODE_HALF_RES_SDFGI,
- MODE_HALF_RES_COMBINED,
- MODE_MAX
- };
-
- bool half_resolution = false;
- GiShaderRD shader;
- RID shader_version;
- RID pipelines[MODE_MAX];
- } gi;
-
bool screen_space_roughness_limiter = false;
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
@@ -1326,7 +446,6 @@ private:
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 _sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform);
/* Cluster */
@@ -1592,17 +711,17 @@ private:
uint64_t scene_pass = 0;
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
+ /* !BAS! is this used anywhere?
struct SDFGICosineNeighbour {
uint32_t neighbour;
float weight;
};
+ */
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);
- void _render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances);
- void _render_sdfgi_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);
public:
virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0;
@@ -1646,12 +765,12 @@ public:
/* SDFGI UPDATE */
- int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }
virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position);
virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const;
virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const;
virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const;
RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
+
/* SKY API */
virtual RID sky_allocate();
@@ -1662,10 +781,6 @@ public:
void sky_set_material(RID p_sky, RID p_material);
Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size);
- RID sky_get_radiance_texture_rd(RID p_sky) const;
- RID sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const;
- RID sky_get_material(RID p_sky) const;
-
/* ENVIRONMENT API */
virtual RID environment_allocate();
@@ -1974,57 +1089,16 @@ public:
return li->transform;
}
+ /* gi light probes */
+
RID gi_probe_instance_create(RID p_base);
void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
bool gi_probe_needs_update(RID p_probe) const;
void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects);
+ void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi.gi_probe_quality = p_quality; }
- void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi_probe_quality = p_quality; }
-
- _FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->slot;
- }
- _FORCE_INLINE_ RID gi_probe_instance_get_base_probe(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->probe;
- }
- _FORCE_INLINE_ Transform gi_probe_instance_get_transform_to_cell(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return storage->gi_probe_get_to_cell_xform(gi_probe->probe) * gi_probe->transform.affine_inverse();
- }
-
- _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->texture;
- }
+ /* render buffers */
- _FORCE_INLINE_ void gi_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!gi_probe);
- gi_probe->render_index = p_render_index;
- }
-
- _FORCE_INLINE_ uint32_t gi_probe_instance_get_render_index(RID p_instance) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!gi_probe, 0);
-
- return gi_probe->render_index;
- }
- /*
- _FORCE_INLINE_ void gi_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
- GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!g_probe);
- g_probe->last_pass = p_render_pass;
- }
-
- _FORCE_INLINE_ uint32_t gi_probe_instance_get_render_pass(RID p_instance) {
- GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!g_probe, 0);
-
- return g_probe->last_pass;
- }
-*/
RID render_buffers_create();
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding);
void gi_set_use_half_resolution(bool p_enable);
@@ -2108,7 +1182,7 @@ public:
return debug_draw;
}
- virtual void set_time(double p_time, double p_step);
+ void set_time(double p_time, double p_step);
RID get_reflection_probe_buffer();
RID get_omni_light_buffer();
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
new file mode 100644
index 0000000000..769335ac16
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -0,0 +1,1491 @@
+/*************************************************************************/
+/* renderer_scene_sky_rd.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_sky_rd.h"
+#include "core/config/project_settings.h"
+#include "renderer_scene_render_rd.h"
+#include "servers/rendering/rendering_server_default.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// SKY SHADER
+
+void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+ ShaderCompilerRD::IdentifierActions actions;
+
+ uses_time = false;
+ uses_half_res = false;
+ uses_quarter_res = false;
+ uses_position = false;
+ uses_light = false;
+
+ actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
+ actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
+
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["POSITION"] = &uses_position;
+ actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
+
+ actions.uniforms = &uniforms;
+
+ // !BAS! Contemplate making `SkyShader sky` accessible from this struct or even part of this struct.
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = scene_singleton->sky.sky_shader.shader.version_create();
+ }
+
+#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->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);
+ ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //update pipelines
+
+ for (int i = 0; i < SKY_VERSION_MAX; i++) {
+ RD::PipelineDepthStencilState depth_stencil_state;
+ depth_stencil_state.enable_depth_test = true;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+
+ RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
+ pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+
+ valid = true;
+}
+
+void RendererSceneSkyRD::SkyShaderData::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 RendererSceneSkyRD::SkyShaderData::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_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ 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 RendererSceneSkyRD::SkyShaderData::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 RendererSceneSkyRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RendererSceneSkyRD::SkyShaderData::is_animated() const {
+ return false;
+}
+
+bool RendererSceneSkyRD::SkyShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant RendererSceneSkyRD::SkyShaderData::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 RendererSceneSkyRD::SkyShaderData::get_native_source_code() const {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ return scene_singleton->sky.sky_shader.shader.version_get_native_source_code(version);
+}
+
+RendererSceneSkyRD::SkyShaderData::SkyShaderData() {
+ valid = false;
+}
+
+RendererSceneSkyRD::SkyShaderData::~SkyShaderData() {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+ ERR_FAIL_COND(!scene_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ scene_singleton->sky.sky_shader.shader.version_free(version);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Sky material
+
+void RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ uniform_set_updated = true;
+
+ 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());
+ }
+
+ 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->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
+}
+
+RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() {
+ 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);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ReflectionData
+
+void RendererSceneSkyRD::ReflectionData::clear_reflection_data() {
+ layers.clear();
+ radiance_base_cubemap = RID();
+ if (downsampled_radiance_cubemap.is_valid()) {
+ RD::get_singleton()->free(downsampled_radiance_cubemap);
+ }
+ downsampled_radiance_cubemap = RID();
+ downsampled_layer.mipmaps.clear();
+ coefficient_buffer = RID();
+}
+
+void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) {
+ //recreate radiance and all data
+
+ int mipmaps = p_mipmaps;
+ uint32_t w = p_size, h = p_size;
+
+ if (p_use_array) {
+ int num_layers = p_low_quality ? 8 : p_roughness_layers;
+
+ for (int i = 0; i < num_layers; i++) {
+ ReflectionData::Layer layer;
+ uint32_t mmw = w;
+ uint32_t mmh = h;
+ layer.mipmaps.resize(mipmaps);
+ layer.views.resize(mipmaps);
+ for (int j = 0; j < mipmaps; j++) {
+ ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
+ mm.size.width = mmw;
+ mm.size.height = mmh;
+ for (int k = 0; k < 6; k++) {
+ mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j);
+ Vector<RID> fbtex;
+ fbtex.push_back(mm.views[k]);
+ mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+
+ layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP);
+
+ mmw = MAX(1, mmw >> 1);
+ mmh = MAX(1, mmh >> 1);
+ }
+
+ layers.push_back(layer);
+ }
+
+ } else {
+ mipmaps = p_low_quality ? 8 : mipmaps;
+ //regular cubemap, lower quality (aliasing, less memory)
+ ReflectionData::Layer layer;
+ uint32_t mmw = w;
+ uint32_t mmh = h;
+ layer.mipmaps.resize(mipmaps);
+ layer.views.resize(mipmaps);
+ for (int j = 0; j < mipmaps; j++) {
+ ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
+ mm.size.width = mmw;
+ mm.size.height = mmh;
+ for (int k = 0; k < 6; k++) {
+ mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j);
+ Vector<RID> fbtex;
+ fbtex.push_back(mm.views[k]);
+ mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+
+ layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP);
+
+ mmw = MAX(1, mmw >> 1);
+ mmh = MAX(1, mmh >> 1);
+ }
+
+ layers.push_back(layer);
+ }
+
+ radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = 64; // Always 64x64
+ tf.height = 64;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE;
+ tf.array_layers = 6;
+ tf.mipmaps = 7;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ {
+ uint32_t mmw = 64;
+ uint32_t mmh = 64;
+ downsampled_layer.mipmaps.resize(7);
+ for (int j = 0; j < downsampled_layer.mipmaps.size(); j++) {
+ ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j];
+ mm.size.width = mmw;
+ mm.size.height = mmh;
+ mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
+
+ mmw = MAX(1, mmw >> 1);
+ mmh = MAX(1, mmh >> 1);
+ }
+ }
+}
+
+void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
+ p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+
+ for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+ p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
+ }
+
+ Vector<RID> views;
+ if (p_use_arrays) {
+ for (int i = 1; i < layers.size(); i++) {
+ views.push_back(layers[i].views[0]);
+ }
+ } else {
+ for (int i = 1; i < layers[0].views.size(); i++) {
+ views.push_back(layers[0].views[i]);
+ }
+ }
+
+ p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+}
+
+void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
+ if (p_use_arrays) {
+ //render directly to the layers
+ p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ } else {
+ p_storage->get_effects()->cubemap_roughness(
+ layers[0].views[p_base_layer - 1],
+ layers[0].views[p_base_layer],
+ p_cube_side,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+ layers[0].mipmaps[p_base_layer].size.x);
+ }
+}
+
+void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
+ for (int i = p_start; i < p_end; i++) {
+ for (int j = 0; j < layers[i].views.size() - 1; j++) {
+ RID view = layers[i].views[j];
+ RID texture = layers[i].views[j + 1];
+ Size2i size = layers[i].mipmaps[j + 1].size;
+ p_storage->get_effects()->cubemap_downsample(view, texture, size);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RendererSceneSkyRD::Sky
+
+void RendererSceneSkyRD::Sky::free(RendererStorageRD *p_storage) {
+ if (radiance.is_valid()) {
+ RD::get_singleton()->free(radiance);
+ radiance = RID();
+ }
+ reflection.clear_reflection_data();
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ if (half_res_pass.is_valid()) {
+ RD::get_singleton()->free(half_res_pass);
+ half_res_pass = RID();
+ }
+
+ if (quarter_res_pass.is_valid()) {
+ RD::get_singleton()->free(quarter_res_pass);
+ quarter_res_pass = RID();
+ }
+
+ if (material.is_valid()) {
+ p_storage->free(material);
+ }
+}
+
+RID RendererSceneSkyRD::Sky::get_textures(RendererStorageRD *p_storage, SkyTextureSetVersion p_version, RID p_default_shader_rd) {
+ if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) {
+ return texture_uniform_sets[p_version];
+ }
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) {
+ u.ids.push_back(radiance);
+ } else {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1; // half res
+ if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
+ if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(reflection.layers[0].views[1]);
+ } else {
+ u.ids.push_back(half_res_pass);
+ }
+ } else {
+ if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ } else {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2; // quarter res
+ if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
+ if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(reflection.layers[0].views[2]);
+ } else {
+ u.ids.push_back(quarter_res_pass);
+ }
+ } else {
+ if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ } else {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ }
+ uniforms.push_back(u);
+ }
+
+ texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES);
+ return texture_uniform_sets[p_version];
+}
+
+bool RendererSceneSkyRD::Sky::set_radiance_size(int p_radiance_size) {
+ ERR_FAIL_COND_V(p_radiance_size < 32 || p_radiance_size > 2048, false);
+ if (radiance_size == p_radiance_size) {
+ return false;
+ }
+ radiance_size = p_radiance_size;
+
+ if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) {
+ WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
+ radiance_size = 256;
+ }
+
+ if (radiance.is_valid()) {
+ RD::get_singleton()->free(radiance);
+ radiance = RID();
+ }
+ reflection.clear_reflection_data();
+
+ return true;
+}
+
+bool RendererSceneSkyRD::Sky::set_mode(RS::SkyMode p_mode) {
+ if (mode == p_mode) {
+ return false;
+ }
+
+ mode = p_mode;
+
+ if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) {
+ WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
+ set_radiance_size(256);
+ }
+
+ if (radiance.is_valid()) {
+ RD::get_singleton()->free(radiance);
+ radiance = RID();
+ }
+ reflection.clear_reflection_data();
+
+ return true;
+}
+
+bool RendererSceneSkyRD::Sky::set_material(RID p_material) {
+ if (material == p_material) {
+ return false;
+ }
+
+ material = p_material;
+ return true;
+}
+
+Ref<Image> RendererSceneSkyRD::Sky::bake_panorama(RendererStorageRD *p_storage, float p_energy, int p_roughness_layers, const Size2i &p_size) {
+ if (radiance.is_valid()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ tf.width = p_size.width;
+ tf.height = p_size.height;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+
+ RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ p_storage->get_effects()->copy_cubemap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1);
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0);
+ RD::get_singleton()->free(rad_tex);
+
+ Ref<Image> img;
+ img.instance();
+ img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
+ for (int i = 0; i < p_size.width; i++) {
+ for (int j = 0; j < p_size.height; j++) {
+ Color c = img->get_pixel(i, j);
+ c.r *= p_energy;
+ c.g *= p_energy;
+ c.b *= p_energy;
+ img->set_pixel(i, j, c);
+ }
+ }
+ return img;
+ }
+
+ return Ref<Image>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RendererSceneSkyRD
+
+RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_func() {
+ SkyShaderData *shader_data = memnew(SkyShaderData);
+ return shader_data;
+}
+
+RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_funcs() {
+ // !BAS! Why isn't _create_sky_shader_func not just static too?
+ return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func();
+};
+
+RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_func(SkyShaderData *p_shader) {
+ SkyMaterialData *material_data = memnew(SkyMaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ // !BAS! same here, we could just make _create_sky_material_func static?
+ return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast<SkyShaderData *>(p_shader));
+};
+
+RendererSceneSkyRD::RendererSceneSkyRD() {
+ roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers");
+ sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
+ sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections");
+}
+
+void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
+ storage = p_storage;
+
+ {
+ // Start with the directional lights for the sky
+ sky_scene_state.max_directional_lights = 4;
+ uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData);
+ sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
+ sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
+ sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1;
+ sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
+
+ String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n";
+
+ // Initialize sky
+ Vector<String> sky_modes;
+ sky_modes.push_back(""); // Full size
+ sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res
+ sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res
+ sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap
+ sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap
+ sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap
+ sky_shader.shader.initialize(sky_modes, defines);
+ }
+
+ // register our shader funds
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs);
+
+ {
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["COLOR"] = "color";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["EYEDIR"] = "cube_normal";
+ actions.renames["POSITION"] = "params.position_multiplier.xyz";
+ actions.renames["SKY_COORDS"] = "panorama_coords";
+ actions.renames["SCREEN_UV"] = "uv";
+ actions.renames["TIME"] = "params.time";
+ actions.renames["HALF_RES_COLOR"] = "half_res_color";
+ actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
+ actions.renames["RADIANCE"] = "radiance";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
+ actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";
+ actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w";
+ actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz";
+ actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w";
+ actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
+ actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz";
+ actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w";
+ actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz";
+ actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w";
+ actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
+ actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz";
+ actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w";
+ actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz";
+ actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w";
+ actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
+ actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz";
+ actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w";
+ actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz";
+ actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w";
+ actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
+ actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
+ actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
+ actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
+ actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
+ actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
+ actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = 1;
+ 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";
+
+ sky_shader.compiler.initialize(actions);
+ }
+
+ {
+ // default material and shader for sky shader
+ 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");
+
+ sky_shader.default_material = storage->material_allocate();
+ storage->material_initialize(sky_shader.default_material);
+
+ storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader);
+
+ SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
+ sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
+
+ sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 0;
+ 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.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.push_back(vfog);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ }
+
+ {
+ // Need defaults for using fog with clear color
+ 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");
+ sky_scene_state.fog_material = storage->material_allocate();
+ storage->material_initialize(sky_scene_state.fog_material);
+
+ storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
+ }
+}
+
+void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+ ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky...
+
+ SkyMaterialData *material = nullptr;
+ Sky *sky = get_sky(p_env->sky);
+
+ RID sky_material;
+
+ SkyShaderData *shader_data = nullptr;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ // !BAS! Possibly silently fail here, we now get error spam when you select sky as the background but haven't setup the sky yet.
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+ }
+
+ if (sky) {
+ // Invalidate supbass buffers if screen size changes
+ if (sky->screen_size != p_screen_size) {
+ sky->screen_size = p_screen_size;
+ sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
+ sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
+ if (shader_data->uses_half_res) {
+ if (sky->half_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->half_res_pass);
+ sky->half_res_pass = RID();
+ }
+ invalidate_sky(sky);
+ }
+ if (shader_data->uses_quarter_res) {
+ if (sky->quarter_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->quarter_res_pass);
+ sky->quarter_res_pass = RID();
+ }
+ invalidate_sky(sky);
+ }
+ }
+
+ // Create new subpass buffers if necessary
+ if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
+ (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
+ sky->radiance.is_null()) {
+ invalidate_sky(sky);
+ update_dirty_skys();
+ }
+
+ if (shader_data->uses_time && p_scene_render->time - sky->prev_time > 0.00001) {
+ sky->prev_time = p_scene_render->time;
+ sky->reflection.dirty = true;
+ RenderingServerDefault::redraw_request();
+ }
+
+ if (material != sky->prev_material) {
+ sky->prev_material = material;
+ sky->reflection.dirty = true;
+ }
+
+ if (material->uniform_set_updated) {
+ material->uniform_set_updated = false;
+ sky->reflection.dirty = true;
+ }
+
+ if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_transform.origin;
+ sky->reflection.dirty = true;
+ }
+
+ if (shader_data->uses_light) {
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
+
+ if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
+ sky_scene_state.directional_lights[i].enabled = false;
+ }
+ }
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
+ if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
+ sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
+ sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
+ sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
+ sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
+ sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
+ sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
+ sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
+ sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
+ }
+ }
+ }
+
+ if (light_data_dirty) {
+ RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights);
+
+ SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
+ sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
+ sky_scene_state.directional_lights = temp;
+ sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
+ sky->reflection.dirty = true;
+ }
+ }
+ }
+
+ //setup fog variables
+ sky_scene_state.ubo.volumetric_fog_enabled = false;
+ if (p_render_buffers.is_valid()) {
+ if (p_scene_render->render_buffers_has_volumetric_fog(p_render_buffers)) {
+ sky_scene_state.ubo.volumetric_fog_enabled = true;
+
+ float fog_end = p_scene_render->render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
+
+ float fog_detail_spread = p_scene_render->render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+ }
+ }
+
+ RID fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
+
+ if (fog_uniform_set != RID()) {
+ sky_scene_state.fog_uniform_set = fog_uniform_set;
+ } else {
+ sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
+ }
+ }
+
+ sky_scene_state.ubo.z_far = p_projection.get_z_far();
+ sky_scene_state.ubo.fog_enabled = p_env->fog_enabled;
+ sky_scene_state.ubo.fog_density = p_env->fog_density;
+ sky_scene_state.ubo.fog_aerial_perspective = p_env->fog_aerial_perspective;
+ Color fog_color = p_env->fog_light_color.to_linear();
+ float fog_energy = p_env->fog_light_energy;
+ sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+ sky_scene_state.ubo.fog_sun_scatter = p_env->fog_sun_scatter;
+
+ RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
+}
+
+void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+ ERR_FAIL_COND(!p_env);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ RID sky_material = sky_get_material(p_env->sky);
+
+ SkyMaterialData *material = nullptr;
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ float multiplier = p_env->bg_energy;
+
+ bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
+ RS::SkyMode sky_mode = sky->mode;
+
+ if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
+ if (shader_data->uses_time || shader_data->uses_position) {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_REALTIME;
+ } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
+ update_single_frame = false;
+ sky_mode = RS::SKY_MODE_INCREMENTAL;
+ } else {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+ }
+
+ if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
+ // On the first frame after creating sky, rebuild in single frame
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+
+ int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size();
+
+ // Update radiance cubemap
+ if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
+ static const Vector3 view_normals[6] = {
+ Vector3(+1, 0, 0),
+ Vector3(-1, 0, 0),
+ Vector3(0, +1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1)
+ };
+ static const Vector3 view_up[6] = {
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1),
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0)
+ };
+
+ CameraMatrix cm;
+ cm.set_perspective(90, 1, 0.01, 10.0);
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ cm = correction * cm;
+
+ if (shader_data->uses_quarter_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+ RD::DrawListID cubemap_draw_list;
+
+ for (int i = 0; i < 6; i++) {
+ Transform local_view;
+ local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
+
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ if (shader_data->uses_half_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+ RD::DrawListID cubemap_draw_list;
+
+ for (int i = 0; i < 6; i++) {
+ Transform local_view;
+ local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
+
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ RD::DrawListID cubemap_draw_list;
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
+
+ for (int i = 0; i < 6; i++) {
+ Transform local_view;
+ local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
+
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (sky_mode == RS::SKY_MODE_REALTIME) {
+ sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array);
+ if (sky_use_cubemap_array) {
+ sky->reflection.update_reflection_mipmaps(storage, 0, sky->reflection.layers.size());
+ }
+ } else {
+ if (update_single_frame) {
+ for (int i = 1; i < max_processing_layer; i++) {
+ sky->reflection.create_reflection_importance_sample(storage, sky_use_cubemap_array, 10, i, sky_ggx_samples_quality);
+ }
+ if (sky_use_cubemap_array) {
+ sky->reflection.update_reflection_mipmaps(storage, 0, sky->reflection.layers.size());
+ }
+ } else {
+ if (sky_use_cubemap_array) {
+ // Multi-Frame so just update the first array level
+ sky->reflection.update_reflection_mipmaps(storage, 0, 1);
+ }
+ }
+ sky->processing_layer = 1;
+ }
+
+ sky->reflection.dirty = false;
+
+ } else {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
+ sky->reflection.create_reflection_importance_sample(storage, sky_use_cubemap_array, 10, sky->processing_layer, sky_ggx_samples_quality);
+
+ if (sky_use_cubemap_array) {
+ sky->reflection.update_reflection_mipmaps(storage, sky->processing_layer, sky->processing_layer + 1);
+ }
+
+ sky->processing_layer++;
+ }
+ }
+}
+
+void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+ ERR_FAIL_COND(!p_env);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ SkyMaterialData *material = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+ }
+
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+
+ float multiplier = p_env->bg_energy;
+ float custom_fov = p_env->sky_custom_fov;
+ // Camera
+ CameraMatrix camera;
+
+ if (custom_fov) {
+ float near_plane = p_projection.get_z_near();
+ float far_plane = p_projection.get_z_far();
+ float aspect = p_projection.get_aspect();
+
+ camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+
+ } else {
+ camera = p_projection;
+ }
+
+ sky_transform = p_transform.basis * sky_transform;
+
+ if (shader_data->uses_quarter_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (shader_data->uses_half_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
+
+ RID texture_uniform_set;
+ if (sky) {
+ texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
+ } else {
+ texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+ }
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+}
+
+void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) {
+ if (!p_sky->dirty) {
+ p_sky->dirty = true;
+ p_sky->dirty_list = dirty_sky_list;
+ dirty_sky_list = p_sky;
+ }
+}
+
+void RendererSceneSkyRD::update_dirty_skys() {
+ Sky *sky = dirty_sky_list;
+
+ while (sky) {
+ bool texture_set_dirty = false;
+ //update sky configuration if texture is missing
+
+ if (sky->radiance.is_null()) {
+ int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
+
+ uint32_t w = sky->radiance_size, h = sky->radiance_size;
+ int layers = roughness_layers;
+ if (sky->mode == RS::SKY_MODE_REALTIME) {
+ layers = 8;
+ if (roughness_layers != 8) {
+ WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections");
+ }
+ }
+
+ if (sky_use_cubemap_array) {
+ //array (higher quality, 6 times more memory)
+ RD::TextureFormat tf;
+ tf.array_layers = layers * 6;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+ tf.mipmaps = mipmaps;
+ tf.width = w;
+ tf.height = h;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+
+ } else {
+ //regular cubemap, lower quality (aliasing, less memory)
+ RD::TextureFormat tf;
+ tf.array_layers = 6;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE;
+ tf.mipmaps = MIN(mipmaps, layers);
+ tf.width = w;
+ tf.height = h;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+ }
+ texture_set_dirty = true;
+ }
+
+ // Create subpass buffers if they haven't been created already
+ if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.width = sky->screen_size.x / 2;
+ tformat.height = sky->screen_size.y / 2;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D;
+
+ sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+ Vector<RID> texs;
+ texs.push_back(sky->half_res_pass);
+ sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
+ texture_set_dirty = true;
+ }
+
+ if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.width = sky->screen_size.x / 4;
+ tformat.height = sky->screen_size.y / 4;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D;
+
+ sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+ Vector<RID> texs;
+ texs.push_back(sky->quarter_res_pass);
+ sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
+ texture_set_dirty = true;
+ }
+
+ if (texture_set_dirty) {
+ for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) {
+ if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) {
+ RD::get_singleton()->free(sky->texture_uniform_sets[i]);
+ sky->texture_uniform_sets[i] = RID();
+ }
+ }
+ }
+
+ sky->reflection.dirty = true;
+ sky->processing_layer = 0;
+
+ Sky *next = sky->dirty_list;
+ sky->dirty_list = nullptr;
+ sky->dirty = false;
+ sky = next;
+ }
+
+ dirty_sky_list = nullptr;
+}
+
+RID RendererSceneSkyRD::sky_get_material(RID p_sky) const {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, RID());
+
+ return sky->material;
+}
+
+RID RendererSceneSkyRD::allocate_sky_rid() {
+ return sky_owner.allocate_rid();
+}
+
+void RendererSceneSkyRD::initialize_sky_rid(RID p_rid) {
+ sky_owner.initialize_rid(p_rid, Sky());
+}
+
+RendererSceneSkyRD::Sky *RendererSceneSkyRD::get_sky(RID p_sky) const {
+ return sky_owner.getornull(p_sky);
+}
+
+void RendererSceneSkyRD::free_sky(RID p_sky) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ sky->free(storage);
+ sky_owner.free(p_sky);
+}
+
+void RendererSceneSkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->set_radiance_size(p_radiance_size)) {
+ invalidate_sky(sky);
+ }
+}
+
+void RendererSceneSkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->set_mode(p_mode)) {
+ invalidate_sky(sky);
+ }
+}
+
+void RendererSceneSkyRD::sky_set_material(RID p_sky, RID p_material) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->set_material(p_material)) {
+ invalidate_sky(sky);
+ }
+}
+
+Ref<Image> RendererSceneSkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, Ref<Image>());
+
+ update_dirty_skys();
+
+ return sky->bake_panorama(storage, p_energy, p_bake_irradiance ? roughness_layers : 0, p_size);
+}
+
+RID RendererSceneSkyRD::sky_get_radiance_texture_rd(RID p_sky) const {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, RID());
+
+ return sky->radiance;
+}
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
new file mode 100644
index 0000000000..73390a586b
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
@@ -0,0 +1,292 @@
+/*************************************************************************/
+/* renderer_scene_sky_rd.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_SKY_RD_H
+#define RENDERING_SERVER_SCENE_SKY_RD_H
+
+#include "core/templates/rid_owner.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h"
+#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
+class RendererSceneRenderRD;
+
+class RendererSceneSkyRD {
+private:
+ RendererStorageRD *storage;
+
+public:
+ enum SkySet {
+ SKY_SET_UNIFORMS,
+ SKY_SET_MATERIAL,
+ SKY_SET_TEXTURES,
+ SKY_SET_FOG,
+ SKY_SET_MAX
+ };
+
+ enum SkyTextureSetVersion {
+ SKY_TEXTURE_SET_BACKGROUND,
+ SKY_TEXTURE_SET_HALF_RES,
+ SKY_TEXTURE_SET_QUARTER_RES,
+ SKY_TEXTURE_SET_CUBEMAP,
+ SKY_TEXTURE_SET_CUBEMAP_HALF_RES,
+ SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES,
+ SKY_TEXTURE_SET_MAX
+ };
+
+ enum SkyVersion {
+ SKY_VERSION_BACKGROUND,
+ SKY_VERSION_HALF_RES,
+ SKY_VERSION_QUARTER_RES,
+ SKY_VERSION_CUBEMAP,
+ SKY_VERSION_CUBEMAP_HALF_RES,
+ SKY_VERSION_CUBEMAP_QUARTER_RES,
+ SKY_VERSION_MAX
+ };
+
+ // Skys need less info from Directional Lights than the normal shaders
+ struct SkyDirectionalLightData {
+ float direction[3];
+ float energy;
+ float color[3];
+ float size;
+ uint32_t enabled;
+ uint32_t pad[3];
+ };
+
+ struct SkySceneState {
+ struct UBO {
+ uint32_t volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+
+ float fog_aerial_perspective;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ uint32_t fog_enabled;
+ float fog_density;
+
+ float z_far;
+ uint32_t directional_light_count;
+ };
+
+ UBO ubo;
+
+ SkyDirectionalLightData *directional_lights;
+ SkyDirectionalLightData *last_frame_directional_lights;
+ uint32_t max_directional_lights;
+ uint32_t last_frame_directional_light_count;
+ RID directional_light_buffer;
+ RID uniform_set;
+ RID uniform_buffer;
+ RID fog_uniform_set;
+ RID default_fog_uniform_set;
+
+ RID fog_shader;
+ RID fog_material;
+ RID fog_only_texture_uniform_set;
+ } sky_scene_state;
+
+ struct ReflectionData {
+ struct Layer {
+ struct Mipmap {
+ RID framebuffers[6];
+ RID views[6];
+ Size2i size;
+ };
+ Vector<Mipmap> mipmaps; //per-face view
+ Vector<RID> views; // per-cubemap view
+ };
+
+ struct DownsampleLayer {
+ struct Mipmap {
+ RID view;
+ Size2i size;
+ };
+ Vector<Mipmap> mipmaps;
+ };
+
+ RID radiance_base_cubemap; //cubemap for first layer, first cubemap
+ RID downsampled_radiance_cubemap;
+ DownsampleLayer downsampled_layer;
+ RID coefficient_buffer;
+
+ bool dirty = true;
+
+ Vector<Layer> layers;
+
+ void clear_reflection_data();
+ void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers);
+ void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays);
+ void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
+ void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end);
+ };
+
+ struct SkyShaderData : public RendererStorageRD::ShaderData {
+ bool valid;
+ RID version;
+
+ PipelineCacheRD pipelines[SKY_VERSION_MAX];
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ bool uses_time;
+ bool uses_position;
+ bool uses_half_res;
+ bool uses_quarter_res;
+ bool uses_light;
+
+ 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;
+ virtual 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;
+ SkyShaderData();
+ virtual ~SkyShaderData();
+ };
+
+ /* Sky shader */
+
+ struct SkyShader {
+ SkyShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID default_shader_rd;
+ } sky_shader;
+
+ struct SkyMaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ SkyShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ bool uniform_set_updated;
+
+ 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 ~SkyMaterialData();
+ };
+
+ struct Sky {
+ RID radiance;
+ RID half_res_pass;
+ RID half_res_framebuffer;
+ RID quarter_res_pass;
+ RID quarter_res_framebuffer;
+ Size2i screen_size;
+
+ RID texture_uniform_sets[SKY_TEXTURE_SET_MAX];
+ RID uniform_set;
+
+ RID material;
+ RID uniform_buffer;
+
+ int radiance_size = 256;
+
+ RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
+
+ ReflectionData reflection;
+ bool dirty = false;
+ int processing_layer = 0;
+ Sky *dirty_list = nullptr;
+
+ //State to track when radiance cubemap needs updating
+ SkyMaterialData *prev_material;
+ Vector3 prev_position;
+ float prev_time;
+
+ void free(RendererStorageRD *p_storage);
+
+ RID get_textures(RendererStorageRD *p_storage, SkyTextureSetVersion p_version, RID p_default_shader_rd);
+ bool set_radiance_size(int p_radiance_size);
+ bool set_mode(RS::SkyMode p_mode);
+ bool set_material(RID p_material);
+ Ref<Image> bake_panorama(RendererStorageRD *p_storage, float p_energy, int p_roughness_layers, const Size2i &p_size);
+ };
+
+ uint32_t sky_ggx_samples_quality;
+ bool sky_use_cubemap_array;
+ Sky *dirty_sky_list = nullptr;
+ mutable RID_Owner<Sky, true> sky_owner;
+ int roughness_layers;
+
+ RendererStorageRD::ShaderData *_create_sky_shader_func();
+ static RendererStorageRD::ShaderData *_create_sky_shader_funcs();
+
+ RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader);
+
+ RendererSceneSkyRD();
+
+ void init(RendererStorageRD *p_storage);
+
+ void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
+ void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
+
+ void invalidate_sky(Sky *p_sky);
+ void update_dirty_skys();
+
+ RID sky_get_material(RID p_sky) const;
+
+ RID allocate_sky_rid();
+ void initialize_sky_rid(RID p_rid);
+ Sky *get_sky(RID p_sky) const;
+ void free_sky(RID p_sky);
+ void sky_set_radiance_size(RID p_sky, int p_radiance_size);
+ void sky_set_mode(RID p_sky, RS::SkyMode p_mode);
+ void sky_set_material(RID p_sky, RID p_material);
+ Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size);
+
+ RID sky_get_radiance_texture_rd(RID p_sky) const;
+};
+
+#endif /* RENDERING_SERVER_SCENE_SKY_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 2a34049675..ba5ace8f31 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -5121,6 +5121,7 @@ void RendererStorageRD::particles_collision_height_field_update(RID p_particles_
void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
if (particles_collision->heightfield_resolution == p_resolution) {
return;
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 68256dc155..cd3d4604eb 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -2263,7 +2263,7 @@ public:
void render_info_end_capture() {}
int get_captured_render_info(RS::RenderInfo p_info) { return 0; }
- int get_render_info(RS::RenderInfo p_info) { return 0; }
+ uint64_t get_render_info(RS::RenderInfo p_info) { return 0; }
String get_video_adapter_name() const { return String(); }
String get_video_adapter_vendor() const { return String(); }
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub
index c192574ff2..fc513d3fb9 100644
--- a/servers/rendering/renderer_rd/shaders/SCsub
+++ b/servers/rendering/renderer_rd/shaders/SCsub
@@ -3,46 +3,15 @@
Import("env")
if "RD_GLSL" in env["BUILDERS"]:
- env.RD_GLSL("canvas.glsl")
- env.RD_GLSL("canvas_occlusion.glsl")
- env.RD_GLSL("canvas_sdf.glsl")
- env.RD_GLSL("copy.glsl")
- env.RD_GLSL("copy_to_fb.glsl")
- env.RD_GLSL("cubemap_roughness.glsl")
- env.RD_GLSL("cubemap_downsampler.glsl")
- env.RD_GLSL("cubemap_filter.glsl")
- env.RD_GLSL("scene_forward.glsl")
- env.RD_GLSL("sky.glsl")
- env.RD_GLSL("tonemap.glsl")
- env.RD_GLSL("cube_to_dp.glsl")
- env.RD_GLSL("giprobe.glsl")
- env.RD_GLSL("giprobe_debug.glsl")
- env.RD_GLSL("giprobe_sdf.glsl")
- env.RD_GLSL("luminance_reduce.glsl")
- env.RD_GLSL("bokeh_dof.glsl")
- env.RD_GLSL("ssao.glsl")
- env.RD_GLSL("ssao_downsample.glsl")
- env.RD_GLSL("ssao_importance_map.glsl")
- env.RD_GLSL("ssao_blur.glsl")
- env.RD_GLSL("ssao_interleave.glsl")
- env.RD_GLSL("roughness_limiter.glsl")
- env.RD_GLSL("screen_space_reflection.glsl")
- env.RD_GLSL("screen_space_reflection_filter.glsl")
- env.RD_GLSL("screen_space_reflection_scale.glsl")
- env.RD_GLSL("subsurface_scattering.glsl")
- env.RD_GLSL("specular_merge.glsl")
- env.RD_GLSL("gi.glsl")
- env.RD_GLSL("resolve.glsl")
- env.RD_GLSL("sdfgi_preprocess.glsl")
- env.RD_GLSL("sdfgi_integrate.glsl")
- env.RD_GLSL("sdfgi_direct_light.glsl")
- env.RD_GLSL("sdfgi_debug.glsl")
- env.RD_GLSL("sdfgi_debug_probes.glsl")
- env.RD_GLSL("volumetric_fog.glsl")
- env.RD_GLSL("particles.glsl")
- env.RD_GLSL("particles_copy.glsl")
- env.RD_GLSL("sort.glsl")
- env.RD_GLSL("skeleton.glsl")
- env.RD_GLSL("cluster_render.glsl")
- env.RD_GLSL("cluster_store.glsl")
- env.RD_GLSL("cluster_debug.glsl")
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files)
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index 8723ea78e4..ca92d2104e 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -65,7 +65,7 @@ void main() {
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/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 1cea9bf8db..7b86dac143 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -4,7 +4,7 @@
VERSION_DEFINES
-#include "scene_forward_inc.glsl"
+#include "scene_forward_clustered_inc.glsl"
/* INPUT ATTRIBS */
@@ -327,7 +327,7 @@ VERTEX_SHADER_CODE
VERSION_DEFINES
-#include "scene_forward_inc.glsl"
+#include "scene_forward_clustered_inc.glsl"
/* Varyings */
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index d78890fa9e..4ea05c9ccc 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_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
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index e7ba8feb80..ce8a459b24 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -5,10 +5,10 @@
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
*/
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index 69ad2cc191..22cf6acb19 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -608,7 +608,7 @@ public:
virtual void render_info_end_capture() = 0;
virtual int get_captured_render_info(RS::RenderInfo p_info) = 0;
- virtual int get_render_info(RS::RenderInfo p_info) = 0;
+ virtual uint64_t get_render_info(RS::RenderInfo p_info) = 0;
virtual String get_video_adapter_name() const = 0;
virtual String get_video_adapter_vendor() const = 0;
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..2de0549e8d 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,29 @@ 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
+ };
+
+ 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 +111,8 @@ private:
protected:
static void _bind_methods();
+ Capabilities device_capabilities;
+
public:
//base numeric ID for all types
enum {
@@ -597,6 +628,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.cpp b/servers/rendering/rendering_server_default.cpp
index 61d1efaf22..c6fe6a07e0 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -257,7 +257,7 @@ void RenderingServerDefault::finish() {
/* STATUS INFORMATION */
-int RenderingServerDefault::get_render_info(RenderInfo p_info) {
+uint64_t RenderingServerDefault::get_render_info(RenderInfo p_info) {
return RSG::storage->get_render_info(p_info);
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 73b463f6e7..e82d5cc3f8 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -233,7 +233,7 @@ public:
FUNC2(shader_set_code, RID, const String &)
FUNC1RC(String, shader_get_code, RID)
- FUNC2C(shader_get_param_list, RID, List<PropertyInfo> *)
+ FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *)
FUNC3(shader_set_default_texture_param, RID, const StringName &, RID)
FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &)
@@ -901,7 +901,7 @@ public:
/* STATUS INFORMATION */
- virtual int get_render_info(RenderInfo p_info) override;
+ virtual uint64_t get_render_info(RenderInfo p_info) override;
virtual String get_video_adapter_name() const override;
virtual String get_video_adapter_vendor() const override;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index e52d97e4d9..df1a7d58d0 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -558,13 +558,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
hexa_found = true;
- } else if (GETCHAR(i) == 'e') {
- if (hexa_found || exponent_found || float_suffix_found) {
+ } else if (GETCHAR(i) == 'e' && !hexa_found) {
+ if (exponent_found || float_suffix_found) {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
exponent_found = true;
- } else if (GETCHAR(i) == 'f') {
- if (hexa_found || exponent_found) {
+ } else if (GETCHAR(i) == 'f' && !hexa_found) {
+ if (exponent_found) {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
float_suffix_found = true;
@@ -5861,6 +5861,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_BUG;
}
+ String return_struct_name = String(b->parent_function->return_struct_name);
+
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
flow->flow_op = FLOW_OP_RETURN;
@@ -5869,7 +5871,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_SEMICOLON) {
//all is good
if (b->parent_function->return_type != TYPE_VOID) {
- _set_error("Expected return with expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
return ERR_PARSE_ERROR;
}
} else {
@@ -5879,8 +5881,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- if (b->parent_function->return_type != expr->get_datatype()) {
- _set_error("Expected return expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+ if (b->parent_function->return_type != expr->get_datatype() || return_struct_name != expr->get_datatype_name()) {
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
return ERR_PARSE_ERROR;
}
@@ -5924,15 +5926,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- //all is good
_set_error("Expected ';' after discard");
+ return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
} else if (tk.type == TK_CF_BREAK) {
if (!p_can_break) {
- //all is good
- _set_error("Breaking is not allowed here");
+ _set_error("'break' is not allowed outside of a loop or 'switch' statement");
+ return ERR_PARSE_ERROR;
}
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
@@ -5941,8 +5943,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- //all is good
_set_error("Expected ';' after break");
+ return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
@@ -5957,8 +5959,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
} else if (tk.type == TK_CF_CONTINUE) {
if (!p_can_continue) {
- //all is good
- _set_error("Continuing is not allowed here");
+ _set_error("'continue' is not allowed outside of a loop");
+ return ERR_PARSE_ERROR;
}
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
@@ -5969,6 +5971,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type != TK_SEMICOLON) {
//all is good
_set_error("Expected ';' after continue");
+ return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
@@ -6133,6 +6136,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
st.name = tk.text;
+ if (shader->structs.has(st.name)) {
+ _set_error("Redefinition of '" + String(st.name) + "'");
+ return ERR_PARSE_ERROR;
+ }
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
_set_error("Expected '{'");
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 65065841a6..6a8bb83ec1 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1419,7 +1419,7 @@ public:
INFO_VERTEX_MEM_USED,
};
- virtual int get_render_info(RenderInfo p_info) = 0;
+ virtual uint64_t get_render_info(RenderInfo p_info) = 0;
virtual String get_video_adapter_name() const = 0;
virtual String get_video_adapter_vendor() const = 0;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 27fdd090f1..8b03565291 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -219,6 +219,11 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_font_system", "name", "base_size"), &TextServer::create_font_system, DEFVAL(16));
ClassDB::bind_method(D_METHOD("create_font_resource", "filename", "base_size"), &TextServer::create_font_resource, DEFVAL(16));
ClassDB::bind_method(D_METHOD("create_font_memory", "data", "type", "base_size"), &TextServer::_create_font_memory, DEFVAL(16));
+ ClassDB::bind_method(D_METHOD("create_font_bitmap", "height", "ascent", "base_size"), &TextServer::create_font_bitmap);
+
+ ClassDB::bind_method(D_METHOD("font_bitmap_add_texture", "font", "texture"), &TextServer::font_bitmap_add_texture);
+ ClassDB::bind_method(D_METHOD("font_bitmap_add_char", "font", "char", "texture_idx", "rect", "align", "advance"), &TextServer::font_bitmap_add_char);
+ ClassDB::bind_method(D_METHOD("font_bitmap_add_kerning_pair", "font", "A", "B", "kerning"), &TextServer::font_bitmap_add_kerning_pair);
ClassDB::bind_method(D_METHOD("font_get_height", "font", "size"), &TextServer::font_get_height);
ClassDB::bind_method(D_METHOD("font_get_ascent", "font", "size"), &TextServer::font_get_ascent);
@@ -286,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));
@@ -398,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) };
@@ -1207,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 3268741a74..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.
@@ -192,18 +198,6 @@ public:
Vector<TextServer::Glyph> glyphs_logical;
};
- struct BitmapFontData {
- int height = 0;
- int ascent = 0;
- int charcount = 0;
- const int *char_rects = nullptr;
- int kerning_count = 0;
- const int *kernings = nullptr;
- int w = 0;
- int h = 0;
- const unsigned char *img = nullptr;
- };
-
protected:
static void _bind_methods();
@@ -236,6 +230,11 @@ public:
virtual RID create_font_system(const String &p_name, int p_base_size = 16) = 0;
virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) = 0;
virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) = 0;
+ virtual RID create_font_bitmap(float p_height, float p_ascent, int p_base_size = 16) = 0;
+
+ virtual void font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) = 0;
+ virtual void font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) = 0;
+ virtual void font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) = 0;
virtual float font_get_height(RID p_font, int p_size) const = 0;
virtual float font_get_ascent(RID p_font, int p_size) const = 0;
@@ -293,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;
@@ -379,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;
@@ -461,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();