summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/audio_stream_player_3d.cpp32
-rw-r--r--scene/3d/audio_stream_player_3d.h3
-rw-r--r--scene/3d/baked_lightmap.cpp1
-rw-r--r--scene/3d/camera.cpp29
-rw-r--r--scene/3d/camera.h3
-rw-r--r--scene/3d/collision_object.cpp2
-rw-r--r--scene/3d/collision_object.h1
-rw-r--r--scene/3d/collision_shape.h1
-rw-r--r--scene/3d/cpu_particles.cpp12
-rw-r--r--scene/3d/gi_probe.cpp1
-rw-r--r--scene/3d/light.cpp1
-rw-r--r--scene/3d/mesh_instance.cpp3
-rw-r--r--scene/3d/mesh_instance.h1
-rw-r--r--scene/3d/navigation.cpp36
-rw-r--r--scene/3d/navigation_mesh.cpp8
-rw-r--r--scene/3d/particles.cpp2
-rw-r--r--scene/3d/physics_body.cpp222
-rw-r--r--scene/3d/physics_body.h31
-rw-r--r--scene/3d/reflection_probe.cpp1
-rw-r--r--scene/3d/skeleton.cpp141
-rw-r--r--scene/3d/skeleton.h10
-rw-r--r--scene/3d/soft_body.cpp799
-rw-r--r--scene/3d/soft_body.h200
-rw-r--r--scene/3d/spatial.cpp37
-rw-r--r--scene/3d/spatial.h5
-rw-r--r--scene/3d/spatial_velocity_tracker.cpp6
-rw-r--r--scene/3d/vehicle_body.cpp30
-rw-r--r--scene/3d/vehicle_body.h2
-rw-r--r--scene/3d/visual_instance.cpp16
-rw-r--r--scene/3d/visual_instance.h3
-rw-r--r--scene/3d/voxel_light_baker.cpp130
31 files changed, 1548 insertions, 221 deletions
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 35c52a26c9..5f0ac3dd80 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -36,7 +36,7 @@
void AudioStreamPlayer3D::_mix_audio() {
if (!stream_playback.is_valid() || !active ||
- (stream_paused && stream_paused_fade <= 0.f)) {
+ (stream_paused && !stream_paused_fade_out)) {
return;
}
@@ -51,9 +51,13 @@ void AudioStreamPlayer3D::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
+ if (stream_paused_fade_out) {
+ // Short fadeout ramp
+ buffer_size = MIN(buffer_size, 128);
+ }
+
// Mix if we're not paused or we're fading out
- if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) &&
- (!stream_paused || stream_paused_fade > 0.f)) {
+ if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
float output_pitch_scale = 0.0;
if (output_count) {
@@ -103,15 +107,10 @@ void AudioStreamPlayer3D::_mix_audio() {
int buffers = AudioServer::get_singleton()->get_channel_count();
for (int k = 0; k < buffers; k++) {
- AudioFrame vol_inc = (current.vol[k] - prev_outputs[i].vol[k]) / float(buffer_size);
- AudioFrame vol = current.vol[k];
-
- if (stream_paused) {
- vol = vol * stream_paused_fade;
- if (stream_paused_fade > 0.f) {
- stream_paused_fade -= 0.1f;
- }
- }
+ AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k];
+ AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k];
+ AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
+ AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k];
AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
@@ -193,6 +192,8 @@ void AudioStreamPlayer3D::_mix_audio() {
}
output_ready = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
}
float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
@@ -846,7 +847,8 @@ void AudioStreamPlayer3D::set_stream_paused(bool p_pause) {
if (p_pause != stream_paused) {
stream_paused = p_pause;
- stream_paused_fade = stream_paused ? 1.f : 0.f;
+ stream_paused_fade_in = stream_paused ? false : true;
+ stream_paused_fade_out = stream_paused ? true : false;
}
}
@@ -984,10 +986,12 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
out_of_range_mode = OUT_OF_RANGE_MIX;
doppler_tracking = DOPPLER_TRACKING_DISABLED;
stream_paused = false;
- stream_paused_fade = 0.f;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
velocity_tracker.instance();
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
+ set_disable_scale(true);
}
AudioStreamPlayer3D::~AudioStreamPlayer3D() {
}
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index cab1ff121a..14413d0702 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -107,9 +107,10 @@ private:
float unit_size;
float max_db;
float pitch_scale;
- float stream_paused_fade;
bool autoplay;
bool stream_paused;
+ bool stream_paused_fade_in;
+ bool stream_paused_fade_out;
StringName bus;
void _mix_audio();
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 204aaef7ec..26fd5ed658 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -811,4 +811,5 @@ BakedLightmap::BakedLightmap() {
propagation = 1;
hdr = false;
image_path = ".";
+ set_disable_scale(true);
}
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index e11e8abe5b..2176b45faf 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -74,10 +74,7 @@ void Camera::_update_camera() {
if (!is_inside_tree())
return;
- Transform tr = get_camera_transform();
- tr.origin += tr.basis.get_axis(1) * v_offset;
- tr.origin += tr.basis.get_axis(0) * h_offset;
- VisualServer::get_singleton()->camera_set_transform(camera, tr);
+ VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
// here goes listener stuff
/*
@@ -143,7 +140,10 @@ void Camera::_notification(int p_what) {
Transform Camera::get_camera_transform() const {
- return get_global_transform().orthonormalized();
+ Transform tr = get_global_transform().orthonormalized();
+ tr.origin += tr.basis.get_axis(1) * v_offset;
+ tr.origin += tr.basis.get_axis(0) * h_offset;
+ return tr;
}
void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
@@ -468,6 +468,10 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode);
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
+
+ ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit);
+
//ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
@@ -550,6 +554,20 @@ uint32_t Camera::get_cull_mask() const {
return layers;
}
+void Camera::set_cull_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_cull_mask(layers | (1 << p_layer));
+ } else {
+ set_cull_mask(layers & (~(1 << p_layer)));
+ }
+}
+
+bool Camera::get_cull_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (layers & (1 << p_layer));
+}
+
Vector<Plane> Camera::get_frustum() const {
ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
@@ -613,6 +631,7 @@ Camera::Camera() {
velocity_tracker.instance();
doppler_tracking = DOPPLER_TRACKING_DISABLED;
set_notify_transform(true);
+ set_disable_scale(true);
}
Camera::~Camera() {
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 1b506e0c4f..97705d8ae0 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -142,6 +142,9 @@ public:
void set_cull_mask(uint32_t p_layers);
uint32_t get_cull_mask() const;
+ void set_cull_mask_bit(int p_layer, bool p_enable);
+ bool get_cull_mask_bit(int p_layer) const;
+
virtual Vector<Plane> get_frustum() const;
void set_environment(const Ref<Environment> &p_environment);
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index 1d5d1b2afe..e19e45b263 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -305,7 +305,7 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().shapes.size(); i++) {
if (E->get().shapes[i].index > index_to_remove) {
- E->get().shapes[i].index -= 1;
+ E->get().shapes.write[i].index -= 1;
}
}
}
diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h
index f31d65e411..f8ef04b78f 100644
--- a/scene/3d/collision_object.h
+++ b/scene/3d/collision_object.h
@@ -39,6 +39,7 @@ class CollisionObject : public Spatial {
GDCLASS(CollisionObject, Spatial);
bool area;
+
RID rid;
struct ShapeData {
diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h
index c9c91a5824..6ca8e80ea1 100644
--- a/scene/3d/collision_shape.h
+++ b/scene/3d/collision_shape.h
@@ -49,6 +49,7 @@ class CollisionShape : public Spatial {
void resource_changed(RES res);
bool disabled;
+protected:
void _create_debug_shape();
void _update_in_shape_owner(bool p_xform_only = false);
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 2e897c1c73..8b2000d2e9 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -25,6 +25,8 @@ void CPUParticles::set_emitting(bool p_emitting) {
update_mutex->lock();
#endif
VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
+
#ifndef NO_THREADS
update_mutex->unlock();
#endif
@@ -446,6 +448,8 @@ float rand_from_seed_m1_p1(uint32_t &seed) {
void CPUParticles::_particles_process(float p_delta) {
+ p_delta *= speed_scale;
+
int pcount = particles.size();
PoolVector<Particle>::Write w = particles.write();
@@ -475,7 +479,7 @@ void CPUParticles::_particles_process(float p_delta) {
if (!emitting && !p.active)
continue;
- float restart_time = float(i) / float(pcount);
+ float restart_time = (float(i) / float(pcount)) * lifetime;
float local_delta = p_delta;
if (randomness_ratio > 0.0) {
@@ -643,7 +647,7 @@ void CPUParticles::_particles_process(float p_delta) {
uint32_t alt_seed = p.seed;
p.time += local_delta;
- p.custom[1] += p.time / lifetime;
+ p.custom[1] = p.time / lifetime;
float tex_linear_velocity = 0.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
@@ -979,6 +983,7 @@ void CPUParticles::_notification(int p_what) {
update_mutex->lock();
#endif
VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
#ifndef NO_THREADS
update_mutex->unlock();
#endif
@@ -992,6 +997,7 @@ void CPUParticles::_notification(int p_what) {
update_mutex->lock();
#endif
VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
#ifndef NO_THREADS
update_mutex->unlock();
#endif
@@ -1018,6 +1024,8 @@ void CPUParticles::_notification(int p_what) {
update_mutex->lock();
#endif
VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
+
#ifndef NO_THREADS
update_mutex->unlock();
#endif
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 4ad2eb60ee..6276d02eff 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -557,6 +557,7 @@ GIProbe::GIProbe() {
compress = false;
gi_probe = VS::get_singleton()->gi_probe_create();
+ set_disable_scale(true);
}
GIProbe::~GIProbe() {
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 7c42638107..16164cf3bf 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -306,6 +306,7 @@ Light::Light(VisualServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0);
set_param(PARAM_SHADOW_BIAS, 0.15);
+ set_disable_scale(true);
}
Light::Light() {
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index e836a6154a..e277cae5b7 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -36,6 +36,7 @@
#include "scene/resources/material.h"
#include "scene/scene_string_names.h"
#include "skeleton.h"
+
bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) {
//this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
@@ -256,7 +257,7 @@ void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_ma
ERR_FAIL_INDEX(p_surface, materials.size());
- materials[p_surface] = p_material;
+ materials.write[p_surface] = p_material;
if (materials[p_surface].is_valid())
VS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid());
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 5d359cd4d5..0dfec538f9 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -41,6 +41,7 @@ class MeshInstance : public GeometryInstance {
GDCLASS(MeshInstance, GeometryInstance);
+protected:
Ref<Mesh> mesh;
NodePath skeleton_path;
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index 77bf703706..f5b77d361c 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -73,7 +73,7 @@ void Navigation::_navmesh_link(int p_id) {
Vector3 ep = nm.xform.xform(r[idx]);
center += ep;
e.point = _get_point(ep);
- p.edges[j] = e;
+ p.edges.write[j] = e;
if (j >= 2) {
Vector3 epa = nm.xform.xform(r[indices[j - 2]]);
@@ -118,7 +118,7 @@ void Navigation::_navmesh_link(int p_id) {
ConnectionPending pending;
pending.polygon = &p;
pending.edge = j;
- p.edges[j].P = C->get().pending.push_back(pending);
+ p.edges.write[j].P = C->get().pending.push_back(pending);
continue;
//print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
}
@@ -126,10 +126,10 @@ void Navigation::_navmesh_link(int p_id) {
C->get().B = &p;
C->get().B_edge = j;
- C->get().A->edges[C->get().A_edge].C = &p;
- C->get().A->edges[C->get().A_edge].C_edge = j;
- p.edges[j].C = C->get().A;
- p.edges[j].C_edge = C->get().A_edge;
+ C->get().A->edges.write[C->get().A_edge].C = &p;
+ C->get().A->edges.write[C->get().A_edge].C_edge = j;
+ p.edges.write[j].C = C->get().A;
+ p.edges.write[j].C_edge = C->get().A_edge;
//connection successful.
}
}
@@ -165,10 +165,10 @@ void Navigation::_navmesh_unlink(int p_id) {
} else if (C->get().B) {
//disconnect
- C->get().B->edges[C->get().B_edge].C = NULL;
- C->get().B->edges[C->get().B_edge].C_edge = -1;
- C->get().A->edges[C->get().A_edge].C = NULL;
- C->get().A->edges[C->get().A_edge].C_edge = -1;
+ C->get().B->edges.write[C->get().B_edge].C = NULL;
+ C->get().B->edges.write[C->get().B_edge].C_edge = -1;
+ C->get().A->edges.write[C->get().A_edge].C = NULL;
+ C->get().A->edges.write[C->get().A_edge].C_edge = -1;
if (C->get().A == &E->get()) {
@@ -185,11 +185,11 @@ void Navigation::_navmesh_unlink(int p_id) {
C->get().B = cp.polygon;
C->get().B_edge = cp.edge;
- C->get().A->edges[C->get().A_edge].C = cp.polygon;
- C->get().A->edges[C->get().A_edge].C_edge = cp.edge;
- cp.polygon->edges[cp.edge].C = C->get().A;
- cp.polygon->edges[cp.edge].C_edge = C->get().A_edge;
- cp.polygon->edges[cp.edge].P = NULL;
+ C->get().A->edges.write[C->get().A_edge].C = cp.polygon;
+ C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge;
+ cp.polygon->edges.write[cp.edge].C = C->get().A;
+ cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge;
+ cp.polygon->edges.write[cp.edge].P = NULL;
}
} else {
@@ -320,8 +320,8 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
Vector<Vector3> path;
path.resize(2);
- path[0] = begin_point;
- path[1] = end_point;
+ path.write[0] = begin_point;
+ path.write[1] = end_point;
//print_line("Direct Path");
return path;
}
@@ -375,7 +375,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
for (int i = 0; i < p->edges.size(); i++) {
- Polygon::Edge &e = p->edges[i];
+ Polygon::Edge &e = p->edges.write[i];
if (!e.C)
continue;
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 073e56fdb4..99680b7273 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -55,9 +55,9 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
for (int j = 0; j < rlen; j += 3) {
Vector<int> vi;
vi.resize(3);
- vi[0] = r[j + 0] + from;
- vi[1] = r[j + 1] + from;
- vi[2] = r[j + 2] + from;
+ vi.write[0] = r[j + 0] + from;
+ vi.write[1] = r[j + 1] + from;
+ vi.write[2] = r[j + 2] + from;
add_polygon(vi);
}
@@ -215,7 +215,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) {
polygons.resize(p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- polygons[i].indices = p_array[i];
+ polygons.write[i].indices = p_array[i];
}
}
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 2b3a62fcdc..4900692155 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -185,7 +185,7 @@ void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
ERR_FAIL_INDEX(p_pass, draw_passes.size());
- draw_passes[p_pass] = p_mesh;
+ draw_passes.write[p_pass] = p_mesh;
RID mesh_rid;
if (p_mesh.is_valid())
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index e851c8d643..84a0fb9b1d 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -30,6 +30,7 @@
#include "physics_body.h"
+#include "core/core_string_names.h"
#include "engine.h"
#include "method_bind_ext.gen.inc"
#include "scene/scene_string_names.h"
@@ -121,23 +122,23 @@ bool PhysicsBody::get_collision_layer_bit(int p_bit) const {
void PhysicsBody::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
- PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node);
- if (!physics_body) {
- ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
}
- ERR_FAIL_COND(!physics_body);
- PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid());
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid());
}
void PhysicsBody::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
- PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node);
- if (!physics_body) {
- ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
}
- ERR_FAIL_COND(!physics_body);
- PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid());
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
void PhysicsBody::_set_layers(uint32_t p_mask) {
@@ -178,28 +179,77 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) :
collision_mask = 1;
}
+#ifndef DISABLE_DEPRECATED
void StaticBody::set_friction(real_t p_friction) {
+ ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
+
ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
- friction = p_friction;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+
+ physics_material_override->set_friction(p_friction);
}
+
real_t StaticBody::get_friction() const {
- return friction;
+ ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 1;
+ }
+
+ return physics_material_override->get_friction();
}
void StaticBody::set_bounce(real_t p_bounce) {
+ ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
+
ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
- bounce = p_bounce;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_bounce(p_bounce);
}
+
real_t StaticBody::get_bounce() const {
- return bounce;
+ ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 0;
+ }
+
+ return physics_material_override->get_bounce();
+}
+#endif
+
+void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> StaticBody::get_physics_material_override() const {
+ return physics_material_override;
}
void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) {
@@ -230,30 +280,45 @@ void StaticBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody::get_constant_linear_velocity);
ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody::get_constant_angular_velocity);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &StaticBody::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &StaticBody::get_friction);
ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce);
ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with);
+#ifndef DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
-
+#endif // DISABLE_DEPRECATED
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
}
StaticBody::StaticBody() :
PhysicsBody(PhysicsServer::BODY_MODE_STATIC) {
-
- bounce = 0;
- friction = 1;
}
-StaticBody::~StaticBody() {
+StaticBody::~StaticBody() {}
+
+void StaticBody::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
}
void RigidBody::_body_enter_tree(ObjectID p_id) {
@@ -550,28 +615,68 @@ real_t RigidBody::get_weight() const {
return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
}
+#ifndef DISABLE_DEPRECATED
void RigidBody::set_friction(real_t p_friction) {
+ ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
- friction = p_friction;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_friction(p_friction);
}
real_t RigidBody::get_friction() const {
- return friction;
+ ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
+ if (physics_material_override.is_null()) {
+ return 1;
+ }
+
+ return physics_material_override->get_friction();
}
void RigidBody::set_bounce(real_t p_bounce) {
-
+ ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
- bounce = p_bounce;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_bounce(p_bounce);
}
real_t RigidBody::get_bounce() const {
+ ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
+ WARN_DEPRECATED
+ if (physics_material_override.is_null()) {
+ return 0;
+ }
- return bounce;
+ return physics_material_override->get_bounce();
+}
+#endif // DISABLE_DEPRECATED
+
+void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> RigidBody::get_physics_material_override() const {
+ return physics_material_override;
}
void RigidBody::set_gravity_scale(real_t p_gravity_scale) {
@@ -693,6 +798,22 @@ int RigidBody::get_max_contacts_reported() const {
return max_contacts_reported;
}
+void RigidBody::add_central_force(const Vector3 &p_force) {
+ PhysicsServer::get_singleton()->body_add_central_force(get_rid(), p_force);
+}
+
+void RigidBody::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
+ PhysicsServer::get_singleton()->body_add_force(get_rid(), p_force, p_pos);
+}
+
+void RigidBody::add_torque(const Vector3 &p_torque) {
+ PhysicsServer::get_singleton()->body_add_torque(get_rid(), p_torque);
+}
+
+void RigidBody::apply_central_impulse(const Vector3 &p_impulse) {
+ PhysicsServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
+}
+
void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
@@ -806,11 +927,18 @@ void RigidBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody::set_weight);
ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody::get_weight);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &RigidBody::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &RigidBody::get_friction);
ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce);
ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody::_reload_physics_characteristics);
ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity);
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity);
@@ -840,6 +968,12 @@ void RigidBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody::is_using_continuous_collision_detection);
ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity);
+
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody::add_force);
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody::add_torque);
+
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody::apply_central_impulse);
ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody::apply_impulse);
ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody::apply_torque_impulse);
@@ -863,8 +997,11 @@ void RigidBody::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
+#ifndef DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+#endif // DISABLE_DEPRECATED
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
@@ -903,9 +1040,7 @@ RigidBody::RigidBody() :
mode = MODE_RIGID;
- bounce = 0;
mass = 1;
- friction = 1;
max_contacts_reported = 0;
state = NULL;
@@ -929,6 +1064,17 @@ RigidBody::~RigidBody() {
if (contact_monitor)
memdelete(contact_monitor);
}
+
+void RigidBody::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
+}
+
//////////////////////////////////////////////////////
//////////////////////////
@@ -979,6 +1125,9 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
return colliding;
}
+//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+#define FLOOR_ANGLE_THRESHOLD 0.01
+
Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector3 lv = p_linear_velocity;
@@ -1011,7 +1160,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
//all is a wall
on_wall = true;
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
on_floor = true;
floor_velocity = collision.collider_vel;
@@ -1025,7 +1174,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
set_global_transform(gt);
return floor_velocity - p_floor_direction * p_floor_direction.dot(floor_velocity);
}
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
@@ -1117,11 +1266,11 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
}
if (slide_colliders[p_bounce].is_null()) {
- slide_colliders[p_bounce].instance();
- slide_colliders[p_bounce]->owner = this;
+ slide_colliders.write[p_bounce].instance();
+ slide_colliders.write[p_bounce]->owner = this;
}
- slide_colliders[p_bounce]->collision = colliders[p_bounce];
+ slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
return slide_colliders[p_bounce];
}
@@ -1174,7 +1323,7 @@ KinematicBody::~KinematicBody() {
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
- slide_colliders[i]->owner = NULL;
+ slide_colliders.write[i]->owner = NULL;
}
}
}
@@ -2228,6 +2377,7 @@ void PhysicalBone::set_bounce(real_t p_bounce) {
bounce = p_bounce;
PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
}
+
real_t PhysicalBone::get_bounce() const {
return bounce;
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 0190dcbfc3..80bf422c98 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -32,6 +32,7 @@
#define PHYSICS_BODY__H
#include "scene/3d/collision_object.h"
+#include "scene/resources/physics_material.h"
#include "servers/physics_server.h"
#include "skeleton.h"
#include "vset.h"
@@ -81,18 +82,22 @@ class StaticBody : public PhysicsBody {
Vector3 constant_linear_velocity;
Vector3 constant_angular_velocity;
- real_t bounce;
- real_t friction;
+ Ref<PhysicsMaterial> physics_material_override;
protected:
static void _bind_methods();
public:
+#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
+#endif
+
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
void set_constant_linear_velocity(const Vector3 &p_vel);
void set_constant_angular_velocity(const Vector3 &p_vel);
@@ -102,6 +107,9 @@ public:
StaticBody();
~StaticBody();
+
+private:
+ void _reload_physics_characteristics();
};
class RigidBody : public PhysicsBody {
@@ -121,9 +129,8 @@ protected:
PhysicsDirectBodyState *state;
Mode mode;
- real_t bounce;
real_t mass;
- real_t friction;
+ Ref<PhysicsMaterial> physics_material_override;
Vector3 linear_velocity;
Vector3 angular_velocity;
@@ -196,11 +203,16 @@ public:
void set_weight(real_t p_weight);
real_t get_weight() const;
+#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
+#endif
+
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
void set_linear_velocity(const Vector3 &p_velocity);
Vector3 get_linear_velocity() const;
@@ -242,6 +254,11 @@ public:
Array get_colliding_bodies() const;
+ void add_central_force(const Vector3 &p_force);
+ void add_force(const Vector3 &p_force, const Vector3 &p_pos);
+ void add_torque(const Vector3 &p_torque);
+
+ void apply_central_impulse(const Vector3 &p_impulse);
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
void apply_torque_impulse(const Vector3 &p_impulse);
@@ -249,6 +266,9 @@ public:
RigidBody();
~RigidBody();
+
+private:
+ void _reload_physics_characteristics();
};
VARIANT_ENUM_CAST(RigidBody::Mode);
@@ -294,7 +314,7 @@ protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision);
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz);
bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
@@ -537,6 +557,7 @@ protected:
private:
static Skeleton *find_skeleton_parent(Node *p_parent);
+
void _fix_joint_offset();
void _reload_joint();
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 4d50945062..fe522bbe97 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -274,6 +274,7 @@ ReflectionProbe::ReflectionProbe() {
probe = VisualServer::get_singleton()->reflection_probe_create();
VS::get_singleton()->instance_set_base(get_instance(), probe);
+ set_disable_scale(true);
}
ReflectionProbe::~ReflectionProbe() {
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 8d91b6f09f..c796e47f25 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -66,7 +66,7 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
Array children = p_value;
if (is_inside_tree()) {
- bones[which].nodes_bound.clear();
+ bones.write[which].nodes_bound.clear();
for (int i = 0; i < children.size(); i++) {
@@ -131,7 +131,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
String prep = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
- p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(i - 1) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
@@ -139,6 +139,59 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void Skeleton::_update_process_order() {
+
+ if (!process_order_dirty)
+ return;
+
+ Bone *bonesptr = bones.ptrw();
+ int len = bones.size();
+
+ process_order.resize(len);
+ int *order = process_order.ptrw();
+ for (int i = 0; i < len; i++) {
+
+ if (bonesptr[i].parent >= len) {
+ //validate this just in case
+ ERR_PRINTS("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
+ bonesptr[i].parent = -1;
+ }
+ order[i] = i;
+ bonesptr[i].sort_index = i;
+ }
+ //now check process order
+ int pass_count = 0;
+ while (pass_count < len * len) {
+ //using bubblesort because of simplicity, it wont run every frame though.
+ //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
+ bool swapped = false;
+ for (int i = 0; i < len; i++) {
+ int parent_idx = bonesptr[order[i]].parent;
+ if (parent_idx < 0)
+ continue; //do nothing because it has no parent
+ //swap indices
+ int parent_order = bonesptr[parent_idx].sort_index;
+ if (parent_order > i) {
+ bonesptr[order[i]].sort_index = parent_order;
+ bonesptr[parent_idx].sort_index = i;
+ //swap order
+ SWAP(order[i], order[parent_order]);
+ swapped = true;
+ }
+ }
+
+ if (!swapped)
+ break;
+ pass_count++;
+ }
+
+ if (pass_count == len * len) {
+ ERR_PRINT("Skeleton parenthood graph is cyclic");
+ }
+
+ process_order_dirty = false;
+}
+
void Skeleton::_notification(int p_what) {
switch (p_what) {
@@ -176,24 +229,28 @@ void Skeleton::_notification(int p_what) {
case NOTIFICATION_UPDATE_SKELETON: {
VisualServer *vs = VisualServer::get_singleton();
- Bone *bonesptr = &bones[0];
+ Bone *bonesptr = bones.ptrw();
int len = bones.size();
vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens
+ _update_process_order();
+
+ const int *order = process_order.ptr();
+
// pose changed, rebuild cache of inverses
if (rest_global_inverse_dirty) {
// calculate global rests and invert them
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
if (b.parent >= 0)
b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest;
else
b.rest_global_inverse = b.rest;
}
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
b.rest_global_inverse.affine_invert();
}
@@ -205,7 +262,7 @@ void Skeleton::_notification(int p_what) {
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
if (b.disable_rest) {
if (b.enabled) {
@@ -319,12 +376,13 @@ void Skeleton::add_bone(const String &p_name) {
for (int i = 0; i < bones.size(); i++) {
- ERR_FAIL_COND(bones[i].name == "p_name");
+ ERR_FAIL_COND(bones[i].name == p_name);
}
Bone b;
b.name = p_name;
bones.push_back(b);
+ process_order_dirty = true;
rest_global_inverse_dirty = true;
_make_dirty();
@@ -368,10 +426,11 @@ int Skeleton::get_bone_count() const {
void Skeleton::set_bone_parent(int p_bone, int p_parent) {
ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(p_parent != -1 && (p_parent < 0 || p_parent >= p_bone));
+ ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
- bones[p_bone].parent = p_parent;
+ bones.write[p_bone].parent = p_parent;
rest_global_inverse_dirty = true;
+ process_order_dirty = true;
_make_dirty();
}
@@ -379,21 +438,24 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
ERR_FAIL_INDEX(p_bone, bones.size());
+ _update_process_order();
+
int parent = bones[p_bone].parent;
while (parent >= 0) {
- bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
+ bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
parent = bones[parent].parent;
}
- bones[p_bone].parent = -1;
- bones[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
+ bones.write[p_bone].parent = -1;
+ bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
+ process_order_dirty = true;
_make_dirty();
}
void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].ignore_animation = p_ignore;
+ bones.write[p_bone].ignore_animation = p_ignore;
}
bool Skeleton::is_bone_ignore_animation(int p_bone) const {
@@ -405,7 +467,7 @@ bool Skeleton::is_bone_ignore_animation(int p_bone) const {
void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].disable_rest = p_disable;
+ bones.write[p_bone].disable_rest = p_disable;
}
bool Skeleton::is_bone_rest_disabled(int p_bone) const {
@@ -425,7 +487,7 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].rest = p_rest;
+ bones.write[p_bone].rest = p_rest;
rest_global_inverse_dirty = true;
_make_dirty();
}
@@ -440,7 +502,7 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].enabled = p_enabled;
+ bones.write[p_bone].enabled = p_enabled;
rest_global_inverse_dirty = true;
_make_dirty();
}
@@ -457,13 +519,13 @@ void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) {
uint32_t id = p_node->get_instance_id();
- for (List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
+ for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
if (E->get() == id)
return; // already here
}
- bones[p_bone].nodes_bound.push_back(id);
+ bones.write[p_bone].nodes_bound.push_back(id);
}
void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) {
@@ -471,7 +533,7 @@ void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) {
ERR_FAIL_INDEX(p_bone, bones.size());
uint32_t id = p_node->get_instance_id();
- bones[p_bone].nodes_bound.erase(id);
+ bones.write[p_bone].nodes_bound.erase(id);
}
void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const {
@@ -489,6 +551,8 @@ void Skeleton::clear_bones() {
bones.clear();
rest_global_inverse_dirty = true;
+ process_order_dirty = true;
+
_make_dirty();
}
@@ -499,7 +563,7 @@ void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
ERR_FAIL_COND(!is_inside_tree());
- bones[p_bone].pose = p_pose;
+ bones.write[p_bone].pose = p_pose;
_make_dirty();
}
Transform Skeleton::get_bone_pose(int p_bone) const {
@@ -513,8 +577,8 @@ void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose)
ERR_FAIL_INDEX(p_bone, bones.size());
//ERR_FAIL_COND( !is_inside_scene() );
- bones[p_bone].custom_pose_enable = (p_custom_pose != Transform());
- bones[p_bone].custom_pose = p_custom_pose;
+ bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
+ bones.write[p_bone].custom_pose = p_custom_pose;
_make_dirty();
}
@@ -538,12 +602,21 @@ void Skeleton::_make_dirty() {
dirty = true;
}
+int Skeleton::get_process_order(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, bones.size(), -1);
+ _update_process_order();
+ return process_order[p_idx];
+}
+
void Skeleton::localize_rests() {
- for (int i = bones.size() - 1; i >= 0; i--) {
+ _update_process_order();
- if (bones[i].parent >= 0)
- set_bone_rest(i, bones[bones[i].parent].rest.affine_inverse() * bones[i].rest);
+ for (int i = bones.size() - 1; i >= 0; i--) {
+ int idx = process_order[i];
+ if (bones[idx].parent >= 0) {
+ set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest);
+ }
}
}
@@ -553,14 +626,14 @@ void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_b
ERR_FAIL_INDEX(p_bone, bones.size());
ERR_FAIL_COND(bones[p_bone].physical_bone);
ERR_FAIL_COND(!p_physical_bone);
- bones[p_bone].physical_bone = p_physical_bone;
+ bones.write[p_bone].physical_bone = p_physical_bone;
_rebuild_physical_bones_cache();
}
void Skeleton::unbind_physical_bone_from_bone(int p_bone) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].physical_bone = NULL;
+ bones.write[p_bone].physical_bone = NULL;
_rebuild_physical_bones_cache();
}
@@ -600,9 +673,12 @@ PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) {
void Skeleton::_rebuild_physical_bones_cache() {
const int b_size = bones.size();
for (int i = 0; i < b_size; ++i) {
- bones[i].cache_parent_physical_bone = _get_physical_bone_parent(i);
- if (bones[i].physical_bone)
- bones[i].physical_bone->_on_bone_parent_changed();
+ PhysicalBone *parent_pb = _get_physical_bone_parent(i);
+ if (parent_pb != bones[i].physical_bone) {
+ bones.write[i].cache_parent_physical_bone = parent_pb;
+ if (bones[i].physical_bone)
+ bones[i].physical_bone->_on_bone_parent_changed();
+ }
}
}
@@ -660,7 +736,7 @@ void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
if (Variant::STRING == p_bones.get(i).get_type()) {
int bone_id = find_bone(p_bones.get(i));
if (bone_id != -1)
- sim_bones[c++] = bone_id;
+ sim_bones.write[c++] = bone_id;
}
}
sim_bones.resize(c);
@@ -740,6 +816,8 @@ void Skeleton::_bind_methods() {
#endif // _3D_DISABLED
+ ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation);
+
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@@ -747,6 +825,7 @@ Skeleton::Skeleton() {
rest_global_inverse_dirty = true;
dirty = false;
+ process_order_dirty = true;
skeleton = VisualServer::get_singleton()->skeleton_create();
set_notify_transform(true);
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index 9672acb57a..e044e08437 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -39,6 +39,8 @@
*/
#ifndef _3D_DISABLED
+typedef int BoneId;
+
class PhysicalBone;
#endif // _3D_DISABLED
@@ -52,6 +54,7 @@ class Skeleton : public Spatial {
bool enabled;
int parent;
+ int sort_index; //used for re-sorting process order
bool ignore_animation;
@@ -90,13 +93,15 @@ class Skeleton : public Spatial {
bool rest_global_inverse_dirty;
Vector<Bone> bones;
+ Vector<int> process_order;
+ bool process_order_dirty;
RID skeleton;
void _make_dirty();
bool dirty;
- //bind helpers
+ // bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const {
Array bound;
@@ -110,6 +115,8 @@ class Skeleton : public Spatial {
return bound;
}
+ void _update_process_order();
+
protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
@@ -170,6 +177,7 @@ public:
Transform get_bone_custom_pose(int p_bone) const;
void localize_rests(); // used for loaders and tools
+ int get_process_order(int p_idx);
#ifndef _3D_DISABLED
// Physical bone API
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
new file mode 100644
index 0000000000..980c348c9b
--- /dev/null
+++ b/scene/3d/soft_body.cpp
@@ -0,0 +1,799 @@
+/*************************************************************************/
+/* soft_physics_body.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "soft_body.h"
+#include "os/os.h"
+#include "scene/3d/collision_object.h"
+#include "scene/3d/skeleton.h"
+#include "servers/physics_server.h"
+
+SoftBodyVisualServerHandler::SoftBodyVisualServerHandler() {}
+
+void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) {
+ clear();
+
+ ERR_FAIL_COND(!p_mesh.is_valid());
+
+ mesh = p_mesh;
+ surface = p_surface;
+
+ const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, surface);
+ const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface);
+ const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface);
+ uint32_t surface_offsets[VS::ARRAY_MAX];
+
+ buffer = VS::get_singleton()->mesh_surface_get_array(mesh, surface);
+ stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets);
+ offset_vertices = surface_offsets[VS::ARRAY_VERTEX];
+ offset_normal = surface_offsets[VS::ARRAY_NORMAL];
+}
+
+void SoftBodyVisualServerHandler::clear() {
+
+ if (mesh.is_valid()) {
+ buffer.resize(0);
+ }
+
+ mesh = RID();
+}
+
+void SoftBodyVisualServerHandler::open() {
+ write_buffer = buffer.write();
+}
+
+void SoftBodyVisualServerHandler::close() {
+ write_buffer = PoolVector<uint8_t>::Write();
+}
+
+void SoftBodyVisualServerHandler::commit_changes() {
+ VS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer);
+}
+
+void SoftBodyVisualServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
+ copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+}
+
+void SoftBodyVisualServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
+ copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+}
+
+void SoftBodyVisualServerHandler::set_aabb(const AABB &p_aabb) {
+ VS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
+}
+
+SoftBody::PinnedPoint::PinnedPoint() :
+ point_index(-1),
+ spatial_attachment(NULL) {
+}
+
+SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
+ point_index = obj_tocopy.point_index;
+ spatial_attachment_path = obj_tocopy.spatial_attachment_path;
+ spatial_attachment = obj_tocopy.spatial_attachment;
+ offset = obj_tocopy.offset;
+}
+
+void SoftBody::_update_pickable() {
+ if (!is_inside_tree())
+ return;
+ bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree();
+ PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
+}
+
+bool SoftBody::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ String which = name.get_slicec('/', 0);
+
+ if ("pinned_points" == which) {
+
+ return _set_property_pinned_points_indices(p_value);
+
+ } else if ("attachments" == which) {
+
+ int idx = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+
+ return _set_property_pinned_points_attachment(idx, what, p_value);
+ }
+
+ return false;
+}
+
+bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const {
+ String name = p_name;
+ String which = name.get_slicec('/', 0);
+
+ if ("pinned_points" == which) {
+ Array arr_ret;
+ const int pinned_points_indices_size = pinned_points.size();
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ arr_ret.resize(pinned_points_indices_size);
+
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ arr_ret[i] = r[i].point_index;
+ }
+
+ r_ret = arr_ret;
+ return true;
+
+ } else if ("attachments" == which) {
+
+ int idx = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+
+ return _get_property_pinned_points(idx, what, r_ret);
+ }
+
+ return false;
+}
+
+void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ const int pinned_points_indices_size = pinned_points.size();
+
+ p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points"));
+
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index"));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset"));
+ }
+}
+
+bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) {
+
+ const int p_indices_size = p_indices.size();
+
+ { // Remove the pined points on physics server that will be removed by resize
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ if (p_indices_size < pinned_points.size()) {
+ for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) {
+ pin_point(r[i].point_index, false);
+ }
+ }
+ }
+
+ pinned_points.resize(p_indices_size);
+
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ int point_index;
+ for (int i = 0; i < p_indices_size; ++i) {
+ point_index = p_indices.get(i);
+ if (w[i].point_index != point_index) {
+ if (-1 != w[i].point_index)
+ pin_point(w[i].point_index, false);
+ w[i].point_index = point_index;
+ pin_point(w[i].point_index, true);
+ }
+ }
+ return true;
+}
+
+bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
+ if (pinned_points.size() <= p_item) {
+ return false;
+ }
+
+ if ("spatial_attachment_path" == p_what) {
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ pin_point(w[p_item].point_index, true, p_value);
+ _make_cache_dirty();
+ } else if ("offset" == p_what) {
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ w[p_item].offset = p_value;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
+ if (pinned_points.size() <= p_item) {
+ return false;
+ }
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+
+ if ("point_index" == p_what) {
+ r_ret = r[p_item].point_index;
+ } else if ("spatial_attachment_path" == p_what) {
+ r_ret = r[p_item].spatial_attachment_path;
+ } else if ("offset" == p_what) {
+ r_ret = r[p_item].offset;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) {
+ update_physics_server();
+ _reset_points_offsets();
+#ifdef TOOLS_ENABLED
+ if (p_changed == this) {
+ update_configuration_warning();
+ }
+#endif
+}
+
+void SoftBody::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_WORLD: {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ add_change_receptor(this);
+ }
+
+ RID space = get_world()->get_space();
+ PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space);
+ update_physics_server();
+ } break;
+ case NOTIFICATION_READY: {
+ if (!parent_collision_ignore.is_empty())
+ add_collision_exception_with(get_node(parent_collision_ignore));
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ _reset_points_offsets();
+ return;
+ }
+
+ PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform());
+
+ set_notify_transform(false);
+ // Required to be top level with Transform at center of world in order to modify VisualServer only to support custom Transform
+ set_as_toplevel(true);
+ set_transform(Transform());
+ set_notify_transform(true);
+
+ } break;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+
+ if (!simulation_started)
+ return;
+
+ _update_cache_pin_points_datas();
+ // Submit bone attachment
+ const int pinned_points_indices_size = pinned_points.size();
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ if (r[i].spatial_attachment) {
+ PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset));
+ }
+ }
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_pickable();
+
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, RID());
+
+ } break;
+ }
+
+#ifdef TOOLS_ENABLED
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warning();
+ }
+ }
+
+#endif
+}
+
+void SoftBody::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_draw_soft_mesh"), &SoftBody::_draw_soft_mesh);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody::get_collision_layer);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody::get_collision_layer_bit);
+
+ ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore);
+
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with);
+
+ ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody::set_simulation_precision);
+ ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody::get_simulation_precision);
+
+ ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody::set_total_mass);
+ ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody::get_total_mass);
+
+ ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody::set_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody::get_linear_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody::set_areaAngular_stiffness);
+ ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody::get_areaAngular_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody::set_volume_stiffness);
+ ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody::get_volume_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody::set_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody::get_pressure_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody::set_pose_matching_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody::get_pose_matching_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody::set_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody::get_damping_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody::set_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody::get_drag_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody::set_ray_pickable);
+ ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody::is_ray_pickable);
+
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient");
+}
+
+String SoftBody::get_configuration_warning() const {
+
+ String warning = MeshInstance::get_configuration_warning();
+
+ if (get_mesh().is_null()) {
+ if (!warning.empty())
+ warning += "\n\n";
+
+ warning += TTR("This body will be ignored until you set a mesh");
+ }
+
+ Transform t = get_transform();
+ if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) {
+ if (!warning.empty())
+ warning += "\n\n";
+
+ warning += TTR("Size changes to SoftBody will be overriden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ }
+
+ return warning;
+}
+
+void SoftBody::_draw_soft_mesh() {
+ if (get_mesh().is_null())
+ return;
+
+ if (!visual_server_handler.is_ready()) {
+
+ visual_server_handler.prepare(get_mesh()->get_rid(), 0);
+
+ /// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
+ simulation_started = true;
+ call_deferred("set_as_toplevel", true);
+ call_deferred("set_transform", Transform());
+ }
+
+ visual_server_handler.open();
+ PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler);
+ visual_server_handler.close();
+
+ visual_server_handler.commit_changes();
+}
+
+void SoftBody::update_physics_server() {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ if (get_mesh().is_valid())
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ else
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
+
+ return;
+ }
+
+ if (get_mesh().is_valid()) {
+
+ become_mesh_owner();
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ VS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh");
+ } else {
+
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ }
+}
+
+void SoftBody::become_mesh_owner() {
+ if (mesh.is_null())
+ return;
+
+ if (!mesh_owner) {
+ mesh_owner = true;
+
+ Vector<Ref<Material> > copy_materials;
+ copy_materials.append_array(materials);
+
+ ERR_FAIL_COND(!mesh->get_surface_count());
+
+ // Get current mesh array and create new mesh array with necessary flag for softbody
+ Array surface_arrays = mesh->surface_get_arrays(0);
+ Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
+ uint32_t surface_format = mesh->surface_get_format(0);
+
+ surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL);
+ surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
+
+ Ref<ArrayMesh> soft_mesh;
+ soft_mesh.instance();
+ soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format);
+ soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
+
+ set_mesh(soft_mesh);
+
+ for (int i = copy_materials.size() - 1; 0 <= i; --i) {
+ set_surface_material(i, copy_materials[i]);
+ }
+ }
+}
+
+void SoftBody::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ PhysicsServer::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
+}
+
+uint32_t SoftBody::get_collision_mask() const {
+ return collision_mask;
+}
+void SoftBody::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ PhysicsServer::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
+}
+
+uint32_t SoftBody::get_collision_layer() const {
+ return collision_layer;
+}
+
+void SoftBody::set_collision_mask_bit(int p_bit, bool p_value) {
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask |= 1 << p_bit;
+ else
+ mask &= ~(1 << p_bit);
+ set_collision_mask(mask);
+}
+
+bool SoftBody::get_collision_mask_bit(int p_bit) const {
+ return get_collision_mask() & (1 << p_bit);
+}
+
+void SoftBody::set_collision_layer_bit(int p_bit, bool p_value) {
+ uint32_t layer = get_collision_layer();
+ if (p_value)
+ layer |= 1 << p_bit;
+ else
+ layer &= ~(1 << p_bit);
+ set_collision_layer(layer);
+}
+
+bool SoftBody::get_collision_layer_bit(int p_bit) const {
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void SoftBody::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+ parent_collision_ignore = p_parent_collision_ignore;
+}
+
+const NodePath &SoftBody::get_parent_collision_ignore() const {
+ return parent_collision_ignore;
+}
+
+void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) {
+ pinned_points = p_pinned_points_indices;
+ PoolVector<PinnedPoint>::Read w = pinned_points.read();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+ pin_point(p_pinned_points_indices[i].point_index, true);
+ }
+}
+
+PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() {
+ return pinned_points;
+}
+
+void SoftBody::add_collision_exception_with(Node *p_node) {
+ ERR_FAIL_NULL(p_node);
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
+ }
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
+}
+
+void SoftBody::remove_collision_exception_with(Node *p_node) {
+ ERR_FAIL_NULL(p_node);
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
+ }
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
+}
+
+int SoftBody::get_simulation_precision() {
+ return PhysicsServer::get_singleton()->soft_body_get_simulation_precision(physics_rid);
+}
+
+void SoftBody::set_simulation_precision(int p_simulation_precision) {
+ PhysicsServer::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
+}
+
+real_t SoftBody::get_total_mass() {
+ return PhysicsServer::get_singleton()->soft_body_get_total_mass(physics_rid);
+}
+
+void SoftBody::set_total_mass(real_t p_total_mass) {
+ PhysicsServer::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
+}
+
+void SoftBody::set_linear_stiffness(real_t p_linear_stiffness) {
+ PhysicsServer::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
+}
+
+real_t SoftBody::get_linear_stiffness() {
+ return PhysicsServer::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
+}
+
+void SoftBody::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) {
+ PhysicsServer::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness);
+}
+
+real_t SoftBody::get_areaAngular_stiffness() {
+ return PhysicsServer::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid);
+}
+
+void SoftBody::set_volume_stiffness(real_t p_volume_stiffness) {
+ PhysicsServer::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness);
+}
+
+real_t SoftBody::get_volume_stiffness() {
+ return PhysicsServer::get_singleton()->soft_body_get_volume_stiffness(physics_rid);
+}
+
+real_t SoftBody::get_pressure_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
+}
+
+void SoftBody::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient);
+}
+
+real_t SoftBody::get_pose_matching_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid);
+}
+
+void SoftBody::set_pressure_coefficient(real_t p_pressure_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
+}
+
+real_t SoftBody::get_damping_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
+}
+
+void SoftBody::set_damping_coefficient(real_t p_damping_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
+}
+
+real_t SoftBody::get_drag_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
+}
+
+void SoftBody::set_drag_coefficient(real_t p_drag_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
+}
+
+Vector3 SoftBody::get_point_transform(int p_point_index) {
+ return PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
+}
+
+void SoftBody::pin_point_toggle(int p_point_index) {
+ pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
+}
+
+void SoftBody::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
+ _pin_point_on_physics_server(p_point_index, pin);
+ if (pin) {
+ _add_pinned_point(p_point_index, p_spatial_attachment_path);
+ } else {
+ _remove_pinned_point(p_point_index);
+ }
+}
+
+bool SoftBody::is_point_pinned(int p_point_index) const {
+ return -1 != _has_pinned_point(p_point_index);
+}
+
+void SoftBody::set_ray_pickable(bool p_ray_pickable) {
+
+ ray_pickable = p_ray_pickable;
+ _update_pickable();
+}
+
+bool SoftBody::is_ray_pickable() const {
+
+ return ray_pickable;
+}
+
+SoftBody::SoftBody() :
+ MeshInstance(),
+ physics_rid(PhysicsServer::get_singleton()->soft_body_create()),
+ mesh_owner(false),
+ collision_mask(1),
+ collision_layer(1),
+ simulation_started(false),
+ pinned_points_cache_dirty(true) {
+
+ PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
+ //set_notify_transform(true);
+ set_physics_process_internal(true);
+}
+
+SoftBody::~SoftBody() {
+}
+
+void SoftBody::reset_softbody_pin() {
+ PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
+ PoolVector<PinnedPoint>::Read pps = pinned_points.read();
+ for (int i = pinned_points.size() - 1; 0 < i; --i) {
+ PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
+ }
+}
+
+void SoftBody::_make_cache_dirty() {
+ pinned_points_cache_dirty = true;
+}
+
+void SoftBody::_update_cache_pin_points_datas() {
+ if (!pinned_points_cache_dirty)
+ return;
+
+ pinned_points_cache_dirty = false;
+
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+
+ if (!w[i].spatial_attachment_path.is_empty()) {
+ w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path));
+ }
+ if (!w[i].spatial_attachment) {
+ ERR_PRINT("Spatial node not defined in the pinned point, Softbody undefined behaviour!");
+ }
+ }
+}
+
+void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) {
+ PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
+}
+
+void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
+ SoftBody::PinnedPoint *pinned_point;
+ if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
+
+ // Create new
+ PinnedPoint pp;
+ pp.point_index = p_point_index;
+ pp.spatial_attachment_path = p_spatial_attachment_path;
+
+ if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
+ pp.spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
+ pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index));
+ }
+
+ pinned_points.push_back(pp);
+
+ } else {
+
+ pinned_point->point_index = p_point_index;
+ pinned_point->spatial_attachment_path = p_spatial_attachment_path;
+
+ if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
+ pinned_point->spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
+ pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index));
+ }
+ }
+}
+
+void SoftBody::_reset_points_offsets() {
+
+ if (!Engine::get_singleton()->is_editor_hint())
+ return;
+
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+
+ if (!r[i].spatial_attachment)
+ w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(r[i].spatial_attachment_path));
+
+ if (!r[i].spatial_attachment)
+ continue;
+
+ w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index));
+ }
+}
+
+void SoftBody::_remove_pinned_point(int p_point_index) {
+ const int id(_has_pinned_point(p_point_index));
+ if (-1 != id) {
+ pinned_points.remove(id);
+ }
+}
+
+int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_point) const {
+ const int id = _has_pinned_point(p_point_index);
+ if (-1 == id) {
+ r_point = NULL;
+ return -1;
+ } else {
+ r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.read()[id]);
+ return id;
+ }
+}
+
+int SoftBody::_has_pinned_point(int p_point_index) const {
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+ if (p_point_index == r[i].point_index) {
+ return i;
+ }
+ }
+ return -1;
+}
diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h
new file mode 100644
index 0000000000..cee32b9651
--- /dev/null
+++ b/scene/3d/soft_body.h
@@ -0,0 +1,200 @@
+/*************************************************************************/
+/* soft_physics_body.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SOFT_PHYSICS_BODY_H
+#define SOFT_PHYSICS_BODY_H
+
+#include "scene/3d/mesh_instance.h"
+
+class SoftBody;
+
+class SoftBodyVisualServerHandler {
+
+ friend class SoftBody;
+
+ RID mesh;
+ int surface;
+ PoolVector<uint8_t> buffer;
+ uint32_t stride;
+ uint32_t offset_vertices;
+ uint32_t offset_normal;
+
+ PoolVector<uint8_t>::Write write_buffer;
+
+private:
+ SoftBodyVisualServerHandler();
+ bool is_ready() { return mesh.is_valid(); }
+ void prepare(RID p_mesh_rid, int p_surface);
+ void clear();
+ void open();
+ void close();
+ void commit_changes();
+
+public:
+ void set_vertex(int p_vertex_id, const void *p_vector3);
+ void set_normal(int p_vertex_id, const void *p_vector3);
+ void set_aabb(const AABB &p_aabb);
+};
+
+class SoftBody : public MeshInstance {
+ GDCLASS(SoftBody, MeshInstance);
+
+public:
+ struct PinnedPoint {
+ int point_index;
+ NodePath spatial_attachment_path;
+ Spatial *spatial_attachment; // Cache
+ Vector3 offset;
+
+ PinnedPoint();
+ PinnedPoint(const PinnedPoint &obj_tocopy);
+ };
+
+private:
+ SoftBodyVisualServerHandler visual_server_handler;
+
+ RID physics_rid;
+
+ bool mesh_owner;
+ uint32_t collision_mask;
+ uint32_t collision_layer;
+ NodePath parent_collision_ignore;
+ PoolVector<PinnedPoint> pinned_points;
+ bool simulation_started;
+ bool pinned_points_cache_dirty;
+
+ Ref<ArrayMesh> debug_mesh_cache;
+ class MeshInstance *debug_mesh;
+
+ bool capture_input_on_drag;
+ bool ray_pickable;
+
+ void _update_pickable();
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ bool _set_property_pinned_points_indices(const Array &p_indices);
+ bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value);
+ bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const;
+
+ virtual void _changed_callback(Object *p_changed, const char *p_prop);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ virtual String get_configuration_warning() const;
+
+protected:
+ void _draw_soft_mesh();
+
+public:
+ void update_physics_server();
+ void become_mesh_owner();
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
+ void set_collision_layer_bit(int p_bit, bool p_value);
+ bool get_collision_layer_bit(int p_bit) const;
+
+ void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
+ const NodePath &get_parent_collision_ignore() const;
+
+ void set_pinned_points_indices(PoolVector<PinnedPoint> p_pinned_points_indices);
+ PoolVector<PinnedPoint> get_pinned_points_indices();
+
+ void set_simulation_precision(int p_simulation_precision);
+ int get_simulation_precision();
+
+ void set_total_mass(real_t p_total_mass);
+ real_t get_total_mass();
+
+ void set_linear_stiffness(real_t p_linear_stiffness);
+ real_t get_linear_stiffness();
+
+ void set_areaAngular_stiffness(real_t p_areaAngular_stiffness);
+ real_t get_areaAngular_stiffness();
+
+ void set_volume_stiffness(real_t p_volume_stiffness);
+ real_t get_volume_stiffness();
+
+ void set_pressure_coefficient(real_t p_pressure_coefficient);
+ real_t get_pressure_coefficient();
+
+ void set_pose_matching_coefficient(real_t p_pose_matching_coefficient);
+ real_t get_pose_matching_coefficient();
+
+ void set_damping_coefficient(real_t p_damping_coefficient);
+ real_t get_damping_coefficient();
+
+ void set_drag_coefficient(real_t p_drag_coefficient);
+ real_t get_drag_coefficient();
+
+ void add_collision_exception_with(Node *p_node);
+ void remove_collision_exception_with(Node *p_node);
+
+ Vector3 get_point_transform(int p_point_index);
+
+ void pin_point_toggle(int p_point_index);
+ void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
+ bool is_point_pinned(int p_point_index) const;
+
+ void set_ray_pickable(bool p_ray_pickable);
+ bool is_ray_pickable() const;
+
+ SoftBody();
+ ~SoftBody();
+
+private:
+ void reset_softbody_pin();
+
+ void _make_cache_dirty();
+ void _update_cache_pin_points_datas();
+
+ void _pin_point_on_physics_server(int p_point_index, bool pin);
+ void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path);
+ void _reset_points_offsets();
+
+ void _remove_pinned_point(int p_point_index);
+ int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const;
+ int _has_pinned_point(int p_point_index) const;
+};
+
+#endif // SOFT_PHYSICS_BODY_H
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 748aa8aad4..3f494264e7 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -202,6 +202,7 @@ void Spatial::_notification(int p_what) {
#ifdef TOOLS_ENABLED
if (data.gizmo.is_valid()) {
data.gizmo->free();
+ data.gizmo.unref();
}
#endif
@@ -280,6 +281,10 @@ Transform Spatial::get_global_transform() const {
data.global_transform = data.local_transform;
}
+ if (data.disable_scale) {
+ data.global_transform.basis.orthonormalize();
+ }
+
data.dirty &= ~DIRTY_GLOBAL;
}
@@ -467,6 +472,15 @@ void Spatial::set_disable_gizmo(bool p_enabled) {
#endif
+void Spatial::set_disable_scale(bool p_enabled) {
+
+ data.disable_scale = p_enabled;
+}
+
+bool Spatial::is_scale_disabled() const {
+ return data.disable_scale;
+}
+
void Spatial::set_as_toplevel(bool p_enabled) {
if (data.toplevel == p_enabled)
@@ -632,19 +646,15 @@ void Spatial::scale_object_local(const Vector3 &p_scale) {
void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) {
- Basis rotation(p_axis, p_angle);
Transform t = get_global_transform();
- t.basis = rotation * t.basis;
+ t.basis.rotate(p_axis, p_angle);
set_global_transform(t);
}
void Spatial::global_scale(const Vector3 &p_scale) {
- Basis s;
- s.set_scale(p_scale);
-
Transform t = get_global_transform();
- t.basis = s * t.basis;
+ t.basis.scale(p_scale);
set_global_transform(t);
}
@@ -735,6 +745,8 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification);
ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel);
ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Spatial::set_disable_scale);
+ ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Spatial::is_scale_disabled);
ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world);
ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
@@ -755,15 +767,6 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Spatial::set_notify_transform);
ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Spatial::is_transform_notification_enabled);
- void rotate(const Vector3 &p_axis, float p_angle);
- void rotate_x(float p_angle);
- void rotate_y(float p_angle);
- void rotate_z(float p_angle);
- void translate(const Vector3 &p_offset);
- void scale(const Vector3 &p_ratio);
- void global_rotate(const Vector3 &p_axis, float p_angle);
- void global_translate(const Vector3 &p_offset);
-
ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Spatial::rotate);
ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Spatial::global_rotate);
ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Spatial::global_scale);
@@ -791,12 +794,13 @@ void Spatial::_bind_methods() {
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
ADD_GROUP("Transform", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
+ ADD_GROUP("Matrix", "");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_GROUP("Visibility", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
@@ -817,6 +821,7 @@ Spatial::Spatial() :
data.viewport = NULL;
data.inside_world = false;
data.visible = true;
+ data.disable_scale = false;
#ifdef TOOLS_ENABLED
data.gizmo_disabled = false;
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index a43bed3e4a..bc054a8763 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -51,6 +51,7 @@ public:
virtual bool can_draw() const = 0;
SpatialGizmo();
+ virtual ~SpatialGizmo() {}
};
class Spatial : public Node {
@@ -92,6 +93,7 @@ class Spatial : public Node {
bool notify_transform;
bool visible;
+ bool disable_scale;
#ifdef TOOLS_ENABLED
Ref<SpatialGizmo> gizmo;
@@ -153,6 +155,9 @@ public:
void set_as_toplevel(bool p_enabled);
bool is_set_as_toplevel() const;
+ void set_disable_scale(bool p_enabled);
+ bool is_scale_disabled() const;
+
void set_disable_gizmo(bool p_enabled);
void update_gizmo();
void set_gizmo(const Ref<SpatialGizmo> &p_gizmo);
diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp
index c547e76e30..d96b003a81 100644
--- a/scene/3d/spatial_velocity_tracker.cpp
+++ b/scene/3d/spatial_velocity_tracker.cpp
@@ -53,11 +53,11 @@ void SpatialVelocityTracker::update_position(const Vector3 &p_position) {
if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest
position_history_len = MIN(position_history.size(), position_history_len + 1);
for (int i = position_history_len - 1; i > 0; i--) {
- position_history[i] = position_history[i - 1];
+ position_history.write[i] = position_history[i - 1];
}
}
- position_history[0] = ph;
+ position_history.write[0] = ph;
}
Vector3 SpatialVelocityTracker::get_tracked_linear_velocity() const {
@@ -114,7 +114,7 @@ void SpatialVelocityTracker::reset(const Vector3 &p_new_pos) {
ph.frame = Engine::get_singleton()->get_idle_frame_ticks();
}
- position_history[0] = ph;
+ position_history.write[0] = ph;
position_history_len = 1;
}
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index 385956dc16..26958930e4 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -524,7 +524,7 @@ void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) {
//bilateral constraint between two dynamic objects
void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1,
- PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence) {
+ PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) {
real_t normalLenSqr = normal.length_squared();
//ERR_FAIL_COND( normalLenSqr < real_t(1.1));
@@ -677,8 +677,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
//collapse all those loops into one!
for (int i = 0; i < wheels.size(); i++) {
- m_sideImpulse[i] = real_t(0.);
- m_forwardImpulse[i] = real_t(0.);
+ m_sideImpulse.write[i] = real_t(0.);
+ m_forwardImpulse.write[i] = real_t(0.);
}
{
@@ -693,22 +693,22 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis;
- m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
+ m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
//m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
real_t proj = m_axle[i].dot(surfNormalWS);
- m_axle[i] -= surfNormalWS * proj;
- m_axle[i] = m_axle[i].normalized();
+ m_axle.write[i] -= surfNormalWS * proj;
+ m_axle.write[i] = m_axle[i].normalized();
- m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
- m_forwardWS[i].normalize();
+ m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]);
+ m_forwardWS.write[i].normalize();
_resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
- m_axle[i], m_sideImpulse[i], wheelInfo.m_rollInfluence);
+ m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence);
- m_sideImpulse[i] *= sideFrictionStiffness2;
+ m_sideImpulse.write[i] *= sideFrictionStiffness2;
}
}
}
@@ -739,7 +739,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
//switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
- m_forwardImpulse[wheel] = real_t(0.);
+ m_forwardImpulse.write[wheel] = real_t(0.);
wheelInfo.m_skidInfo = real_t(1.);
if (wheelInfo.m_raycastInfo.m_isInContact) {
@@ -750,7 +750,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
real_t maximpSquared = maximp * maximpSide;
- m_forwardImpulse[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
+ m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
real_t x = (m_forwardImpulse[wheel]) * fwdFactor;
real_t y = (m_sideImpulse[wheel]) * sideFactor;
@@ -772,8 +772,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
for (int wheel = 0; wheel < wheels.size(); wheel++) {
if (m_sideImpulse[wheel] != real_t(0.)) {
if (wheels[wheel]->m_skidInfo < real_t(1.)) {
- m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo;
- m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+ m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
+ m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
}
}
}
@@ -942,8 +942,6 @@ VehicleBody::VehicleBody() :
engine_force = 0;
brake = 0;
- friction = 1;
-
state = NULL;
ccd = false;
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
index 1ac3693cc4..68fbf8d873 100644
--- a/scene/3d/vehicle_body.h
+++ b/scene/3d/vehicle_body.h
@@ -168,7 +168,7 @@ class VehicleBody : public RigidBody {
btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse);
};
- void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence);
+ void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence);
real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
void _update_friction(PhysicsDirectBodyState *s);
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 00541a7d8a..767518dc83 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -105,12 +105,28 @@ uint32_t VisualInstance::get_layer_mask() const {
return layers;
}
+void VisualInstance::set_layer_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_layer_mask(layers | (1 << p_layer));
+ } else {
+ set_layer_mask(layers & (~(1 << p_layer)));
+ }
+}
+
+bool VisualInstance::get_layer_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (layers & (1 << p_layer));
+}
+
void VisualInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid);
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base);
ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance::set_layer_mask);
ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance::get_layer_mask);
+ ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance::get_layer_mask_bit);
ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance::get_transformed_aabb);
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 8458a343b2..9249bc04ce 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -73,6 +73,9 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
+ void set_layer_mask_bit(int p_layer, bool p_enable);
+ bool get_layer_mask_bit(int p_layer) const;
+
VisualInstance();
~VisualInstance();
};
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 670df5cc7f..f3abdc6bbe 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -113,7 +113,7 @@ static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
if (min > rad || max < -rad) return false;
- /*======================== Z-tests ========================*/
+/*======================== Z-tests ========================*/
#define AXISTEST_Z12(a, b, fa, fb) \
p1 = a * v1.x - b * v1.y; \
@@ -409,16 +409,16 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
}
//put this temporarily here, corrected in a later step
- bake_cells[p_idx].albedo[0] += albedo_accum.r;
- bake_cells[p_idx].albedo[1] += albedo_accum.g;
- bake_cells[p_idx].albedo[2] += albedo_accum.b;
- bake_cells[p_idx].emission[0] += emission_accum.r;
- bake_cells[p_idx].emission[1] += emission_accum.g;
- bake_cells[p_idx].emission[2] += emission_accum.b;
- bake_cells[p_idx].normal[0] += normal_accum.x;
- bake_cells[p_idx].normal[1] += normal_accum.y;
- bake_cells[p_idx].normal[2] += normal_accum.z;
- bake_cells[p_idx].alpha += alpha;
+ bake_cells.write[p_idx].albedo[0] += albedo_accum.r;
+ bake_cells.write[p_idx].albedo[1] += albedo_accum.g;
+ bake_cells.write[p_idx].albedo[2] += albedo_accum.b;
+ bake_cells.write[p_idx].emission[0] += emission_accum.r;
+ bake_cells.write[p_idx].emission[1] += emission_accum.g;
+ bake_cells.write[p_idx].emission[2] += emission_accum.b;
+ bake_cells.write[p_idx].normal[0] += normal_accum.x;
+ bake_cells.write[p_idx].normal[1] += normal_accum.y;
+ bake_cells.write[p_idx].normal[2] += normal_accum.z;
+ bake_cells.write[p_idx].alpha += alpha;
} else {
//go down
@@ -465,9 +465,9 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
//sub cell must be created
uint32_t child_idx = bake_cells.size();
- bake_cells[p_idx].children[i] = child_idx;
+ bake_cells.write[p_idx].children[i] = child_idx;
bake_cells.resize(bake_cells.size() + 1);
- bake_cells[child_idx].level = p_level + 1;
+ bake_cells.write[child_idx].level = p_level + 1;
}
_plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb);
@@ -483,7 +483,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color
ret.resize(bake_texture_size * bake_texture_size);
for (int i = 0; i < bake_texture_size * bake_texture_size; i++) {
- ret[i] = p_color_add;
+ ret.write[i] = p_color_add;
}
return ret;
@@ -509,7 +509,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color
c.a = r[i * 4 + 3] / 255.0;
- ret[i] = c;
+ ret.write[i] = c;
}
return ret;
@@ -686,13 +686,13 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) {
- bake_light[p_idx].x = p_x;
- bake_light[p_idx].y = p_y;
- bake_light[p_idx].z = p_z;
+ bake_light.write[p_idx].x = p_x;
+ bake_light.write[p_idx].y = p_y;
+ bake_light.write[p_idx].z = p_z;
if (p_level == cell_subdiv - 1) {
- bake_light[p_idx].next_leaf = first_leaf;
+ bake_light.write[p_idx].next_leaf = first_leaf;
first_leaf = p_idx;
} else {
@@ -1197,33 +1197,33 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
leaf_voxel_count++;
float alpha = bake_cells[p_idx].alpha;
- bake_cells[p_idx].albedo[0] /= alpha;
- bake_cells[p_idx].albedo[1] /= alpha;
- bake_cells[p_idx].albedo[2] /= alpha;
+ bake_cells.write[p_idx].albedo[0] /= alpha;
+ bake_cells.write[p_idx].albedo[1] /= alpha;
+ bake_cells.write[p_idx].albedo[2] /= alpha;
//transfer emission to light
- bake_cells[p_idx].emission[0] /= alpha;
- bake_cells[p_idx].emission[1] /= alpha;
- bake_cells[p_idx].emission[2] /= alpha;
+ bake_cells.write[p_idx].emission[0] /= alpha;
+ bake_cells.write[p_idx].emission[1] /= alpha;
+ bake_cells.write[p_idx].emission[2] /= alpha;
- bake_cells[p_idx].normal[0] /= alpha;
- bake_cells[p_idx].normal[1] /= alpha;
- bake_cells[p_idx].normal[2] /= alpha;
+ bake_cells.write[p_idx].normal[0] /= alpha;
+ bake_cells.write[p_idx].normal[1] /= alpha;
+ bake_cells.write[p_idx].normal[2] /= alpha;
Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]);
if (n.length() < 0.01) {
//too much fight over normal, zero it
- bake_cells[p_idx].normal[0] = 0;
- bake_cells[p_idx].normal[1] = 0;
- bake_cells[p_idx].normal[2] = 0;
+ bake_cells.write[p_idx].normal[0] = 0;
+ bake_cells.write[p_idx].normal[1] = 0;
+ bake_cells.write[p_idx].normal[2] = 0;
} else {
n.normalize();
- bake_cells[p_idx].normal[0] = n.x;
- bake_cells[p_idx].normal[1] = n.y;
- bake_cells[p_idx].normal[2] = n.z;
+ bake_cells.write[p_idx].normal[0] = n.x;
+ bake_cells.write[p_idx].normal[1] = n.y;
+ bake_cells.write[p_idx].normal[2] = n.z;
}
- bake_cells[p_idx].alpha = 1.0;
+ bake_cells.write[p_idx].alpha = 1.0;
/*if (bake_light.size()) {
for(int i=0;i<6;i++) {
@@ -1235,20 +1235,20 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
//go down
- bake_cells[p_idx].emission[0] = 0;
- bake_cells[p_idx].emission[1] = 0;
- bake_cells[p_idx].emission[2] = 0;
- bake_cells[p_idx].normal[0] = 0;
- bake_cells[p_idx].normal[1] = 0;
- bake_cells[p_idx].normal[2] = 0;
- bake_cells[p_idx].albedo[0] = 0;
- bake_cells[p_idx].albedo[1] = 0;
- bake_cells[p_idx].albedo[2] = 0;
+ bake_cells.write[p_idx].emission[0] = 0;
+ bake_cells.write[p_idx].emission[1] = 0;
+ bake_cells.write[p_idx].emission[2] = 0;
+ bake_cells.write[p_idx].normal[0] = 0;
+ bake_cells.write[p_idx].normal[1] = 0;
+ bake_cells.write[p_idx].normal[2] = 0;
+ bake_cells.write[p_idx].albedo[0] = 0;
+ bake_cells.write[p_idx].albedo[1] = 0;
+ bake_cells.write[p_idx].albedo[2] = 0;
if (bake_light.size()) {
for (int j = 0; j < 6; j++) {
- bake_light[p_idx].accum[j][0] = 0;
- bake_light[p_idx].accum[j][1] = 0;
- bake_light[p_idx].accum[j][2] = 0;
+ bake_light.write[p_idx].accum[j][0] = 0;
+ bake_light.write[p_idx].accum[j][1] = 0;
+ bake_light.write[p_idx].accum[j][2] = 0;
}
}
@@ -1267,29 +1267,29 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
if (bake_light.size() > 0) {
for (int j = 0; j < 6; j++) {
- bake_light[p_idx].accum[j][0] += bake_light[child].accum[j][0];
- bake_light[p_idx].accum[j][1] += bake_light[child].accum[j][1];
- bake_light[p_idx].accum[j][2] += bake_light[child].accum[j][2];
+ bake_light.write[p_idx].accum[j][0] += bake_light[child].accum[j][0];
+ bake_light.write[p_idx].accum[j][1] += bake_light[child].accum[j][1];
+ bake_light.write[p_idx].accum[j][2] += bake_light[child].accum[j][2];
}
- bake_cells[p_idx].emission[0] += bake_cells[child].emission[0];
- bake_cells[p_idx].emission[1] += bake_cells[child].emission[1];
- bake_cells[p_idx].emission[2] += bake_cells[child].emission[2];
+ bake_cells.write[p_idx].emission[0] += bake_cells[child].emission[0];
+ bake_cells.write[p_idx].emission[1] += bake_cells[child].emission[1];
+ bake_cells.write[p_idx].emission[2] += bake_cells[child].emission[2];
}
children_found++;
}
- bake_cells[p_idx].alpha = alpha_average / 8.0;
+ bake_cells.write[p_idx].alpha = alpha_average / 8.0;
if (bake_light.size() && children_found) {
float divisor = Math::lerp(8, children_found, propagation);
for (int j = 0; j < 6; j++) {
- bake_light[p_idx].accum[j][0] /= divisor;
- bake_light[p_idx].accum[j][1] /= divisor;
- bake_light[p_idx].accum[j][2] /= divisor;
+ bake_light.write[p_idx].accum[j][0] /= divisor;
+ bake_light.write[p_idx].accum[j][1] /= divisor;
+ bake_light.write[p_idx].accum[j][2] /= divisor;
}
- bake_cells[p_idx].emission[0] /= divisor;
- bake_cells[p_idx].emission[1] /= divisor;
- bake_cells[p_idx].emission[2] /= divisor;
+ bake_cells.write[p_idx].emission[0] /= divisor;
+ bake_cells.write[p_idx].emission[1] /= divisor;
+ bake_cells.write[p_idx].emission[2] /= divisor;
}
}
}
@@ -1961,7 +1961,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
#endif
for (int i = 0; i < height; i++) {
- //print_line("bake line " + itos(i) + " / " + itos(height));
+ //print_line("bake line " + itos(i) + " / " + itos(height));
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, 1)
#endif
@@ -2403,25 +2403,25 @@ PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) {
new_size++;
demap.push_back(i);
}
- remap[i] = c;
+ remap.write[i] = c;
}
Vector<VoxelLightBakerOctree> octree;
octree.resize(new_size);
for (int i = 0; i < new_size; i++) {
- octree[i].alpha = bake_cells[demap[i]].alpha;
+ octree.write[i].alpha = bake_cells[demap[i]].alpha;
for (int j = 0; j < 6; j++) {
for (int k = 0; k < 3; k++) {
float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light
l += bake_cells[demap[i]].emission[k]; //add emission
- octree[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree
+ octree.write[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree
}
}
for (int j = 0; j < 8; j++) {
uint32_t child = bake_cells[demap[i]].children[j];
- octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child];
+ octree.write[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child];
}
}