summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/audio/audio_stream.cpp84
-rw-r--r--servers/audio/audio_stream.h37
-rw-r--r--servers/audio/effects/audio_effect_pitch_shift.cpp2
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp4
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.cpp18
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.h2
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp8
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h2
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h2
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp12
-rw-r--r--servers/physics_2d/shape_2d_sw.h168
-rw-r--r--servers/physics_2d/space_2d_sw.cpp10
-rw-r--r--servers/physics_3d/area_3d_sw.cpp30
-rw-r--r--servers/physics_3d/area_3d_sw.h50
-rw-r--r--servers/physics_3d/area_pair_3d_sw.cpp82
-rw-r--r--servers/physics_3d/area_pair_3d_sw.h18
-rw-r--r--servers/physics_3d/body_3d_sw.cpp2
-rw-r--r--servers/physics_3d/body_3d_sw.h12
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp4
-rw-r--r--servers/physics_3d/gjk_epa.cpp2
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp2
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.cpp2
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/jacobian_entry_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.cpp2
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.cpp2
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp2
-rw-r--r--servers/physics_3d/shape_3d_sw.h204
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp128
-rw-r--r--servers/physics_3d/soft_body_3d_sw.h32
-rw-r--r--servers/physics_3d/space_3d_sw.cpp14
-rw-r--r--servers/physics_server_2d.cpp18
-rw-r--r--servers/physics_server_2d.h14
-rw-r--r--servers/physics_server_3d.cpp18
-rw-r--r--servers/physics_server_3d.h16
-rw-r--r--servers/register_server_types.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp487
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h95
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp15
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp82
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h35
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp6
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp435
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h41
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp13
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h15
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h4
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster.glsl98
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl15
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof.glsl38
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl37
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl253
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cube_to_dp.glsl14
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/decal_data_inc.glsl28
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl84
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl144
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl96
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl80
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl10
-rw-r--r--servers/rendering/renderer_scene_cull.cpp11
-rw-r--r--servers/rendering/rendering_device.cpp14
-rw-r--r--servers/rendering/rendering_device.h8
-rw-r--r--servers/rendering/shader_language.cpp21
-rw-r--r--servers/rendering/shader_language.h1
-rw-r--r--servers/rendering/shader_types.cpp1
-rw-r--r--servers/text_server.cpp6
81 files changed, 2194 insertions, 1057 deletions
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index f3fa857682..5544a09ac0 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -33,6 +33,63 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+void AudioStreamPlayback::start(float p_from_pos) {
+ if (GDVIRTUAL_CALL(_start, p_from_pos)) {
+ return;
+ }
+ ERR_FAIL_MSG("AudioStreamPlayback::start unimplemented!");
+}
+void AudioStreamPlayback::stop() {
+ if (GDVIRTUAL_CALL(_stop)) {
+ return;
+ }
+ ERR_FAIL_MSG("AudioStreamPlayback::stop unimplemented!");
+}
+bool AudioStreamPlayback::is_playing() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_is_playing, ret)) {
+ return ret;
+ }
+ ERR_FAIL_V_MSG(false, "AudioStreamPlayback::is_playing unimplemented!");
+}
+
+int AudioStreamPlayback::get_loop_count() const {
+ int ret;
+ if (GDVIRTUAL_CALL(_get_loop_count, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+float AudioStreamPlayback::get_playback_position() const {
+ float ret;
+ if (GDVIRTUAL_CALL(_get_playback_position, ret)) {
+ return ret;
+ }
+ ERR_FAIL_V_MSG(0, "AudioStreamPlayback::get_playback_position unimplemented!");
+}
+void AudioStreamPlayback::seek(float p_time) {
+ if (GDVIRTUAL_CALL(_seek, p_time)) {
+ return;
+ }
+}
+
+void AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+ if (GDVIRTUAL_CALL(_mix, p_buffer, p_rate_scale, p_frames)) {
+ return;
+ }
+ WARN_PRINT_ONCE("AudioStreamPlayback::mix unimplemented!");
+}
+
+void AudioStreamPlayback::_bind_methods() {
+ GDVIRTUAL_BIND(_start, "from_pos")
+ GDVIRTUAL_BIND(_stop)
+ GDVIRTUAL_BIND(_is_playing)
+ GDVIRTUAL_BIND(_get_loop_count)
+ GDVIRTUAL_BIND(_get_playback_position)
+ GDVIRTUAL_BIND(_seek, "position")
+ GDVIRTUAL_BIND(_mix, "buffer", "rate_scale", "frames");
+}
//////////////////////////////
void AudioStreamPlaybackResampled::_begin_resample() {
@@ -92,8 +149,34 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
////////////////////////////////
+Ref<AudioStreamPlayback> AudioStream::instance_playback() {
+ Ref<AudioStreamPlayback> ret;
+ if (GDVIRTUAL_CALL(_instance_playback, ret)) {
+ return ret;
+ }
+ ERR_FAIL_V_MSG(Ref<AudioStreamPlayback>(), "Method must be implemented!");
+}
+String AudioStream::get_stream_name() const {
+ String ret;
+ if (GDVIRTUAL_CALL(_get_stream_name, ret)) {
+ return ret;
+ }
+ return String();
+}
+
+float AudioStream::get_length() const {
+ float ret;
+ if (GDVIRTUAL_CALL(_get_length, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
void AudioStream::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length);
+ GDVIRTUAL_BIND(_instance_playback);
+ GDVIRTUAL_BIND(_get_stream_name);
+ GDVIRTUAL_BIND(_get_length);
}
////////////////////////////////
@@ -358,3 +441,4 @@ void AudioStreamPlaybackRandomPitch::mix(AudioFrame *p_buffer, float p_rate_scal
AudioStreamPlaybackRandomPitch::~AudioStreamPlaybackRandomPitch() {
random_pitch->playbacks.erase(this);
}
+/////////////////////////////////////////////
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index 0d426f99b2..25f0017211 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -36,20 +36,33 @@
#include "servers/audio/audio_filter_sw.h"
#include "servers/audio_server.h"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+
class AudioStreamPlayback : public RefCounted {
GDCLASS(AudioStreamPlayback, RefCounted);
+protected:
+ static void _bind_methods();
+ GDVIRTUAL1(_start, float)
+ GDVIRTUAL0(_stop)
+ GDVIRTUAL0RC(bool, _is_playing)
+ GDVIRTUAL0RC(int, _get_loop_count)
+ GDVIRTUAL0RC(float, _get_playback_position)
+ GDVIRTUAL1(_seek, float)
+ GDVIRTUAL3(_mix, GDNativePtr<AudioFrame>, float, int)
public:
- virtual void start(float p_from_pos = 0.0) = 0;
- virtual void stop() = 0;
- virtual bool is_playing() const = 0;
+ virtual void start(float p_from_pos = 0.0);
+ virtual void stop();
+ virtual bool is_playing() const;
- virtual int get_loop_count() const = 0; //times it looped
+ virtual int get_loop_count() const; //times it looped
- virtual float get_playback_position() const = 0;
- virtual void seek(float p_time) = 0;
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
- virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) = 0;
+ virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames);
};
class AudioStreamPlaybackResampled : public AudioStreamPlayback {
@@ -84,11 +97,15 @@ class AudioStream : public Resource {
protected:
static void _bind_methods();
+ GDVIRTUAL0RC(Ref<AudioStreamPlayback>, _instance_playback)
+ GDVIRTUAL0RC(String, _get_stream_name)
+ GDVIRTUAL0RC(float, _get_length)
+
public:
- virtual Ref<AudioStreamPlayback> instance_playback() = 0;
- virtual String get_stream_name() const = 0;
+ virtual Ref<AudioStreamPlayback> instance_playback();
+ virtual String get_stream_name() const;
- virtual float get_length() const = 0; //if supported, otherwise return 0
+ virtual float get_length() const;
};
// Microphone
diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp
index bfbaeee3f3..d6c396e0a5 100644
--- a/servers/audio/effects/audio_effect_pitch_shift.cpp
+++ b/servers/audio/effects/audio_effect_pitch_shift.cpp
@@ -40,7 +40,7 @@
*
* NAME: smbPitchShift.cpp
* VERSION: 1.2
-* HOME URL: http://blogs.zynaptiq.com/bernsee
+* HOME URL: https://blogs.zynaptiq.com/bernsee
* KNOWN BUGS: none
*
* SYNOPSIS: Routine for doing pitch shifting while maintaining
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index 45b9e6414d..30a99d3d74 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/collision_solver_2d_sat.cpp
@@ -1114,12 +1114,12 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const
bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
PhysicsServer2D::ShapeType type_A = p_shape_A->get_type();
- ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_LINE, false);
+ ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN, false);
ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
PhysicsServer2D::ShapeType type_B = p_shape_B->get_type();
- ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_LINE, false);
+ ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN, false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
static const CollisionFunc collision_table[5][5] = {
diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp
index ed398a24e5..8f8a4a862c 100644
--- a/servers/physics_2d/collision_solver_2d_sw.cpp
+++ b/servers/physics_2d/collision_solver_2d_sw.cpp
@@ -34,14 +34,14 @@
#define collision_solver sat_2d_calculate_penetration
//#define collision_solver gjk_epa_calculate_penetration
-bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
- const LineShape2DSW *line = static_cast<const LineShape2DSW *>(p_shape_A);
- if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_LINE) {
+bool CollisionSolver2DSW::solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+ const WorldMarginShape2DSW *world_margin = static_cast<const WorldMarginShape2DSW *>(p_shape_A);
+ if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_MARGIN) {
return false;
}
- Vector2 n = p_transform_A.basis_xform(line->get_normal()).normalized();
- Vector2 p = p_transform_A.xform(line->get_normal() * line->get_d());
+ Vector2 n = p_transform_A.basis_xform(world_margin->get_normal()).normalized();
+ Vector2 p = p_transform_A.xform(world_margin->get_normal() * world_margin->get_d());
real_t d = n.dot(p);
Vector2 supports[2];
@@ -166,15 +166,15 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
swap = true;
}
- if (type_A == PhysicsServer2D::SHAPE_LINE) {
- if (type_B == PhysicsServer2D::SHAPE_LINE) {
+ if (type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN) {
+ if (type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN) {
return false;
}
if (swap) {
- return solve_static_line(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ return solve_static_world_margin(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
} else {
- return solve_static_line(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ return solve_static_world_margin(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
} else if (concave_B) {
diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h
index 4f12ca9e88..17c0c2fe70 100644
--- a/servers/physics_2d/collision_solver_2d_sw.h
+++ b/servers/physics_2d/collision_solver_2d_sw.h
@@ -38,7 +38,7 @@ public:
typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata);
private:
- static bool solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static void concave_callback(void *p_userdata, Shape2DSW *p_convex);
static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
static bool solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr);
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 4dcc4a9cfd..88c097453e 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -42,8 +42,8 @@
RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
Shape2DSW *shape = nullptr;
switch (p_shape) {
- case SHAPE_LINE: {
- shape = memnew(LineShape2DSW);
+ case SHAPE_WORLD_MARGIN: {
+ shape = memnew(WorldMarginShape2DSW);
} break;
case SHAPE_SEGMENT: {
shape = memnew(SegmentShape2DSW);
@@ -75,8 +75,8 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
return id;
}
-RID PhysicsServer2DSW::line_shape_create() {
- return _shape_create(SHAPE_LINE);
+RID PhysicsServer2DSW::world_margin_shape_create() {
+ return _shape_create(SHAPE_WORLD_MARGIN);
}
RID PhysicsServer2DSW::segment_shape_create() {
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index e1ad6a56ee..3610f43f93 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -87,7 +87,7 @@ public:
Vector2 *ptr;
};
- virtual RID line_shape_create() override;
+ virtual RID world_margin_shape_create() override;
virtual RID segment_shape_create() override;
virtual RID circle_shape_create() override;
virtual RID rectangle_shape_create() override;
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index 7bc1096f93..b93178919d 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -79,7 +79,7 @@ public:
#include "servers/server_wrap_mt_common.h"
//FUNC1RID(shape,ShapeType); todo fix
- FUNCRID(line_shape)
+ FUNCRID(world_margin_shape)
FUNCRID(segment_shape)
FUNCRID(circle_shape)
FUNCRID(rectangle_shape)
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index b16efbfe64..b3e4ca84c3 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -88,15 +88,15 @@ Shape2DSW::~Shape2DSW() {
/*********************************************************/
/*********************************************************/
-void LineShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
+void WorldMarginShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
r_amount = 0;
}
-bool LineShape2DSW::contains_point(const Vector2 &p_point) const {
+bool WorldMarginShape2DSW::contains_point(const Vector2 &p_point) const {
return normal.dot(p_point) < d;
}
-bool LineShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+bool WorldMarginShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
Vector2 segment = p_begin - p_end;
real_t den = normal.dot(segment);
@@ -118,11 +118,11 @@ bool LineShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_e
return true;
}
-real_t LineShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+real_t WorldMarginShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
return 0;
}
-void LineShape2DSW::set_data(const Variant &p_data) {
+void WorldMarginShape2DSW::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY);
Array arr = p_data;
ERR_FAIL_COND(arr.size() != 2);
@@ -131,7 +131,7 @@ void LineShape2DSW::set_data(const Variant &p_data) {
configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2)));
}
-Variant LineShape2DSW::get_data() const {
+Variant WorldMarginShape2DSW::get_data() const {
Array arr;
arr.resize(2);
arr[0] = normal;
diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h
index 3e4271b156..45d3379dfa 100644
--- a/servers/physics_2d/shape_2d_sw.h
+++ b/servers/physics_2d/shape_2d_sw.h
@@ -34,18 +34,6 @@
#include "servers/physics_server_2d.h"
#define _SEGMENT_IS_VALID_SUPPORT_THRESHOLD 0.99998
-/*
-
-SHAPE_LINE, ///< plane:"plane"
-SHAPE_SEGMENT, ///< real_t:"length"
-SHAPE_CIRCLE, ///< real_t:"radius"
-SHAPE_RECTANGLE, ///< vec3:"extents"
-SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
-SHAPE_CONCAVE_POLYGON, ///< Vector2 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector2 array)
-SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
-
-*/
-
class Shape2DSW;
class ShapeOwner2DSW {
@@ -137,22 +125,22 @@ public:
};
//let the optimizer do the magic
-#define DEFAULT_PROJECT_RANGE_CAST \
- virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { \
- project_range_cast(p_cast, p_normal, p_transform, r_min, r_max); \
- } \
- _FORCE_INLINE_ void project_range_cast(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { \
- real_t mina, maxa; \
- real_t minb, maxb; \
- Transform2D ofsb = p_transform; \
- ofsb.elements[2] += p_cast; \
- project_range(p_normal, p_transform, mina, maxa); \
- project_range(p_normal, ofsb, minb, maxb); \
- r_min = MIN(mina, minb); \
- r_max = MAX(maxa, maxb); \
+#define DEFAULT_PROJECT_RANGE_CAST \
+ virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { \
+ project_range_cast(p_cast, p_normal, p_transform, r_min, r_max); \
+ } \
+ _FORCE_INLINE_ void project_range_cast(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { \
+ real_t mina, maxa; \
+ real_t minb, maxb; \
+ Transform2D ofsb = p_transform; \
+ ofsb.elements[2] += p_cast; \
+ project_range(p_normal, p_transform, mina, maxa); \
+ project_range(p_normal, ofsb, minb, maxb); \
+ r_min = MIN(mina, minb); \
+ r_max = MAX(maxa, maxb); \
}
-class LineShape2DSW : public Shape2DSW {
+class WorldMarginShape2DSW : public Shape2DSW {
Vector2 normal;
real_t d;
@@ -160,17 +148,17 @@ public:
_FORCE_INLINE_ Vector2 get_normal() const { return normal; }
_FORCE_INLINE_ real_t get_d() const { return d; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_LINE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_WORLD_MARGIN; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -178,7 +166,7 @@ public:
r_max = 1e10;
}
- virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
+ virtual void project_range_castv(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override {
project_range_cast(p_cast, p_normal, p_transform, r_min, r_max);
}
@@ -199,20 +187,20 @@ public:
_FORCE_INLINE_ const Vector2 &get_b() const { return b; }
_FORCE_INLINE_ const Vector2 &get_normal() const { return n; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_SEGMENT; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_SEGMENT; }
_FORCE_INLINE_ Vector2 get_xformed_normal(const Transform2D &p_xform) const {
return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal();
}
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -239,17 +227,17 @@ class CircleShape2DSW : public Shape2DSW {
public:
_FORCE_INLINE_ const real_t &get_radius() const { return radius; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CIRCLE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CIRCLE; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
//real large
@@ -272,17 +260,17 @@ class RectangleShape2DSW : public Shape2DSW {
public:
_FORCE_INLINE_ const Vector2 &get_half_extents() const { return half_extents; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_RECTANGLE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_RECTANGLE; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
// no matter the angle, the box is mirrored anyway
@@ -346,17 +334,17 @@ public:
_FORCE_INLINE_ const real_t &get_radius() const { return radius; }
_FORCE_INLINE_ const real_t &get_height() const { return height; }
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CAPSULE; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CAPSULE; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
// no matter the angle, the box is mirrored anyway
@@ -399,17 +387,17 @@ public:
return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal();
}
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); }
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
if (!points || point_count <= 0) {
@@ -437,7 +425,7 @@ public:
class ConcaveShape2DSW : public Shape2DSW {
public:
- virtual bool is_concave() const { return true; }
+ virtual bool is_concave() const override { return true; }
typedef void (*Callback)(void *p_userdata, Shape2DSW *p_convex);
virtual void cull(const Rect2 &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
@@ -474,23 +462,31 @@ class ConcavePolygonShape2DSW : public ConcaveShape2DSW {
int _generate_bvh(BVH *p_bvh, int p_len, int p_depth);
public:
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONCAVE_POLYGON; }
+ virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_CONCAVE_POLYGON; }
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/
+ virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override {
+ r_min = 0;
+ r_max = 0;
+ ERR_FAIL_MSG("Unsupported call to project_rangev in ConcavePolygonShape2DSW");
}
- virtual void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/
+
+ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
+ r_min = 0;
+ r_max = 0;
+ ERR_FAIL_MSG("Unsupported call to project_range in ConcavePolygonShape2DSW");
}
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
+ virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override;
+
+ virtual bool contains_point(const Vector2 &p_point) const override;
+ virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const override;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return 0; }
+ virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const override { return 0; }
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
- virtual void cull(const Rect2 &p_local_aabb, Callback p_callback, void *p_userdata) const;
+ virtual void cull(const Rect2 &p_local_aabb, Callback p_callback, void *p_userdata) const override;
DEFAULT_PROJECT_RANGE_CAST
};
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 65dc198592..f04f3ab583 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -560,7 +560,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (!shapes_found) {
if (r_result) {
*r_result = PhysicsServer2D::MotionResult();
- r_result->motion = p_motion;
+ r_result->travel = p_motion;
}
return false;
}
@@ -954,9 +954,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Vector2 rel_vec = r_result->collision_point - body->get_transform().get_origin();
r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- r_result->motion = safe * p_motion;
+ r_result->travel = safe * p_motion;
r_result->remainder = p_motion - safe * p_motion;
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ r_result->travel += (body_transform.get_origin() - p_from.get_origin());
}
collided = true;
@@ -964,9 +964,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
if (!collided && r_result) {
- r_result->motion = p_motion;
+ r_result->travel = p_motion;
r_result->remainder = Vector2();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ r_result->travel += (body_transform.get_origin() - p_from.get_origin());
}
return collided;
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp
index a9f5c4aec3..c292abad48 100644
--- a/servers/physics_3d/area_3d_sw.cpp
+++ b/servers/physics_3d/area_3d_sw.cpp
@@ -30,8 +30,16 @@
#include "area_3d_sw.h"
#include "body_3d_sw.h"
+#include "soft_body_3d_sw.h"
#include "space_3d_sw.h"
+Area3DSW::BodyKey::BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+ rid = p_body->get_self();
+ instance_id = p_body->get_instance_id();
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+}
+
Area3DSW::BodyKey::BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
rid = p_body->get_self();
instance_id = p_body->get_instance_id();
@@ -155,6 +163,20 @@ void Area3DSW::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &
case PhysicsServer3D::AREA_PARAM_PRIORITY:
priority = p_value;
break;
+ case PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE:
+ ERR_FAIL_COND_MSG(wind_force_magnitude < 0, "Wind force magnitude must be a non-negative real number, but a negative number was specified.");
+ wind_force_magnitude = p_value;
+ break;
+ case PhysicsServer3D::AREA_PARAM_WIND_SOURCE:
+ wind_source = p_value;
+ break;
+ case PhysicsServer3D::AREA_PARAM_WIND_DIRECTION:
+ wind_direction = p_value;
+ break;
+ case PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR:
+ ERR_FAIL_COND_MSG(wind_attenuation_factor < 0, "Wind attenuation factor must be a non-negative real number, but a negative number was specified.");
+ wind_attenuation_factor = p_value;
+ break;
}
}
@@ -176,6 +198,14 @@ Variant Area3DSW::get_param(PhysicsServer3D::AreaParameter p_param) const {
return angular_damp;
case PhysicsServer3D::AREA_PARAM_PRIORITY:
return priority;
+ case PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE:
+ return wind_force_magnitude;
+ case PhysicsServer3D::AREA_PARAM_WIND_SOURCE:
+ return wind_source;
+ case PhysicsServer3D::AREA_PARAM_WIND_DIRECTION:
+ return wind_direction;
+ case PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR:
+ return wind_attenuation_factor;
}
return Variant();
diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h
index 12f7545c08..814472885c 100644
--- a/servers/physics_3d/area_3d_sw.h
+++ b/servers/physics_3d/area_3d_sw.h
@@ -38,6 +38,7 @@
class Space3DSW;
class Body3DSW;
+class SoftBody3DSW;
class Constraint3DSW;
class Area3DSW : public CollisionObject3DSW {
@@ -49,6 +50,10 @@ class Area3DSW : public CollisionObject3DSW {
real_t point_attenuation;
real_t linear_damp;
real_t angular_damp;
+ real_t wind_force_magnitude = 0.0;
+ real_t wind_attenuation_factor = 0.0;
+ Vector3 wind_source;
+ Vector3 wind_direction;
int priority;
bool monitorable;
@@ -80,6 +85,7 @@ class Area3DSW : public CollisionObject3DSW {
}
_FORCE_INLINE_ BodyKey() {}
+ BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
};
@@ -91,6 +97,7 @@ class Area3DSW : public CollisionObject3DSW {
_FORCE_INLINE_ BodyState() { state = 0; }
};
+ Map<BodyKey, BodyState> monitored_soft_bodies;
Map<BodyKey, BodyState> monitored_bodies;
Map<BodyKey, BodyState> monitored_areas;
@@ -115,6 +122,9 @@ public:
_FORCE_INLINE_ void add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ _FORCE_INLINE_ void add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape);
+ _FORCE_INLINE_ void remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape);
+
_FORCE_INLINE_ void add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
_FORCE_INLINE_ void remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
@@ -148,6 +158,18 @@ public:
_FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
+ _FORCE_INLINE_ void set_wind_force_magnitude(real_t p_wind_force_magnitude) { wind_force_magnitude = p_wind_force_magnitude; }
+ _FORCE_INLINE_ real_t get_wind_force_magnitude() const { return wind_force_magnitude; }
+
+ _FORCE_INLINE_ void set_wind_attenuation_factor(real_t p_wind_attenuation_factor) { wind_attenuation_factor = p_wind_attenuation_factor; }
+ _FORCE_INLINE_ real_t get_wind_attenuation_factor() const { return wind_attenuation_factor; }
+
+ _FORCE_INLINE_ void set_wind_source(const Vector3 &p_wind_source) { wind_source = p_wind_source; }
+ _FORCE_INLINE_ const Vector3 &get_wind_source() const { return wind_source; }
+
+ _FORCE_INLINE_ void set_wind_direction(const Vector3 &p_wind_direction) { wind_direction = p_wind_direction; }
+ _FORCE_INLINE_ const Vector3 &get_wind_direction() const { return wind_direction; }
+
_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; }
@@ -166,6 +188,22 @@ public:
~Area3DSW();
};
+void Area3DSW::add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) {
+ BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape);
+ monitored_soft_bodies[bk].inc();
+ if (!monitor_query_list.in_list()) {
+ _queue_monitor_update();
+ }
+}
+
+void Area3DSW::remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) {
+ BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape);
+ monitored_soft_bodies[bk].dec();
+ if (!monitor_query_list.in_list()) {
+ _queue_monitor_update();
+ }
+}
+
void Area3DSW::add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
BodyKey bk(p_body, p_body_shape, p_area_shape);
monitored_bodies[bk].inc();
@@ -198,4 +236,16 @@ void Area3DSW::remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, u
}
}
+struct AreaCMP {
+ Area3DSW *area;
+ int refCount;
+ _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); }
+ _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); }
+ _FORCE_INLINE_ AreaCMP() {}
+ _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) {
+ area = p_area;
+ refCount = 1;
+ }
+};
+
#endif // AREA__SW_H
diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp
index f43c2c965e..e740565da6 100644
--- a/servers/physics_3d/area_pair_3d_sw.cpp
+++ b/servers/physics_3d/area_pair_3d_sw.cpp
@@ -181,3 +181,85 @@ Area2Pair3DSW::~Area2Pair3DSW() {
area_a->remove_constraint(this);
area_b->remove_constraint(this);
}
+
+////////////////////////////////////////////////////
+
+bool AreaSoftBodyPair3DSW::setup(real_t p_step) {
+ bool result = false;
+ if (
+ area->interacts_with(soft_body) &&
+ CollisionSolver3DSW::solve_static(
+ soft_body->get_shape(soft_body_shape),
+ soft_body->get_transform() * soft_body->get_shape_transform(soft_body_shape),
+ area->get_shape(area_shape),
+ area->get_transform() * area->get_shape_transform(area_shape),
+ nullptr,
+ this)) {
+ result = true;
+ }
+
+ process_collision = false;
+ if (result != colliding) {
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ process_collision = true;
+ } else if (area->has_monitor_callback()) {
+ process_collision = true;
+ }
+
+ colliding = result;
+ }
+
+ return process_collision;
+}
+
+bool AreaSoftBodyPair3DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ soft_body->add_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->add_soft_body_to_query(soft_body, soft_body_shape, area_shape);
+ }
+ } else {
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ soft_body->remove_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->remove_soft_body_from_query(soft_body, soft_body_shape, area_shape);
+ }
+ }
+
+ return false; // Never do any post solving.
+}
+
+void AreaSoftBodyPair3DSW::solve(real_t p_step) {
+ // Nothing to do.
+}
+
+AreaSoftBodyPair3DSW::AreaSoftBodyPair3DSW(SoftBody3DSW *p_soft_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape) {
+ soft_body = p_soft_body;
+ area = p_area;
+ soft_body_shape = p_soft_body_shape;
+ area_shape = p_area_shape;
+ soft_body->add_constraint(this);
+ area->add_constraint(this);
+}
+
+AreaSoftBodyPair3DSW::~AreaSoftBodyPair3DSW() {
+ if (colliding) {
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ soft_body->remove_area(area);
+ }
+ if (area->has_monitor_callback()) {
+ area->remove_soft_body_from_query(soft_body, soft_body_shape, area_shape);
+ }
+ }
+ soft_body->remove_constraint(this);
+ area->remove_constraint(this);
+}
diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h
index 596d893082..8cc9e9ad63 100644
--- a/servers/physics_3d/area_pair_3d_sw.h
+++ b/servers/physics_3d/area_pair_3d_sw.h
@@ -34,6 +34,7 @@
#include "area_3d_sw.h"
#include "body_3d_sw.h"
#include "constraint_3d_sw.h"
+#include "soft_body_3d_sw.h"
class AreaPair3DSW : public Constraint3DSW {
Body3DSW *body;
@@ -69,4 +70,21 @@ public:
~Area2Pair3DSW();
};
+class AreaSoftBodyPair3DSW : public Constraint3DSW {
+ SoftBody3DSW *soft_body;
+ Area3DSW *area;
+ int soft_body_shape;
+ int area_shape;
+ bool colliding = false;
+ bool process_collision = false;
+
+public:
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
+
+ AreaSoftBodyPair3DSW(SoftBody3DSW *p_sof_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape);
+ ~AreaSoftBodyPair3DSW();
+};
+
#endif // AREA_PAIR__SW_H
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index ea6064cb4c..0c4079332d 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -578,7 +578,7 @@ void Body3DSW::integrate_velocities(real_t p_step) {
real_t ang_vel = total_angular_velocity.length();
Transform3D transform = get_transform();
- if (ang_vel != 0.0) {
+ if (!Math::is_zero_approx(ang_vel)) {
Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
Basis rot(ang_vel_axis, ang_vel * p_step);
Basis identity3(1, 0, 0, 0, 1, 0, 0, 0, 1);
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index bdc615ab6c..efb114a325 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -96,18 +96,6 @@ class Body3DSW : public CollisionObject3DSW {
Map<Constraint3DSW *, int> constraint_map;
- struct AreaCMP {
- Area3DSW *area;
- int refCount;
- _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); }
- _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); }
- _FORCE_INLINE_ AreaCMP() {}
- _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) {
- area = p_area;
- refCount = 1;
- }
- };
-
Vector<AreaCMP> areas;
struct Contact {
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
index 161e7e101b..dcecac1c73 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -102,6 +102,10 @@ void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, i
++cinfo.contact_count;
+ if (!cinfo.result_callback) {
+ return;
+ }
+
if (cinfo.swap_result) {
cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata);
} else {
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index 2df991563d..f2f712193a 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -37,7 +37,7 @@
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2008 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
index 56aba24b42..d2b64ce6e3 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
index d0f3dbbd35..c2a0443aff 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
@@ -40,7 +40,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
index b928f18231..e2bf2845fe 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
@@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h
index 22eb2f4660..572c35266f 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.h
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h
@@ -40,7 +40,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/jacobian_entry_3d_sw.h
index 6afa70c816..30c80db23f 100644
--- a/servers/physics_3d/joints/jacobian_entry_3d_sw.h
+++ b/servers/physics_3d/joints/jacobian_entry_3d_sw.h
@@ -37,7 +37,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
index 8eb84d1c2f..7a713c1161 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
@@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h
index 3d91452850..09deefc5c4 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.h
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.h
@@ -40,7 +40,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
index 1895fe1e2e..9f01196c30 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
@@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h
index f357bbd67a..f09476f570 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.h
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.h
@@ -40,7 +40,7 @@ Adapted to Godot from the Bullet library.
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index a84405de81..664308ed7b 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -39,7 +39,7 @@
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
+Copyright (c) 2003-2009 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index c11c3a08f6..ca58900111 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -33,17 +33,6 @@
#include "core/math/geometry_3d.h"
#include "servers/physics_server_3d.h"
-/*
-
-SHAPE_LINE, ///< plane:"plane"
-SHAPE_SEGMENT, ///< real_t:"length"
-SHAPE_CIRCLE, ///< real_t:"radius"
-SHAPE_RECTANGLE, ///< vec3:"extents"
-SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
-SHAPE_CONCAVE_POLYGON, ///< Vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
-SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
-
-*/
class Shape3DSW;
@@ -111,9 +100,9 @@ public:
class ConcaveShape3DSW : public Shape3DSW {
public:
- virtual bool is_concave() const { return true; }
+ virtual bool is_concave() const override { return true; }
typedef void (*Callback)(void *p_userdata, Shape3DSW *p_convex);
- 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 void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
@@ -153,21 +142,21 @@ class SphereShape3DSW : public Shape3DSW {
public:
real_t get_radius() const;
- virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius; }
+ virtual real_t get_area() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SPHERE; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SPHERE; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
- 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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
SphereShape3DSW();
};
@@ -178,21 +167,21 @@ class BoxShape3DSW : public Shape3DSW {
public:
_FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; }
- virtual real_t get_area() const { return 8 * half_extents.x * half_extents.y * half_extents.z; }
+ virtual real_t get_area() const override { return 8 * half_extents.x * half_extents.y * half_extents.z; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_BOX; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_BOX; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
- 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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
BoxShape3DSW();
};
@@ -207,21 +196,21 @@ public:
_FORCE_INLINE_ real_t get_height() const { return height; }
_FORCE_INLINE_ real_t get_radius() const { return radius; }
- virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius + (height - radius * 2.0) * Math_PI * radius * radius; }
+ virtual real_t get_area() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius + (height - radius * 2.0) * Math_PI * radius * radius; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CAPSULE; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CAPSULE; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
- 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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
CapsuleShape3DSW();
};
@@ -236,21 +225,21 @@ public:
_FORCE_INLINE_ real_t get_height() const { return height; }
_FORCE_INLINE_ real_t get_radius() const { return radius; }
- virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius + height * Math_PI * radius * radius; }
+ virtual real_t get_area() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius + height * Math_PI * radius * radius; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CYLINDER; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CYLINDER; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
- 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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
CylinderShape3DSW();
};
@@ -263,19 +252,19 @@ struct ConvexPolygonShape3DSW : public Shape3DSW {
public:
const Geometry3D::MeshData &get_mesh() const { return mesh; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
- 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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
ConvexPolygonShape3DSW();
};
@@ -341,21 +330,21 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
public:
Vector<Vector3> get_faces() const;
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
- 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 bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const;
+ virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
ConcavePolygonShape3DSW();
};
@@ -385,20 +374,20 @@ public:
int get_width() const;
int get_depth() const;
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_HEIGHTMAP; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_HEIGHTMAP; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const;
- virtual bool intersect_point(const Vector3 &p_point) const;
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
- virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
- virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
+ virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const override;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
+ virtual void set_data(const Variant &p_data) override;
+ virtual Variant get_data() const override;
HeightMapShape3DSW();
};
@@ -409,21 +398,21 @@ struct FaceShape3DSW : public Shape3DSW {
Vector3 vertex[3];
bool backface_collision = false;
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
const Vector3 &get_vertex(int p_idx) const { return vertex[p_idx]; }
- void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
- 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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
+ virtual Vector3 get_support(const Vector3 &p_normal) const override;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+ virtual bool intersect_point(const Vector3 &p_point) const override;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
- Vector3 get_moment_of_inertia(real_t p_mass) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
- virtual void set_data(const Variant &p_data) {}
- virtual Variant get_data() const { return Variant(); }
+ virtual void set_data(const Variant &p_data) override {}
+ virtual Variant get_data() const override { return Variant(); }
FaceShape3DSW();
};
@@ -432,9 +421,9 @@ struct MotionShape3DSW : public Shape3DSW {
Shape3DSW *shape;
Vector3 motion;
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }
+ virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }
- void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override {
Vector3 cast = p_transform.basis.xform(motion);
real_t mina, maxa;
real_t minb, maxb;
@@ -446,22 +435,23 @@ struct MotionShape3DSW : public Shape3DSW {
r_max = MAX(maxa, maxb);
}
- Vector3 get_support(const Vector3 &p_normal) const {
+ virtual Vector3 get_support(const Vector3 &p_normal) const override {
Vector3 support = shape->get_support(p_normal);
if (p_normal.dot(motion) > 0) {
support += motion;
}
return support;
}
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
- bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { return false; }
- virtual bool intersect_point(const Vector3 &p_point) const { return false; }
- virtual Vector3 get_closest_point_to(const Vector3 &p_point) const { return p_point; }
- Vector3 get_moment_of_inertia(real_t p_mass) const { return Vector3(); }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override { return false; }
+ virtual bool intersect_point(const Vector3 &p_point) const override { return false; }
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override { return p_point; }
+
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const override { return Vector3(); }
- virtual void set_data(const Variant &p_data) {}
- virtual Variant get_data() const { return Variant(); }
+ virtual void set_data(const Variant &p_data) override {}
+ virtual Variant get_data() const override { return Variant(); }
MotionShape3DSW() { configure(AABB()); }
};
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
index 724125bea8..ead6497f1f 100644
--- a/servers/physics_3d/soft_body_3d_sw.cpp
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -38,7 +38,7 @@
/*
Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
@@ -165,7 +165,7 @@ void SoftBody3DSW::update_rendering_server(RenderingServerHandler *p_rendering_s
p_rendering_server_handler->set_aabb(bounds);
}
-void SoftBody3DSW::update_normals() {
+void SoftBody3DSW::update_normals_and_centroids() {
uint32_t i, ni;
for (i = 0, ni = nodes.size(); i < ni; ++i) {
@@ -180,6 +180,7 @@ void SoftBody3DSW::update_normals() {
face.n[2]->n += n;
face.normal = n;
face.normal.normalize();
+ face.centroid = 0.33333333333 * (face.n[0]->x + face.n[1]->x + face.n[2]->x);
}
for (i = 0, ni = nodes.size(); i < ni; ++i) {
@@ -310,7 +311,7 @@ void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) {
face_tree.clear();
- update_normals();
+ update_normals_and_centroids();
update_bounds();
update_constants();
}
@@ -574,7 +575,7 @@ bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vecto
reoptimize_link_order();
update_constants();
- update_normals();
+ update_normals_and_centroids();
update_bounds();
return true;
@@ -898,36 +899,95 @@ void SoftBody3DSW::add_velocity(const Vector3 &p_velocity) {
}
}
-void SoftBody3DSW::apply_forces() {
- if (pressure_coefficient < CMP_EPSILON) {
- return;
- }
+void SoftBody3DSW::apply_forces(bool p_has_wind_forces) {
+ int ac = areas.size();
if (nodes.is_empty()) {
return;
}
uint32_t i, ni;
+ int32_t j;
- // Calculate volume.
real_t volume = 0.0;
const Vector3 &org = nodes[0].x;
+
+ // Iterate over faces (try not to iterate elsewhere if possible).
for (i = 0, ni = faces.size(); i < ni; ++i) {
+ bool stopped = false;
const Face &face = faces[i];
+
+ Vector3 wind_force(0, 0, 0);
+
+ // Compute volume.
volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org));
+
+ // Compute nodal forces from area winds.
+ if (ac && p_has_wind_forces) {
+ const AreaCMP *aa = &areas[0];
+ for (j = ac - 1; j >= 0 && !stopped; j--) {
+ PhysicsServer3D::AreaSpaceOverrideMode mode = aa[j].area->get_space_override_mode();
+ switch (mode) {
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ wind_force += _compute_area_windforce(aa[j].area, &face);
+ stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ wind_force = _compute_area_windforce(aa[j].area, &face);
+ stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {
+ }
+ }
+ }
+
+ for (j = 0; j < 3; j++) {
+ Node *current_node = face.n[j];
+ current_node->f += wind_force;
+ }
+ }
}
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);
+ // Apply nodal pressure forces.
+ if (pressure_coefficient > CMP_EPSILON) {
+ 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::_compute_area_gravity(const Area3DSW *p_area) {
+ if (p_area->is_gravity_point()) {
+ if (p_area->get_gravity_distance_scale() > 0) {
+ Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
+ gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
+ } else {
+ gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
}
+ } else {
+ gravity += p_area->get_gravity_vector() * p_area->get_gravity();
}
}
+Vector3 SoftBody3DSW::_compute_area_windforce(const Area3DSW *p_area, const Face *p_face) {
+ real_t wfm = p_area->get_wind_force_magnitude();
+ real_t waf = p_area->get_wind_attenuation_factor();
+ const Vector3 &wd = p_area->get_wind_direction();
+ const Vector3 &ws = p_area->get_wind_source();
+ real_t projection_on_tri_normal = vec3_dot(p_face->normal, wd);
+ real_t projection_toward_centroid = vec3_dot(p_face->centroid - ws, wd);
+ real_t attenuation_over_distance = pow(projection_toward_centroid, -waf);
+ real_t nodal_force_magnitude = wfm * 0.33333333333 * p_face->ra * projection_on_tri_normal * attenuation_over_distance;
+ return nodal_force_magnitude * p_face->normal;
+}
+
void SoftBody3DSW::predict_motion(real_t p_delta) {
const real_t inv_delta = 1.0 / p_delta;
@@ -935,11 +995,43 @@ void SoftBody3DSW::predict_motion(real_t p_delta) {
Area3DSW *def_area = get_space()->get_default_area();
ERR_FAIL_COND(!def_area);
+ gravity = def_area->get_gravity_vector() * def_area->get_gravity();
+
+ int ac = areas.size();
+ bool stopped = false;
+ bool has_wind_forces = false;
+
+ if (ac) {
+ areas.sort();
+ const AreaCMP *aa = &areas[0];
+ for (int i = ac - 1; i >= 0 && !stopped; i--) {
+ // Avoids unnecessary loop in apply_forces().
+ has_wind_forces = has_wind_forces || aa[i].area->get_wind_force_magnitude() > CMP_EPSILON;
+
+ PhysicsServer3D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
+ switch (mode) {
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ _compute_area_gravity(aa[i].area);
+ stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ gravity = Vector3(0, 0, 0);
+ _compute_area_gravity(aa[i].area);
+ stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {
+ }
+ }
+ }
+ }
// Apply forces.
- Vector3 gravity = def_area->get_gravity_vector() * def_area->get_gravity();
add_velocity(gravity * p_delta);
- apply_forces();
+ if (pressure_coefficient > CMP_EPSILON || has_wind_forces) {
+ apply_forces(has_wind_forces);
+ }
// Avoid soft body from 'exploding' so use some upper threshold of maximum motion
// that a node can travel per frame.
@@ -1018,7 +1110,7 @@ void SoftBody3DSW::solve_constraints(real_t p_delta) {
node.q = node.x;
}
- update_normals();
+ update_normals_and_centroids();
}
void SoftBody3DSW::solve_links(real_t kst, real_t ti) {
diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h
index ac8bcbf0b9..58fd234fde 100644
--- a/servers/physics_3d/soft_body_3d_sw.h
+++ b/servers/physics_3d/soft_body_3d_sw.h
@@ -31,6 +31,7 @@
#ifndef SOFT_BODY_3D_SW_H
#define SOFT_BODY_3D_SW_H
+#include "area_3d_sw.h"
#include "collision_object_3d_sw.h"
#include "core/math/aabb.h"
@@ -70,6 +71,7 @@ class SoftBody3DSW : public CollisionObject3DSW {
};
struct Face {
+ Vector3 centroid;
Node *n[3] = { nullptr, nullptr, nullptr }; // Node pointers
Vector3 normal; // Normal
real_t ra = 0.0; // Rest area
@@ -100,14 +102,21 @@ class SoftBody3DSW : public CollisionObject3DSW {
real_t drag_coefficient = 0.0; // [0,1]
LocalVector<int> pinned_vertices;
+ Vector3 gravity;
+
SelfList<SoftBody3DSW> active_list;
Set<Constraint3DSW *> constraints;
+ Vector<AreaCMP> areas;
+
VSet<RID> exceptions;
uint64_t island_step = 0;
+ _FORCE_INLINE_ void _compute_area_gravity(const Area3DSW *p_area);
+ _FORCE_INLINE_ Vector3 _compute_area_windforce(const Area3DSW *p_area, const Face *p_face);
+
public:
SoftBody3DSW();
@@ -129,6 +138,25 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
+ _FORCE_INLINE_ void add_area(Area3DSW *p_area) {
+ int index = areas.find(AreaCMP(p_area));
+ if (index > -1) {
+ areas.write[index].refCount += 1;
+ } else {
+ areas.ordered_insert(AreaCMP(p_area));
+ }
+ }
+
+ _FORCE_INLINE_ void remove_area(Area3DSW *p_area) {
+ int index = areas.find(AreaCMP(p_area));
+ if (index > -1) {
+ areas.write[index].refCount -= 1;
+ if (areas[index].refCount < 1) {
+ areas.remove(index);
+ }
+ }
+ }
+
virtual void set_space(Space3DSW *p_space);
void set_mesh(const Ref<Mesh> &p_mesh);
@@ -194,7 +222,7 @@ protected:
virtual void _shapes_changed();
private:
- void update_normals();
+ void update_normals_and_centroids();
void update_bounds();
void update_constants();
void update_area();
@@ -205,7 +233,7 @@ private:
void add_velocity(const Vector3 &p_velocity);
- void apply_forces();
+ void apply_forces(bool p_has_wind_forces);
bool create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices);
void generate_bending_constraints(int p_distance);
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 730460d66a..f9e55ad525 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -600,7 +600,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
if (!shapes_found) {
if (r_result) {
*r_result = PhysicsServer3D::MotionResult();
- r_result->motion = p_motion;
+ r_result->travel = p_motion;
}
return false;
@@ -879,9 +879,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
- r_result->motion = safe * p_motion;
+ r_result->travel = safe * p_motion;
r_result->remainder = p_motion - safe * p_motion;
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ r_result->travel += (body_transform.get_origin() - p_from.get_origin());
}
collided = true;
@@ -889,9 +889,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
}
if (!collided && r_result) {
- r_result->motion = p_motion;
+ r_result->travel = p_motion;
r_result->remainder = Vector3();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ r_result->travel += (body_transform.get_origin() - p_from.get_origin());
}
return collided;
@@ -921,7 +921,9 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll
Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A));
return area2_pair;
} else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
- // Area/Soft Body, not supported.
+ SoftBody3DSW *softbody = static_cast<SoftBody3DSW *>(B);
+ AreaSoftBodyPair3DSW *soft_area_pair = memnew(AreaSoftBodyPair3DSW(softbody, p_subindex_B, area, p_subindex_A));
+ return soft_area_pair;
} else {
Body3DSW *body = static_cast<Body3DSW *>(B);
AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A));
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index c2dedde0be..c96f85446c 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -422,11 +422,11 @@ void PhysicsDirectSpaceState2D::_bind_methods() {
///////////////////////////////
-Vector2 PhysicsTestMotionResult2D::get_motion() const {
- return result.motion;
+Vector2 PhysicsTestMotionResult2D::get_travel() const {
+ return result.travel;
}
-Vector2 PhysicsTestMotionResult2D::get_motion_remainder() const {
+Vector2 PhysicsTestMotionResult2D::get_remainder() const {
return result.remainder;
}
@@ -471,8 +471,8 @@ real_t PhysicsTestMotionResult2D::get_collision_unsafe_fraction() const {
}
void PhysicsTestMotionResult2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult2D::get_motion);
- ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult2D::get_motion_remainder);
+ ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult2D::get_travel);
+ ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult2D::get_remainder);
ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult2D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult2D::get_collision_normal);
ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult2D::get_collider_velocity);
@@ -484,8 +484,8 @@ void PhysicsTestMotionResult2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult2D::get_collision_safe_fraction);
ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult2D::get_collision_unsafe_fraction);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "", "get_motion");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_remainder"), "", "get_motion_remainder");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "travel"), "", "get_travel");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "remainder"), "", "get_remainder");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_point"), "", "get_collision_point");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity");
@@ -513,7 +513,7 @@ bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, c
}
void PhysicsServer2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("line_shape_create"), &PhysicsServer2D::line_shape_create);
+ ClassDB::bind_method(D_METHOD("world_margin_shape_create"), &PhysicsServer2D::world_margin_shape_create);
ClassDB::bind_method(D_METHOD("segment_shape_create"), &PhysicsServer2D::segment_shape_create);
ClassDB::bind_method(D_METHOD("circle_shape_create"), &PhysicsServer2D::circle_shape_create);
ClassDB::bind_method(D_METHOD("rectangle_shape_create"), &PhysicsServer2D::rectangle_shape_create);
@@ -674,7 +674,7 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);
- BIND_ENUM_CONSTANT(SHAPE_LINE);
+ BIND_ENUM_CONSTANT(SHAPE_WORLD_MARGIN);
BIND_ENUM_CONSTANT(SHAPE_SEGMENT);
BIND_ENUM_CONSTANT(SHAPE_CIRCLE);
BIND_ENUM_CONSTANT(SHAPE_RECTANGLE);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index dbbc128793..4c559dd7bd 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -219,7 +219,7 @@ public:
static PhysicsServer2D *get_singleton();
enum ShapeType {
- SHAPE_LINE, ///< plane:"plane"
+ SHAPE_WORLD_MARGIN, ///< plane:"plane"
SHAPE_SEGMENT, ///< float:"length"
SHAPE_CIRCLE, ///< float:"radius"
SHAPE_RECTANGLE, ///< vec3:"extents"
@@ -229,7 +229,7 @@ public:
SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
};
- virtual RID line_shape_create() = 0;
+ virtual RID world_margin_shape_create() = 0;
virtual RID segment_shape_create() = 0;
virtual RID circle_shape_create() = 0;
virtual RID rectangle_shape_create() = 0;
@@ -465,7 +465,7 @@ public:
virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) = 0;
struct MotionResult {
- Vector2 motion;
+ Vector2 travel;
Vector2 remainder;
Vector2 collision_point;
@@ -479,6 +479,10 @@ public:
RID collider;
int collider_shape = 0;
Variant collider_metadata;
+
+ real_t get_angle(Vector2 p_up_direction) const {
+ return Math::acos(collision_normal.dot(p_up_direction));
+ }
};
virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) = 0;
@@ -588,8 +592,8 @@ protected:
public:
PhysicsServer2D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer2D::MotionResult *>(&result); }
- Vector2 get_motion() const;
- Vector2 get_motion_remainder() const;
+ Vector2 get_travel() const;
+ Vector2 get_remainder() const;
Vector2 get_collision_point() const;
Vector2 get_collision_normal() const;
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 89987b5fe9..1f46a96b27 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -369,11 +369,11 @@ void PhysicsDirectSpaceState3D::_bind_methods() {
///////////////////////////////
-Vector3 PhysicsTestMotionResult3D::get_motion() const {
- return result.motion;
+Vector3 PhysicsTestMotionResult3D::get_travel() const {
+ return result.travel;
}
-Vector3 PhysicsTestMotionResult3D::get_motion_remainder() const {
+Vector3 PhysicsTestMotionResult3D::get_remainder() const {
return result.remainder;
}
@@ -418,8 +418,8 @@ real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const {
}
void PhysicsTestMotionResult3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult3D::get_motion);
- ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult3D::get_motion_remainder);
+ ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult3D::get_travel);
+ ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult3D::get_remainder);
ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult3D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult3D::get_collision_normal);
ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult3D::get_collider_velocity);
@@ -431,8 +431,8 @@ void PhysicsTestMotionResult3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult3D::get_collision_safe_fraction);
ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult3D::get_collision_unsafe_fraction);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "", "get_motion");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_remainder"), "", "get_motion_remainder");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_point"), "", "get_collision_point");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_normal"), "", "get_collision_normal");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity");
@@ -766,6 +766,10 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP);
BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP);
BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY);
+ BIND_ENUM_CONSTANT(AREA_PARAM_WIND_FORCE_MAGNITUDE);
+ BIND_ENUM_CONSTANT(AREA_PARAM_WIND_SOURCE);
+ BIND_ENUM_CONSTANT(AREA_PARAM_WIND_DIRECTION);
+ BIND_ENUM_CONSTANT(AREA_PARAM_WIND_ATTENUATION_FACTOR);
BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_DISABLED);
BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 31ae352d9e..5201e76498 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -298,7 +298,11 @@ public:
AREA_PARAM_GRAVITY_POINT_ATTENUATION,
AREA_PARAM_LINEAR_DAMP,
AREA_PARAM_ANGULAR_DAMP,
- AREA_PARAM_PRIORITY
+ AREA_PARAM_PRIORITY,
+ AREA_PARAM_WIND_FORCE_MAGNITUDE,
+ AREA_PARAM_WIND_SOURCE,
+ AREA_PARAM_WIND_DIRECTION,
+ AREA_PARAM_WIND_ATTENUATION_FACTOR,
};
virtual RID area_create() = 0;
@@ -473,7 +477,7 @@ public:
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0;
struct MotionResult {
- Vector3 motion;
+ Vector3 travel;
Vector3 remainder;
Vector3 collision_point;
@@ -487,6 +491,10 @@ public:
RID collider;
int collider_shape = 0;
Variant collider_metadata;
+
+ real_t get_angle(Vector3 p_up_direction) const {
+ return Math::acos(collision_normal.dot(p_up_direction));
+ }
};
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) = 0;
@@ -752,8 +760,8 @@ protected:
public:
PhysicsServer3D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer3D::MotionResult *>(&result); }
- Vector3 get_motion() const;
- Vector3 get_motion_remainder() const;
+ Vector3 get_travel() const;
+ Vector3 get_remainder() const;
Vector3 get_collision_point() const;
Vector3 get_collision_normal() const;
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 857f112102..8e86957d9b 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -140,8 +140,8 @@ void register_server_types() {
GDREGISTER_VIRTUAL_CLASS(XRInterface);
GDREGISTER_CLASS(XRPositionalTracker);
- GDREGISTER_VIRTUAL_CLASS(AudioStream);
- GDREGISTER_VIRTUAL_CLASS(AudioStreamPlayback);
+ GDREGISTER_CLASS(AudioStream);
+ GDREGISTER_CLASS(AudioStreamPlayback);
GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackResampled);
GDREGISTER_CLASS(AudioStreamMicrophone);
GDREGISTER_CLASS(AudioStreamRandomPitch);
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index c609f25e31..80d843227b 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -739,7 +739,27 @@ void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const S
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip) {
+void EffectsRD::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of mipmap with the clustered renderer.");
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+
+ BlurRasterMode mode = BLUR_MIPMAP;
+
+ blur_raster.push_constant.pixel_size[0] = 1.0 / float(p_size.x);
+ blur_raster.push_constant.pixel_size[1] = 1.0 / float(p_size.y);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) {
CopyToDPPushConstant push_constant;
push_constant.screen_rect[0] = p_rect.position.x;
push_constant.screen_rect[1] = p_rect.position.y;
@@ -747,7 +767,9 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe
push_constant.screen_rect[3] = p_rect.size.height;
push_constant.z_far = p_z_far;
push_constant.z_near = p_z_near;
- push_constant.z_flip = p_dp_flip;
+ push_constant.texel_size[0] = 1.0f / p_dst_size.x;
+ push_constant.texel_size[1] = 1.0f / p_dst_size.y;
+ push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
@@ -928,7 +950,7 @@ void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_
}
}
-void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+void EffectsRD::bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of BOKEH DOF with the mobile renderer.");
bokeh.push_constant.blur_far_active = p_dof_far;
@@ -957,22 +979,22 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
// The alpha channel of the source color texture is filled with the expected circle size
// If used for DOF far, the size is positive, if used for near, its negative.
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BLUR_SIZE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.depth_texture), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
//second pass
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
static const int quality_samples[4] = { 6, 12, 12, 24 };
@@ -981,18 +1003,18 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
- bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
bokeh.push_constant.blur_size *= 0.5;
} else {
//medium and high quality use full size
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.secondary_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@@ -1004,11 +1026,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
bokeh.push_constant.second_pass = true;
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture2), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[1]), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1);
} else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.secondary_texture), 1);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@@ -1019,25 +1041,25 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
//forth pass, upscale for low quality
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[1]), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
bokeh.push_constant.half_size = false;
bokeh.push_constant.second_pass = false;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
} else {
//circle
//second pass
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
@@ -1046,11 +1068,11 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
//circle always runs in half size, otherwise too expensive
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.half_texture[0]), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.base_texture), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
- bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
bokeh.push_constant.half_size = true;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
@@ -1062,93 +1084,195 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
// upscale
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_buffers.base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_buffers.half_texture[0]), 1);
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y;
bokeh.push_constant.half_size = false;
bokeh.push_constant.second_pass = false;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_base_texture_size.x, p_base_texture_size.y, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
}
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+void EffectsRD::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use blur DOF with the clustered renderer.");
- memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
-
- BlurRasterMode blur_mode;
- int qsteps[4] = { 4, 4, 10, 20 };
- uint32_t base_flags = p_cam_orthogonal ? BLUR_FLAG_USE_ORTHOGONAL_PROJECTION : 0;
+ memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
- Vector2 pixel_size = Vector2(1.0 / p_base_texture_size.width, 1.0 / p_base_texture_size.height);
+ bokeh.push_constant.orthogonal = p_cam_orthogonal;
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.width;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.height;
+ bokeh.push_constant.z_far = p_cam_zfar;
+ bokeh.push_constant.z_near = p_cam_znear;
- blur_raster.push_constant.dof_radius = (p_dof_blur_amount * p_dof_blur_amount) / qsteps[p_quality];
- blur_raster.push_constant.pixel_size[0] = pixel_size.x;
- blur_raster.push_constant.pixel_size[1] = pixel_size.y;
- blur_raster.push_constant.camera_z_far = p_cam_zfar;
- blur_raster.push_constant.camera_z_near = p_cam_znear;
+ bokeh.push_constant.second_pass = false;
+ bokeh.push_constant.half_size = false;
+ bokeh.push_constant.blur_size = p_dof_blur_amount;
if (p_dof_far || p_dof_near) {
- if (p_quality == RS::DOF_BLUR_QUALITY_HIGH) {
- blur_mode = BLUR_MODE_DOF_HIGH;
- } else if (p_quality == RS::DOF_BLUR_QUALITY_MEDIUM) {
- blur_mode = BLUR_MODE_DOF_MEDIUM;
- } else { // for LOW or VERYLOW we use LOW
- blur_mode = BLUR_MODE_DOF_LOW;
- }
-
if (p_dof_far) {
- base_flags |= BLUR_FLAG_DOF_FAR;
- blur_raster.push_constant.dof_far_begin = p_dof_far_begin;
- blur_raster.push_constant.dof_far_end = p_dof_far_begin + p_dof_far_size;
+ bokeh.push_constant.blur_far_active = true;
+ bokeh.push_constant.blur_far_begin = p_dof_far_begin;
+ bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
}
if (p_dof_near) {
- base_flags |= BLUR_FLAG_DOF_NEAR;
- blur_raster.push_constant.dof_near_begin = p_dof_near_begin;
- blur_raster.push_constant.dof_near_end = p_dof_near_begin - p_dof_near_size;
+ bokeh.push_constant.blur_near_active = true;
+ bokeh.push_constant.blur_near_begin = p_dof_near_begin;
+ bokeh.push_constant.blur_near_end = p_dof_near_begin - p_dof_near_size;
}
- //HORIZONTAL
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_secondary_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_secondary_fb)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base_texture), 0);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ {
+ // generate our depth data
+ RID framebuffer = p_buffers.base_weight_fb;
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[BOKEH_GEN_BLUR_SIZE].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.depth_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
- blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL;
- blur_raster.push_constant.dof_dir[0] = 1.0;
- blur_raster.push_constant.dof_dir[1] = 0.0;
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
+ if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
+ // double pass approach
+ BokehMode mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
- //VERTICAL
- draw_list = RD::get_singleton()->draw_list_begin(p_base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_base_fb)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary_texture), 0);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ //box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
+ bokeh.push_constant.half_size = true;
+ bokeh.push_constant.blur_size *= 0.5;
+ }
- blur_raster.push_constant.flags = base_flags;
- blur_raster.push_constant.dof_dir[0] = 0.0;
- blur_raster.push_constant.dof_dir[1] = 1.0;
+ static const int quality_samples[4] = { 6, 12, 12, 24 };
+ bokeh.push_constant.blur_scale = 0.5;
+ bokeh.push_constant.steps = quality_samples[p_quality];
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+ RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
+ // Pass 1
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ // Pass 2
+ if (!bokeh.push_constant.half_size) {
+ // do not output weight, we're writing back into our base buffer
+ mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
+ }
+ bokeh.push_constant.second_pass = true;
+
+ framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[1] : p_buffers.base_fb;
+ RID texture = bokeh.push_constant.half_size ? p_buffers.half_texture[0] : p_buffers.secondary_texture;
+ RID weight = bokeh.push_constant.half_size ? p_buffers.weight_texture[2] : p_buffers.weight_texture[1];
+
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(weight), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ if (bokeh.push_constant.half_size) {
+ // Compose pass
+ mode = BOKEH_COMPOSITE;
+ framebuffer = p_buffers.base_fb;
+
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[1]), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[3]), 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ } else {
+ // circular is a single pass approach
+ BokehMode mode = BOKEH_GEN_BOKEH_CIRCULAR;
+
+ {
+ // circle always runs in half size, otherwise too expensive (though the code below does support making this optional)
+ bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
+ bokeh.push_constant.half_size = true;
+ // bokeh.push_constant.blur_size *= 0.5;
+ }
+
+ static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
+ bokeh.push_constant.blur_scale = quality_scale[p_quality];
+ bokeh.push_constant.steps = 0.0;
+
+ RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.base_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ if (bokeh.push_constant.half_size) {
+ // Compose
+ mode = BOKEH_COMPOSITE;
+ framebuffer = p_buffers.base_fb;
+
+ draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, bokeh.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.half_texture[0]), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[2]), 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.weight_texture[0]), 2);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ } else {
+ // Just copy it back (we use our blur raster shader here)..
+ draw_list = RD::get_singleton()->draw_list_begin(p_buffers.base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[BLUR_MODE_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_buffers.base_fb)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_buffers.secondary_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
}
}
@@ -1771,12 +1895,11 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
// init blur shader (on compute use copy shader)
Vector<String> blur_modes;
+ blur_modes.push_back("\n#define MODE_MIPMAP\n"); // BLUR_MIPMAP
blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW
blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE
- blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_LOW\n"); // BLUR_MODE_DOF_LOW
- blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_MEDIUM\n"); // BLUR_MODE_DOF_MEDIUM
- blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_HIGH\n"); // BLUR_MODE_DOF_HIGH
+ blur_modes.push_back("\n#define MODE_COPY\n"); // BLUR_MODE_COPY
blur_raster.shader.initialize(blur_modes);
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
@@ -1793,7 +1916,7 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
}
}
- { // Initialize copy
+ if (!prefer_raster_effects) { // Initialize copy
Vector<String> copy_modes;
copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n");
copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define DST_IMAGE_8BIT\n");
@@ -1956,27 +2079,43 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0);
}
+ // Initialize bokeh
+ Vector<String> bokeh_modes;
+ bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n#define OUTPUT_WEIGHT\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n#define OUTPUT_WEIGHT\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n#define OUTPUT_WEIGHT\n");
+ bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
if (prefer_raster_effects) {
- // not supported
- } else {
- // Initialize bokeh
- Vector<String> bokeh_modes;
- bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n");
- bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
+ bokeh.raster_shader.initialize(bokeh_modes);
+
+ bokeh.shader_version = bokeh.raster_shader.version_create();
- bokeh.shader.initialize(bokeh_modes);
+ const int att_count[BOKEH_MAX] = { 1, 2, 1, 2, 1, 2, 1 };
+ for (int i = 0; i < BOKEH_MAX; i++) {
+ RD::PipelineColorBlendState blend_state = (i == BOKEH_COMPOSITE) ? RD::PipelineColorBlendState::create_blend(att_count[i]) : RD::PipelineColorBlendState::create_disabled(att_count[i]);
+ bokeh.raster_pipelines[i].setup(bokeh.raster_shader.version_get_shader(bokeh.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ }
+ } else {
+ bokeh.compute_shader.initialize(bokeh_modes);
+ bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_BOX_NOWEIGHT, false);
+ bokeh.compute_shader.set_variant_enabled(BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT, false);
+ bokeh.shader_version = bokeh.compute_shader.version_create();
- bokeh.shader_version = bokeh.shader.version_create();
+ for (int i = 0; i < BOKEH_MAX; i++) {
+ if (bokeh.compute_shader.is_variant_enabled(i)) {
+ bokeh.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i));
+ }
+ }
for (int i = 0; i < BOKEH_MAX; i++) {
- bokeh.pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.shader.version_get_shader(bokeh.shader_version, i));
+ bokeh.raster_pipelines[i].clear();
}
}
- {
+ if (!prefer_raster_effects) {
// Initialize ssao
RD::SamplerState sampler;
@@ -2032,10 +2171,8 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
for (int pass = 0; pass < 4; pass++) {
for (int subPass = 0; subPass < sub_pass_count; subPass++) {
int a = pass;
- int b = subPass;
-
int spmap[5]{ 0, 1, 4, 3, 2 };
- b = spmap[subPass];
+ int b = spmap[subPass];
float ca, sa;
float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f;
@@ -2120,7 +2257,7 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
ERR_FAIL_COND(pipeline != SSAO_MAX);
}
- {
+ if (!prefer_raster_effects) {
// Initialize roughness limiter
Vector<String> shader_modes;
shader_modes.push_back("");
@@ -2173,12 +2310,13 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
if (prefer_raster_effects) {
filter.raster_shader.initialize(cubemap_filter_modes);
- filter.shader_version = filter.raster_shader.version_create();
// array variants are not supported in raster
filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
+ filter.shader_version = filter.raster_shader.version_create();
+
for (int i = 0; i < FILTER_MODE_MAX; i++) {
if (filter.raster_shader.is_variant_enabled(i)) {
filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
@@ -2217,7 +2355,7 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
}
}
- {
+ if (!prefer_raster_effects) {
Vector<String> specular_modes;
specular_modes.push_back("\n#define MODE_MERGE\n");
specular_modes.push_back("\n#define MODE_MERGE\n#define MODE_SSR\n");
@@ -2253,72 +2391,74 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
}
}
- {
- Vector<String> ssr_modes;
- ssr_modes.push_back("\n");
- ssr_modes.push_back("\n#define MODE_ROUGH\n");
+ if (!prefer_raster_effects) {
+ {
+ Vector<String> ssr_modes;
+ ssr_modes.push_back("\n");
+ ssr_modes.push_back("\n#define MODE_ROUGH\n");
- ssr.shader.initialize(ssr_modes);
+ ssr.shader.initialize(ssr_modes);
- ssr.shader_version = ssr.shader.version_create();
+ ssr.shader_version = ssr.shader.version_create();
- for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
- ssr.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i));
+ for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
+ ssr.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i));
+ }
}
- }
- {
- Vector<String> ssr_filter_modes;
- ssr_filter_modes.push_back("\n");
- ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n");
+ {
+ Vector<String> ssr_filter_modes;
+ ssr_filter_modes.push_back("\n");
+ ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n");
- ssr_filter.shader.initialize(ssr_filter_modes);
+ ssr_filter.shader.initialize(ssr_filter_modes);
- ssr_filter.shader_version = ssr_filter.shader.version_create();
+ ssr_filter.shader_version = ssr_filter.shader.version_create();
- for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
- ssr_filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i));
+ for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
+ ssr_filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i));
+ }
}
- }
- {
- Vector<String> ssr_scale_modes;
- ssr_scale_modes.push_back("\n");
+ {
+ Vector<String> ssr_scale_modes;
+ ssr_scale_modes.push_back("\n");
- ssr_scale.shader.initialize(ssr_scale_modes);
+ ssr_scale.shader.initialize(ssr_scale_modes);
- ssr_scale.shader_version = ssr_scale.shader.version_create();
+ ssr_scale.shader_version = ssr_scale.shader.version_create();
- ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0));
- }
+ ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0));
+ }
- {
- Vector<String> sss_modes;
- sss_modes.push_back("\n#define USE_11_SAMPLES\n");
- sss_modes.push_back("\n#define USE_17_SAMPLES\n");
- sss_modes.push_back("\n#define USE_25_SAMPLES\n");
+ {
+ Vector<String> sss_modes;
+ sss_modes.push_back("\n#define USE_11_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_17_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_25_SAMPLES\n");
- sss.shader.initialize(sss_modes);
+ sss.shader.initialize(sss_modes);
- sss.shader_version = sss.shader.version_create();
+ sss.shader_version = sss.shader.version_create();
- for (int i = 0; i < sss_modes.size(); i++) {
- sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
+ for (int i = 0; i < sss_modes.size(); i++) {
+ sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
+ }
}
- }
- {
- Vector<String> resolve_modes;
- resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n");
- resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n");
- resolve_modes.push_back("\n#define MODE_RESOLVE_DEPTH\n");
+ {
+ Vector<String> resolve_modes;
+ resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n");
+ resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n");
+ resolve_modes.push_back("\n#define MODE_RESOLVE_DEPTH\n");
- resolve.shader.initialize(resolve_modes);
+ resolve.shader.initialize(resolve_modes);
- resolve.shader_version = resolve.shader.version_create();
+ resolve.shader_version = resolve.shader.version_create();
- for (int i = 0; i < RESOLVE_MODE_MAX; i++) {
- resolve.pipelines[i] = RD::get_singleton()->compute_pipeline_create(resolve.shader.version_get_shader(resolve.shader_version, i));
+ for (int i = 0; i < RESOLVE_MODE_MAX; i++) {
+ resolve.pipelines[i] = RD::get_singleton()->compute_pipeline_create(resolve.shader.version_get_shader(resolve.shader_version, i));
+ }
}
}
@@ -2384,38 +2524,41 @@ EffectsRD::~EffectsRD() {
RD::get_singleton()->free(index_buffer); //array gets freed as dependency
RD::get_singleton()->free(filter.coefficient_buffer);
- RD::get_singleton()->free(ssao.mirror_sampler);
- RD::get_singleton()->free(ssao.gather_constants_buffer);
- RD::get_singleton()->free(ssao.importance_map_load_counter);
-
if (prefer_raster_effects) {
blur_raster.shader.version_free(blur_raster.shader_version);
+ bokeh.raster_shader.version_free(blur_raster.shader_version);
luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
roughness.raster_shader.version_free(roughness.shader_version);
cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
filter.raster_shader.version_free(filter.shader_version);
} else {
- bokeh.shader.version_free(bokeh.shader_version);
+ bokeh.compute_shader.version_free(bokeh.shader_version);
luminance_reduce.shader.version_free(luminance_reduce.shader_version);
roughness.compute_shader.version_free(roughness.shader_version);
cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);
filter.compute_shader.version_free(filter.shader_version);
}
- copy.shader.version_free(copy.shader_version);
+ if (!prefer_raster_effects) {
+ copy.shader.version_free(copy.shader_version);
+ resolve.shader.version_free(resolve.shader_version);
+ specular_merge.shader.version_free(specular_merge.shader_version);
+ ssao.blur_shader.version_free(ssao.blur_shader_version);
+ ssao.gather_shader.version_free(ssao.gather_shader_version);
+ ssao.downsample_shader.version_free(ssao.downsample_shader_version);
+ ssao.interleave_shader.version_free(ssao.interleave_shader_version);
+ ssao.importance_map_shader.version_free(ssao.importance_map_shader_version);
+ roughness_limiter.shader.version_free(roughness_limiter.shader_version);
+ ssr.shader.version_free(ssr.shader_version);
+ ssr_filter.shader.version_free(ssr_filter.shader_version);
+ ssr_scale.shader.version_free(ssr_scale.shader_version);
+ sss.shader.version_free(sss.shader_version);
+
+ RD::get_singleton()->free(ssao.mirror_sampler);
+ RD::get_singleton()->free(ssao.gather_constants_buffer);
+ RD::get_singleton()->free(ssao.importance_map_load_counter);
+ }
copy_to_fb.shader.version_free(copy_to_fb.shader_version);
cube_to_dp.shader.version_free(cube_to_dp.shader_version);
- resolve.shader.version_free(resolve.shader_version);
- roughness_limiter.shader.version_free(roughness_limiter.shader_version);
sort.shader.version_free(sort.shader_version);
- specular_merge.shader.version_free(specular_merge.shader_version);
- ssao.blur_shader.version_free(ssao.blur_shader_version);
- ssao.gather_shader.version_free(ssao.gather_shader_version);
- ssao.downsample_shader.version_free(ssao.downsample_shader_version);
- ssao.interleave_shader.version_free(ssao.interleave_shader_version);
- ssao.importance_map_shader.version_free(ssao.importance_map_shader_version);
- ssr.shader.version_free(ssr.shader_version);
- ssr_filter.shader.version_free(ssr_filter.shader_version);
- ssr_scale.shader.version_free(ssr_scale.shader_version);
- sss.shader.version_free(sss.shader_version);
tonemap.shader.version_free(tonemap.shader_version);
}
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index 79d9a8b738..c8d4cb7ad4 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -35,6 +35,7 @@
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
@@ -69,13 +70,12 @@ private:
bool prefer_raster_effects;
enum BlurRasterMode {
+ BLUR_MIPMAP,
+
BLUR_MODE_GAUSSIAN_BLUR,
BLUR_MODE_GAUSSIAN_GLOW,
BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
-
- BLUR_MODE_DOF_LOW,
- BLUR_MODE_DOF_MEDIUM,
- BLUR_MODE_DOF_HIGH,
+ BLUR_MODE_COPY,
BLUR_MODE_MAX
};
@@ -84,8 +84,6 @@ private:
BLUR_FLAG_HORIZONTAL = (1 << 0),
BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1),
BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2),
- BLUR_FLAG_DOF_FAR = (1 << 3),
- BLUR_FLAG_DOF_NEAR = (1 << 4),
};
struct BlurRasterPushConstant {
@@ -103,19 +101,6 @@ private:
float glow_white;
float glow_luminance_cap;
float glow_auto_exposure_grey;
-
- //dof
- float dof_far_begin;
- float dof_far_end;
- float dof_near_begin;
- float dof_near_end;
-
- float dof_radius;
- float dof_pad[3];
-
- float dof_dir[2];
- float camera_z_far;
- float camera_z_near;
};
struct BlurRaster {
@@ -252,29 +237,29 @@ private:
};
struct TonemapPushConstant {
- float bcs[3];
- uint32_t use_bcs;
+ float bcs[3]; // 12 - 12
+ uint32_t use_bcs; // 4 - 16
- uint32_t use_glow;
- uint32_t use_auto_exposure;
- uint32_t use_color_correction;
- uint32_t tonemapper;
+ uint32_t use_glow; // 4 - 20
+ uint32_t use_auto_exposure; // 4 - 24
+ uint32_t use_color_correction; // 4 - 28
+ uint32_t tonemapper; // 4 - 32
- uint32_t glow_texture_size[2];
- float glow_intensity;
- uint32_t pad3;
+ uint32_t glow_texture_size[2]; // 8 - 40
+ float glow_intensity; // 4 - 44
+ uint32_t pad3; // 4 - 48
- uint32_t glow_mode;
- float glow_levels[7];
+ uint32_t glow_mode; // 4 - 52
+ float glow_levels[7]; // 28 - 80
- float exposure;
- float white;
- float auto_exposure_grey;
- uint32_t pad2;
+ float exposure; // 4 - 84
+ float white; // 4 - 88
+ float auto_exposure_grey; // 4 - 92
+ uint32_t pad2; // 4 - 96
- float pixel_size[2];
- uint32_t use_fxaa;
- uint32_t use_debanding;
+ float pixel_size[2]; // 8 - 104
+ uint32_t use_fxaa; // 4 - 108
+ uint32_t use_debanding; // 4 - 112
};
/* tonemap actually writes to a framebuffer, which is
@@ -336,8 +321,7 @@ private:
struct CopyToDPPushConstant {
float z_far;
float z_near;
- uint32_t z_flip;
- uint32_t pad;
+ float texel_size[2];
float screen_rect[4];
};
@@ -375,7 +359,9 @@ private:
enum BokehMode {
BOKEH_GEN_BLUR_SIZE,
BOKEH_GEN_BOKEH_BOX,
+ BOKEH_GEN_BOKEH_BOX_NOWEIGHT,
BOKEH_GEN_BOKEH_HEXAGONAL,
+ BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT,
BOKEH_GEN_BOKEH_CIRCULAR,
BOKEH_COMPOSITE,
BOKEH_MAX
@@ -383,9 +369,11 @@ private:
struct Bokeh {
BokehPushConstant push_constant;
- BokehDofShaderRD shader;
+ BokehDofShaderRD compute_shader;
+ BokehDofRasterShaderRD raster_shader;
RID shader_version;
- RID pipelines[BOKEH_MAX];
+ RID compute_pipelines[BOKEH_MAX];
+ PipelineCacheRD raster_pipelines[BOKEH_MAX];
} bokeh;
enum SSAOMode {
@@ -780,12 +768,31 @@ public:
void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
- void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip);
+ void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size);
+ void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip);
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
- void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
- void blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
+ struct BokehBuffers {
+ // bokeh buffers
+
+ // textures
+ Size2i base_texture_size;
+ RID base_texture;
+ RID depth_texture;
+ RID secondary_texture;
+ RID half_texture[2];
+
+ // raster only
+ RID base_fb;
+ RID secondary_fb; // with weights
+ RID half_fb[2]; // with weights
+ RID base_weight_fb;
+ RID weight_texture[4];
+ };
+
+ void bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
+ void bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
struct TonemapSettings {
bool use_glow = false;
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 0d304556c2..611f7c6494 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1533,6 +1533,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
+ if (scene_state.used_screen_texture) {
+ // Copy screen texture to backbuffer so we can read from it
+ _render_buffers_copy_screen_texture(p_render_data);
+ }
+
+ if (scene_state.used_depth_texture) {
+ // Copy depth texture to backbuffer so we can read from it
+ _render_buffers_copy_depth_texture(p_render_data);
+ }
+
RENDER_TIMESTAMP("Render Transparent Pass");
RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
@@ -2219,7 +2229,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID();
+ RID texture = (dbt.is_valid()) ? dbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
u.ids.push_back(texture);
uniforms.push_back(u);
}
@@ -3051,7 +3062,7 @@ RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
- defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
{
//lightmaps
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 89d14e871a..be18a73989 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -131,9 +131,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
- if (err != OK) {
- return;
- }
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index f810ae2454..2064d9c5c5 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -414,7 +414,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID();
+ RID texture = (dbt.is_valid()) ? dbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
u.ids.push_back(texture);
uniforms.push_back(u);
}
@@ -664,6 +665,23 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_pre_opaque_render(p_render_data, false, false, RID(), RID());
+ uint32_t spec_constant_base_flags = 0;
+
+ {
+ //figure out spec constants
+
+ if (p_render_data->directional_light_count > 0) {
+ if (p_render_data->directional_light_soft_shadows) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS;
+ }
+ } else {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
+ }
+
+ if (!is_environment(p_render_data->environment) || environment_is_fog_enabled(p_render_data->environment)) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
+ }
+ }
{
if (render_buffer) {
RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
@@ -706,7 +724,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -752,6 +770,16 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
}
+ if (scene_state.used_screen_texture) {
+ // Copy screen texture to backbuffer so we can read from it
+ _render_buffers_copy_screen_texture(p_render_data);
+ }
+
+ if (scene_state.used_depth_texture) {
+ // Copy depth texture to backbuffer so we can read from it
+ _render_buffers_copy_depth_texture(p_render_data);
+ }
+
// transparent pass
RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass");
@@ -760,7 +788,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (using_subpass_transparent) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -797,7 +825,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -924,7 +952,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
_render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
@@ -964,7 +992,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, 0);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -1005,7 +1033,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, 0);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -1079,7 +1107,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
{
//regular forward for now
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, 0);
_render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
}
RD::get_singleton()->draw_command_end_label();
@@ -1722,7 +1750,7 @@ void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_para
}
}
-void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, const GeometryInstanceForwardMobile *p_instance) {
+void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
// first zero out our indices
p_push_constant->omni_lights[0] = 0xFFFF;
@@ -1737,6 +1765,19 @@ void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceF
p_push_constant->reflection_probes[0] = 0xFFFF;
p_push_constant->reflection_probes[1] = 0xFFFF;
+ if (p_instance->omni_light_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
+ }
+ if (p_instance->spot_light_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
+ }
+ if (p_instance->reflection_probe_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
+ }
+ if (p_instance->decals_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
+ }
+
for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
uint32_t ofs = i < 4 ? 0 : 1;
uint32_t shift = (i & 0x3) << 3;
@@ -1784,6 +1825,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
const RenderElementInfo &element_info = p_params->element_info[i];
const GeometryInstanceForwardMobile *inst = surf->owner;
+ uint32_t base_spec_constants = p_params->spec_constant_base_flags;
+
// GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
GeometryInstanceForwardMobile::PushConstant push_constant;
@@ -1819,7 +1862,13 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
mesh_surface = surf->surface_shadow;
} else {
- _fill_push_constant_instance_indices(&push_constant, inst);
+ if (inst->use_projector) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_USING_PROJECTOR;
+ }
+ if (inst->use_soft_shadow) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
+ }
+ _fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
@@ -1911,7 +1960,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_index_array_rd = index_array_rd;
}
- RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass);
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass, base_spec_constants);
if (pipeline_rd != prev_pipeline_rd) {
// checking with prev shader does not make so much sense, as
@@ -2170,6 +2219,11 @@ void RenderForwardMobile::geometry_instance_pair_voxel_gi_instances(GeometryInst
}
void RenderForwardMobile::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->use_projector = p_projector;
+ ginstance->use_soft_shadow = p_softshadow;
}
void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
@@ -2548,12 +2602,12 @@ void RenderForwardMobile::_update_shader_quality_settings() {
spec_constants.push_back(sc);
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
- sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
+ sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
- sc.constant_id = SPEC_CONSTANT_PROJECTOR_FILTER;
+ sc.constant_id = SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS;
sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
@@ -2576,7 +2630,7 @@ RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
// defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
- defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
{
//lightmaps
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index b981592840..764d8e80df 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -65,12 +65,27 @@ protected:
};
enum {
- SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
- SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
- SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 8,
- SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 9,
- SPEC_CONSTANT_DECAL_FILTER = 10,
- SPEC_CONSTANT_PROJECTOR_FILTER = 11,
+
+ SPEC_CONSTANT_USING_PROJECTOR = 0,
+ SPEC_CONSTANT_USING_SOFT_SHADOWS = 1,
+ SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS = 2,
+
+ SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 3,
+ SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 4,
+ SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 5,
+ SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 6,
+
+ SPEC_CONSTANT_DECAL_USE_MIPMAPS = 7,
+ SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS = 8,
+
+ SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 9,
+ SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 10,
+ SPEC_CONSTANT_DISABLE_REFLECTION_PROBES = 11,
+ SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 12,
+
+ SPEC_CONSTANT_DISABLE_DECALS = 13,
+ SPEC_CONSTANT_DISABLE_FOG = 14,
+
};
enum {
@@ -159,6 +174,7 @@ protected:
bool force_wireframe = false;
Vector2 uv_offset;
Plane lod_plane;
+ uint32_t spec_constant_base_flags = 0;
float lod_distance_multiplier = 0.0;
float screen_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
@@ -166,7 +182,7 @@ protected:
uint32_t barrier = RD::BARRIER_MASK_ALL;
uint32_t subpass = 0;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -182,6 +198,7 @@ protected:
screen_lod_threshold = p_screen_lod_threshold;
element_offset = p_element_offset;
barrier = p_barrier;
+ spec_constant_base_flags = p_spec_constant_base_flags;
}
};
@@ -526,6 +543,8 @@ protected:
RID transforms_uniform_set;
float depth = 0;
bool mirror = false;
+ bool use_projector = false;
+ bool use_soft_shadow = false;
Transform3D transform;
bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform
bool non_uniform_scale = false;
@@ -584,7 +603,7 @@ protected:
dirty_list_element(this) {}
};
- _FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, const GeometryInstanceForwardMobile *p_instance);
+ _FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
void _update_shader_quality_settings() override;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index bcdcb05653..735014a2ec 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -135,8 +135,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 14b2768c29..f8aefdb29c 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1970,8 +1970,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton;
Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = canvas_singleton->shader.canvas_shader.version_create();
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 02d548bf13..62e9386f95 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -281,6 +281,8 @@ RendererCompositorRD::RendererCompositorRD() {
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
}
+ scene->init();
+
// now we're ready to create our effects,
storage->init_effects(!scene->_render_buffers_can_be_storage());
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
index 98d08f68e8..098e2a5c87 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -2812,8 +2812,6 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
{
//kinda complicated to compute the amount of slots, we try to use as many as we can
- voxel_gi_max_lights = 32;
-
voxel_gi_lights = memnew_arr(VoxelGILight, voxel_gi_max_lights);
voxel_gi_lights_uniform = RD::get_singleton()->uniform_buffer_create(voxel_gi_max_lights * sizeof(VoxelGILight));
voxel_gi_quality = RS::VoxelGIQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/voxel_gi/quality")), 0, 1));
@@ -3009,7 +3007,9 @@ void RendererSceneGIRD::free() {
sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
- memdelete_arr(voxel_gi_lights);
+ if (voxel_gi_lights) {
+ memdelete_arr(voxel_gi_lights);
+ }
}
RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
index 128bf09063..0b4622646f 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
@@ -110,8 +110,8 @@ private:
float pad[3];
};
- VoxelGILight *voxel_gi_lights;
- uint32_t voxel_gi_max_lights;
+ VoxelGILight *voxel_gi_lights = nullptr;
+ uint32_t voxel_gi_max_lights = 32;
RID voxel_gi_lights_uniform;
enum {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 057d108578..8496ef631b 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -860,7 +860,7 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool
shadow_atlas->shadow_owners.clear();
shadow_atlas->size = p_size;
- shadow_atlas->use_16_bits = p_size;
+ shadow_atlas->use_16_bits = p_16_bits;
}
void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
@@ -935,7 +935,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,
//look for an empty space
int sc = shadow_atlas->quadrants[qidx].shadows.size();
- ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw();
+ const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
int found_free_idx = -1; //found a free one
int found_used_idx = -1; //found existing one, must steal it
@@ -980,6 +980,78 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,
return false;
}
+bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
+ for (int i = p_quadrant_count - 1; i >= 0; i--) {
+ int qidx = p_in_quadrants[i];
+
+ if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+ return false;
+ }
+
+ //look for an empty space
+ int sc = shadow_atlas->quadrants[qidx].shadows.size();
+ const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
+
+ int found_idx = -1;
+ uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair
+
+ for (int j = 0; j < sc - 1; j++) {
+ uint64_t pass = 0;
+
+ if (sarr[j].owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.getornull(sarr[j].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass == scene_pass) {
+ continue;
+ }
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+ pass += sli->last_scene_pass;
+ }
+
+ if (sarr[j + 1].owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.getornull(sarr[j + 1].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass == scene_pass) {
+ continue;
+ }
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+ pass += sli->last_scene_pass;
+ }
+
+ if (found_idx == -1 || pass < min_pass) {
+ found_idx = j;
+ min_pass = pass;
+
+ // we found two empty spots, no need to check the rest
+ if (pass == 0) {
+ break;
+ }
+ }
+ }
+
+ if (found_idx == -1) {
+ continue; //nothing found
+ }
+
+ r_quadrant = qidx;
+ r_shadow = found_idx;
+
+ return true;
+ }
+
+ return false;
+}
+
bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
ERR_FAIL_COND_V(!shadow_atlas, false);
@@ -1025,94 +1097,104 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i
uint64_t tick = OS::get_singleton()->get_ticks_msec();
- //see if it already exists
+ uint32_t old_key = ShadowAtlas::SHADOW_INVALID;
+ uint32_t old_quadrant = ShadowAtlas::SHADOW_INVALID;
+ uint32_t old_shadow = ShadowAtlas::SHADOW_INVALID;
+ int old_subdivision = -1;
+
+ bool should_realloc = false;
+ bool should_redraw = false;
if (shadow_atlas->shadow_owners.has(p_light_intance)) {
- //it does!
- uint32_t key = shadow_atlas->shadow_owners[p_light_intance];
- uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
+ old_key = shadow_atlas->shadow_owners[p_light_intance];
+ old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK;
- bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
- bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version;
+ should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
+ should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version;
if (!should_realloc) {
- shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version;
//already existing, see if it should redraw or it's just OK
return should_redraw;
}
- int new_quadrant, new_shadow;
+ old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision;
+ }
- //find a better place
- if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) {
- //found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- if (sh->owner.is_valid()) {
- //is taken, but is invalid, erasing it
- shadow_atlas->shadow_owners.erase(sh->owner);
- LightInstance *sli = light_instance_owner.getornull(sh->owner);
- sli->shadow_atlases.erase(p_atlas);
- }
+ bool is_omni = li->light_type == RS::LIGHT_OMNI;
+ bool found_shadow = false;
+ int new_quadrant = -1;
+ int new_shadow = -1;
- //erase previous
- shadow_atlas->quadrants[q].shadows.write[s].version = 0;
- shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+ if (is_omni) {
+ found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
+ } else {
+ found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
+ }
- sh->owner = p_light_intance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
- li->shadow_atlases.insert(p_atlas);
-
- //make new key
- key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- key |= new_shadow;
- //update it in map
- shadow_atlas->shadow_owners[p_light_intance] = key;
- //make it dirty, as it should redraw anyway
- return true;
+ if (found_shadow) {
+ if (old_quadrant != ShadowAtlas::SHADOW_INVALID) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID();
+
+ if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID();
+ }
}
- //no better place for this shadow found, keep current
+ uint32_t new_key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
+ new_key |= new_shadow;
- //already existing, see if it should redraw or it's just OK
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow);
- shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+ sh->owner = p_light_intance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
- return should_redraw;
- }
+ if (is_omni) {
+ new_key |= ShadowAtlas::OMNI_LIGHT_FLAG;
- int new_quadrant, new_shadow;
+ int new_omni_shadow = new_shadow + 1;
+ ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow];
+ _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow);
- //find a better place
- if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) {
- //found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- if (sh->owner.is_valid()) {
- //is taken, but is invalid, erasing it
- shadow_atlas->shadow_owners.erase(sh->owner);
- LightInstance *sli = light_instance_owner.getornull(sh->owner);
- sli->shadow_atlases.erase(p_atlas);
+ extra_sh->owner = p_light_intance;
+ extra_sh->alloc_tick = tick;
+ extra_sh->version = p_light_version;
}
- sh->owner = p_light_intance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
li->shadow_atlases.insert(p_atlas);
- //make new key
- uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- key |= new_shadow;
//update it in map
- shadow_atlas->shadow_owners[p_light_intance] = key;
+ shadow_atlas->shadow_owners[p_light_intance] = new_key;
//make it dirty, as it should redraw anyway
-
return true;
}
- //no place to allocate this light, apologies
+ return should_redraw;
+}
- return false;
+void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) {
+ if (p_shadow->owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.getornull(p_shadow->owner);
+ uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner];
+
+ if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ uint32_t s = old_key & ShadowAtlas::SHADOW_INDEX_MASK;
+ uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1);
+ RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx];
+ omni_shadow->version = 0;
+ omni_shadow->owner = RID();
+ }
+
+ p_shadow->version = 0;
+ p_shadow->owner = RID();
+ sli->shadow_atlases.erase(p_atlas);
+ p_shadow_atlas->shadow_owners.erase(p_shadow->owner);
+ }
}
void RendererSceneRenderRD::_update_directional_shadow_atlas() {
@@ -1137,6 +1219,7 @@ void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p
}
directional_shadow.size = p_size;
+ directional_shadow.use_16_bits = p_16_bits;
if (directional_shadow.depth.is_valid()) {
RD::get_singleton()->free(directional_shadow.depth);
@@ -1464,6 +1547,85 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
base_width = MAX(1, base_width >> 1);
base_height = MAX(1, base_height >> 1);
}
+
+ if (!_render_buffers_can_be_storage()) {
+ // create 4 weight textures, 2 full size, 2 half size
+
+ tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
+ tf.array_layers = rb->view_count;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tf.mipmaps = 1;
+ for (uint32_t i = 0; i < 4; i++) {
+ // associated blur texture
+ RID texture;
+ if (i == 0) {
+ texture = rb->texture;
+ } else if (i == 1) {
+ texture = rb->blur[0].mipmaps[0].texture;
+ } else if (i == 2) {
+ texture = rb->blur[1].mipmaps[0].texture;
+ } else if (i == 3) {
+ texture = rb->blur[0].mipmaps[1].texture;
+ }
+
+ // create weight texture
+ rb->weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ // create frame buffer
+ Vector<RID> fb;
+ fb.push_back(texture);
+ fb.push_back(rb->weight_buffers[i].weight);
+ rb->weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb);
+
+ if (i == 1) {
+ // next 2 are half size
+ tf.width = MAX(1, tf.width >> 1);
+ tf.height = MAX(1, tf.height >> 1);
+ }
+ }
+
+ {
+ // and finally an FB for just our base weights
+ Vector<RID> fb;
+ fb.push_back(rb->weight_buffers[0].weight);
+ rb->base_weight_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ }
+}
+
+void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *rb) {
+ ERR_FAIL_COND(!rb->depth_back_texture.is_null());
+
+ {
+ RD::TextureFormat tf;
+ if (rb->view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
+ // We're not using this as a depth stencil, just copying our data into this. May need to look into using a different format on mobile, maybe R16?
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+ tf.array_layers = rb->view_count; // create a layer for every view
+
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // set this as color attachment because we're copying data into it, it's not actually used as a depth buffer
+
+ rb->depth_back_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ if (!_render_buffers_can_be_storage()) {
+ // create framebuffer so we can write into this...
+
+ Vector<RID> fb;
+ fb.push_back(rb->depth_back_texture);
+
+ rb->depth_back_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count);
+ }
}
void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
@@ -1532,6 +1694,16 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
rb->depth_texture = RID();
}
+ if (rb->depth_back_fb.is_valid()) {
+ RD::get_singleton()->free(rb->depth_back_fb);
+ rb->depth_back_fb = RID();
+ }
+
+ if (rb->depth_back_texture.is_valid()) {
+ RD::get_singleton()->free(rb->depth_back_texture);
+ rb->depth_back_texture = RID();
+ }
+
for (int i = 0; i < 2; i++) {
for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) {
// do we free the texture slice here? or is it enough to free the main texture?
@@ -1832,6 +2004,58 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set);
}
+void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ RD::get_singleton()->draw_command_begin_label("Copy screen texture");
+
+ if (rb->blur[0].texture.is_null()) {
+ _allocate_blur_textures(rb);
+ }
+
+ // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
+
+ bool can_use_storage = _render_buffers_can_be_storage();
+
+ if (can_use_storage) {
+ storage->get_effects()->copy_to_rect(rb->texture, rb->blur[0].mipmaps[0].texture, Rect2i(0, 0, rb->width, rb->height));
+ for (int i = 1; i < rb->blur[0].mipmaps.size(); i++) {
+ storage->get_effects()->make_mipmap(rb->blur[0].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i].texture, Size2i(rb->blur[0].mipmaps[i].width, rb->blur[0].mipmaps[i].height));
+ }
+ } else {
+ storage->get_effects()->copy_to_fb_rect(rb->texture, rb->blur[0].mipmaps[0].fb, Rect2i(0, 0, rb->width, rb->height));
+ for (int i = 1; i < rb->blur[0].mipmaps.size(); i++) {
+ storage->get_effects()->make_mipmap_raster(rb->blur[0].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i].fb, Size2i(rb->blur[0].mipmaps[i].width, rb->blur[0].mipmaps[i].height));
+ }
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ RD::get_singleton()->draw_command_begin_label("Copy depth texture");
+
+ if (rb->depth_back_texture.is_null()) {
+ _allocate_depth_backbuffer_textures(rb);
+ }
+
+ // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
+
+ bool can_use_storage = _render_buffers_can_be_storage();
+
+ if (can_use_storage) {
+ storage->get_effects()->copy_to_rect(rb->depth_texture, rb->depth_back_texture, Rect2i(0, 0, rb->width, rb->height));
+ } else {
+ storage->get_effects()->copy_to_fb_rect(rb->depth_texture, rb->depth_back_fb, Rect2i(0, 0, rb->width, rb->height));
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
ERR_FAIL_COND(!rb);
@@ -1851,11 +2075,34 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
_allocate_blur_textures(rb);
}
+ EffectsRD::BokehBuffers buffers;
+
+ // textures we use
+ buffers.base_texture_size = Size2i(rb->width, rb->height);
+ buffers.base_texture = rb->texture;
+ buffers.depth_texture = rb->depth_texture;
+ buffers.secondary_texture = rb->blur[0].mipmaps[0].texture;
+ buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture;
+ buffers.half_texture[1] = rb->blur[0].mipmaps[1].texture;
+
+ float bokeh_size = camfx->dof_blur_amount * 64.0;
if (can_use_storage) {
- float bokeh_size = camfx->dof_blur_amount * 64.0;
- storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ storage->get_effects()->bokeh_dof(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
} else {
- storage->get_effects()->blur_dof_raster(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->texture_fb, rb->blur[0].mipmaps[0].texture, rb->blur[0].mipmaps[0].fb, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, camfx->dof_blur_amount, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ // set framebuffers
+ buffers.base_fb = rb->texture_fb;
+ buffers.secondary_fb = rb->weight_buffers[1].fb;
+ buffers.half_fb[0] = rb->weight_buffers[2].fb;
+ buffers.half_fb[1] = rb->weight_buffers[3].fb;
+ buffers.weight_texture[0] = rb->weight_buffers[0].weight;
+ buffers.weight_texture[1] = rb->weight_buffers[1].weight;
+ buffers.weight_texture[2] = rb->weight_buffers[2].weight;
+ buffers.weight_texture[3] = rb->weight_buffers[3].weight;
+
+ // set weight buffers
+ buffers.base_weight_fb = rb->base_weight_fb;
+
+ storage->get_effects()->bokeh_dof_raster(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -2157,6 +2404,15 @@ RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_b
return rb->blur[0].texture;
}
+RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_buffers) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, RID());
+ if (!rb->depth_back_texture.is_valid()) {
+ return RID(); //not valid at the moment
+ }
+ return rb->depth_back_texture;
+}
+
RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
@@ -2947,18 +3203,19 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.shadow_enabled = true;
- if (type == RS::LIGHT_SPOT) {
- light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0);
+ float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
+ light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0;
- } else { //omni
+ if (type == RS::LIGHT_SPOT) {
light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0;
- float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
- light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space
+ } else { //omni
+ light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS);
}
light_data.transmittance_bias = storage->light_get_transmittance_bias(base);
- Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas);
+ Vector2i omni_offset;
+ Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas, omni_offset);
light_data.atlas_rect[0] = rect.position.x;
light_data.atlas_rect[1] = rect.position.y;
@@ -2969,7 +3226,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base);
if (type == RS::LIGHT_OMNI) {
- light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
Transform3D proj = (inverse_transform * light_transform).inverse();
RendererStorageRD::store_transform(proj, light_data.shadow_matrix);
@@ -2981,6 +3237,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
}
+ light_data.direction[0] = omni_offset.x * float(rect.size.width);
+ light_data.direction[1] = omni_offset.y * float(rect.size.height);
} else if (type == RS::LIGHT_SPOT) {
Transform3D modelview = (inverse_transform * light_transform).inverse();
CameraMatrix bias;
@@ -3893,7 +4151,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
render_state.voxel_gi_count = 0;
- if (rb != nullptr) {
+ if (rb != nullptr && is_dynamic_gi_supported()) {
if (rb->sdfgi) {
rb->sdfgi->update_cascades();
rb->sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
@@ -3966,6 +4224,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
bool using_dual_paraboloid = false;
bool using_dual_paraboloid_flip = false;
+ Vector2i dual_paraboloid_offset;
RID render_fb;
RID render_texture;
float zfar;
@@ -4059,6 +4318,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) {
+ bool wrap = (shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision == 0;
+ dual_paraboloid_offset = wrap ? Vector2i(1 - shadow_atlas->quadrants[quadrant].subdivision, 1) : Vector2i(1, 0);
+
if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) {
ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2);
@@ -4078,12 +4340,16 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
}
} else {
+ atlas_rect.position.x += 1;
+ atlas_rect.position.y += 1;
+ atlas_rect.size.x -= 2;
+ atlas_rect.size.y -= 2;
+
+ atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
+
light_projection = light_instance->shadow_transform[0].camera;
light_transform = light_instance->shadow_transform[0].transform;
- atlas_rect.size.height /= 2;
- atlas_rect.position.y += p_pass * atlas_rect.size.height;
-
using_dual_paraboloid = true;
using_dual_paraboloid_flip = p_pass == 1;
render_fb = shadow_atlas->fb;
@@ -4112,10 +4378,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
atlas_rect_norm.position.y /= float(atlas_size);
atlas_rect_norm.size.x /= float(atlas_size);
atlas_rect_norm.size.y /= float(atlas_size);
- atlas_rect_norm.size.height /= 2;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), false);
- atlas_rect_norm.position.y += atlas_rect_norm.size.height;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), true);
+ storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
+ storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
//restore transform so it can be properly used
light_instance_set_shadow_transform(p_light, CameraMatrix(), light_instance->transform, zfar, 0, 0, 0);
@@ -4217,6 +4482,12 @@ bool RendererSceneRenderRD::free(RID p_rid) {
uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+
+ if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ // Omni lights use two atlas spots, make sure to clear the other as well
+ shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID();
+ }
+
shadow_atlas->shadow_owners.erase(p_rid);
}
@@ -4414,10 +4685,12 @@ uint32_t RendererSceneRenderRD::get_max_elements() const {
}
RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
- max_cluster_elements = get_max_elements();
-
storage = p_storage;
singleton = this;
+}
+
+void RendererSceneRenderRD::init() {
+ max_cluster_elements = get_max_elements();
directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 336dd6e1a7..37533baecf 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -134,6 +134,8 @@ protected:
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer);
+ void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
+ void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data);
void _disable_clear_request(const RenderDataRD *p_render_data);
@@ -253,7 +255,8 @@ private:
struct ShadowAtlas {
enum {
QUADRANT_SHIFT = 27,
- SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1,
+ OMNI_LIGHT_FLAG = 1 << 26,
+ SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
SHADOW_INVALID = 0xFFFFFFFF
};
@@ -297,7 +300,9 @@ private:
void _update_shadow_atlas(ShadowAtlas *shadow_atlas);
+ void _shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
+ bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
@@ -377,10 +382,6 @@ private:
uint32_t cull_mask = 0;
uint32_t light_directional_index = 0;
- uint32_t current_shadow_atlas_key = 0;
-
- Vector2 dp;
-
Rect2 directional_rect;
Set<RID> shadow_atlases; //shadow atlases where this light is registered
@@ -483,6 +484,18 @@ private:
Blur blur[2]; //the second one starts from the first mipmap
+ struct WeightBuffers {
+ RID weight;
+ RID fb; // FB with both texture and weight
+ };
+
+ // 2 full size, 2 half size
+ WeightBuffers weight_buffers[4]; // Only used in raster
+ RID base_weight_fb; // base buffer for weight
+
+ RID depth_back_texture;
+ RID depth_back_fb; // only used on mobile
+
struct Luminance {
Vector<RID> reduce;
RID current;
@@ -526,6 +539,7 @@ private:
void _free_render_buffer_data(RenderBuffers *rb);
void _allocate_blur_textures(RenderBuffers *rb);
+ void _allocate_depth_backbuffer_textures(RenderBuffers *rb);
void _allocate_luminance_textures(RenderBuffers *rb);
void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
@@ -560,7 +574,7 @@ private:
struct LightData {
float position[3];
float inv_radius;
- float direction[3];
+ float direction[3]; // in omni, x and y are used for dual paraboloid offset
float size;
float color[3];
@@ -949,7 +963,7 @@ public:
return li->transform;
}
- _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas) {
+ _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
LightInstance *li = light_instance_owner.getornull(p_light_instance);
uint32_t key = shadow_atlas->shadow_owners[li->self];
@@ -969,6 +983,16 @@ public:
x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
+ if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) {
+ r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision);
+ r_omni_offset.y = 1;
+ } else {
+ r_omni_offset.x = 1;
+ r_omni_offset.y = 0;
+ }
+ }
+
uint32_t width = shadow_size;
uint32_t height = shadow_size;
@@ -1174,6 +1198,7 @@ public:
RID render_buffers_get_ao_texture(RID p_render_buffers);
RID render_buffers_get_back_buffer_texture(RID p_render_buffers);
+ RID render_buffers_get_back_depth_texture(RID p_render_buffers);
RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers);
RID render_buffers_get_default_voxel_gi_buffer();
RID render_buffers_get_gi_ambient_texture(RID p_render_buffers);
@@ -1274,6 +1299,8 @@ public:
virtual bool is_volumetric_supported() const;
virtual uint32_t get_max_elements() const;
+ void init();
+
RendererSceneRenderRD(RendererStorageRD *p_storage);
~RendererSceneRenderRD();
};
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index 9331cab090..9e85608f1e 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -92,8 +92,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = scene_singleton->sky.sky_shader.shader.version_create();
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 096d5563e6..8cc20618fc 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -5268,8 +5268,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
actions.uniforms = &uniforms;
Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = base_singleton->particles_shader.shader.version_create();
@@ -9311,15 +9310,6 @@ RendererStorageRD::RendererStorageRD() {
}
}
- {
- Vector<String> sdf_versions;
- sdf_versions.push_back(""); //one only
- voxel_gi_sdf_shader.initialize(sdf_versions);
- voxel_gi_sdf_shader_version = voxel_gi_sdf_shader.version_create();
- voxel_gi_sdf_shader_version_shader = voxel_gi_sdf_shader.version_get_shader(voxel_gi_sdf_shader_version, 0);
- voxel_gi_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(voxel_gi_sdf_shader_version_shader);
- }
-
using_lightmap_array = true; // high end
if (using_lightmap_array) {
uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
@@ -9539,7 +9529,6 @@ RendererStorageRD::~RendererStorageRD() {
RD::get_singleton()->free(mesh_default_rd_buffers[i]);
}
- voxel_gi_sdf_shader.version_free(voxel_gi_sdf_shader_version);
particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
rt_sdf.shader.version_free(rt_sdf.shader_version);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index c048be5dc8..02395a884f 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -668,14 +668,14 @@ private:
};
uint32_t emitting;
- double system_phase;
- double prev_system_phase;
+ float system_phase;
+ float prev_system_phase;
uint32_t cycle;
real_t explosiveness;
real_t randomness;
- double time;
- double delta;
+ float time;
+ float delta;
uint32_t frame;
uint32_t pad0;
@@ -812,7 +812,7 @@ private:
struct ParticlesShader {
struct PushConstant {
- double lifetime;
+ float lifetime;
uint32_t clear;
uint32_t total_particles;
uint32_t trail_size;
@@ -1100,11 +1100,6 @@ private:
Dependency dependency;
};
- VoxelGiSdfShaderRD voxel_gi_sdf_shader;
- RID voxel_gi_sdf_shader_version;
- RID voxel_gi_sdf_shader_version_shader;
- RID voxel_gi_sdf_shader_pipeline;
-
mutable RID_Owner<VoxelGI, true> voxel_gi_owner;
/* REFLECTION PROBE */
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index 8aa03b6426..bad37f5c25 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -213,7 +213,7 @@ static String _interpstr(SL::DataInterpolation p_interp) {
return "";
}
-static String _prestr(SL::DataPrecision p_pres) {
+static String _prestr(SL::DataPrecision p_pres, bool p_force_highp = false) {
switch (p_pres) {
case SL::PRECISION_LOWP:
return "lowp ";
@@ -222,7 +222,7 @@ static String _prestr(SL::DataPrecision p_pres) {
case SL::PRECISION_HIGHP:
return "highp ";
case SL::PRECISION_DEFAULT:
- return "";
+ return p_force_highp ? "highp " : "";
}
return "";
}
@@ -617,7 +617,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
//this is an integer to index the global table
ucode += _typestr(ShaderLanguage::TYPE_UINT);
} else {
- ucode += _prestr(uniform.precision);
+ ucode += _prestr(uniform.precision, ShaderLanguage::is_float_type(uniform.type));
ucode += _typestr(uniform.type);
}
@@ -742,7 +742,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
String vcode;
String interp_mode = _interpstr(varying.interpolation);
- vcode += _prestr(varying.precision);
+ vcode += _prestr(varying.precision, ShaderLanguage::is_float_type(varying.type));
vcode += _typestr(varying.type);
vcode += " " + _mkid(varying_name);
if (varying.array_size > 0) {
@@ -777,7 +777,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
const SL::ShaderNode::Constant &cnode = pnode->vconstants[i];
String gcode;
gcode += "const ";
- gcode += _prestr(cnode.precision);
+ gcode += _prestr(cnode.precision, ShaderLanguage::is_float_type(cnode.type));
if (cnode.type == SL::TYPE_STRUCT) {
gcode += _mkid(cnode.type_str);
} else {
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index 5bb12fc168..82efa1318c 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -279,7 +279,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
return;
}
- Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(stages);
+ Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(stages, name + ":" + itos(p_variant));
ERR_FAIL_COND(shader_data.size() == 0);
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index 44705b2bd6..529328f0ed 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -142,9 +142,7 @@ public:
ERR_FAIL_COND_V(!variants_enabled[p_variant], RID());
Version *version = version_owner.getornull(p_version);
- if (!version) {
- return RID();
- }
+ ERR_FAIL_COND_V(!version, RID());
if (version->dirty) {
_compile_version(version);
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
index b1d1c2365e..0789a4b396 100644
--- a/servers/rendering/renderer_rd/shaders/blur_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
@@ -37,32 +37,6 @@ layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(location = 0) out vec4 frag_color;
-//DOF
-#ifdef MODE_DOF_BLUR
-
-layout(set = 1, binding = 0) uniform sampler2D dof_source_depth;
-
-#ifdef DOF_QUALITY_LOW
-const int dof_kernel_size = 5;
-const int dof_kernel_from = 2;
-const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388);
-#endif
-
-#ifdef DOF_QUALITY_MEDIUM
-const int dof_kernel_size = 11;
-const int dof_kernel_from = 5;
-const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037);
-
-#endif
-
-#ifdef DOF_QUALITY_HIGH
-const int dof_kernel_size = 21;
-const int dof_kernel_from = 10;
-const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174);
-#endif
-
-#endif
-
void main() {
#ifdef MODE_MIPMAP
@@ -155,74 +129,8 @@ void main() {
#endif
-#ifdef MODE_DOF_BLUR
-
- vec4 color_accum = vec4(0.0);
-
- float depth = texture(dof_source_depth, uv_interp, 0.0).r;
- depth = depth * 2.0 - 1.0;
-
- if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
- depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
- } else {
- depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near));
- }
-
- // mix near and far blur amount
- float amount = 1.0;
- if (bool(blur.flags & FLAG_DOF_FAR)) {
- amount *= 1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, depth);
- }
- if (bool(blur.flags & FLAG_DOF_NEAR)) {
- amount *= smoothstep(blur.dof_near_end, blur.dof_near_begin, depth);
- }
- amount = 1.0 - amount;
-
- if (amount > 0.0) {
- float k_accum = 0.0;
-
- for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius;
-
- float tap_k = dof_kernel[i];
-
- float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
-
- if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
- tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
- } else {
- tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near));
- }
-
- // mix near and far blur amount
- float tap_amount = 1.0;
- if (bool(blur.flags & FLAG_DOF_FAR)) {
- tap_amount *= mix(1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, tap_depth), 0.0, int_ofs == 0);
- }
- if (bool(blur.flags & FLAG_DOF_NEAR)) {
- tap_amount *= mix(smoothstep(blur.dof_near_end, blur.dof_near_begin, tap_depth), 0.0, int_ofs == 0);
- }
- tap_amount = 1.0 - tap_amount;
-
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
- vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k;
-
- k_accum += tap_k * tap_amount;
- color_accum += tap_color * tap_amount;
- }
-
- if (k_accum > 0.0) {
- color_accum /= k_accum;
- }
-
- frag_color = color_accum; ///k_accum;
- } else {
- // we are in focus, don't waste time
- frag_color = texture(source_color, uv_interp, 0.0);
- }
-
+#ifdef MODE_COPY
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
+ frag_color = color;
#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
index 6ea968e595..52bf2886b5 100644
--- a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
@@ -1,8 +1,6 @@
#define FLAG_HORIZONTAL (1 << 0)
#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1)
#define FLAG_GLOW_FIRST_PASS (1 << 2)
-#define FLAG_DOF_FAR (1 << 3)
-#define FLAG_DOF_NEAR (1 << 4)
layout(push_constant, binding = 1, std430) uniform Blur {
vec2 pixel_size;
@@ -19,18 +17,5 @@ layout(push_constant, binding = 1, std430) uniform Blur {
float glow_white;
float glow_luminance_cap;
float glow_auto_exposure_grey;
-
- // DOF.
- float dof_far_begin;
- float dof_far_end;
- float dof_near_begin;
- float dof_near_end;
-
- float dof_radius;
- float dof_pad[3];
-
- vec2 dof_dir;
- float camera_z_far;
- float camera_z_near;
}
blur;
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
index b70e0b6bd5..0438671dd2 100644
--- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
@@ -25,34 +25,7 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
// based on https://www.shadertoy.com/view/Xd3GDl
-layout(push_constant, binding = 1, std430) uniform Params {
- ivec2 size;
- float z_far;
- float z_near;
-
- bool orthogonal;
- float blur_size;
- float blur_scale;
- int blur_steps;
-
- bool blur_near_active;
- float blur_near_begin;
- float blur_near_end;
- bool blur_far_active;
-
- float blur_far_begin;
- float blur_far_end;
- bool second_pass;
- bool half_size;
-
- bool use_jitter;
- float jitter_seed;
- uint pad[2];
-}
-params;
-
-//used to work around downsampling filter
-#define DEPTH_GAP 0.0
+#include "bokeh_dof_inc.glsl"
#ifdef MODE_GEN_BLUR_SIZE
@@ -80,15 +53,6 @@ float get_blur_size(float depth) {
#endif
-const float GOLDEN_ANGLE = 2.39996323;
-
-//note: uniform pdf rand [0;1[
-float hash12n(vec2 p) {
- p = fract(p * vec2(5.3987, 5.4421));
- p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
- return fract(p.x * p.y * 95.4307);
-}
-
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl
new file mode 100644
index 0000000000..fadea1631c
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_inc.glsl
@@ -0,0 +1,37 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+ ivec2 size;
+ float z_far;
+ float z_near;
+
+ bool orthogonal;
+ float blur_size;
+ float blur_scale;
+ int blur_steps;
+
+ bool blur_near_active;
+ float blur_near_begin;
+ float blur_near_end;
+ bool blur_far_active;
+
+ float blur_far_begin;
+ float blur_far_end;
+ bool second_pass;
+ bool half_size;
+
+ bool use_jitter;
+ float jitter_seed;
+ uint pad[2];
+}
+params;
+
+//used to work around downsampling filter
+#define DEPTH_GAP 0.0
+
+const float GOLDEN_ANGLE = 2.39996323;
+
+//note: uniform pdf rand [0;1[
+float hash12n(vec2 p) {
+ p = fract(p * vec2(5.3987, 5.4421));
+ p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
+ return fract(p.x * p.y * 95.4307);
+}
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl
new file mode 100644
index 0000000000..a3b3938ee9
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl
@@ -0,0 +1,253 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "bokeh_dof_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "bokeh_dof_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+#ifdef MODE_GEN_BLUR_SIZE
+layout(location = 0) out float weight;
+
+layout(set = 0, binding = 0) uniform sampler2D source_depth;
+#else
+layout(location = 0) out vec4 frag_color;
+#ifdef OUTPUT_WEIGHT
+layout(location = 1) out float weight;
+#endif
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+layout(set = 1, binding = 0) uniform sampler2D source_weight;
+#ifdef MODE_COMPOSITE_BOKEH
+layout(set = 2, binding = 0) uniform sampler2D original_weight;
+#endif
+#endif
+
+//DOF
+// Bokeh single pass implementation based on https://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html
+
+#ifdef MODE_GEN_BLUR_SIZE
+
+float get_depth_at_pos(vec2 uv) {
+ float depth = textureLod(source_depth, uv, 0.0).x;
+ if (params.orthogonal) {
+ depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ } else {
+ depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
+ }
+ return depth;
+}
+
+float get_blur_size(float depth) {
+ if (params.blur_near_active && depth < params.blur_near_begin) {
+ return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
+ }
+
+ if (params.blur_far_active && depth > params.blur_far_begin) {
+ return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ }
+
+ return 0.0;
+}
+
+#endif
+
+#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
+
+vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
+ dir *= pixel_size;
+ vec4 color = texture(source_color, uv);
+ color.a = texture(source_weight, uv).r;
+
+ vec4 accum = color;
+ float total = 1.0;
+
+ float blur_scale = params.blur_size / float(params.blur_steps);
+
+ if (params.use_jitter) {
+ uv += dir * (hash12n(uv + params.jitter_seed) - 0.5);
+ }
+
+ for (int i = -params.blur_steps; i <= params.blur_steps; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float radius = float(i) * blur_scale;
+ vec2 suv = uv + dir * radius;
+ radius = abs(radius);
+
+ vec4 sample_color = texture(source_color, suv);
+ sample_color.a = texture(source_weight, suv).r;
+ float limit;
+
+ if (sample_color.a < color.a) {
+ limit = abs(sample_color.a);
+ } else {
+ limit = abs(color.a);
+ }
+
+ limit -= DEPTH_GAP;
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, limit);
+
+ accum += mix(color, sample_color, m);
+
+ total += 1.0;
+ }
+
+ return accum / total;
+}
+
+#endif
+
+void main() {
+ vec2 pixel_size = 1.0 / vec2(params.size);
+ vec2 uv = uv_interp;
+
+#ifdef MODE_GEN_BLUR_SIZE
+ uv += pixel_size * 0.5;
+ float center_depth = get_depth_at_pos(uv);
+ weight = get_blur_size(center_depth);
+#endif
+
+#ifdef MODE_BOKEH_BOX
+ //pixel_size*=0.5; //resolution is doubled
+ if (params.second_pass || !params.half_size) {
+ uv += pixel_size * 0.5; //half pixel to read centers
+ } else {
+ uv += pixel_size * 0.25; //half pixel to read centers from full res
+ }
+
+ float alpha = texture(source_color, uv).a; // retain this
+ vec2 dir = (params.second_pass ? vec2(0.0, 1.0) : vec2(1.0, 0.0));
+
+ vec4 color = weighted_filter_dir(dir, uv, pixel_size);
+
+ frag_color = color;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color.a;
+#endif
+
+#endif
+
+#ifdef MODE_BOKEH_HEXAGONAL
+
+ //pixel_size*=0.5; //resolution is doubled
+ if (params.second_pass || !params.half_size) {
+ uv += pixel_size * 0.5; //half pixel to read centers
+ } else {
+ uv += pixel_size * 0.25; //half pixel to read centers from full res
+ }
+
+ float alpha = texture(source_color, uv).a; // retain this
+
+ vec2 dir = (params.second_pass ? normalize(vec2(1.0, 0.577350269189626)) : vec2(0.0, 1.0));
+
+ vec4 color = weighted_filter_dir(dir, uv, pixel_size);
+
+ if (params.second_pass) {
+ dir = normalize(vec2(-1.0, 0.577350269189626));
+
+ vec4 color2 = weighted_filter_dir(dir, uv, pixel_size);
+
+ color.rgb = min(color.rgb, color2.rgb);
+ color.a = (color.a + color2.a) * 0.5;
+ }
+
+ frag_color = color;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color.a;
+#endif
+
+#endif
+
+#ifdef MODE_BOKEH_CIRCULAR
+ if (params.half_size) {
+ pixel_size *= 0.5; //resolution is doubled
+ }
+
+ uv += pixel_size * 0.5; //half pixel to read centers
+
+ vec4 color = texture(source_color, uv);
+ float alpha = color.a; // retain this
+ color.a = texture(source_weight, uv).r;
+
+ vec4 color_accum = color;
+ float accum = 1.0;
+
+ float radius = params.blur_scale;
+ for (float ang = 0.0; radius < params.blur_size; ang += GOLDEN_ANGLE) {
+ vec2 uv_adj = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
+
+ vec4 sample_color = texture(source_color, uv_adj);
+ sample_color.a = texture(source_weight, uv_adj).r;
+
+ float limit;
+
+ if (sample_color.a < color.a) {
+ limit = abs(sample_color.a);
+ } else {
+ limit = abs(color.a);
+ }
+
+ limit -= DEPTH_GAP;
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, limit);
+ color_accum += mix(color_accum / accum, sample_color, m);
+ accum += 1.0;
+
+ radius += params.blur_scale / radius;
+ }
+
+ color_accum = color_accum / accum;
+
+ frag_color.rgb = color_accum.rgb;
+ frag_color.a = alpha; // attempt to retain this in case we have a transparent background, ignored if half_size
+#ifdef OUTPUT_WEIGHT
+ weight = color_accum.a;
+#endif
+
+#endif
+
+#ifdef MODE_COMPOSITE_BOKEH
+ frag_color.rgb = texture(source_color, uv).rgb;
+
+ float center_weigth = texture(source_weight, uv).r;
+ float sample_weight = texture(original_weight, uv).r;
+
+ float mix_amount;
+ if (sample_weight < center_weigth) {
+ mix_amount = min(1.0, max(0.0, max(abs(center_weigth), abs(sample_weight)) - DEPTH_GAP));
+ } else {
+ mix_amount = min(1.0, max(0.0, abs(center_weigth) - DEPTH_GAP));
+ }
+
+ // let alpha blending take care of mixing
+ frag_color.a = mix_amount;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index da7d189281..6d95722a57 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -117,7 +117,7 @@ void main() {
uint cluster_thread_group_index;
if (!gl_HelperInvocation) {
- //http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
+ //https://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf
uvec4 mask;
diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
index dfbce29119..69b895ed29 100644
--- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
@@ -7,8 +7,7 @@
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
float z_near;
- bool z_flip;
- uint pad;
+ vec2 texel_size;
vec4 screen_rect;
}
params;
@@ -35,22 +34,23 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
float z_near;
- bool z_flip;
- uint pad;
+ vec2 texel_size;
vec4 screen_rect;
}
params;
void main() {
vec2 uv = uv_interp;
+ vec2 texel_size = abs(params.texel_size);
- vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ uv = clamp(uv * (1.0 + 2.0 * texel_size) - texel_size, vec2(0.0), vec2(1.0));
- normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ normal.z = 0.5 * (1.0 - dot(normal.xy, normal.xy)); // z = 1/2 - 1/2 * (x^2 + y^2)
normal = normalize(normal);
normal.y = -normal.y; //needs to be flipped to match projection matrix
- if (!params.z_flip) {
+ if (params.texel_size.x >= 0.0) { // Sign is used to encode Z flip
normal.z = -normal.z;
}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
index 80c0ac4fb4..be12be5dec 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
@@ -69,13 +69,13 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
return TangentX * H.x + TangentY * H.y + N * H.z;
}
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
float GGX(float NdotV, float a) {
float k = a / 2.0;
return NdotV / (NdotV * (1.0 - k) + k);
}
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
float G_Smith(float a, float nDotV, float nDotL) {
return GGX(nDotL, a * a) * GGX(nDotV, a * a);
}
diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
index ccaad13311..158096d3c7 100644
--- a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
@@ -1,18 +1,18 @@
struct DecalData {
- mat4 xform; //to decal transform
- vec3 inv_extents;
- float albedo_mix;
- vec4 albedo_rect;
- vec4 normal_rect;
- vec4 orm_rect;
- vec4 emission_rect;
- vec4 modulate;
- float emission_energy;
+ highp mat4 xform; //to decal transform
+ highp vec3 inv_extents;
+ mediump float albedo_mix;
+ highp vec4 albedo_rect;
+ highp vec4 normal_rect;
+ highp vec4 orm_rect;
+ highp vec4 emission_rect;
+ highp vec4 modulate;
+ mediump float emission_energy;
uint mask;
- float upper_fade;
- float lower_fade;
- mat3x4 normal_xform;
- vec3 normal;
- float normal_fade;
+ mediump float upper_fade;
+ mediump float lower_fade;
+ mediump mat3x4 normal_xform;
+ mediump vec3 normal;
+ mediump float normal_fade;
};
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 9155216d7e..fdc7729338 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -4,28 +4,28 @@
struct LightData { //this structure needs to be as packed as possible
highp vec3 position;
- float inv_radius;
+ highp float inv_radius;
- vec3 direction;
- float size;
+ mediump vec3 direction;
+ highp float size;
- vec3 color;
- float attenuation;
+ mediump vec3 color;
+ mediump float attenuation;
- float cone_attenuation;
- float cone_angle;
- float specular_amount;
+ mediump float cone_attenuation;
+ mediump float cone_angle;
+ mediump float specular_amount;
bool shadow_enabled;
highp vec4 atlas_rect; // rect in the shadow atlas
highp mat4 shadow_matrix;
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
- float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
+ highp float shadow_bias;
+ highp float shadow_normal_bias;
+ highp float transmittance_bias;
+ highp float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ highp float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask;
- float shadow_volumetric_fog_fade;
+ mediump float shadow_volumetric_fog_fade;
uint bake_mode;
highp vec4 projector_rect; //projector rect in srgb decal atlas
};
@@ -35,53 +35,53 @@ struct LightData { //this structure needs to be as packed as possible
#define REFLECTION_AMBIENT_COLOR 2
struct ReflectionData {
- vec3 box_extents;
- float index;
- vec3 box_offset;
+ highp vec3 box_extents;
+ mediump float index;
+ highp vec3 box_offset;
uint mask;
- vec3 ambient; // ambient color
- float intensity;
+ mediump vec3 ambient; // ambient color
+ mediump float intensity;
bool exterior;
bool box_project;
uint ambient_mode;
uint pad;
//0-8 is intensity,8-9 is ambient, mode
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ highp mat4 local_matrix; // up to here for spot and omni, rest is for directional
// notes: for ambientblend, use distance to edge to blend between already existing global environment
};
struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float size;
- float specular;
+ mediump vec3 direction;
+ mediump float energy;
+ mediump vec3 color;
+ mediump float size;
+ mediump float specular;
uint mask;
- float softshadow_angle;
- float soft_shadow_scale;
+ highp float softshadow_angle;
+ highp float soft_shadow_scale;
bool blend_splits;
bool shadow_enabled;
- float fade_from;
- float fade_to;
+ highp float fade_from;
+ highp float fade_to;
uvec2 pad;
uint bake_mode;
- float shadow_volumetric_fog_fade;
- vec4 shadow_bias;
- vec4 shadow_normal_bias;
- vec4 shadow_transmittance_bias;
+ mediump float shadow_volumetric_fog_fade;
+ highp vec4 shadow_bias;
+ highp vec4 shadow_normal_bias;
+ highp vec4 shadow_transmittance_bias;
highp vec4 shadow_z_range;
highp vec4 shadow_range_begin;
- vec4 shadow_split_offsets;
+ highp vec4 shadow_split_offsets;
highp mat4 shadow_matrix1;
highp mat4 shadow_matrix2;
highp mat4 shadow_matrix3;
highp mat4 shadow_matrix4;
- vec4 shadow_color1;
- vec4 shadow_color2;
- vec4 shadow_color3;
- vec4 shadow_color4;
- vec2 uv_scale1;
- vec2 uv_scale2;
- vec2 uv_scale3;
- vec2 uv_scale4;
+ mediump vec4 shadow_color1;
+ mediump vec4 shadow_color2;
+ mediump vec4 shadow_color3;
+ mediump vec4 shadow_color4;
+ highp vec2 uv_scale1;
+ highp vec2 uv_scale2;
+ highp vec2 uv_scale3;
+ highp vec2 uv_scale4;
};
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 4f140dd10d..7a11f8904e 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -118,7 +118,7 @@ void main() {
mat3 world_normal_matrix;
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
- world_normal_matrix = inverse(mat3(world_matrix));
+ world_normal_matrix = transpose(inverse(mat3(world_matrix)));
} else {
world_normal_matrix = mat3(world_matrix);
}
@@ -881,7 +881,7 @@ void main() {
#ifdef NORMAL_USED
if (scene_data.roughness_limiter_enabled) {
- //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
@@ -1601,7 +1601,7 @@ void main() {
continue; // Statically baked light and object uses lightmap, skip
}
- float shadow = light_process_omni_shadow(light_index, vertex, view);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
@@ -1677,7 +1677,7 @@ void main() {
continue; // Statically baked light and object uses lightmap, skip
}
- float shadow = light_process_spot_shadow(light_index, vertex, view);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index 4a41c66ef3..9fa5d3280d 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -279,7 +279,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
}
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
+ alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
#endif //defined(LIGHT_CODE_USED)
@@ -288,7 +288,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
#ifndef USE_NO_SHADOWS
// Interleaved Gradient Noise
-// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
float quick_hash(vec2 pos) {
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
return fract(magic.z * fract(dot(pos, magic.xy)));
@@ -320,7 +320,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
return avg * (1.0 / float(sc_directional_soft_shadow_samples));
}
-float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) {
vec2 pos = coord.xy;
float depth = coord.z;
@@ -346,6 +346,49 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
return avg * (1.0 / float(sc_soft_shadow_samples));
}
+float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec4 uv_rect, vec2 flip_offset, float depth) {
+ //if only one sample is taken, take it from the center
+ if (sc_soft_shadow_samples == 1) {
+ vec2 pos = coord * 0.5 + 0.5;
+ pos = uv_rect.xy + pos * uv_rect.zw;
+ return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
+ }
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float avg = 0.0;
+ vec2 offset_scale = blur_scale * 2.0 * scene_data.shadow_atlas_pixel_size / uv_rect.zw;
+
+ for (uint i = 0; i < sc_soft_shadow_samples; i++) {
+ vec2 offset = offset_scale * (disk_rotation * scene_data.soft_shadow_kernel[i].xy);
+ vec2 sample_coord = coord + offset;
+
+ float sample_coord_length_sqaured = dot(sample_coord, sample_coord);
+ bool do_flip = sample_coord_length_sqaured > 1.0;
+
+ if (do_flip) {
+ float len = sqrt(sample_coord_length_sqaured);
+ sample_coord = sample_coord * (2.0 / len - 1.0);
+ }
+
+ sample_coord = sample_coord * 0.5 + 0.5;
+ sample_coord = uv_rect.xy + sample_coord * uv_rect.zw;
+
+ if (do_flip) {
+ sample_coord += flip_offset;
+ }
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(sample_coord, depth, 1.0));
+ }
+
+ return avg * (1.0 / float(sc_soft_shadow_samples));
+}
+
float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
//find blocker
float blocker_count = 0.0;
@@ -403,15 +446,21 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
#ifndef USE_NO_SHADOWS
if (omni_lights.data[idx].shadow_enabled) {
// there is a shadowmap
+ vec2 texel_size = scene_data.shadow_atlas_pixel_size;
+ vec4 base_uv_rect = omni_lights.data[idx].atlas_rect;
+ base_uv_rect.xy += texel_size;
+ base_uv_rect.zw -= texel_size * 2.0;
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
+ // Omni lights use direction.xy to store to store the offset between the two paraboloid regions
+ vec2 flip_offset = omni_lights.data[idx].direction.xy;
- vec4 v = vec4(vertex, 1.0);
+ vec3 local_vert = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
- vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
+ float shadow_len = length(local_vert); //need to remember shadow len from here
+ vec3 shadow_dir = normalize(local_vert);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
+ vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal);
+ vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir)));
float shadow;
@@ -431,10 +480,10 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
}
- vec3 normal = normalize(splane.xyz);
- vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
- vec3 tangent = normalize(cross(v0, normal));
- vec3 bitangent = normalize(cross(tangent, normal));
+ vec3 basis_normal = shadow_dir;
+ vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, basis_normal));
+ vec3 bitangent = normalize(cross(tangent, basis_normal));
float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
@@ -443,18 +492,17 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+ vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ vec4 uv_rect = base_uv_rect;
if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
+ uv_rect.xy += flip_offset;
}
+ pos.z = 1.0 + abs(pos.z);
pos.xy /= pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
@@ -479,18 +527,18 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
shadow = 0.0;
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+ vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+ pos = normalize(pos + normal_bias);
+
+ vec4 uv_rect = base_uv_rect;
if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
+ uv_rect.xy += flip_offset;
}
+ pos.z = 1.0 + abs(pos.z);
pos.xy /= pos.z;
pos.xy = pos.xy * 0.5 + 0.5;
@@ -505,26 +553,19 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
shadow = 1.0;
}
} else {
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
+ vec4 uv_rect = base_uv_rect;
- clamp_rect.y += clamp_rect.w;
-
- } else {
- splane.z = 1.0 - splane.z;
+ vec3 shadow_sample = normalize(shadow_dir + normal_bias);
+ if (shadow_sample.z >= 0.0) {
+ uv_rect.xy += flip_offset;
+ flip_offset *= -1.0;
}
- splane.xy /= splane.z;
-
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = shadow_len * omni_lights.data[idx].inv_radius;
- splane.z -= omni_lights.data[idx].shadow_bias;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
- shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
+ shadow_sample.z = 1.0 + abs(shadow_sample.z);
+ vec2 pos = shadow_sample.xy / shadow_sample.z;
+ float depth = shadow_len - omni_lights.data[idx].shadow_bias;
+ depth *= omni_lights.data[idx].inv_radius;
+ shadow = sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth);
}
return shadow;
@@ -608,13 +649,11 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
vec4 atlas_rect = omni_lights.data[idx].projector_rect;
if (local_v.z >= 0.0) {
- local_v.z += 1.0;
atlas_rect.y += atlas_rect.w;
-
- } else {
- local_v.z = 1.0 - local_v.z;
}
+ local_v.z = 1.0 + abs(local_v.z);
+
local_v.xy /= local_v.z;
local_v.xy = local_v.xy * 0.5 + 0.5;
vec2 proj_uv = local_v.xy * atlas_rect.zw;
@@ -694,15 +733,18 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
vec3 spot_dir = spot_lights.data[idx].direction;
- //there is a shadowmap
- vec4 v = vec4(vertex, 1.0);
- float shadow;
+ vec3 shadow_dir = light_rel_vec / light_length;
+ vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir)));
+
+ //there is a shadowmap
+ vec4 v = vec4(vertex + normal_bias, 1.0);
vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
+ splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
splane /= splane.w;
- splane.z -= spot_lights.data[idx].shadow_bias;
+ float shadow;
if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
@@ -753,11 +795,9 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
//no blockers found, so no shadow
shadow = 1.0;
}
-
} else {
//hard shadow
- vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
-
+ vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z);
shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index 2babe92c1c..7e2cc8fe01 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -92,7 +92,7 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) out float dp_clip;
+layout(location = 8) out highp float dp_clip;
#endif
@@ -124,7 +124,7 @@ void main() {
mat3 world_normal_matrix;
if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
- world_normal_matrix = inverse(mat3(world_matrix));
+ world_normal_matrix = transpose(inverse(mat3(world_matrix)));
} else {
world_normal_matrix = mat3(world_matrix);
}
@@ -370,29 +370,36 @@ void main() {
#VERSION_DEFINES
-//use medium precision for floats on mobile.
+/* Specialization Constants */
-precision mediump float;
+#if !defined(MODE_RENDER_DEPTH)
-/* Specialization Constants */
+#if !defined(MODE_UNSHADED)
-/* Specialization Constants (Toggles) */
+layout(constant_id = 0) const bool sc_use_light_projector = false;
+layout(constant_id = 1) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 2) const bool sc_use_directional_soft_shadows = false;
-layout(constant_id = 0) const bool sc_use_forward_gi = false;
-layout(constant_id = 1) const bool sc_use_light_projector = false;
-layout(constant_id = 2) const bool sc_use_light_soft_shadows = false;
-layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false;
+layout(constant_id = 3) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 4) const uint sc_penumbra_shadow_samples = 4;
-/* Specialization Constants (Values) */
+layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4;
-layout(constant_id = 6) const uint sc_soft_shadow_samples = 4;
-layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
+layout(constant_id = 8) const bool sc_projector_use_mipmaps = true;
-layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
-layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
+layout(constant_id = 9) const bool sc_disable_omni_lights = false;
+layout(constant_id = 10) const bool sc_disable_spot_lights = false;
+layout(constant_id = 11) const bool sc_disable_reflection_probes = false;
+layout(constant_id = 12) const bool sc_disable_directional_lights = false;
-layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
-layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
+#endif //!MODE_UNSHADED
+
+layout(constant_id = 7) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 13) const bool sc_disable_decals = false;
+layout(constant_id = 14) const bool sc_disable_fog = false;
+
+#endif //!MODE_RENDER_DEPTH
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
@@ -486,7 +493,7 @@ layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
#else
-layout(location = 0) out vec4 frag_color;
+layout(location = 0) out mediump vec4 frag_color;
#endif // MODE_MULTIPLE_RENDER_TARGETS
#endif // RENDER DEPTH
@@ -735,7 +742,7 @@ void main() {
// to maximize VGPR usage
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
- if (scene_data.fog_enabled) {
+ if (!sc_disable_fog && scene_data.fog_enabled) {
fog = fog_process(vertex);
}
@@ -753,7 +760,7 @@ void main() {
vec3 vertex_ddx = dFdx(vertex);
vec3 vertex_ddy = dFdy(vertex);
- { //Decals
+ if (!sc_disable_decals) { //Decals
// must implement
uint decal_indices = draw_call.decals.x;
@@ -774,25 +781,35 @@ void main() {
continue; //out of decal
}
- //we need ddx/ddy for mipmaps, so simulate them
- vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
- vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
-
float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
if (decals.data[decal_index].normal_fade > 0.0) {
fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
}
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
- vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ vec4 decal_albedo;
+ if (sc_decal_use_mipmaps) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
+ }
decal_albedo *= decals.data[decal_index].modulate;
decal_albedo.a *= fade;
albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
- vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ vec3 decal_normal;
+ if (sc_decal_use_mipmaps) {
+ decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ } else {
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
+ }
decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
//convert to view space, use xzy because y is up
@@ -802,7 +819,12 @@ void main() {
}
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ vec3 decal_orm;
+ if (sc_decal_use_mipmaps) {
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ } else {
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
+ }
ao = mix(ao, decal_orm.r, decal_albedo.a);
roughness = mix(roughness, decal_orm.g, decal_albedo.a);
metallic = mix(metallic, decal_orm.b, decal_albedo.a);
@@ -811,7 +833,11 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
- emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ if (sc_decal_use_mipmaps) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ }
}
}
} //Decals
@@ -821,7 +847,7 @@ void main() {
#ifdef NORMAL_USED
if (scene_data.roughness_limiter_enabled) {
- //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ //https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
@@ -951,7 +977,7 @@ void main() {
// skipping ssao, do we remove ssao totally?
- { //Reflection probes
+ if (!sc_disable_reflection_probes) { //Reflection probes
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
@@ -1017,7 +1043,7 @@ void main() {
// LIGHTING
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
- { //directional light
+ if (!sc_disable_directional_lights) { //directional light
// Do shadow and lighting in two passes to reduce register pressure
uint shadow0 = 0;
@@ -1347,7 +1373,7 @@ void main() {
}
} //directional light
- { //omni lights
+ if (!sc_disable_omni_lights) { //omni lights
uint light_indices = draw_call.omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
@@ -1361,7 +1387,7 @@ void main() {
break;
}
- float shadow = light_process_omni_shadow(light_index, vertex, view);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
@@ -1394,7 +1420,7 @@ void main() {
}
} //omni lights
- { //spot lights
+ if (!sc_disable_spot_lights) { //spot lights
uint light_indices = draw_call.spot_lights.x;
for (uint i = 0; i < 8; i++) {
@@ -1409,7 +1435,7 @@ void main() {
break;
}
- float shadow = light_process_spot_shadow(light_index, vertex, view);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal);
shadow = blur_shadow(shadow);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
index f1e554d01c..dd8879acb4 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -93,7 +93,7 @@ directional_lights;
#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
struct Lightmap {
- mat3 normal_xform;
+ mediump mat3 normal_xform;
};
layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
@@ -102,7 +102,7 @@ layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
lightmaps;
struct LightmapCapture {
- vec4 sh[9];
+ mediump vec4 sh[9];
};
layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
@@ -110,8 +110,8 @@ layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures
}
lightmap_captures;
-layout(set = 0, binding = 11) uniform texture2D decal_atlas;
-layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform mediump texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform mediump texture2D decal_atlas_srgb;
layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
@@ -119,7 +119,7 @@ layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
decals;
layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
- vec4 data[];
+ highp vec4 data[];
}
global_variables;
@@ -135,56 +135,56 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
highp mat4 projection_matrix_view[MAX_VIEWS];
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
- vec2 viewport_size;
- vec2 screen_pixel_size;
+ highp vec2 viewport_size;
+ highp vec2 screen_pixel_size;
// Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
- vec4 directional_penumbra_shadow_kernel[32];
- vec4 directional_soft_shadow_kernel[32];
- vec4 penumbra_shadow_kernel[32];
- vec4 soft_shadow_kernel[32];
+ highp vec4 directional_penumbra_shadow_kernel[32];
+ highp vec4 directional_soft_shadow_kernel[32];
+ highp vec4 penumbra_shadow_kernel[32];
+ highp vec4 soft_shadow_kernel[32];
- vec4 ambient_light_color_energy;
+ mediump vec4 ambient_light_color_energy;
- float ambient_color_sky_mix;
+ mediump float ambient_color_sky_mix;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
- mat3 radiance_inverse_xform;
+ mediump mat3 radiance_inverse_xform;
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
+ highp vec2 shadow_atlas_pixel_size;
+ highp vec2 directional_shadow_pixel_size;
uint directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
+ mediump float dual_paraboloid_side;
+ highp float z_far;
+ highp float z_near;
bool ssao_enabled;
- float ssao_light_affect;
- float ssao_ao_affect;
+ mediump float ssao_light_affect;
+ mediump float ssao_ao_affect;
bool roughness_limiter_enabled;
- float roughness_limiter_amount;
- float roughness_limiter_limit;
+ mediump float roughness_limiter_amount;
+ mediump float roughness_limiter_limit;
uvec2 roughness_limiter_pad;
- vec4 ao_color;
+ mediump vec4 ao_color;
bool fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
+ highp float fog_density;
+ highp float fog_height;
+ highp float fog_height_density;
- vec3 fog_light_color;
- float fog_sun_scatter;
+ mediump vec3 fog_light_color;
+ mediump float fog_sun_scatter;
- float fog_aerial_perspective;
+ mediump float fog_aerial_perspective;
bool material_uv2_mode;
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
+ highp float time;
+ mediump float reflection_multiplier; // one normally, zero when rendering reflections
bool pancake_shadows;
uint pad1;
@@ -195,30 +195,30 @@ scene_data;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap;
#else
-layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+layout(set = 1, binding = 2) uniform mediump textureCube radiance_cubemap;
#endif
-layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+layout(set = 1, binding = 3) uniform mediump textureCubeArray reflection_atlas;
-layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+layout(set = 1, binding = 4) uniform highp texture2D shadow_atlas;
-layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+layout(set = 1, binding = 5) uniform highp texture2D directional_shadow_atlas;
// this needs to change to providing just the lightmap we're using..
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 9) uniform texture2D depth_buffer;
-layout(set = 1, binding = 10) uniform texture2D color_buffer;
+layout(set = 1, binding = 9) uniform highp texture2D depth_buffer;
+layout(set = 1, binding = 10) uniform mediump texture2D color_buffer;
/* Set 2 Skeleton & Instancing (can change per item) */
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
- vec4 data[];
+ highp vec4 data[];
}
transforms;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
index 0eacbc5363..4290d5b869 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
@@ -24,7 +24,7 @@ layout(push_constant, binding = 0, std430) uniform Params {
}
params;
-// http://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
+// https://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
vec3 get_sphere_vertex(uint p_vertex_id) {
float x_angle = float(p_vertex_id & 1u) + (p_vertex_id >> params.band_power);
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 3c685c25b9..f997101183 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -37,15 +37,15 @@ layout(location = 0) in vec2 uv_interp;
#ifdef SUBPASS
layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color;
-#else
-#if MULTIVIEW
+#elif defined(MULTIVIEW)
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
#else
layout(set = 0, binding = 0) uniform sampler2D source_color;
#endif
-#endif
+
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(set = 2, binding = 0) uniform sampler2D source_glow;
+
#ifdef USE_1D_LUT
layout(set = 3, binding = 0) uniform sampler2D source_color_correction;
#else
@@ -349,7 +349,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
}
#endif // !SUBPASS
-// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
+// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
vec3 screen_space_dither(vec2 frag_coord) {
@@ -365,7 +365,7 @@ void main() {
#ifdef SUBPASS
// SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer
vec3 color = subpassLoad(input_color).rgb;
-#elif MULTIVIEW
+#elif defined(MULTIVIEW)
vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb;
#else
vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 4a4976718c..cd8014632d 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -2180,8 +2180,6 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex);
- Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z);
-
RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {
@@ -2215,7 +2213,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
CameraMatrix cm;
- cm.set_perspective(90, 1, 0.01, radius);
+ cm.set_perspective(90, 1, radius * 0.005f, radius);
for (int i = 0; i < 6; i++) {
RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i));
@@ -2301,7 +2299,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
CameraMatrix cm;
- cm.set_perspective(angle * 2.0, 1.0, 0.01, radius);
+ cm.set_perspective(angle * 2.0, 1.0, 0.005f * radius, radius);
Vector<Plane> planes = cm.get_projection_planes(light_transform);
@@ -2794,12 +2792,9 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
//rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal);
- Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform);
-
- Plane near_plane(p_camera_data->main_transform.origin, -p_camera_data->main_transform.basis.get_axis(2).normalized());
-
/* STEP 2 - CULL */
+ Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform);
cull.frustum = Frustum(planes);
Vector<RID> directional_lights;
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index bb9ffffe8a..b302c6b793 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -74,8 +74,8 @@ String RenderingDevice::shader_get_spirv_cache_key() const {
return String();
}
-RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv) {
- Vector<uint8_t> bytecode = shader_compile_binary_from_spirv(p_spirv);
+RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
+ Vector<uint8_t> bytecode = shader_compile_binary_from_spirv(p_spirv, p_shader_name);
ERR_FAIL_COND_V(bytecode.size() == 0, RID());
return shader_create_from_bytecode(bytecode);
}
@@ -192,7 +192,7 @@ Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<
return bytecode;
}
-Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv) {
+Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
ERR_FAIL_COND_V(p_spirv.is_null(), Vector<uint8_t>());
Vector<ShaderStageSPIRVData> stage_data;
@@ -209,10 +209,10 @@ Vector<uint8_t> RenderingDevice::_shader_compile_binary_from_spirv(const Ref<RDS
stage_data.push_back(sd);
}
- return shader_compile_binary_from_spirv(stage_data);
+ return shader_compile_binary_from_spirv(stage_data, p_shader_name);
}
-RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv) {
+RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name) {
ERR_FAIL_COND_V(p_spirv.is_null(), RID());
Vector<ShaderStageSPIRVData> stage_data;
@@ -392,8 +392,8 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create);
ClassDB::bind_method(D_METHOD("shader_compile_spirv_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_spirv_from_source, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("shader_compile_binary_from_spirv", "spirv_data"), &RenderingDevice::_shader_compile_binary_from_spirv);
- ClassDB::bind_method(D_METHOD("shader_create_from_spirv", "spirv_data"), &RenderingDevice::_shader_compile_binary_from_spirv);
+ ClassDB::bind_method(D_METHOD("shader_compile_binary_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_compile_binary_from_spirv, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("shader_create_from_spirv", "spirv_data", "name"), &RenderingDevice::_shader_create_from_spirv, DEFVAL(""));
ClassDB::bind_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::shader_create_from_bytecode);
ClassDB::bind_method(D_METHOD("shader_get_vertex_input_attribute_mask", "shader"), &RenderingDevice::shader_get_vertex_input_attribute_mask);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index bb028cb84c..e2d207dab2 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -668,9 +668,9 @@ public:
};
virtual String shader_get_binary_cache_key() const = 0;
- virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv) = 0;
+ virtual Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "") = 0;
- virtual RID shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv);
+ virtual RID shader_create_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");
virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary) = 0;
virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
@@ -1200,8 +1200,8 @@ protected:
RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers);
Ref<RDShaderSPIRV> _shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache = true);
- Vector<uint8_t> _shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_bytecode);
- RID _shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv);
+ Vector<uint8_t> _shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_bytecode, const String &p_shader_name = "");
+ RID _shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name = "");
RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set);
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 20fcb1396d..4218214fda 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -2877,6 +2877,27 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) {
return p_type == TYPE_BOOL || p_type == TYPE_INT || p_type == TYPE_UINT || p_type == TYPE_FLOAT;
}
+bool ShaderLanguage::is_float_type(DataType p_type) {
+ switch (p_type) {
+ case TYPE_FLOAT:
+ case TYPE_VEC2:
+ case TYPE_VEC3:
+ case TYPE_VEC4:
+ case TYPE_MAT2:
+ case TYPE_MAT3:
+ case TYPE_MAT4:
+ case TYPE_SAMPLER2D:
+ case TYPE_SAMPLER2DARRAY:
+ case TYPE_SAMPLER3D:
+ case TYPE_SAMPLERCUBE:
+ case TYPE_SAMPLERCUBEARRAY: {
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
bool ShaderLanguage::is_sampler_type(DataType p_type) {
return p_type == TYPE_SAMPLER2D ||
p_type == TYPE_ISAMPLER2D ||
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 9e0a63f0f7..18525e054e 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -774,6 +774,7 @@ public:
static DataType get_scalar_type(DataType p_type);
static int get_cardinality(DataType p_type);
static bool is_scalar_type(DataType p_type);
+ static bool is_float_type(DataType p_type);
static bool is_sampler_type(DataType p_type);
static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 4488069698..0bfcccef28 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -342,7 +342,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
- shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 6bace8cf9e..e51e229418 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -665,9 +665,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
continue;
}
if (l_gl[i].count > 0) {
- //Ignore trailing spaces.
- bool is_space = (l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE;
- if ((p_width > 0) && (width + (is_space ? 0 : l_gl[i].advance) > p_width) && (last_safe_break >= 0)) {
+ if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 0)) {
lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end));
line_start = l_gl[last_safe_break].end;
i = last_safe_break;
@@ -698,7 +696,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
last_safe_break = i;
}
}
- width += l_gl[i].advance;
+ width += l_gl[i].advance * l_gl[i].repeat;
}
if (l_size > 0) {