summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/camera.cpp6
-rw-r--r--scene/3d/cpu_particles.cpp178
-rw-r--r--scene/3d/cpu_particles.h1
-rw-r--r--scene/3d/navigation_mesh.cpp35
-rw-r--r--scene/3d/navigation_mesh.h16
-rw-r--r--scene/3d/skeleton.cpp28
-rw-r--r--scene/3d/skeleton.h7
-rw-r--r--scene/3d/soft_body.cpp11
-rw-r--r--scene/3d/spatial.cpp5
-rw-r--r--scene/3d/sprite_3d.cpp11
10 files changed, 208 insertions, 90 deletions
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 9f8510248c..9797b5f3ab 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -548,9 +548,9 @@ void Camera::_bind_methods() {
BIND_ENUM_CONSTANT(KEEP_WIDTH);
BIND_ENUM_CONSTANT(KEEP_HEIGHT);
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED)
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP)
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP)
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED);
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP);
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
}
float Camera::get_fov() const {
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 93ff60bc4e..86daabefd2 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -46,9 +46,17 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
void CPUParticles::set_emitting(bool p_emitting) {
+ if (emitting == p_emitting)
+ return;
+
emitting = p_emitting;
- if (emitting)
+ if (emitting) {
set_process_internal(true);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (time == 0)
+ _update_internal();
+ }
}
void CPUParticles::set_amount(int p_amount) {
@@ -232,8 +240,7 @@ void CPUParticles::restart() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
-
- set_emitting(true);
+ emitting = false;
{
int pc = particles.size();
@@ -243,6 +250,8 @@ void CPUParticles::restart() {
w[i].active = false;
}
}
+
+ set_emitting(true);
}
void CPUParticles::set_direction(Vector3 p_direction) {
@@ -508,6 +517,81 @@ static float rand_from_seed(uint32_t &seed) {
return float(seed % uint32_t(65536)) / 65535.0;
}
+void CPUParticles::_update_internal() {
+
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
+ return;
+ }
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+ _set_redraw(false);
+
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+ _set_redraw(true);
+
+ bool processed = false;
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ processed = true;
+ }
+
+ if (processed) {
+ _update_particle_data_buffer();
+ }
+}
+
void CPUParticles::_particles_process(float p_delta) {
p_delta *= speed_scale;
@@ -1040,7 +1124,9 @@ void CPUParticles::_set_redraw(bool p_redraw) {
VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
} else {
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_update_render_thread")) {
+ 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);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
}
@@ -1068,85 +1154,24 @@ void CPUParticles::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
set_process_internal(emitting);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
}
if (p_what == NOTIFICATION_EXIT_TREE) {
_set_redraw(false);
}
- if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
- return;
- }
-
- float delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
-
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
- }
- _set_redraw(true);
-
- bool processed = false;
-
- if (time == 0 && pre_process_time > 0.0) {
-
- float frame_time;
- if (fixed_fps > 0)
- frame_time = 1.0 / fixed_fps;
- else
- frame_time = 1.0 / 30.0;
-
- float todo = pre_process_time;
-
- while (todo >= 0) {
- _particles_process(frame_time);
- processed = true;
- todo -= frame_time;
- }
- }
-
- if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
-
- float ldelta = delta;
- if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
- ldelta = 0.1;
- } else if (ldelta <= 0.0) { //unlikely but..
- ldelta = 0.001;
- }
- float todo = frame_remainder + ldelta;
-
- while (todo >= frame_time) {
- _particles_process(frame_time);
- processed = true;
- todo -= decr;
- }
-
- frame_remainder = todo;
-
- } else {
- _particles_process(delta);
- processed = true;
- }
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+ }
- if (processed) {
- _update_particle_data_buffer();
- }
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+ _update_internal();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
@@ -1472,6 +1497,7 @@ CPUParticles::CPUParticles() {
frame_remainder = 0;
cycle = 0;
redraw = false;
+ emitting = false;
set_notify_transform(true);
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index 66b37f359a..635265be7f 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -173,6 +173,7 @@ private:
Vector3 gravity;
+ void _update_internal();
void _particles_process(float p_delta);
void _update_particle_data_buffer();
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index f82543b789..496dc4b411 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -108,6 +108,24 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit);
}
+void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) {
+ ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX);
+ source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode);
+ _change_notify();
+}
+
+int NavigationMesh::get_source_geometry_mode() const {
+ return source_geometry_mode;
+}
+
+void NavigationMesh::set_source_group_name(StringName p_group_name) {
+ source_group_name = p_group_name;
+}
+
+StringName NavigationMesh::get_source_group_name() const {
+ return source_group_name;
+}
+
void NavigationMesh::set_cell_size(float p_value) {
cell_size = p_value;
}
@@ -387,6 +405,12 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_source_geometry_mode", "mask"), &NavigationMesh::set_source_geometry_mode);
+ ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationMesh::get_source_geometry_mode);
+
+ ClassDB::bind_method(D_METHOD("set_source_group_name", "mask"), &NavigationMesh::set_source_group_name);
+ ClassDB::bind_method(D_METHOD("get_source_group_name"), &NavigationMesh::get_source_group_name);
+
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size);
@@ -462,6 +486,8 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
@@ -489,6 +515,13 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const {
return;
}
}
+
+ if (property.name == "geometry/source_group_name") {
+ if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
+ property.usage = 0;
+ return;
+ }
+ }
}
NavigationMesh::NavigationMesh() {
@@ -509,6 +542,8 @@ NavigationMesh::NavigationMesh() {
partition_type = SAMPLE_PARTITION_WATERSHED;
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
collision_mask = 0xFFFFFFFF;
+ source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
+ source_group_name = "navmesh";
filter_low_hanging_obstacles = false;
filter_ledge_spans = false;
filter_walkable_low_height_spans = false;
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
index 5fbf3998ff..d5de653e40 100644
--- a/scene/3d/navigation_mesh.h
+++ b/scene/3d/navigation_mesh.h
@@ -77,6 +77,13 @@ public:
PARSED_GEOMETRY_MAX
};
+ enum SourceGeometryMode {
+ SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0,
+ SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
+ SOURCE_GEOMETRY_GROUPS_EXPLICIT,
+ SOURCE_GEOMETRY_MAX
+ };
+
protected:
float cell_size;
float cell_height;
@@ -96,6 +103,9 @@ protected:
ParsedGeometryType parsed_geometry_type;
uint32_t collision_mask;
+ SourceGeometryMode source_geometry_mode;
+ StringName source_group_name;
+
bool filter_low_hanging_obstacles;
bool filter_ledge_spans;
bool filter_walkable_low_height_spans;
@@ -114,6 +124,12 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
+ void set_source_geometry_mode(int p_geometry_mode);
+ int get_source_geometry_mode() const;
+
+ void set_source_group_name(StringName p_group_name);
+ StringName get_source_group_name() const;
+
void set_cell_size(float p_value);
float get_cell_size() const;
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index ead1e69f90..ae79b4eebf 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -245,6 +245,9 @@ void Skeleton::_notification(int p_what) {
if (b.enabled) {
Transform pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * pose;
@@ -267,7 +270,9 @@ void Skeleton::_notification(int p_what) {
if (b.enabled) {
Transform pose = b.pose;
-
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
@@ -533,6 +538,23 @@ Transform Skeleton::get_bone_pose(int p_bone) const {
return bones[p_bone].pose;
}
+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.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
+ bones.write[p_bone].custom_pose = p_custom_pose;
+
+ _make_dirty();
+}
+
+Transform Skeleton::get_bone_custom_pose(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+ return bones[p_bone].custom_pose;
+}
+
void Skeleton::_make_dirty() {
if (dirty)
@@ -770,6 +792,7 @@ Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
skin_bindings.insert(skin_ref.operator->());
skin->connect("changed", skin_ref.operator->(), "_skin_changed");
+ _make_dirty();
return skin_ref;
}
@@ -808,6 +831,9 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose);
+ ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton::get_bone_custom_pose);
+ ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton::set_bone_custom_pose);
+
#ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index f20c550055..824d9567fa 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -87,6 +87,9 @@ private:
Transform pose;
Transform pose_global;
+ bool custom_pose_enable;
+ Transform custom_pose;
+
float global_pose_override_amount;
bool global_pose_override_reset;
Transform global_pose_override;
@@ -102,6 +105,7 @@ private:
parent = -1;
enabled = true;
disable_rest = false;
+ custom_pose_enable = false;
global_pose_override_amount = 0;
global_pose_override_reset = false;
#ifndef _3D_DISABLED
@@ -184,6 +188,9 @@ public:
void set_bone_pose(int p_bone, const Transform &p_pose);
Transform get_bone_pose(int p_bone) const;
+ void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose);
+ Transform get_bone_custom_pose(int p_bone) const;
+
void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx);
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index 6c3949a0a8..6883da7f6d 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -115,7 +115,7 @@ SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) {
void SoftBody::_update_pickable() {
if (!is_inside_tree())
return;
- bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree();
+ bool pickable = ray_pickable && is_visible_in_tree();
PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
@@ -395,6 +395,8 @@ void SoftBody::_bind_methods() {
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");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
}
String SoftBody::get_configuration_warning() const {
@@ -460,7 +462,9 @@ void SoftBody::update_physics_server() {
} else {
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_draw_soft_mesh")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ }
}
}
@@ -698,7 +702,8 @@ SoftBody::SoftBody() :
collision_mask(1),
collision_layer(1),
simulation_started(false),
- pinned_points_cache_dirty(true) {
+ pinned_points_cache_dirty(true),
+ ray_pickable(true) {
PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
//set_notify_transform(true);
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index df831f92ef..9a659ef4af 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -690,11 +690,10 @@ void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_targe
Transform lookat;
lookat.origin = p_pos;
- Vector3 original_scale(get_global_transform().basis.get_scale());
+ Vector3 original_scale(get_scale());
lookat = lookat.looking_at(p_target, p_up);
- // as basis was normalized, we just need to apply original scale back
- lookat.basis.scale(original_scale);
set_global_transform(lookat);
+ set_scale(original_scale);
}
Vector3 Spatial::to_local(Vector3 p_global) const {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index a9dacc442c..adcd80b0ab 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -577,9 +577,8 @@ void Sprite3D::set_frame(int p_frame) {
ERR_FAIL_INDEX(p_frame, int64_t(vframes) * hframes);
- if (frame != p_frame)
+ frame = p_frame;
- frame = p_frame;
_queue_update();
_change_notify("frame");
@@ -593,8 +592,8 @@ int Sprite3D::get_frame() const {
}
void Sprite3D::set_frame_coords(const Vector2 &p_coord) {
- ERR_FAIL_INDEX(int(p_coord.x), vframes);
- ERR_FAIL_INDEX(int(p_coord.y), hframes);
+ ERR_FAIL_INDEX(int(p_coord.x), hframes);
+ ERR_FAIL_INDEX(int(p_coord.y), vframes);
set_frame(int(p_coord.y) * hframes + int(p_coord.x));
}
@@ -663,6 +662,10 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {
property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (property.name == "frame_coords") {
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
}
void Sprite3D::_bind_methods() {