summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/audio/audio_stream.cpp22
-rw-r--r--servers/audio/audio_stream.h5
-rw-r--r--servers/audio/effects/audio_effect_capture.h1
-rw-r--r--servers/audio/effects/audio_stream_generator.cpp4
-rw-r--r--servers/audio/effects/audio_stream_generator.h1
-rw-r--r--servers/audio_server.cpp88
-rw-r--r--servers/audio_server.h9
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/physics_2d/body_2d_sw.cpp191
-rw-r--r--servers/physics_2d/body_2d_sw.h75
-rw-r--r--servers/physics_2d/body_direct_state_2d_sw.cpp4
-rw-r--r--servers/physics_2d/body_direct_state_2d_sw.h1
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp15
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp11
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h6
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h6
-rw-r--r--servers/physics_2d/space_2d_sw.cpp18
-rw-r--r--servers/physics_2d/space_2d_sw.h20
-rw-r--r--servers/physics_3d/body_3d_sw.cpp241
-rw-r--r--servers/physics_3d/body_3d_sw.h55
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp11
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h6
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h6
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp387
-rw-r--r--servers/physics_3d/shape_3d_sw.h21
-rw-r--r--servers/physics_3d/space_3d_sw.cpp14
-rw-r--r--servers/physics_3d/space_3d_sw.h18
-rw-r--r--servers/physics_server_2d.cpp18
-rw-r--r--servers/physics_server_2d.h34
-rw-r--r--servers/physics_server_3d.cpp13
-rw-r--r--servers/physics_server_3d.h32
-rw-r--r--servers/rendering/rasterizer_dummy.h5
-rw-r--r--servers/rendering/renderer_compositor.h3
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp3
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp8
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp1
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp8
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp26
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp6
-rw-r--r--servers/rendering/renderer_rd/shaders/blit.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl48
-rw-r--r--servers/rendering/renderer_viewport.cpp6
-rw-r--r--servers/rendering/rendering_device.cpp16
-rw-r--r--servers/rendering/rendering_device.h20
-rw-r--r--servers/rendering_server.cpp24
-rw-r--r--servers/rendering_server.h2
-rw-r--r--servers/xr/xr_interface.cpp2
-rw-r--r--servers/xr/xr_interface_extension.cpp33
-rw-r--r--servers/xr/xr_interface_extension.h6
53 files changed, 1002 insertions, 572 deletions
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index e1b391b823..c098a97906 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -189,11 +189,21 @@ float AudioStream::get_length() const {
return 0;
}
+bool AudioStream::is_monophonic() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_is_monophonic, ret)) {
+ return ret;
+ }
+ return true;
+}
+
void AudioStream::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length);
+ ClassDB::bind_method(D_METHOD("is_monophonic"), &AudioStream::is_monophonic);
GDVIRTUAL_BIND(_instance_playback);
GDVIRTUAL_BIND(_get_stream_name);
GDVIRTUAL_BIND(_get_length);
+ GDVIRTUAL_BIND(_is_monophonic);
}
////////////////////////////////
@@ -221,6 +231,10 @@ float AudioStreamMicrophone::get_length() const {
return 0;
}
+bool AudioStreamMicrophone::is_monophonic() const {
+ return true;
+}
+
void AudioStreamMicrophone::_bind_methods() {
}
@@ -388,6 +402,14 @@ float AudioStreamRandomPitch::get_length() const {
return 0;
}
+bool AudioStreamRandomPitch::is_monophonic() const {
+ if (audio_stream.is_valid()) {
+ return audio_stream->is_monophonic();
+ }
+
+ return true; // It doesn't really matter what we return here, but no sense instancing a many playbacks of a null stream.
+}
+
void AudioStreamRandomPitch::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_audio_stream", "stream"), &AudioStreamRandomPitch::set_audio_stream);
ClassDB::bind_method(D_METHOD("get_audio_stream"), &AudioStreamRandomPitch::get_audio_stream);
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index 922335508e..12d4343f5c 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -102,12 +102,14 @@ protected:
GDVIRTUAL0RC(Ref<AudioStreamPlayback>, _instance_playback)
GDVIRTUAL0RC(String, _get_stream_name)
GDVIRTUAL0RC(float, _get_length)
+ GDVIRTUAL0RC(bool, _is_monophonic)
public:
virtual Ref<AudioStreamPlayback> instance_playback();
virtual String get_stream_name() const;
virtual float get_length() const;
+ virtual bool is_monophonic() const;
};
// Microphone
@@ -129,6 +131,8 @@ public:
virtual float get_length() const override; //if supported, otherwise return 0
+ virtual bool is_monophonic() const override;
+
AudioStreamMicrophone();
};
@@ -187,6 +191,7 @@ public:
virtual String get_stream_name() const override;
virtual float get_length() const override; //if supported, otherwise return 0
+ virtual bool is_monophonic() const override;
AudioStreamRandomPitch();
};
diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h
index 7f50fc4965..bb1d03be8c 100644
--- a/servers/audio/effects/audio_effect_capture.h
+++ b/servers/audio/effects/audio_effect_capture.h
@@ -34,6 +34,7 @@
#include "core/config/engine.h"
#include "core/math/audio_frame.h"
#include "core/object/ref_counted.h"
+#include "core/templates/ring_buffer.h"
#include "core/templates/vector.h"
#include "servers/audio/audio_effect.h"
#include "servers/audio_server.h"
diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp
index edb5c6d2dd..447acf53a4 100644
--- a/servers/audio/effects/audio_stream_generator.cpp
+++ b/servers/audio/effects/audio_stream_generator.cpp
@@ -64,6 +64,10 @@ float AudioStreamGenerator::get_length() const {
return 0;
}
+bool AudioStreamGenerator::is_monophonic() const {
+ return true;
+}
+
void AudioStreamGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamGenerator::set_mix_rate);
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamGenerator::get_mix_rate);
diff --git a/servers/audio/effects/audio_stream_generator.h b/servers/audio/effects/audio_stream_generator.h
index 6bec744081..918589f6d0 100644
--- a/servers/audio/effects/audio_stream_generator.h
+++ b/servers/audio/effects/audio_stream_generator.h
@@ -54,6 +54,7 @@ public:
virtual String get_stream_name() const override;
virtual float get_length() const override;
+ virtual bool is_monophonic() const override;
AudioStreamGenerator();
};
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 81735d522f..758ce766c3 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -363,10 +363,10 @@ void AudioServer::_mix_step() {
if (mixed_frames != buffer_size) {
// We know we have at least the size of our lookahead buffer for fade-out purposes.
- float fadeout_base = 0.87;
+ float fadeout_base = 0.94;
float fadeout_coefficient = 1;
- static_assert(LOOKAHEAD_BUFFER_SIZE == 32, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE.");
- // 0.87 ^ 32 = 0.0116. There might still be a pop but it'll be way better than if we didn't do this.
+ static_assert(LOOKAHEAD_BUFFER_SIZE == 64, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE.");
+ // 0.94 ^ 64 = 0.01906. There might still be a pop but it'll be way better than if we didn't do this.
for (unsigned int idx = mixed_frames; idx < buffer_size; idx++) {
fadeout_coefficient *= fadeout_base;
buf[idx] *= fadeout_coefficient;
@@ -381,29 +381,24 @@ void AudioServer::_mix_step() {
}
}
- ERR_FAIL_COND(playback->bus_details.load() == nullptr);
+ AudioStreamPlaybackBusDetails *ptr = playback->bus_details.load();
+ ERR_FAIL_COND(ptr == nullptr);
// By putting null into the bus details pointers, we're taking ownership of their memory for the duration of this mix.
- AudioStreamPlaybackBusDetails *bus_details = nullptr;
- {
- std::atomic<AudioStreamPlaybackBusDetails *> bus_details_atomic = nullptr;
- bus_details = playback->bus_details.exchange(bus_details_atomic);
- }
- ERR_FAIL_COND(bus_details == nullptr);
- AudioStreamPlaybackBusDetails *prev_bus_details = playback->prev_bus_details;
+ AudioStreamPlaybackBusDetails bus_details = *ptr;
// Mix to any active buses.
for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) {
- if (!bus_details->bus_active[idx]) {
+ if (!bus_details.bus_active[idx]) {
continue;
}
- int bus_idx = thread_find_bus_index(bus_details->bus[idx]);
+ int bus_idx = thread_find_bus_index(bus_details.bus[idx]);
int prev_bus_idx = -1;
for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) {
- if (!prev_bus_details->bus_active[search_idx]) {
+ if (!playback->prev_bus_details->bus_active[search_idx]) {
continue;
}
- if (prev_bus_details->bus[search_idx].hash() == bus_details->bus[idx].hash()) {
+ if (playback->prev_bus_details->bus[search_idx].hash() == bus_details.bus[idx].hash()) {
prev_bus_idx = search_idx;
}
}
@@ -411,13 +406,13 @@ void AudioServer::_mix_step() {
for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) {
AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx);
if (fading_out) {
- bus_details->volume[idx][channel_idx] = AudioFrame(0, 0);
+ bus_details.volume[idx][channel_idx] = AudioFrame(0, 0);
}
- AudioFrame channel_vol = bus_details->volume[idx][channel_idx];
+ AudioFrame channel_vol = bus_details.volume[idx][channel_idx];
AudioFrame prev_channel_vol = AudioFrame(0, 0);
if (prev_bus_idx != -1) {
- prev_channel_vol = prev_bus_details->volume[prev_bus_idx][channel_idx];
+ prev_channel_vol = playback->prev_bus_details->volume[prev_bus_idx][channel_idx];
}
_mix_step_for_channel(channel_buf, buf, prev_channel_vol, channel_vol, playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]);
}
@@ -425,14 +420,14 @@ void AudioServer::_mix_step() {
// Now go through and fade-out any buses that were being played to previously that we missed by going through current data.
for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) {
- if (!prev_bus_details->bus_active[idx]) {
+ if (!playback->prev_bus_details->bus_active[idx]) {
continue;
}
- int bus_idx = thread_find_bus_index(prev_bus_details->bus[idx]);
+ int bus_idx = thread_find_bus_index(playback->prev_bus_details->bus[idx]);
int current_bus_idx = -1;
for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) {
- if (bus_details->bus[search_idx] == prev_bus_details->bus[idx]) {
+ if (bus_details.bus[search_idx] == playback->prev_bus_details->bus[idx]) {
current_bus_idx = search_idx;
}
}
@@ -443,24 +438,17 @@ void AudioServer::_mix_step() {
for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) {
AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx);
- AudioFrame prev_channel_vol = prev_bus_details->volume[idx][channel_idx];
+ AudioFrame prev_channel_vol = playback->prev_bus_details->volume[idx][channel_idx];
// Fade out to silence
_mix_step_for_channel(channel_buf, buf, prev_channel_vol, AudioFrame(0, 0), playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]);
}
}
// Copy the bus details we mixed with to the previous bus details to maintain volume ramps.
- std::copy(std::begin(bus_details->bus_active), std::end(bus_details->bus_active), std::begin(prev_bus_details->bus_active));
- std::copy(std::begin(bus_details->bus), std::end(bus_details->bus), std::begin(prev_bus_details->bus));
+ std::copy(std::begin(bus_details.bus_active), std::end(bus_details.bus_active), std::begin(playback->prev_bus_details->bus_active));
+ std::copy(std::begin(bus_details.bus), std::end(bus_details.bus), std::begin(playback->prev_bus_details->bus));
for (int bus_idx = 0; bus_idx < MAX_BUSES_PER_PLAYBACK; bus_idx++) {
- std::copy(std::begin(bus_details->volume[bus_idx]), std::end(bus_details->volume[bus_idx]), std::begin(prev_bus_details->volume[bus_idx]));
- }
-
- AudioStreamPlaybackBusDetails *bus_details_expected = nullptr;
- // Only put the bus details pointer back if it hasn't been updated already.
- if (!playback->bus_details.compare_exchange_strong(/* expected= */ bus_details_expected, /* new= */ bus_details)) {
- // If it *has* been updated already, queue the old one for deletion.
- bus_details_graveyard.insert(bus_details);
+ std::copy(std::begin(bus_details.volume[bus_idx]), std::end(bus_details.volume[bus_idx]), std::begin(playback->prev_bus_details->volume[bus_idx]));
}
switch (playback->state.load()) {
@@ -1132,7 +1120,7 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Str
start_playback_stream(p_playback, map, p_start_time);
}
-void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time) {
+void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_highshelf_gain, float p_attenuation_cutoff_hz, float p_pitch_scale) {
ERR_FAIL_COND(p_playback.is_null());
AudioStreamPlaybackListNode *playback_node = new AudioStreamPlaybackListNode();
@@ -1154,10 +1142,9 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map
playback_node->bus_details = new_bus_details;
playback_node->prev_bus_details = new AudioStreamPlaybackBusDetails();
- playback_node->setseek.set(-1);
- playback_node->pitch_scale.set(1);
- playback_node->highshelf_gain.set(0);
- playback_node->attenuation_filter_cutoff_hz.set(0);
+ playback_node->pitch_scale.set(p_pitch_scale);
+ playback_node->highshelf_gain.set(p_highshelf_gain);
+ playback_node->attenuation_filter_cutoff_hz.set(p_attenuation_cutoff_hz);
memset(playback_node->prev_bus_details->volume, 0, sizeof(playback_node->prev_bus_details->volume));
@@ -1181,6 +1168,9 @@ void AudioServer::stop_playback_stream(Ref<AudioStreamPlayback> p_playback) {
AudioStreamPlaybackListNode::PlaybackState new_state, old_state;
do {
old_state = playback_node->state.load();
+ if (old_state == AudioStreamPlaybackListNode::AWAITING_DELETION) {
+ break; // Don't fade out again.
+ }
new_state = AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION;
} while (!playback_node->state.compare_exchange_strong(old_state, new_state));
@@ -1206,6 +1196,9 @@ void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_pla
int idx = 0;
for (KeyValue<StringName, Vector<AudioFrame>> pair : p_bus_volumes) {
+ if (idx >= MAX_BUSES_PER_PLAYBACK) {
+ break;
+ }
ERR_FAIL_COND(pair.value.size() < channel_count);
ERR_FAIL_COND(pair.value.size() != MAX_CHANNELS_PER_BUS);
@@ -1214,6 +1207,7 @@ void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_pla
for (int channel_idx = 0; channel_idx < MAX_CHANNELS_PER_BUS; channel_idx++) {
new_bus_details->volume[idx][channel_idx] = pair.value[channel_idx];
}
+ idx++;
}
do {
@@ -1260,17 +1254,18 @@ void AudioServer::set_playback_paused(Ref<AudioStreamPlayback> p_playback, bool
if (!playback_node) {
return;
}
- if (!p_paused && playback_node->state == AudioStreamPlaybackListNode::PLAYING) {
- return; // No-op.
- }
- if (p_paused && (playback_node->state == AudioStreamPlaybackListNode::PAUSED || playback_node->state == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE)) {
- return; // No-op.
- }
AudioStreamPlaybackListNode::PlaybackState new_state, old_state;
do {
old_state = playback_node->state.load();
new_state = p_paused ? AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE : AudioStreamPlaybackListNode::PLAYING;
+ if (!p_paused && old_state == AudioStreamPlaybackListNode::PLAYING) {
+ return; // No-op.
+ }
+ if (p_paused && (old_state == AudioStreamPlaybackListNode::PAUSED || old_state == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE)) {
+ return; // No-op.
+ }
+
} while (!playback_node->state.compare_exchange_strong(old_state, new_state));
}
@@ -1444,10 +1439,15 @@ void AudioServer::update() {
update_callback_list.maybe_cleanup();
listener_changed_callback_list.maybe_cleanup();
playback_list.maybe_cleanup();
+ for (AudioStreamPlaybackBusDetails *bus_details : bus_details_graveyard_frame_old) {
+ bus_details_graveyard_frame_old.erase(bus_details, [](AudioStreamPlaybackBusDetails *d) { delete d; });
+ }
for (AudioStreamPlaybackBusDetails *bus_details : bus_details_graveyard) {
- bus_details_graveyard.erase(bus_details, [](AudioStreamPlaybackBusDetails *d) { delete d; });
+ bus_details_graveyard_frame_old.insert(bus_details);
+ bus_details_graveyard.erase(bus_details);
}
bus_details_graveyard.maybe_cleanup();
+ bus_details_graveyard_frame_old.maybe_cleanup();
}
void AudioServer::load_default_bus_layout() {
diff --git a/servers/audio_server.h b/servers/audio_server.h
index affcb3df7b..a60d4ae4c4 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -163,7 +163,7 @@ public:
AUDIO_DATA_INVALID_ID = -1,
MAX_CHANNELS_PER_BUS = 4,
MAX_BUSES_PER_PLAYBACK = 6,
- LOOKAHEAD_BUFFER_SIZE = 32,
+ LOOKAHEAD_BUFFER_SIZE = 64,
};
typedef void (*AudioCallback)(void *p_userdata);
@@ -262,6 +262,9 @@ private:
SafeList<AudioStreamPlaybackListNode *> playback_list;
SafeList<AudioStreamPlaybackBusDetails *> bus_details_graveyard;
+ // TODO document if this is necessary.
+ SafeList<AudioStreamPlaybackBusDetails *> bus_details_graveyard_frame_old;
+
Vector<Vector<AudioFrame>> temp_buffer; //temp_buffer for each level
Vector<AudioFrame> mix_buffer;
Vector<Bus *> buses;
@@ -364,8 +367,10 @@ public:
void set_playback_speed_scale(float p_scale);
float get_playback_speed_scale() const;
+ // Convenience method.
void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0);
- void start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0);
+ // Expose all parameters.
+ void start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0, float p_pitch_scale = 1);
void stop_playback_stream(Ref<AudioStreamPlayback> p_playback);
void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 3d44484033..cdf892094d 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -605,4 +605,5 @@ DisplayServer::DisplayServer() {
}
DisplayServer::~DisplayServer() {
+ singleton = nullptr;
}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 64f71fd25c..edd769aa9a 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -34,47 +34,72 @@
#include "body_direct_state_2d_sw.h"
#include "space_2d_sw.h"
-void Body2DSW::_update_inertia() {
- if (!user_inertia && get_space() && !inertia_update_list.in_list()) {
- get_space()->body_add_to_inertia_update_list(&inertia_update_list);
+void Body2DSW::_mass_properties_changed() {
+ if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) {
+ get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list);
}
}
-void Body2DSW::update_inertias() {
+void Body2DSW::update_mass_properties() {
//update shapes and motions
switch (mode) {
case PhysicsServer2D::BODY_MODE_DYNAMIC: {
- if (user_inertia) {
- _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
- break;
- }
- //update tensor for allshapes, not the best way but should be somehow OK. (inspired from bullet)
real_t total_area = 0;
-
for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
total_area += get_shape_aabb(i).get_area();
}
- inertia = 0;
+ if (calculate_center_of_mass) {
+ // We have to recompute the center of mass.
+ center_of_mass = Vector2();
- for (int i = 0; i < get_shape_count(); i++) {
- if (is_shape_disabled(i)) {
- continue;
+ if (total_area != 0.0) {
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
+
+ real_t area = get_shape_aabb(i).get_area();
+
+ real_t mass = area * this->mass / total_area;
+
+ // NOTE: we assume that the shape origin is also its center of mass.
+ center_of_mass += mass * get_shape_transform(i).get_origin();
+ }
+
+ center_of_mass /= mass;
}
+ }
+
+ if (calculate_inertia) {
+ inertia = 0;
+
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
- const Shape2DSW *shape = get_shape(i);
+ const Shape2DSW *shape = get_shape(i);
- real_t area = get_shape_aabb(i).get_area();
+ real_t area = get_shape_aabb(i).get_area();
+ if (area == 0.0) {
+ continue;
+ }
- real_t mass = area * this->mass / total_area;
+ real_t mass = area * this->mass / total_area;
- Transform2D mtx = get_shape_transform(i);
- Vector2 scale = mtx.get_scale();
- inertia += shape->get_moment_of_inertia(mass, scale) + mass * mtx.get_origin().length_squared();
+ Transform2D mtx = get_shape_transform(i);
+ Vector2 scale = mtx.get_scale();
+ Vector2 shape_origin = mtx.get_origin() - center_of_mass;
+ inertia += shape->get_moment_of_inertia(mass, scale) + mass * shape_origin.length_squared();
+ }
}
- _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
+ _inv_inertia = inertia > 0.0 ? (1.0 / inertia) : 0.0;
if (mass) {
_inv_mass = 1.0 / mass;
@@ -94,9 +119,12 @@ void Body2DSW::update_inertias() {
} break;
}
- //_update_inertia_tensor();
+}
- //_update_shapes();
+void Body2DSW::reset_mass_properties() {
+ calculate_inertia = true;
+ calculate_center_of_mass = true;
+ _mass_properties_changed();
}
void Body2DSW::set_active(bool p_active) {
@@ -118,7 +146,7 @@ void Body2DSW::set_active(bool p_active) {
}
}
-void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) {
+void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value) {
switch (p_param) {
case PhysicsServer2D::BODY_PARAM_BOUNCE: {
bounce = p_value;
@@ -127,21 +155,32 @@ void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value)
friction = p_value;
} break;
case PhysicsServer2D::BODY_PARAM_MASS: {
- ERR_FAIL_COND(p_value <= 0);
- mass = p_value;
- _update_inertia();
-
+ real_t mass_value = p_value;
+ ERR_FAIL_COND(mass_value <= 0);
+ mass = mass_value;
+ if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ _mass_properties_changed();
+ }
} break;
case PhysicsServer2D::BODY_PARAM_INERTIA: {
- if (p_value <= 0) {
- user_inertia = false;
- _update_inertia();
+ real_t inertia_value = p_value;
+ if (inertia_value <= 0.0) {
+ calculate_inertia = true;
+ if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ _mass_properties_changed();
+ }
} else {
- user_inertia = true;
- inertia = p_value;
- _inv_inertia = 1.0 / p_value;
+ calculate_inertia = false;
+ inertia = inertia_value;
+ if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ _inv_inertia = 1.0 / inertia;
+ }
}
} break;
+ case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: {
+ calculate_center_of_mass = false;
+ center_of_mass = p_value;
+ } break;
case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
gravity_scale = p_value;
} break;
@@ -156,7 +195,7 @@ void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value)
}
}
-real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const {
+Variant Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const {
switch (p_param) {
case PhysicsServer2D::BODY_PARAM_BOUNCE: {
return bounce;
@@ -170,6 +209,9 @@ real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const {
case PhysicsServer2D::BODY_PARAM_INERTIA: {
return inertia;
}
+ case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: {
+ return center_of_mass;
+ }
case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
return gravity_scale;
}
@@ -207,7 +249,10 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) {
} break;
case PhysicsServer2D::BODY_MODE_DYNAMIC: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
- _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
+ if (!calculate_inertia) {
+ _inv_inertia = 1.0 / inertia;
+ }
+ _mass_properties_changed();
_set_static(false);
set_active(true);
@@ -215,18 +260,11 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) {
case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = 0;
+ angular_velocity = 0;
_set_static(false);
set_active(true);
- angular_velocity = 0;
- } break;
- }
- if (p_mode == PhysicsServer2D::BODY_MODE_DYNAMIC && _inv_inertia == 0) {
- _update_inertia();
+ }
}
- /*
- if (get_space())
- _update_queries();
- */
}
PhysicsServer2D::BodyMode Body2DSW::get_mode() const {
@@ -234,7 +272,7 @@ PhysicsServer2D::BodyMode Body2DSW::get_mode() const {
}
void Body2DSW::_shapes_changed() {
- _update_inertia();
+ _mass_properties_changed();
wakeup_neighbours();
}
@@ -269,11 +307,13 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
linear_velocity = p_variant;
+ constant_linear_velocity = linear_velocity;
wakeup();
} break;
case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
angular_velocity = p_variant;
+ constant_angular_velocity = angular_velocity;
wakeup();
} break;
@@ -296,7 +336,7 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
+ if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
set_active(true);
}
@@ -330,8 +370,8 @@ void Body2DSW::set_space(Space2DSW *p_space) {
if (get_space()) {
wakeup_neighbours();
- if (inertia_update_list.in_list()) {
- get_space()->body_remove_from_inertia_update_list(&inertia_update_list);
+ if (mass_properties_update_list.in_list()) {
+ get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list);
}
if (active_list.in_list()) {
get_space()->body_remove_from_active_list(&active_list);
@@ -344,13 +384,11 @@ void Body2DSW::set_space(Space2DSW *p_space) {
_set_space(p_space);
if (get_space()) {
- _update_inertia();
+ _mass_properties_changed();
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
}
-
- first_integration = false;
}
void Body2DSW::_compute_area_gravity_and_damping(const Area2DSW *p_area) {
@@ -429,10 +467,10 @@ void Body2DSW::integrate_forces(real_t p_step) {
if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
//compute motion, angular and etc. velocities from prev transform
motion = new_transform.get_origin() - get_transform().get_origin();
- linear_velocity = motion / p_step;
+ linear_velocity = constant_linear_velocity + motion / p_step;
real_t rot = new_transform.get_rotation() - get_transform().get_rotation();
- angular_velocity = remainder(rot, 2.0 * Math_PI) / p_step;
+ angular_velocity = constant_angular_velocity + remainder(rot, 2.0 * Math_PI) / p_step;
do_motion = true;
@@ -444,7 +482,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
*/
} else {
- if (!omit_force_integration && !first_integration) {
+ if (!omit_force_integration) {
//overridden by direct state query
Vector2 force = gravity * mass;
@@ -478,7 +516,6 @@ void Body2DSW::integrate_forces(real_t p_step) {
//motion=linear_velocity*p_step;
- first_integration = false;
biased_angular_velocity = 0;
biased_linear_velocity = Vector2();
@@ -515,14 +552,22 @@ void Body2DSW::integrate_velocities(real_t p_step) {
real_t angle = get_transform().get_rotation() + total_angular_velocity * p_step;
Vector2 pos = get_transform().get_origin() + total_linear_velocity * p_step;
+ real_t center_of_mass_distance = center_of_mass.length();
+ if (center_of_mass_distance > CMP_EPSILON) {
+ // Calculate displacement due to center of mass offset.
+ real_t prev_angle = get_transform().get_rotation();
+ real_t angle_base = Math::atan2(center_of_mass.y, center_of_mass.x);
+ Vector2 point1(Math::cos(angle_base + prev_angle), Math::sin(angle_base + prev_angle));
+ Vector2 point2(Math::cos(angle_base + angle), Math::sin(angle_base + angle));
+ pos += center_of_mass_distance * (point1 - point2);
+ }
+
_set_transform(Transform2D(angle, pos), continuous_cd_mode == PhysicsServer2D::CCD_MODE_DISABLED);
_set_inv_transform(get_transform().inverse());
if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) {
new_transform = get_transform();
}
-
- //_update_inertia_tensor();
}
void Body2DSW::wakeup_neighbours() {
@@ -536,7 +581,7 @@ void Body2DSW::wakeup_neighbours() {
continue;
}
Body2DSW *b = n[i];
- if (b->mode != PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (b->mode < PhysicsServer2D::BODY_MODE_DYNAMIC) {
continue;
}
@@ -617,35 +662,9 @@ PhysicsDirectBodyState2DSW *Body2DSW::get_direct_state() {
Body2DSW::Body2DSW() :
CollisionObject2DSW(TYPE_BODY),
active_list(this),
- inertia_update_list(this),
+ mass_properties_update_list(this),
direct_state_query_list(this) {
- mode = PhysicsServer2D::BODY_MODE_DYNAMIC;
- active = true;
- angular_velocity = 0;
- biased_angular_velocity = 0;
- mass = 1;
- inertia = 0;
- user_inertia = false;
- _inv_inertia = 0;
- _inv_mass = 1;
- bounce = 0;
- friction = 1;
- omit_force_integration = false;
- applied_torque = 0;
- island_step = 0;
_set_static(false);
- first_time_kinematic = false;
- linear_damp = -1;
- angular_damp = -1;
- area_angular_damp = 0;
- area_linear_damp = 0;
- contact_count = 0;
- gravity_scale = 1.0;
- first_integration = false;
-
- still_time = 0;
- continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED;
- can_sleep = true;
}
Body2DSW::~Body2DSW() {
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 9cd53ceca1..95e89786cd 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -41,48 +41,55 @@ class Constraint2DSW;
class PhysicsDirectBodyState2DSW;
class Body2DSW : public CollisionObject2DSW {
- PhysicsServer2D::BodyMode mode;
+ PhysicsServer2D::BodyMode mode = PhysicsServer2D::BODY_MODE_DYNAMIC;
Vector2 biased_linear_velocity;
- real_t biased_angular_velocity;
+ real_t biased_angular_velocity = 0.0;
Vector2 linear_velocity;
- real_t angular_velocity;
+ real_t angular_velocity = 0.0;
- real_t linear_damp;
- real_t angular_damp;
- real_t gravity_scale;
+ Vector2 constant_linear_velocity;
+ real_t constant_angular_velocity = 0.0;
- real_t mass;
- real_t inertia;
- real_t bounce;
- real_t friction;
+ real_t linear_damp = -1.0;
+ real_t angular_damp = -1.0;
+ real_t gravity_scale = 1.0;
- real_t _inv_mass;
- real_t _inv_inertia;
- bool user_inertia;
+ real_t bounce = 0.0;
+ real_t friction = 1.0;
+
+ real_t mass = 1.0;
+ real_t _inv_mass = 1.0;
+
+ real_t inertia = 0.0;
+ real_t _inv_inertia = 0.0;
+
+ Vector2 center_of_mass;
+
+ bool calculate_inertia = true;
+ bool calculate_center_of_mass = true;
Vector2 gravity;
- real_t area_linear_damp;
- real_t area_angular_damp;
+ real_t area_linear_damp = 0.0;
+ real_t area_angular_damp = 0.0;
- real_t still_time;
+ real_t still_time = 0.0;
Vector2 applied_force;
- real_t applied_torque;
+ real_t applied_torque = 0.0;
SelfList<Body2DSW> active_list;
- SelfList<Body2DSW> inertia_update_list;
+ SelfList<Body2DSW> mass_properties_update_list;
SelfList<Body2DSW> direct_state_query_list;
VSet<RID> exceptions;
- PhysicsServer2D::CCDMode continuous_cd_mode;
- bool omit_force_integration;
- bool active;
- bool can_sleep;
- bool first_time_kinematic;
- bool first_integration;
- void _update_inertia();
+ PhysicsServer2D::CCDMode continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED;
+ bool omit_force_integration = false;
+ bool active = true;
+ bool can_sleep = true;
+ bool first_time_kinematic = false;
+ void _mass_properties_changed();
virtual void _shapes_changed();
Transform2D new_transform;
@@ -115,7 +122,7 @@ class Body2DSW : public CollisionObject2DSW {
};
Vector<Contact> contacts; //no contacts by default
- int contact_count;
+ int contact_count = 0;
void *body_state_callback_instance = nullptr;
PhysicsServer2D::BodyStateCallback body_state_callback = nullptr;
@@ -129,7 +136,7 @@ class Body2DSW : public CollisionObject2DSW {
PhysicsDirectBodyState2DSW *direct_state = nullptr;
- uint64_t island_step;
+ uint64_t island_step = 0;
_FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area2DSW *p_area);
@@ -207,7 +214,7 @@ public:
_FORCE_INLINE_ void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) {
linear_velocity += p_impulse * _inv_mass;
- angular_velocity += _inv_inertia * p_position.cross(p_impulse);
+ angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse);
}
_FORCE_INLINE_ void apply_torque_impulse(real_t p_torque) {
@@ -216,7 +223,7 @@ public:
_FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) {
biased_linear_velocity += p_impulse * _inv_mass;
- biased_angular_velocity += _inv_inertia * p_position.cross(p_impulse);
+ biased_angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse);
}
void set_active(bool p_active);
@@ -229,8 +236,8 @@ public:
set_active(true);
}
- void set_param(PhysicsServer2D::BodyParameter p_param, real_t);
- real_t get_param(PhysicsServer2D::BodyParameter p_param) const;
+ void set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer2D::BodyParameter p_param) const;
void set_mode(PhysicsServer2D::BodyMode p_mode);
PhysicsServer2D::BodyMode get_mode() const;
@@ -250,7 +257,7 @@ public:
_FORCE_INLINE_ void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) {
applied_force += p_force;
- applied_torque += p_position.cross(p_force);
+ applied_torque += (p_position - center_of_mass).cross(p_force);
}
_FORCE_INLINE_ void add_torque(real_t p_torque) {
@@ -262,8 +269,10 @@ public:
void set_space(Space2DSW *p_space);
- void update_inertias();
+ void update_mass_properties();
+ void reset_mass_properties();
+ _FORCE_INLINE_ Vector2 get_center_of_mass() const { return center_of_mass; }
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
_FORCE_INLINE_ real_t get_inv_inertia() const { return _inv_inertia; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
diff --git a/servers/physics_2d/body_direct_state_2d_sw.cpp b/servers/physics_2d/body_direct_state_2d_sw.cpp
index 1f68cca843..58250c3077 100644
--- a/servers/physics_2d/body_direct_state_2d_sw.cpp
+++ b/servers/physics_2d/body_direct_state_2d_sw.cpp
@@ -46,6 +46,10 @@ real_t PhysicsDirectBodyState2DSW::get_total_linear_damp() const {
return body->area_linear_damp;
}
+Vector2 PhysicsDirectBodyState2DSW::get_center_of_mass() const {
+ return body->get_center_of_mass();
+}
+
real_t PhysicsDirectBodyState2DSW::get_inverse_mass() const {
return body->get_inv_mass();
}
diff --git a/servers/physics_2d/body_direct_state_2d_sw.h b/servers/physics_2d/body_direct_state_2d_sw.h
index aef9186086..34faa174d8 100644
--- a/servers/physics_2d/body_direct_state_2d_sw.h
+++ b/servers/physics_2d/body_direct_state_2d_sw.h
@@ -45,6 +45,7 @@ public:
virtual real_t get_total_angular_damp() const override;
virtual real_t get_total_linear_damp() const override;
+ virtual Vector2 get_center_of_mass() const override;
virtual real_t get_inverse_mass() const override;
virtual real_t get_inverse_inertia() const override;
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index 5a0a628fbc..fa8499a81d 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -68,13 +68,13 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const
{
value += a->get_inv_mass();
- real_t rcn = rA.cross(n);
+ real_t rcn = (rA - a->get_center_of_mass()).cross(n);
value += a->get_inv_inertia() * rcn * rcn;
}
if (b) {
value += b->get_inv_mass();
- real_t rcn = rB.cross(n);
+ real_t rcn = (rB - b->get_center_of_mass()).cross(n);
value += b->get_inv_inertia() * rcn * rcn;
}
@@ -83,9 +83,9 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const
static inline Vector2
relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB) {
- Vector2 sum = a->get_linear_velocity() - rA.orthogonal() * a->get_angular_velocity();
+ Vector2 sum = a->get_linear_velocity() - (rA - a->get_center_of_mass()).orthogonal() * a->get_angular_velocity();
if (b) {
- return (b->get_linear_velocity() - rB.orthogonal() * b->get_angular_velocity()) - sum;
+ return (b->get_linear_velocity() - (rB - b->get_center_of_mass()).orthogonal() * b->get_angular_velocity()) - sum;
} else {
return -sum;
}
@@ -172,11 +172,11 @@ bool PinJoint2DSW::pre_solve(real_t p_step) {
void PinJoint2DSW::solve(real_t p_step) {
// compute relative velocity
- Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity());
+ Vector2 vA = A->get_linear_velocity() - custom_cross(rA - A->get_center_of_mass(), A->get_angular_velocity());
Vector2 rel_vel;
if (B) {
- rel_vel = B->get_linear_velocity() - custom_cross(rB, B->get_angular_velocity()) - vA;
+ rel_vel = B->get_linear_velocity() - custom_cross(rB - B->get_center_of_mass(), B->get_angular_velocity()) - vA;
} else {
rel_vel = -vA;
}
@@ -238,6 +238,9 @@ k_tensor(Body2DSW *a, Body2DSW *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2
k21 = 0.0f;
k22 = m_sum;
+ r1 -= a->get_center_of_mass();
+ r2 -= b->get_center_of_mass();
+
// add the influence from r1
real_t a_i_inv = a->get_inv_inertia();
real_t r1xsq = r1.x * r1.x * a_i_inv;
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 85b5e40752..d0a42ca95b 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -743,20 +743,27 @@ uint32_t PhysicsServer2DSW::body_get_collision_mask(RID p_body) const {
return body->get_collision_mask();
};
-void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
+void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_param(p_param, p_value);
};
-real_t PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const {
+Variant PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_param(p_param);
};
+void PhysicsServer2DSW::body_reset_mass_properties(RID p_body) {
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ return body->reset_mass_properties();
+}
+
void PhysicsServer2DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index ef1306cf59..6a2d9e37e0 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -205,8 +205,10 @@ public:
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override;
virtual uint32_t body_get_collision_mask(RID p_body) const override;
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override;
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override;
+ virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override;
+ virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override;
+
+ virtual void body_reset_mass_properties(RID p_body) override;
virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
virtual Variant body_get_state(RID p_body, BodyState p_state) const override;
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index 6761e37daa..e65c4f5f3a 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -212,8 +212,10 @@ public:
FUNC2(body_set_collision_mask, RID, uint32_t);
FUNC1RC(uint32_t, body_get_collision_mask, RID);
- FUNC3(body_set_param, RID, BodyParameter, real_t);
- FUNC2RC(real_t, body_get_param, RID, BodyParameter);
+ FUNC3(body_set_param, RID, BodyParameter, const Variant &);
+ FUNC2RC(Variant, body_get_param, RID, BodyParameter);
+
+ FUNC1(body_reset_mass_properties, RID);
FUNC3(body_set_state, RID, BodyState, const Variant &);
FUNC2RC(Variant, body_get_state, RID, BodyState);
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 6c23f49928..7dbd1243cc 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -482,7 +482,7 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh
r_info->metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
if (rcd.best_object->get_type() == CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object);
- Vector2 rel_vec = r_info->point - body->get_transform().get_origin();
+ Vector2 rel_vec = r_info->point - (body->get_transform().get_origin() + body->get_center_of_mass());
r_info->linear_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
} else {
@@ -961,7 +961,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object);
- Vector2 rel_vec = r_result->collision_point - body->get_transform().get_origin();
+ Vector2 rel_vec = r_result->collision_point - (body->get_transform().get_origin() + body->get_center_of_mass());
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->travel = safe * p_motion;
@@ -1041,12 +1041,12 @@ void Space2DSW::body_remove_from_active_list(SelfList<Body2DSW> *p_body) {
active_list.remove(p_body);
}
-void Space2DSW::body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body) {
- inertia_update_list.add(p_body);
+void Space2DSW::body_add_to_mass_properties_update_list(SelfList<Body2DSW> *p_body) {
+ mass_properties_update_list.add(p_body);
}
-void Space2DSW::body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body) {
- inertia_update_list.remove(p_body);
+void Space2DSW::body_remove_from_mass_properties_update_list(SelfList<Body2DSW> *p_body) {
+ mass_properties_update_list.remove(p_body);
}
BroadPhase2DSW *Space2DSW::get_broadphase() {
@@ -1112,9 +1112,9 @@ void Space2DSW::call_queries() {
void Space2DSW::setup() {
contact_debug_count = 0;
- while (inertia_update_list.first()) {
- inertia_update_list.first()->self()->update_inertias();
- inertia_update_list.remove(inertia_update_list.first());
+ while (mass_properties_update_list.first()) {
+ mass_properties_update_list.first()->self()->update_mass_properties();
+ mass_properties_update_list.remove(mass_properties_update_list.first());
}
}
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index 5de071a475..ad82a14af5 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -49,13 +49,13 @@ class PhysicsDirectSpaceState2DSW : public PhysicsDirectSpaceState2D {
public:
Space2DSW *space;
- virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override;
- virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override;
- virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override;
+ virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override;
+ virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
PhysicsDirectSpaceState2DSW();
};
@@ -86,7 +86,7 @@ private:
BroadPhase2DSW *broadphase;
SelfList<Body2DSW>::List active_list;
- SelfList<Body2DSW>::List inertia_update_list;
+ SelfList<Body2DSW>::List mass_properties_update_list;
SelfList<Body2DSW>::List state_query_list;
SelfList<Area2DSW>::List monitor_query_list;
SelfList<Area2DSW>::List area_moved_list;
@@ -140,8 +140,8 @@ public:
const SelfList<Body2DSW>::List &get_active_body_list() const;
void body_add_to_active_list(SelfList<Body2DSW> *p_body);
void body_remove_from_active_list(SelfList<Body2DSW> *p_body);
- void body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body);
- void body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body);
+ void body_add_to_mass_properties_update_list(SelfList<Body2DSW> *p_body);
+ void body_remove_from_mass_properties_update_list(SelfList<Body2DSW> *p_body);
void area_add_to_moved_list(SelfList<Area2DSW> *p_area);
void area_remove_from_moved_list(SelfList<Area2DSW> *p_area);
const SelfList<Area2DSW>::List &get_moved_area_list() const;
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 7f62e4eb85..41745545d8 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -34,9 +34,9 @@
#include "body_direct_state_3d_sw.h"
#include "space_3d_sw.h"
-void Body3DSW::_update_inertia() {
- if (get_space() && !inertia_update_list.in_list()) {
- get_space()->body_add_to_inertia_update_list(&inertia_update_list);
+void Body3DSW::_mass_properties_changed() {
+ if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) {
+ get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list);
}
}
@@ -44,7 +44,7 @@ void Body3DSW::_update_transform_dependant() {
center_of_mass = get_transform().basis.xform(center_of_mass_local);
principal_inertia_axes = get_transform().basis * principal_inertia_axes_local;
- // update inertia tensor
+ // Update inertia tensor.
Basis tb = principal_inertia_axes;
Basis tbt = tb.transposed();
Basis diag;
@@ -52,74 +52,95 @@ void Body3DSW::_update_transform_dependant() {
_inv_inertia_tensor = tb * diag * tbt;
}
-void Body3DSW::update_inertias() {
+void Body3DSW::update_mass_properties() {
// Update shapes and motions.
switch (mode) {
case PhysicsServer3D::BODY_MODE_DYNAMIC: {
- // Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
real_t total_area = 0;
-
for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
+
total_area += get_shape_area(i);
}
- // We have to recompute the center of mass.
- center_of_mass_local.zero();
+ if (calculate_center_of_mass) {
+ // We have to recompute the center of mass.
+ center_of_mass_local.zero();
- if (total_area != 0.0) {
- for (int i = 0; i < get_shape_count(); i++) {
- real_t area = get_shape_area(i);
+ if (total_area != 0.0) {
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
- real_t mass = area * this->mass / total_area;
+ real_t area = get_shape_area(i);
- // NOTE: we assume that the shape origin is also its center of mass.
- center_of_mass_local += mass * get_shape_transform(i).origin;
- }
+ real_t mass = area * this->mass / total_area;
+
+ // NOTE: we assume that the shape origin is also its center of mass.
+ center_of_mass_local += mass * get_shape_transform(i).origin;
+ }
- center_of_mass_local /= mass;
+ center_of_mass_local /= mass;
+ }
}
- // Recompute the inertia tensor.
- Basis inertia_tensor;
- inertia_tensor.set_zero();
- bool inertia_set = false;
+ if (calculate_inertia) {
+ // Recompute the inertia tensor.
+ Basis inertia_tensor;
+ inertia_tensor.set_zero();
+ bool inertia_set = false;
- for (int i = 0; i < get_shape_count(); i++) {
- if (is_shape_disabled(i)) {
- continue;
- }
+ for (int i = 0; i < get_shape_count(); i++) {
+ if (is_shape_disabled(i)) {
+ continue;
+ }
- real_t area = get_shape_area(i);
- if (area == 0.0) {
- continue;
- }
+ real_t area = get_shape_area(i);
+ if (area == 0.0) {
+ continue;
+ }
- inertia_set = true;
+ inertia_set = true;
- const Shape3DSW *shape = get_shape(i);
+ const Shape3DSW *shape = get_shape(i);
- real_t mass = area * this->mass / total_area;
+ real_t mass = area * this->mass / total_area;
- Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix();
- Transform3D shape_transform = get_shape_transform(i);
- Basis shape_basis = shape_transform.basis.orthonormalized();
+ Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix();
+ Transform3D shape_transform = get_shape_transform(i);
+ Basis shape_basis = shape_transform.basis.orthonormalized();
- // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor!
- shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
+ // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor!
+ shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
- Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
- inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
- }
+ Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
+ inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
+ }
- // Set the inertia to a valid value when there are no valid shapes.
- if (!inertia_set) {
- inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0));
- }
+ // Set the inertia to a valid value when there are no valid shapes.
+ if (!inertia_set) {
+ inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0));
+ }
- // Compute the principal axes of inertia.
- principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
- _inv_inertia = inertia_tensor.get_main_diagonal().inverse();
+ // Handle partial custom inertia.
+ if (inertia.x > 0.0) {
+ inertia_tensor[0][0] = inertia.x;
+ }
+ if (inertia.y > 0.0) {
+ inertia_tensor[1][1] = inertia.y;
+ }
+ if (inertia.z > 0.0) {
+ inertia_tensor[2][2] = inertia.z;
+ }
+
+ // Compute the principal axes of inertia.
+ principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
+ _inv_inertia = inertia_tensor.get_main_diagonal().inverse();
+ }
if (mass) {
_inv_mass = 1.0 / mass;
@@ -128,10 +149,9 @@ void Body3DSW::update_inertias() {
}
} break;
-
case PhysicsServer3D::BODY_MODE_KINEMATIC:
case PhysicsServer3D::BODY_MODE_STATIC: {
- _inv_inertia_tensor.set_zero();
+ _inv_inertia = Vector3();
_inv_mass = 0;
} break;
case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: {
@@ -141,11 +161,15 @@ void Body3DSW::update_inertias() {
} break;
}
- //_update_shapes();
-
_update_transform_dependant();
}
+void Body3DSW::reset_mass_properties() {
+ calculate_inertia = true;
+ calculate_center_of_mass = true;
+ _mass_properties_changed();
+}
+
void Body3DSW::set_active(bool p_active) {
if (active == p_active) {
return;
@@ -165,7 +189,7 @@ void Body3DSW::set_active(bool p_active) {
}
}
-void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) {
+void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) {
switch (p_param) {
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
bounce = p_value;
@@ -174,10 +198,33 @@ void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value)
friction = p_value;
} break;
case PhysicsServer3D::BODY_PARAM_MASS: {
- ERR_FAIL_COND(p_value <= 0);
- mass = p_value;
- _update_inertia();
-
+ real_t mass_value = p_value;
+ ERR_FAIL_COND(mass_value <= 0);
+ mass = mass_value;
+ if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ _mass_properties_changed();
+ }
+ } break;
+ case PhysicsServer3D::BODY_PARAM_INERTIA: {
+ inertia = p_value;
+ if ((inertia.x <= 0.0) || (inertia.y <= 0.0) || (inertia.z <= 0.0)) {
+ calculate_inertia = true;
+ if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ _mass_properties_changed();
+ }
+ } else {
+ calculate_inertia = false;
+ if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ principal_inertia_axes_local.set_diagonal(Vector3(1.0, 1.0, 1.0));
+ _inv_inertia = inertia.inverse();
+ _update_transform_dependant();
+ }
+ }
+ } break;
+ case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
+ calculate_center_of_mass = false;
+ center_of_mass_local = p_value;
+ _update_transform_dependant();
} break;
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
gravity_scale = p_value;
@@ -193,7 +240,7 @@ void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value)
}
}
-real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const {
+Variant Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const {
switch (p_param) {
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
return bounce;
@@ -204,6 +251,16 @@ real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const {
case PhysicsServer3D::BODY_PARAM_MASS: {
return mass;
} break;
+ case PhysicsServer3D::BODY_PARAM_INERTIA: {
+ if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ return _inv_inertia.inverse();
+ } else {
+ return Vector3();
+ }
+ } break;
+ case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
+ return center_of_mass;
+ } break;
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
return gravity_scale;
} break;
@@ -226,40 +283,42 @@ void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) {
mode = p_mode;
switch (p_mode) {
- //CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
case PhysicsServer3D::BODY_MODE_STATIC:
case PhysicsServer3D::BODY_MODE_KINEMATIC: {
_set_inv_transform(get_transform().affine_inverse());
_inv_mass = 0;
+ _inv_inertia = Vector3();
_set_static(p_mode == PhysicsServer3D::BODY_MODE_STATIC);
- //set_active(p_mode==PhysicsServer3D::BODY_MODE_KINEMATIC);
set_active(p_mode == PhysicsServer3D::BODY_MODE_KINEMATIC && contacts.size());
linear_velocity = Vector3();
angular_velocity = Vector3();
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC && prev != mode) {
first_time_kinematic = true;
}
+ _update_transform_dependant();
} break;
case PhysicsServer3D::BODY_MODE_DYNAMIC: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
+ if (!calculate_inertia) {
+ principal_inertia_axes_local.set_diagonal(Vector3(1.0, 1.0, 1.0));
+ _inv_inertia = inertia.inverse();
+ _update_transform_dependant();
+ }
+ _mass_properties_changed();
_set_static(false);
set_active(true);
} break;
case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
+ _inv_inertia = Vector3();
+ angular_velocity = Vector3();
+ _update_transform_dependant();
_set_static(false);
set_active(true);
- angular_velocity = Vector3();
- } break;
+ }
}
-
- _update_inertia();
- /*
- if (get_space())
- _update_queries();
- */
}
PhysicsServer3D::BodyMode Body3DSW::get_mode() const {
@@ -267,7 +326,7 @@ PhysicsServer3D::BodyMode Body3DSW::get_mode() const {
}
void Body3DSW::_shapes_changed() {
- _update_inertia();
+ _mass_properties_changed();
}
void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
@@ -302,10 +361,12 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
linear_velocity = p_variant;
+ constant_linear_velocity = linear_velocity;
wakeup();
} break;
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
angular_velocity = p_variant;
+ constant_angular_velocity = angular_velocity;
wakeup();
} break;
@@ -326,7 +387,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
+ if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
set_active(true);
}
@@ -358,8 +419,8 @@ Variant Body3DSW::get_state(PhysicsServer3D::BodyState p_state) const {
void Body3DSW::set_space(Space3DSW *p_space) {
if (get_space()) {
- if (inertia_update_list.in_list()) {
- get_space()->body_remove_from_inertia_update_list(&inertia_update_list);
+ if (mass_properties_update_list.in_list()) {
+ get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list);
}
if (active_list.in_list()) {
get_space()->body_remove_from_active_list(&active_list);
@@ -372,13 +433,11 @@ void Body3DSW::set_space(Space3DSW *p_space) {
_set_space(p_space);
if (get_space()) {
- _update_inertia();
+ _mass_properties_changed();
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
}
-
- first_integration = true;
}
void Body3DSW::_compute_area_gravity_and_damping(const Area3DSW *p_area) {
@@ -473,7 +532,7 @@ void Body3DSW::integrate_forces(real_t p_step) {
//compute motion, angular and etc. velocities from prev transform
motion = new_transform.origin - get_transform().origin;
do_motion = true;
- linear_velocity = motion / p_step;
+ linear_velocity = constant_linear_velocity + motion / p_step;
//compute a FAKE angular velocity, not so easy
Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed();
@@ -482,9 +541,9 @@ void Body3DSW::integrate_forces(real_t p_step) {
rot.get_axis_angle(axis, angle);
axis.normalize();
- angular_velocity = axis * (angle / p_step);
+ angular_velocity = constant_angular_velocity + axis * (angle / p_step);
} else {
- if (!omit_force_integration && !first_integration) {
+ if (!omit_force_integration) {
//overridden by direct state query
Vector3 force = gravity * mass;
@@ -518,7 +577,6 @@ void Body3DSW::integrate_forces(real_t p_step) {
applied_force = Vector3();
applied_torque = Vector3();
- first_integration = false;
//motion=linear_velocity*p_step;
@@ -640,7 +698,7 @@ void Body3DSW::wakeup_neighbours() {
continue;
}
Body3DSW *b = n[i];
- if (b->mode != PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ if (b->mode < PhysicsServer3D::BODY_MODE_DYNAMIC) {
continue;
}
@@ -717,32 +775,9 @@ PhysicsDirectBodyState3DSW *Body3DSW::get_direct_state() {
Body3DSW::Body3DSW() :
CollisionObject3DSW(TYPE_BODY),
active_list(this),
- inertia_update_list(this),
+ mass_properties_update_list(this),
direct_state_query_list(this) {
- mode = PhysicsServer3D::BODY_MODE_DYNAMIC;
- active = true;
-
- mass = 1;
- _inv_mass = 1;
- bounce = 0;
- friction = 1;
- omit_force_integration = false;
- //applied_torque=0;
- island_step = 0;
- first_time_kinematic = false;
- first_integration = false;
_set_static(false);
-
- contact_count = 0;
- gravity_scale = 1.0;
- linear_damp = -1;
- angular_damp = -1;
- area_angular_damp = 0;
- area_linear_damp = 0;
-
- still_time = 0;
- continuous_cd = false;
- can_sleep = true;
}
Body3DSW::~Body3DSW() {
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index f58f40652b..8b74c7e5b9 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -39,24 +39,28 @@ class Constraint3DSW;
class PhysicsDirectBodyState3DSW;
class Body3DSW : public CollisionObject3DSW {
- PhysicsServer3D::BodyMode mode;
+ PhysicsServer3D::BodyMode mode = PhysicsServer3D::BODY_MODE_DYNAMIC;
Vector3 linear_velocity;
Vector3 angular_velocity;
+ Vector3 constant_linear_velocity;
+ Vector3 constant_angular_velocity;
+
Vector3 biased_linear_velocity;
Vector3 biased_angular_velocity;
- real_t mass;
- real_t bounce;
- real_t friction;
+ real_t mass = 1.0;
+ real_t bounce = 0.0;
+ real_t friction = 1.0;
+ Vector3 inertia;
- real_t linear_damp;
- real_t angular_damp;
- real_t gravity_scale;
+ real_t linear_damp = -1.0;
+ real_t angular_damp = -1.0;
+ real_t gravity_scale = 1.0;
uint16_t locked_axis = 0;
- real_t _inv_mass;
+ real_t _inv_mass = 1.0;
Vector3 _inv_inertia; // Relative to the principal axes of inertia
// Relative to the local frame of reference
@@ -68,30 +72,32 @@ class Body3DSW : public CollisionObject3DSW {
Basis principal_inertia_axes;
Vector3 center_of_mass;
+ bool calculate_inertia = true;
+ bool calculate_center_of_mass = true;
+
Vector3 gravity;
- real_t still_time;
+ real_t still_time = 0.0;
Vector3 applied_force;
Vector3 applied_torque;
- real_t area_angular_damp;
- real_t area_linear_damp;
+ real_t area_angular_damp = 0.0;
+ real_t area_linear_damp = 0.0;
SelfList<Body3DSW> active_list;
- SelfList<Body3DSW> inertia_update_list;
+ SelfList<Body3DSW> mass_properties_update_list;
SelfList<Body3DSW> direct_state_query_list;
VSet<RID> exceptions;
- bool omit_force_integration;
- bool active;
+ bool omit_force_integration = false;
+ bool active = true;
- bool first_integration;
+ bool continuous_cd = false;
+ bool can_sleep = true;
+ bool first_time_kinematic = false;
- bool continuous_cd;
- bool can_sleep;
- bool first_time_kinematic;
- void _update_inertia();
+ void _mass_properties_changed();
virtual void _shapes_changed();
Transform3D new_transform;
@@ -112,7 +118,7 @@ class Body3DSW : public CollisionObject3DSW {
};
Vector<Contact> contacts; //no contacts by default
- int contact_count;
+ int contact_count = 0;
void *body_state_callback_instance = nullptr;
PhysicsServer3D::BodyStateCallback body_state_callback = nullptr;
@@ -126,7 +132,7 @@ class Body3DSW : public CollisionObject3DSW {
PhysicsDirectBodyState3DSW *direct_state = nullptr;
- uint64_t island_step;
+ uint64_t island_step = 0;
_FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area3DSW *p_area);
@@ -251,8 +257,8 @@ public:
set_active(true);
}
- void set_param(PhysicsServer3D::BodyParameter p_param, real_t);
- real_t get_param(PhysicsServer3D::BodyParameter p_param) const;
+ void set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer3D::BodyParameter p_param) const;
void set_mode(PhysicsServer3D::BodyMode p_mode);
PhysicsServer3D::BodyMode get_mode() const;
@@ -271,7 +277,8 @@ public:
void set_space(Space3DSW *p_space);
- void update_inertias();
+ void update_mass_properties();
+ void reset_mass_properties();
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
_FORCE_INLINE_ const Vector3 &get_inv_inertia() const { return _inv_inertia; }
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index a214e80c6c..8de54c5c48 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -643,20 +643,27 @@ uint32_t PhysicsServer3DSW::body_get_user_flags(RID p_body) const {
return 0;
};
-void PhysicsServer3DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
+void PhysicsServer3DSW::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_param(p_param, p_value);
};
-real_t PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) const {
+Variant PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) const {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_param(p_param);
};
+void PhysicsServer3DSW::body_reset_mass_properties(RID p_body) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ return body->reset_mass_properties();
+}
+
void PhysicsServer3DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index f283f83112..071ad0a694 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -198,8 +198,10 @@ public:
virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override;
virtual uint32_t body_get_user_flags(RID p_body) const override;
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override;
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override;
+ virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override;
+ virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override;
+
+ virtual void body_reset_mass_properties(RID p_body) override;
virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
virtual Variant body_get_state(RID p_body, BodyState p_state) const override;
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index 8865bd4bd2..58986969d4 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -210,8 +210,10 @@ public:
FUNC2(body_set_user_flags, RID, uint32_t);
FUNC1RC(uint32_t, body_get_user_flags, RID);
- FUNC3(body_set_param, RID, BodyParameter, real_t);
- FUNC2RC(real_t, body_get_param, RID, BodyParameter);
+ FUNC3(body_set_param, RID, BodyParameter, const Variant &);
+ FUNC2RC(Variant, body_get_param, RID, BodyParameter);
+
+ FUNC1(body_reset_mass_properties, RID);
FUNC3(body_set_state, RID, BodyState, const Variant &);
FUNC2RC(Variant, body_get_state, RID, BodyState);
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index b81d3272c3..945d0120be 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -1676,6 +1676,17 @@ struct _HeightmapSegmentCullParams {
FaceShape3DSW *face = nullptr;
};
+struct _HeightmapGridCullState {
+ real_t length = 0.0;
+ real_t length_flat = 0.0;
+
+ real_t dist = 0.0;
+ real_t prev_dist = 0.0;
+
+ int x = 0;
+ int z = 0;
+};
+
_FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
Vector3 res;
Vector3 normal;
@@ -1688,11 +1699,11 @@ _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_
return false;
}
-_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, int p_x, int p_z) {
+_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) {
// First triangle.
- p_params.heightmap->_get_point(p_x, p_z, p_params.face->vertex[0]);
- p_params.heightmap->_get_point(p_x + 1, p_z, p_params.face->vertex[1]);
- p_params.heightmap->_get_point(p_x, p_z + 1, p_params.face->vertex[2]);
+ p_params.heightmap->_get_point(p_state.x, p_state.z, p_params.face->vertex[0]);
+ p_params.heightmap->_get_point(p_state.x + 1, p_state.z, p_params.face->vertex[1]);
+ p_params.heightmap->_get_point(p_state.x, p_state.z + 1, p_params.face->vertex[2]);
p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
if (_heightmap_face_cull_segment(p_params)) {
return true;
@@ -1700,7 +1711,7 @@ _FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_
// Second triangle.
p_params.face->vertex[0] = p_params.face->vertex[1];
- p_params.heightmap->_get_point(p_x + 1, p_z + 1, p_params.face->vertex[1]);
+ p_params.heightmap->_get_point(p_state.x + 1, p_state.z + 1, p_params.face->vertex[1]);
p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
if (_heightmap_face_cull_segment(p_params)) {
return true;
@@ -1709,13 +1720,51 @@ _FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_
return false;
}
-bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
- if (heights.is_empty()) {
+_FORCE_INLINE_ bool _heightmap_chunk_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) {
+ const HeightMapShape3DSW::Range &chunk = p_params.heightmap->_get_bounds_chunk(p_state.x, p_state.z);
+
+ Vector3 enter_pos;
+ Vector3 exit_pos;
+
+ if (p_state.length_flat > CMP_EPSILON) {
+ real_t flat_to_3d = p_state.length / p_state.length_flat;
+ real_t enter_param = p_state.prev_dist * flat_to_3d;
+ real_t exit_param = p_state.dist * flat_to_3d;
+ enter_pos = p_params.from + p_params.dir * enter_param;
+ exit_pos = p_params.from + p_params.dir * exit_param;
+ } else {
+ // Consider the ray vertical.
+ // (though we shouldn't reach this often because there is an early check up-front)
+ enter_pos = p_params.from;
+ exit_pos = p_params.to;
+ }
+
+ // Transform positions to heightmap space.
+ enter_pos *= HeightMapShape3DSW::BOUNDS_CHUNK_SIZE;
+ exit_pos *= HeightMapShape3DSW::BOUNDS_CHUNK_SIZE;
+
+ // We did enter the flat projection of the AABB,
+ // but we have to check if we intersect it on the vertical axis.
+ if ((enter_pos.y > chunk.max) && (exit_pos.y > chunk.max)) {
+ return false;
+ }
+ if ((enter_pos.y < chunk.min) && (exit_pos.y < chunk.min)) {
return false;
}
- Vector3 local_begin = p_begin + local_origin;
- Vector3 local_end = p_end + local_origin;
+ return p_params.heightmap->_intersect_grid_segment(_heightmap_cell_cull_segment, enter_pos, exit_pos, p_params.heightmap->width, p_params.heightmap->depth, p_params.heightmap->local_origin, p_params.result, p_params.normal);
+}
+
+template <typename ProcessFunction>
+bool HeightMapShape3DSW::_intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const {
+ Vector3 delta = (p_end - p_begin);
+ real_t length = delta.length();
+
+ if (length < CMP_EPSILON) {
+ return false;
+ }
+
+ Vector3 local_begin = p_begin + offset;
FaceShape3DSW face;
face.backface_collision = false;
@@ -1723,136 +1772,181 @@ bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3
_HeightmapSegmentCullParams params;
params.from = p_begin;
params.to = p_end;
- params.dir = (p_end - p_begin).normalized();
+ params.dir = delta / length;
params.heightmap = this;
params.face = &face;
- // Quantize the ray begin/end.
- int begin_x = floor(local_begin.x);
- int begin_z = floor(local_begin.z);
- int end_x = floor(local_end.x);
- int end_z = floor(local_end.z);
+ _HeightmapGridCullState state;
- if ((begin_x == end_x) && (begin_z == end_z)) {
- // Simple case for rays that don't traverse the grid horizontally.
- // Just perform a test on the given cell.
- int x = CLAMP(begin_x, 0, width - 2);
- int z = CLAMP(begin_z, 0, depth - 2);
- if (_heightmap_cell_cull_segment(params, x, z)) {
- r_point = params.result;
- r_normal = params.normal;
- return true;
- }
- } else {
- // Perform grid query from projected ray.
- Vector2 ray_dir_proj(local_end.x - local_begin.x, local_end.z - local_begin.z);
- real_t ray_dist_proj = ray_dir_proj.length();
+ // Perform grid query from projected ray.
+ Vector2 ray_dir_flat(delta.x, delta.z);
+ state.length = length;
+ state.length_flat = ray_dir_flat.length();
- if (ray_dist_proj < CMP_EPSILON) {
- ray_dir_proj = Vector2();
- } else {
- ray_dir_proj /= ray_dist_proj;
- }
+ if (state.length_flat < CMP_EPSILON) {
+ ray_dir_flat = Vector2();
+ } else {
+ ray_dir_flat /= state.length_flat;
+ }
- const int x_step = (ray_dir_proj.x > CMP_EPSILON) ? 1 : ((ray_dir_proj.x < -CMP_EPSILON) ? -1 : 0);
- const int z_step = (ray_dir_proj.y > CMP_EPSILON) ? 1 : ((ray_dir_proj.y < -CMP_EPSILON) ? -1 : 0);
+ const int x_step = (ray_dir_flat.x > CMP_EPSILON) ? 1 : ((ray_dir_flat.x < -CMP_EPSILON) ? -1 : 0);
+ const int z_step = (ray_dir_flat.y > CMP_EPSILON) ? 1 : ((ray_dir_flat.y < -CMP_EPSILON) ? -1 : 0);
- const real_t infinite = 1e20;
- const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_proj.x) : infinite;
- const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_proj.y) : infinite;
+ const real_t infinite = 1e20;
+ const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_flat.x) : infinite;
+ const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_flat.y) : infinite;
- real_t cross_x; // At which value of `param` we will cross a x-axis lane?
- real_t cross_z; // At which value of `param` we will cross a z-axis lane?
+ real_t cross_x; // At which value of `param` we will cross a x-axis lane?
+ real_t cross_z; // At which value of `param` we will cross a z-axis lane?
- // X initialization.
- if (x_step != 0) {
- if (x_step == 1) {
- cross_x = (ceil(local_begin.x) - local_begin.x) * delta_x;
- } else {
- cross_x = (local_begin.x - floor(local_begin.x)) * delta_x;
- }
+ // X initialization.
+ if (x_step != 0) {
+ if (x_step == 1) {
+ cross_x = (Math::ceil(local_begin.x) - local_begin.x) * delta_x;
} else {
- cross_x = infinite; // Will never cross on X.
+ cross_x = (local_begin.x - Math::floor(local_begin.x)) * delta_x;
}
+ } else {
+ cross_x = infinite; // Will never cross on X.
+ }
- // Z initialization.
- if (z_step != 0) {
- if (z_step == 1) {
- cross_z = (ceil(local_begin.z) - local_begin.z) * delta_z;
- } else {
- cross_z = (local_begin.z - floor(local_begin.z)) * delta_z;
- }
+ // Z initialization.
+ if (z_step != 0) {
+ if (z_step == 1) {
+ cross_z = (Math::ceil(local_begin.z) - local_begin.z) * delta_z;
} else {
- cross_z = infinite; // Will never cross on Z.
+ cross_z = (local_begin.z - Math::floor(local_begin.z)) * delta_z;
}
+ } else {
+ cross_z = infinite; // Will never cross on Z.
+ }
- int x = floor(local_begin.x);
- int z = floor(local_begin.z);
+ int x = Math::floor(local_begin.x);
+ int z = Math::floor(local_begin.z);
- // Workaround cases where the ray starts at an integer position.
- if (Math::is_zero_approx(cross_x)) {
- cross_x += delta_x;
- // If going backwards, we should ignore the position we would get by the above flooring,
- // because the ray is not heading in that direction.
- if (x_step == -1) {
- x -= 1;
- }
+ // Workaround cases where the ray starts at an integer position.
+ if (Math::is_zero_approx(cross_x)) {
+ cross_x += delta_x;
+ // If going backwards, we should ignore the position we would get by the above flooring,
+ // because the ray is not heading in that direction.
+ if (x_step == -1) {
+ x -= 1;
}
+ }
- if (Math::is_zero_approx(cross_z)) {
- cross_z += delta_z;
- if (z_step == -1) {
- z -= 1;
- }
+ if (Math::is_zero_approx(cross_z)) {
+ cross_z += delta_z;
+ if (z_step == -1) {
+ z -= 1;
}
+ }
+
+ // Start inside the grid.
+ int x_start = MAX(MIN(x, p_width - 2), 0);
+ int z_start = MAX(MIN(z, p_depth - 2), 0);
- // Start inside the grid.
- int x_start = CLAMP(x, 0, width - 2);
- int z_start = CLAMP(z, 0, depth - 2);
+ // Adjust initial cross values.
+ cross_x += delta_x * x_step * (x_start - x);
+ cross_z += delta_z * z_step * (z_start - z);
- // Adjust initial cross values.
- cross_x += delta_x * x_step * (x_start - x);
- cross_z += delta_z * z_step * (z_start - z);
+ x = x_start;
+ z = z_start;
- x = x_start;
- z = z_start;
+ while (true) {
+ state.prev_dist = state.dist;
+ state.x = x;
+ state.z = z;
- if (_heightmap_cell_cull_segment(params, x, z)) {
+ if (cross_x < cross_z) {
+ // X lane.
+ x += x_step;
+ // Assign before advancing the param,
+ // to be in sync with the initialization step.
+ state.dist = cross_x;
+ cross_x += delta_x;
+ } else {
+ // Z lane.
+ z += z_step;
+ state.dist = cross_z;
+ cross_z += delta_z;
+ }
+
+ if (state.dist > state.length_flat) {
+ state.dist = state.length_flat;
+ if (p_process(params, state)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+ break;
+ }
+
+ if (p_process(params, state)) {
r_point = params.result;
r_normal = params.normal;
return true;
}
- real_t dist = 0.0;
- while (true) {
- if (cross_x < cross_z) {
- // X lane.
- x += x_step;
- // Assign before advancing the param,
- // to be in sync with the initialization step.
- dist = cross_x;
- cross_x += delta_x;
- } else {
- // Z lane.
- z += z_step;
- dist = cross_z;
- cross_z += delta_z;
- }
+ // Stop when outside the grid.
+ if ((x < 0) || (z < 0) || (x >= p_width - 1) || (z >= p_depth - 1)) {
+ break;
+ }
+ }
- // Stop when outside the grid.
- if ((x < 0) || (z < 0) || (x >= width - 1) || (z >= depth - 1)) {
- break;
- }
+ return false;
+}
- if (_heightmap_cell_cull_segment(params, x, z)) {
- r_point = params.result;
- r_normal = params.normal;
- return true;
- }
+bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
+ if (heights.is_empty()) {
+ return false;
+ }
- if (dist > ray_dist_proj) {
- break;
- }
+ Vector3 local_begin = p_begin + local_origin;
+ Vector3 local_end = p_end + local_origin;
+
+ // Quantize the ray begin/end.
+ int begin_x = Math::floor(local_begin.x);
+ int begin_z = Math::floor(local_begin.z);
+ int end_x = Math::floor(local_end.x);
+ int end_z = Math::floor(local_end.z);
+
+ if ((begin_x == end_x) && (begin_z == end_z)) {
+ // Simple case for rays that don't traverse the grid horizontally.
+ // Just perform a test on the given cell.
+ FaceShape3DSW face;
+ face.backface_collision = false;
+
+ _HeightmapSegmentCullParams params;
+ params.from = p_begin;
+ params.to = p_end;
+ params.dir = (p_end - p_begin).normalized();
+
+ params.heightmap = this;
+ params.face = &face;
+
+ _HeightmapGridCullState state;
+ state.x = MAX(MIN(begin_x, width - 2), 0);
+ state.z = MAX(MIN(begin_z, depth - 2), 0);
+ if (_heightmap_cell_cull_segment(params, state)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+ } else if (bounds_grid.is_empty()) {
+ // Process all cells intersecting the flat projection of the ray.
+ return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal);
+ } else {
+ Vector3 ray_diff = (p_end - p_begin);
+ real_t length_flat_sqr = ray_diff.x * ray_diff.x + ray_diff.z * ray_diff.z;
+ if (length_flat_sqr < BOUNDS_CHUNK_SIZE * BOUNDS_CHUNK_SIZE) {
+ // Don't use chunks, the ray is too short in the plane.
+ return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal);
+ } else {
+ // The ray is long, run raycast on a higher-level grid.
+ Vector3 bounds_from = p_begin / BOUNDS_CHUNK_SIZE;
+ Vector3 bounds_to = p_end / BOUNDS_CHUNK_SIZE;
+ Vector3 bounds_offset = local_origin / BOUNDS_CHUNK_SIZE;
+ return _intersect_grid_segment(_heightmap_chunk_cull_segment, bounds_from, bounds_to, bounds_grid_width, bounds_grid_depth, bounds_offset, r_point, r_normal);
}
}
@@ -1917,7 +2011,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback
_get_point(x, z, face.vertex[0]);
_get_point(x + 1, z, face.vertex[1]);
_get_point(x, z + 1, face.vertex[2]);
- face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
+ face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal;
if (p_callback(p_userdata, &face)) {
return;
}
@@ -1925,7 +2019,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback
// Second triangle.
face.vertex[0] = face.vertex[1];
_get_point(x + 1, z + 1, face.vertex[1]);
- face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
+ face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal;
if (p_callback(p_userdata, &face)) {
return;
}
@@ -1943,6 +2037,75 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const {
(p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
+void HeightMapShape3DSW::_build_accelerator() {
+ bounds_grid.clear();
+
+ bounds_grid_width = width / BOUNDS_CHUNK_SIZE;
+ bounds_grid_depth = depth / BOUNDS_CHUNK_SIZE;
+
+ if (width % BOUNDS_CHUNK_SIZE > 0) {
+ ++bounds_grid_width; // In case terrain size isn't dividable by chunk size.
+ }
+
+ if (depth % BOUNDS_CHUNK_SIZE > 0) {
+ ++bounds_grid_depth;
+ }
+
+ uint32_t bound_grid_size = (uint32_t)(bounds_grid_width * bounds_grid_depth);
+
+ if (bound_grid_size < 2) {
+ // Grid is empty or just one chunk.
+ return;
+ }
+
+ bounds_grid.resize(bound_grid_size);
+
+ // Compute min and max height for all chunks.
+ for (int cz = 0; cz < bounds_grid_depth; ++cz) {
+ int z0 = cz * BOUNDS_CHUNK_SIZE;
+
+ for (int cx = 0; cx < bounds_grid_width; ++cx) {
+ int x0 = cx * BOUNDS_CHUNK_SIZE;
+
+ Range r;
+
+ r.min = _get_height(x0, z0);
+ r.max = r.min;
+
+ // Compute min and max height for this chunk.
+ // We have to include one extra cell to account for neighbors.
+ // Here is why:
+ // Say we have a flat terrain, and a plateau that fits a chunk perfectly.
+ //
+ // Left Right
+ // 0---0---0---1---1---1
+ // | | | | | |
+ // 0---0---0---1---1---1
+ // | | | | | |
+ // 0---0---0---1---1---1
+ // x
+ //
+ // If the AABB for the Left chunk did not share vertices with the Right,
+ // then we would fail collision tests at x due to a gap.
+ //
+ int z_max = MIN(z0 + BOUNDS_CHUNK_SIZE + 1, depth);
+ int x_max = MIN(x0 + BOUNDS_CHUNK_SIZE + 1, width);
+ for (int z = z0; z < z_max; ++z) {
+ for (int x = x0; x < x_max; ++x) {
+ real_t height = _get_height(x, z);
+ if (height < r.min) {
+ r.min = height;
+ } else if (height > r.max) {
+ r.max = height;
+ }
+ }
+ }
+
+ bounds_grid[cx + cz * bounds_grid_width] = r;
+ }
+ }
+}
+
void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
heights = p_heights;
width = p_width;
@@ -1959,6 +2122,8 @@ void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, in
aabb.position -= local_origin;
+ _build_accelerator();
+
configure(aabb);
}
@@ -2017,7 +2182,7 @@ void HeightMapShape3DSW::set_data(const Variant &p_data) {
} else {
int heights_size = heights.size();
for (int i = 0; i < heights_size; ++i) {
- float h = heights[i];
+ real_t h = heights[i];
if (h < min_height) {
min_height = h;
} else if (h > max_height) {
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index b05f65f268..73eddc469c 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -32,6 +32,7 @@
#define SHAPE_SW_H
#include "core/math/geometry_3d.h"
+#include "core/templates/local_vector.h"
#include "servers/physics_server_3d.h"
class Shape3DSW;
@@ -385,6 +386,21 @@ struct HeightMapShape3DSW : public ConcaveShape3DSW {
int depth = 0;
Vector3 local_origin;
+ // Accelerator.
+ struct Range {
+ real_t min = 0.0;
+ real_t max = 0.0;
+ };
+ LocalVector<Range> bounds_grid;
+ int bounds_grid_width = 0;
+ int bounds_grid_depth = 0;
+
+ static const int BOUNDS_CHUNK_SIZE = 16;
+
+ _FORCE_INLINE_ const Range &_get_bounds_chunk(int p_x, int p_z) const {
+ return bounds_grid[(p_z * bounds_grid_width) + p_x];
+ }
+
_FORCE_INLINE_ real_t _get_height(int p_x, int p_z) const {
return heights[(p_z * width) + p_x];
}
@@ -397,6 +413,11 @@ struct HeightMapShape3DSW : public ConcaveShape3DSW {
void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const;
+ void _build_accelerator();
+
+ template <typename ProcessFunction>
+ bool _intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const;
+
void _setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
public:
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 37dee436df..3b08184e00 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -977,12 +977,12 @@ void Space3DSW::body_remove_from_active_list(SelfList<Body3DSW> *p_body) {
active_list.remove(p_body);
}
-void Space3DSW::body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body) {
- inertia_update_list.add(p_body);
+void Space3DSW::body_add_to_mass_properties_update_list(SelfList<Body3DSW> *p_body) {
+ mass_properties_update_list.add(p_body);
}
-void Space3DSW::body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body) {
- inertia_update_list.remove(p_body);
+void Space3DSW::body_remove_from_mass_properties_update_list(SelfList<Body3DSW> *p_body) {
+ mass_properties_update_list.remove(p_body);
}
BroadPhase3DSW *Space3DSW::get_broadphase() {
@@ -1059,9 +1059,9 @@ void Space3DSW::call_queries() {
void Space3DSW::setup() {
contact_debug_count = 0;
- while (inertia_update_list.first()) {
- inertia_update_list.first()->self()->update_inertias();
- inertia_update_list.remove(inertia_update_list.first());
+ while (mass_properties_update_list.first()) {
+ mass_properties_update_list.first()->self()->update_mass_properties();
+ mass_properties_update_list.remove(mass_properties_update_list.first());
}
}
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index eff494a7bc..98c335cb80 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -48,12 +48,12 @@ class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D {
public:
Space3DSW *space;
- virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override;
- virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override;
- virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
- virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override;
+ virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override;
+ virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
+ virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override;
virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override;
PhysicsDirectSpaceState3DSW();
@@ -79,7 +79,7 @@ private:
BroadPhase3DSW *broadphase;
SelfList<Body3DSW>::List active_list;
- SelfList<Body3DSW>::List inertia_update_list;
+ SelfList<Body3DSW>::List mass_properties_update_list;
SelfList<Body3DSW>::List state_query_list;
SelfList<Area3DSW>::List monitor_query_list;
SelfList<Area3DSW>::List area_moved_list;
@@ -137,8 +137,8 @@ public:
const SelfList<Body3DSW>::List &get_active_body_list() const;
void body_add_to_active_list(SelfList<Body3DSW> *p_body);
void body_remove_from_active_list(SelfList<Body3DSW> *p_body);
- void body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body);
- void body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body);
+ void body_add_to_mass_properties_update_list(SelfList<Body3DSW> *p_body);
+ void body_remove_from_mass_properties_update_list(SelfList<Body3DSW> *p_body);
void body_add_to_state_query_list(SelfList<Body3DSW> *p_body);
void body_remove_from_state_query_list(SelfList<Body3DSW> *p_body);
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 4660b83f4d..2656ef1d6d 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -77,6 +77,7 @@ void PhysicsDirectBodyState2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &PhysicsDirectBodyState2D::get_total_linear_damp);
ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState2D::get_total_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &PhysicsDirectBodyState2D::get_center_of_mass);
ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState2D::get_inverse_mass);
ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState2D::get_inverse_inertia);
@@ -123,6 +124,7 @@ void PhysicsDirectBodyState2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "total_gravity"), "", "get_total_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass"), "", "get_center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping");
@@ -257,13 +259,6 @@ void PhysicsShapeQueryParameters2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
}
-PhysicsShapeQueryParameters2D::PhysicsShapeQueryParameters2D() {
- margin = 0;
- collision_mask = 0x7FFFFFFF;
- collide_with_bodies = true;
- collide_with_areas = false;
-}
-
Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
RayResult inters;
Set<RID> exclude;
@@ -411,9 +406,9 @@ PhysicsDirectSpaceState2D::PhysicsDirectSpaceState2D() {
}
void PhysicsDirectSpaceState2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_intersect_shape, DEFVAL(32));
ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &PhysicsDirectSpaceState2D::_cast_motion);
ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_collide_shape, DEFVAL(32));
@@ -614,6 +609,8 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param);
ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param);
+ ClassDB::bind_method(D_METHOD("body_reset_mass_properties", "body"), &PhysicsServer2D::body_reset_mass_properties);
+
ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer2D::body_set_state);
ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer2D::body_get_state);
@@ -709,6 +706,7 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
BIND_ENUM_CONSTANT(BODY_PARAM_MASS);
BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA);
+ BIND_ENUM_CONSTANT(BODY_PARAM_CENTER_OF_MASS);
BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE);
BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP);
BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 021d7be7c0..1145bb8b91 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -48,6 +48,7 @@ public:
virtual real_t get_total_linear_damp() const = 0; // get density of this body space/area
virtual real_t get_total_angular_damp() const = 0; // get density of this body space/area
+ virtual Vector2 get_center_of_mass() const = 0;
virtual real_t get_inverse_mass() const = 0; // get the mass
virtual real_t get_inverse_inertia() const = 0; // get density of this body space
@@ -103,12 +104,12 @@ class PhysicsShapeQueryParameters2D : public RefCounted {
RID shape;
Transform2D transform;
Vector2 motion;
- real_t margin;
+ real_t margin = 0.0;
Set<RID> exclude;
- uint32_t collision_mask;
+ uint32_t collision_mask = UINT32_MAX;
- bool collide_with_bodies;
- bool collide_with_areas;
+ bool collide_with_bodies = true;
+ bool collide_with_areas = false;
protected:
static void _bind_methods();
@@ -139,8 +140,6 @@ public:
void set_exclude(const Vector<RID> &p_exclude);
Vector<RID> get_exclude() const;
-
- PhysicsShapeQueryParameters2D();
};
class PhysicsDirectSpaceState2D : public Object {
@@ -169,7 +168,7 @@ public:
Variant metadata;
};
- virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
struct ShapeResult {
RID rid;
@@ -179,14 +178,14 @@ public:
Variant metadata;
};
- virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
- virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
+ virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
+ virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
- virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
- virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
- virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
struct ShapeRestInfo {
Vector2 point;
@@ -198,7 +197,7 @@ public:
Variant metadata;
};
- virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
PhysicsDirectSpaceState2D();
};
@@ -404,15 +403,18 @@ public:
BODY_PARAM_BOUNCE,
BODY_PARAM_FRICTION,
BODY_PARAM_MASS, ///< unused for static, always infinite
- BODY_PARAM_INERTIA, // read-only: computed from mass & shapes
+ BODY_PARAM_INERTIA,
+ BODY_PARAM_CENTER_OF_MASS,
BODY_PARAM_GRAVITY_SCALE,
BODY_PARAM_LINEAR_DAMP,
BODY_PARAM_ANGULAR_DAMP,
BODY_PARAM_MAX,
};
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0;
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0;
+ virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) = 0;
+ virtual Variant body_get_param(RID p_body, BodyParameter p_param) const = 0;
+
+ virtual void body_reset_mass_properties(RID p_body) = 0;
//state
enum BodyState {
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 6cde4977f4..0c487b83ea 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -249,13 +249,6 @@ void PhysicsShapeQueryParameters3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
}
-PhysicsShapeQueryParameters3D::PhysicsShapeQueryParameters3D() {
- margin = 0;
- collision_mask = 0x7FFFFFFF;
- collide_with_bodies = true;
- collide_with_areas = false;
-}
-
/////////////////////////////////////
Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
@@ -360,7 +353,7 @@ PhysicsDirectSpaceState3D::PhysicsDirectSpaceState3D() {
}
void PhysicsDirectSpaceState3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState3D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState3D::_intersect_ray, DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_intersect_shape, DEFVAL(32));
ClassDB::bind_method(D_METHOD("cast_motion", "shape", "motion"), &PhysicsDirectSpaceState3D::_cast_motion);
ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_collide_shape, DEFVAL(32));
@@ -584,6 +577,8 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer3D::body_set_param);
ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer3D::body_get_param);
+ ClassDB::bind_method(D_METHOD("body_reset_mass_properties", "body"), &PhysicsServer3D::body_reset_mass_properties);
+
ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer3D::body_set_state);
ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer3D::body_get_state);
@@ -789,6 +784,8 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
BIND_ENUM_CONSTANT(BODY_PARAM_MASS);
+ BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA);
+ BIND_ENUM_CONSTANT(BODY_PARAM_CENTER_OF_MASS);
BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE);
BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP);
BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index a365802220..5677604682 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -103,12 +103,12 @@ class PhysicsShapeQueryParameters3D : public RefCounted {
RES shape_ref;
RID shape;
Transform3D transform;
- real_t margin;
+ real_t margin = 0.0;
Set<RID> exclude;
- uint32_t collision_mask;
+ uint32_t collision_mask = UINT32_MAX;
- bool collide_with_bodies;
- bool collide_with_areas;
+ bool collide_with_bodies = true;
+ bool collide_with_areas = false;
protected:
static void _bind_methods();
@@ -136,15 +136,13 @@ public:
void set_collide_with_areas(bool p_enable);
bool is_collide_with_areas_enabled() const;
-
- PhysicsShapeQueryParameters3D();
};
class PhysicsDirectSpaceState3D : public Object {
GDCLASS(PhysicsDirectSpaceState3D, Object);
private:
- Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
Array _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion);
Array _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
@@ -161,7 +159,7 @@ public:
int shape = 0;
};
- virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
struct RayResult {
Vector3 position;
@@ -172,9 +170,9 @@ public:
int shape = 0;
};
- virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0;
+ virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0;
- virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
struct ShapeRestInfo {
Vector3 point;
@@ -185,11 +183,11 @@ public:
Vector3 linear_velocity; //velocity at contact point
};
- virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0;
+ virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0;
- virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
- virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+ virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0;
@@ -407,14 +405,18 @@ public:
BODY_PARAM_BOUNCE,
BODY_PARAM_FRICTION,
BODY_PARAM_MASS, ///< unused for static, always infinite
+ BODY_PARAM_INERTIA,
+ BODY_PARAM_CENTER_OF_MASS,
BODY_PARAM_GRAVITY_SCALE,
BODY_PARAM_LINEAR_DAMP,
BODY_PARAM_ANGULAR_DAMP,
BODY_PARAM_MAX,
};
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0;
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0;
+ virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) = 0;
+ virtual Variant body_get_param(RID p_body, BodyParameter p_param) const = 0;
+
+ virtual void body_reset_mass_properties(RID p_body) = 0;
//state
enum BodyState {
diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h
index f58d124140..35bb7722e7 100644
--- a/servers/rendering/rasterizer_dummy.h
+++ b/servers/rendering/rasterizer_dummy.h
@@ -197,7 +197,7 @@ public:
TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); }
- bool free(RID p_rid) override { return true; }
+ bool free(RID p_rid) override { return false; }
void update() override {}
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {}
@@ -664,8 +664,9 @@ public:
DummyTexture *texture = texture_owner.getornull(p_rid);
texture_owner.free(p_rid);
memdelete(texture);
+ return true;
}
- return true;
+ return false;
}
virtual void update_memory_info() override {}
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 6206849b66..1971c3e781 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -41,7 +41,8 @@
class RendererSceneRender;
struct BlitToScreen {
RID render_target;
- Rect2i rect;
+ Rect2 src_rect = Rect2(0.0, 0.0, 1.0, 1.0);
+ Rect2i dst_rect;
struct {
bool use_layer = 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 1b730567d9..9201f917db 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -223,7 +223,6 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c
RD::TEXTURE_SAMPLES_2,
RD::TEXTURE_SAMPLES_4,
RD::TEXTURE_SAMPLES_8,
- RD::TEXTURE_SAMPLES_16
};
texture_samples = ts[p_msaa];
@@ -1163,7 +1162,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers);
}
RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment);
- static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 };
+ static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8 };
//first of all, make a new render pass
//fill up ubo
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 a24860996c..d0f02b44cb 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
@@ -601,10 +601,10 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.usage_defines["UV2"] = "#define UV2_USED\n";
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
- actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
- actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
- actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
- actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
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 276a44bc27..a5cc2db48f 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -159,7 +159,6 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
RD::TEXTURE_SAMPLES_2,
RD::TEXTURE_SAMPLES_4,
RD::TEXTURE_SAMPLES_8,
- RD::TEXTURE_SAMPLES_16
};
texture_samples = ts[p_msaa];
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 14b3b6d9aa..cd314d8c56 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
@@ -593,10 +593,10 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
actions.usage_defines["UV2"] = "#define UV2_USED\n";
actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
- actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
- actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
- actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
- actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 647c348d9f..3c66fadbe9 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1086,7 +1086,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
}
}
- RID material = ci->material;
+ RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
if (material.is_null() && ci->canvas_group != nullptr) {
material = default_canvas_group_material;
@@ -1354,8 +1354,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
}
- if (ci->material.is_valid()) {
- MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RendererStorageRD::SHADER_TYPE_2D);
+ RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
+
+ if (material.is_valid()) {
+ MaterialData *md = (MaterialData *)storage->material_get_data(material, RendererStorageRD::SHADER_TYPE_2D);
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
if (!material_screen_texture_found) {
@@ -1375,7 +1377,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
// uniform set may be gone because a dependency was erased. In this case, it will happen
// if a texture is deleted, so just re-create it.
- storage->material_force_update_textures(ci->material, RendererStorageRD::SHADER_TYPE_2D);
+ storage->material_force_update_textures(material, RendererStorageRD::SHADER_TYPE_2D);
}
}
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 62e9386f95..c53c202bab 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -46,6 +46,8 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
RID rd_texture = storage->texture_get_rd_texture(texture);
ERR_CONTINUE(rd_texture.is_null());
+ // TODO if keep_3d_linear was set when rendering to this render target we need to add a linear->sRGB conversion in.
+
if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) {
Vector<RD::Uniform> uniforms;
RD::Uniform u;
@@ -65,10 +67,14 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0);
- blit.push_constant.rect[0] = p_render_targets[i].rect.position.x / screen_size.width;
- blit.push_constant.rect[1] = p_render_targets[i].rect.position.y / screen_size.height;
- blit.push_constant.rect[2] = p_render_targets[i].rect.size.width / screen_size.width;
- blit.push_constant.rect[3] = p_render_targets[i].rect.size.height / screen_size.height;
+ blit.push_constant.src_rect[0] = p_render_targets[i].src_rect.position.x;
+ blit.push_constant.src_rect[1] = p_render_targets[i].src_rect.position.y;
+ blit.push_constant.src_rect[2] = p_render_targets[i].src_rect.size.width;
+ blit.push_constant.src_rect[3] = p_render_targets[i].src_rect.size.height;
+ blit.push_constant.dst_rect[0] = p_render_targets[i].dst_rect.position.x / screen_size.width;
+ blit.push_constant.dst_rect[1] = p_render_targets[i].dst_rect.position.y / screen_size.height;
+ blit.push_constant.dst_rect[2] = p_render_targets[i].dst_rect.size.width / screen_size.width;
+ blit.push_constant.dst_rect[3] = p_render_targets[i].dst_rect.size.height / screen_size.height;
blit.push_constant.layer = p_render_targets[i].multi_view.layer;
blit.push_constant.eye_center[0] = p_render_targets[i].lens_distortion.eye_center.x;
blit.push_constant.eye_center[1] = p_render_targets[i].lens_distortion.eye_center.y;
@@ -203,10 +209,14 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0);
- blit.push_constant.rect[0] = screenrect.position.x;
- blit.push_constant.rect[1] = screenrect.position.y;
- blit.push_constant.rect[2] = screenrect.size.width;
- blit.push_constant.rect[3] = screenrect.size.height;
+ blit.push_constant.src_rect[0] = 0.0;
+ blit.push_constant.src_rect[1] = 0.0;
+ blit.push_constant.src_rect[2] = 1.0;
+ blit.push_constant.src_rect[3] = 1.0;
+ blit.push_constant.dst_rect[0] = screenrect.position.x;
+ blit.push_constant.dst_rect[1] = screenrect.position.y;
+ blit.push_constant.dst_rect[2] = screenrect.size.width;
+ blit.push_constant.dst_rect[3] = screenrect.size.height;
blit.push_constant.layer = 0;
blit.push_constant.eye_center[0] = 0;
blit.push_constant.eye_center[1] = 0;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 8639362da9..0230c46800 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -55,7 +55,8 @@ protected:
};
struct BlitPushConstant {
- float rect[4];
+ float src_rect[4];
+ float dst_rect[4];
float eye_center[2];
float k1;
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
index 098e2a5c87..36943c5e5c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -1469,7 +1469,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
lights[idx].type = RS::LIGHT_DIRECTIONAL;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
lights[idx].has_shadow = storage->light_has_shadow(li->light);
idx++;
@@ -1514,7 +1514,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
lights[idx].type = storage->light_get_type(li->light);
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
lights[idx].has_shadow = storage->light_has_shadow(li->light);
lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
@@ -1953,7 +1953,7 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
lights[idx].has_shadow = storage->light_has_shadow(li->light);
lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl
index 967da1e6e4..8051f96738 100644
--- a/servers/rendering/renderer_rd/shaders/blit.glsl
+++ b/servers/rendering/renderer_rd/shaders/blit.glsl
@@ -5,6 +5,7 @@
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
@@ -22,8 +23,8 @@ layout(location = 0) out vec2 uv;
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 = base_arr[gl_VertexIndex];
- vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw;
+ uv = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw;
+ vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw;
gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
}
@@ -34,6 +35,7 @@ void main() {
#VERSION_DEFINES
layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 src_rect;
vec4 dst_rect;
vec2 eye_center;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index edbe1031b7..8cb56fbc83 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -903,6 +903,7 @@ void main() {
if (scene_data.use_reflection_cubemap) {
vec3 ref_vec = reflect(-view, normal);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
@@ -915,7 +916,6 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
- float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index 518b0a6c7f..c3c4139450 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -868,6 +868,7 @@ void main() {
if (scene_data.use_reflection_cubemap) {
vec3 ref_vec = reflect(-view, normal);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
@@ -880,7 +881,6 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
- float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 4411587116..1ce3e04421 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -169,16 +169,33 @@ vec3 tonemap_filmic(vec3 color, float white) {
return color_tonemapped / white_tonemapped;
}
+// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+// (MIT License).
vec3 tonemap_aces(vec3 color, float white) {
- const float exposure_bias = 0.85f;
- const float A = 2.51f * exposure_bias * exposure_bias;
- const float B = 0.03f * exposure_bias;
- const float C = 2.43f * exposure_bias * exposure_bias;
- const float D = 0.59f * exposure_bias;
- const float E = 0.14f;
-
- vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E);
- float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E);
+ const float exposure_bias = 1.8f;
+ const float A = 0.0245786f;
+ const float B = 0.000090537f;
+ const float C = 0.983729f;
+ const float D = 0.432951f;
+ const float E = 0.238081f;
+
+ // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
+ const mat3 rgb_to_rrt = mat3(
+ vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
+ vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
+ vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
+
+ const mat3 odt_to_rgb = mat3(
+ vec3(1.60475f, -0.53108f, -0.07367f),
+ vec3(-0.10208f, 1.10813f, -0.00605f),
+ vec3(-0.00327f, -0.07276f, 1.07602f));
+
+ color *= rgb_to_rrt;
+ vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
+ color_tonemapped *= odt_to_rgb;
+
+ white *= exposure_bias;
+ float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E);
return color_tonemapped / white_tonemapped;
}
@@ -200,15 +217,16 @@ vec3 linear_to_srgb(vec3 color) {
#define TONEMAPPER_ACES 3
vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color
-
+ // Ensure color values passed to tonemappers are positive.
+ // They can be negative in the case of negative lights, which leads to undesired behavior.
if (params.tonemapper == TONEMAPPER_LINEAR) {
return color;
} else if (params.tonemapper == TONEMAPPER_REINHARD) {
- return tonemap_reinhard(color, white);
+ return tonemap_reinhard(max(vec3(0.0f), color), white);
} else if (params.tonemapper == TONEMAPPER_FILMIC) {
- return tonemap_filmic(color, white);
+ return tonemap_filmic(max(vec3(0.0f), color), white);
} else { // TONEMAPPER_ACES
- return tonemap_aces(color, white);
+ return tonemap_aces(max(vec3(0.0f), color), white);
}
}
@@ -401,9 +419,7 @@ void main() {
color += screen_space_dither(gl_FragCoord.xy);
}
- // Ensure color values passed to tonemappers are positive.
- // They can be negative in the case of negative lights, which leads to undesired behavior.
- color = apply_tonemapping(max(vec3(0.0), color), params.white);
+ color = apply_tonemapping(color, params.white);
color = linear_to_srgb(color); // regular linear -> SRGB conversion
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 3ede9fed2d..8af2049ab3 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -626,10 +626,10 @@ void RendererViewport::draw_viewports() {
BlitToScreen blit;
blit.render_target = vp->render_target;
if (vp->viewport_to_screen_rect != Rect2()) {
- blit.rect = vp->viewport_to_screen_rect;
+ blit.dst_rect = vp->viewport_to_screen_rect;
} else {
- blit.rect.position = Vector2();
- blit.rect.size = vp->size;
+ blit.dst_rect.position = Vector2();
+ blit.dst_rect.size = vp->size;
}
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index b302c6b793..70f676e5ac 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -478,12 +478,28 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_memory_usage"), &RenderingDevice::get_memory_usage);
+ ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource);
+
BIND_CONSTANT(BARRIER_MASK_RASTER);
BIND_CONSTANT(BARRIER_MASK_COMPUTE);
BIND_CONSTANT(BARRIER_MASK_TRANSFER);
BIND_CONSTANT(BARRIER_MASK_ALL);
BIND_CONSTANT(BARRIER_MASK_NO_BARRIER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DEVICE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_INSTANCE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_VIEW);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_SAMPLER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_BUFFER);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE);
+ BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE);
+
BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8);
BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 2cf1f165dd..5eb8f1cead 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -60,6 +60,23 @@ public:
DEVICE_DIRECTX
};
+ enum DriverResource {
+ DRIVER_RESOURCE_VULKAN_DEVICE = 0,
+ DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE,
+ DRIVER_RESOURCE_VULKAN_INSTANCE,
+ DRIVER_RESOURCE_VULKAN_QUEUE,
+ DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX,
+ DRIVER_RESOURCE_VULKAN_IMAGE,
+ DRIVER_RESOURCE_VULKAN_IMAGE_VIEW,
+ DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT,
+ DRIVER_RESOURCE_VULKAN_SAMPLER,
+ DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET,
+ DRIVER_RESOURCE_VULKAN_BUFFER,
+ DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE,
+ DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE,
+ //next driver continue enum from 1000 to keep order
+ };
+
enum ShaderStage {
SHADER_STAGE_VERTEX,
SHADER_STAGE_FRAGMENT,
@@ -1183,6 +1200,8 @@ public:
virtual String get_device_name() const = 0;
virtual String get_device_pipeline_cache_uuid() const = 0;
+ virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0) = 0;
+
static RenderingDevice *get_singleton();
RenderingDevice();
@@ -1217,6 +1236,7 @@ protected:
Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits);
};
+VARIANT_ENUM_CAST(RenderingDevice::DriverResource)
VARIANT_ENUM_CAST(RenderingDevice::ShaderStage)
VARIANT_ENUM_CAST(RenderingDevice::ShaderLanguage)
VARIANT_ENUM_CAST(RenderingDevice::CompareOperator)
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 78604dfe8c..1b10e4dcbe 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -500,7 +500,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
case RS::ARRAY_CUSTOM1:
case RS::ARRAY_CUSTOM2:
case RS::ARRAY_CUSTOM3: {
- uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - ai))) & ARRAY_FORMAT_CUSTOM_MASK;
+ uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (ai - RS::ARRAY_CUSTOM0))) & ARRAY_FORMAT_CUSTOM_MASK;
switch (type) {
case ARRAY_CUSTOM_RGBA8_UNORM:
case ARRAY_CUSTOM_RGBA8_SNORM:
@@ -541,14 +541,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
Vector<float> array = p_arrays[ai];
- int32_t s = ARRAY_CUSTOM_R_FLOAT - ai + 1;
+ int32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1;
ERR_FAIL_COND_V(array.size() != p_vertex_array_len * s, ERR_INVALID_PARAMETER);
const float *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], sizeof(float) * s);
}
} break;
default: {
@@ -938,6 +938,13 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
}
}
+ for (uint32_t i = 0; i < RS::ARRAY_CUSTOM_COUNT; ++i) {
+ // include custom array format type.
+ if (format & (1 << (ARRAY_CUSTOM0 + i))) {
+ format |= (RS::ARRAY_FORMAT_CUSTOM_MASK << (RS::ARRAY_FORMAT_CUSTOM_BASE + i * RS::ARRAY_FORMAT_CUSTOM_BITS)) & p_compress_format;
+ }
+ }
+
uint32_t offsets[RS::ARRAY_MAX];
uint32_t vertex_element_size;
@@ -1191,7 +1198,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
case RS::ARRAY_CUSTOM1:
case RS::ARRAY_CUSTOM2:
case RS::ARRAY_CUSTOM3: {
- uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - i))) & ARRAY_FORMAT_CUSTOM_MASK;
+ uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (i - RS::ARRAY_CUSTOM0))) & ARRAY_FORMAT_CUSTOM_MASK;
switch (type) {
case ARRAY_CUSTOM_RGBA8_UNORM:
case ARRAY_CUSTOM_RGBA8_SNORM:
@@ -1219,6 +1226,8 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
uint32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1;
Vector<float> arr;
+ arr.resize(s * p_vertex_len);
+
float *w = arr.ptrw();
for (int j = 0; j < p_vertex_len; j++) {
@@ -1467,6 +1476,11 @@ ShaderLanguage::DataType RenderingServer::global_variable_type_get_shader_dataty
}
}
+RenderingDevice *RenderingServer::get_rendering_device() const {
+ // return the rendering device we're using globally
+ return RenderingDevice::get_singleton();
+}
+
RenderingDevice *RenderingServer::create_local_rendering_device() const {
return RenderingDevice::get_singleton()->create_local_device();
}
@@ -2211,7 +2225,6 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_MSAA_2X);
BIND_ENUM_CONSTANT(VIEWPORT_MSAA_4X);
BIND_ENUM_CONSTANT(VIEWPORT_MSAA_8X);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_16X);
BIND_ENUM_CONSTANT(VIEWPORT_MSAA_MAX);
BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_DISABLED);
@@ -2714,6 +2727,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_sync"), &RenderingServer::sync);
ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &RenderingServer::draw, DEFVAL(true), DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("get_rendering_device"), &RenderingServer::get_rendering_device);
ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device);
}
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 8fbf231d9b..1b04a6e5e2 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -836,7 +836,6 @@ public:
VIEWPORT_MSAA_2X,
VIEWPORT_MSAA_4X,
VIEWPORT_MSAA_8X,
- VIEWPORT_MSAA_16X,
VIEWPORT_MSAA_MAX,
};
@@ -1493,6 +1492,7 @@ public:
virtual void set_print_gpu_profile(bool p_enable) = 0;
+ RenderingDevice *get_rendering_device() const;
RenderingDevice *create_local_rendering_device() const;
bool is_render_loop_enabled() const;
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index fc1d82a964..bf54158905 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "xr_interface.h"
-#include "servers/rendering/renderer_compositor.h"
+// #include "servers/rendering/renderer_compositor.h"
void XRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name);
diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp
index e1519d1463..6340485bde 100644
--- a/servers/xr/xr_interface_extension.cpp
+++ b/servers/xr/xr_interface_extension.cpp
@@ -29,7 +29,8 @@
/*************************************************************************/
#include "xr_interface_extension.h"
-#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_storage.h"
+#include "servers/rendering/rendering_server_globals.h"
void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_name);
@@ -41,15 +42,13 @@ void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_tracking_status);
- ClassDB::bind_method(D_METHOD("add_blit", "render_target", "rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit);
-
GDVIRTUAL_BIND(_get_render_target_size);
GDVIRTUAL_BIND(_get_view_count);
GDVIRTUAL_BIND(_get_camera_transform);
GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform");
GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far");
- GDVIRTUAL_BIND(_commit_views);
+ GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect");
GDVIRTUAL_BIND(_process);
GDVIRTUAL_BIND(_notification, "what");
@@ -60,6 +59,11 @@ void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_anchor_detection_is_enabled);
GDVIRTUAL_BIND(_set_anchor_detection_is_enabled, "enabled");
GDVIRTUAL_BIND(_get_camera_feed_id);
+
+ // helper methods
+ ClassDB::bind_method(D_METHOD("add_blit", "render_target", "src_rect", "dst_rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit);
+ ClassDB::bind_method(D_METHOD("get_render_target_texture", "render_target"), &XRInterfaceExtension::get_render_target_texture);
+ // ClassDB::bind_method(D_METHOD("get_render_target_depth", "render_target"), &XRInterfaceExtension::get_render_target_depth);
}
StringName XRInterfaceExtension::get_name() const {
@@ -198,13 +202,14 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, real
return CameraMatrix();
}
-void XRInterfaceExtension::add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ratio) {
+void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ratio) {
BlitToScreen blit;
ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!");
blit.render_target = p_render_target;
- blit.rect = p_rect;
+ blit.src_rect = p_src_rect;
+ blit.dst_rect = p_dst_rect;
blit.multi_view.use_layer = p_use_layer;
blit.multi_view.layer = p_layer;
@@ -239,3 +244,19 @@ void XRInterfaceExtension::process() {
void XRInterfaceExtension::notification(int p_what) {
GDVIRTUAL_CALL(_notification, p_what);
}
+
+RID XRInterfaceExtension::get_render_target_texture(RID p_render_target) {
+ RendererStorage *storage = RSG::storage;
+ ERR_FAIL_NULL_V_MSG(storage, RID(), "Renderer storage not setup");
+
+ return storage->render_target_get_texture(p_render_target);
+}
+
+/*
+RID XRInterfaceExtension::get_render_target_depth(RID p_render_target) {
+ RendererStorage *storage = RSG::storage;
+ ERR_FAIL_NULL_V_MSG(storage, RID(), "Renderer storage not setup");
+
+ return storage->render_target_get_depth(p_render_target);
+}
+*/
diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h
index ab4d90bfe6..94914a7b3f 100644
--- a/servers/xr/xr_interface_extension.h
+++ b/servers/xr/xr_interface_extension.h
@@ -91,7 +91,7 @@ public:
GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &);
GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, real_t, real_t, real_t);
- void add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), float p_k1 = 0.0, float p_k2 = 0.0, float p_upscale = 1.0, float p_aspect_ratio = 1.0);
+ void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), float p_k1 = 0.0, float p_k2 = 0.0, float p_upscale = 1.0, float p_aspect_ratio = 1.0);
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
GDVIRTUAL2(_commit_views, RID, const Rect2 &);
@@ -100,6 +100,10 @@ public:
GDVIRTUAL0(_process);
GDVIRTUAL1(_notification, int);
+
+ /* access to some internals we need */
+ RID get_render_target_texture(RID p_render_target);
+ // RID get_render_target_depth(RID p_render_target);
};
#endif // !XR_INTERFACE_EXTENSION_H