summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/baked_lightmap.cpp4
-rw-r--r--scene/3d/camera_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.cpp4
-rw-r--r--scene/3d/cpu_particles_3d.cpp4
-rw-r--r--scene/3d/gpu_particles_3d.cpp170
-rw-r--r--scene/3d/gpu_particles_3d.h31
-rw-r--r--scene/3d/lightmapper.cpp9
-rw-r--r--scene/3d/lightmapper.h77
-rw-r--r--scene/3d/mesh_instance_3d.cpp38
-rw-r--r--scene/3d/mesh_instance_3d.h3
-rw-r--r--scene/3d/navigation_agent_3d.cpp17
-rw-r--r--scene/3d/navigation_agent_3d.h1
-rw-r--r--scene/3d/occluder_instance_3d.cpp335
-rw-r--r--scene/3d/occluder_instance_3d.h108
-rw-r--r--scene/3d/ray_cast_3d.cpp2
-rw-r--r--scene/3d/soft_body_3d.cpp8
-rw-r--r--scene/3d/visual_instance_3d.cpp23
-rw-r--r--scene/3d/visual_instance_3d.h4
18 files changed, 816 insertions, 24 deletions
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 2e1b77dfe5..ef648a126e 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -619,10 +619,6 @@ void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell
}
BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
- if (p_image_data_path == "" && (get_light_data().is_null() || !get_light_data()->get_path().is_resource_file())) {
- return BAKE_ERROR_NO_SAVE_PATH;
- }
-
if (p_image_data_path == "") {
if (get_light_data().is_null()) {
return BAKE_ERROR_NO_SAVE_PATH;
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index cd8d02233b..041da4f6ff 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -761,6 +761,7 @@ uint32_t ClippedCamera3D::get_collision_mask() const {
}
void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -771,6 +772,7 @@ void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool ClippedCamera3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 44de4eb449..688509a979 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -110,6 +110,7 @@ uint32_t CollisionObject3D::get_collision_mask() const {
}
void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
collision_layer |= 1 << p_bit;
@@ -120,10 +121,12 @@ void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
}
bool CollisionObject3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -134,6 +137,7 @@ void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 780773bb57..aa29728c73 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -1050,7 +1050,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
Color c = r[idx].color;
@@ -1155,7 +1155,7 @@ void CPUParticles3D::_notification(int p_what) {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
ptr += 20;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index a075dcf990..5339b8a8da 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -181,12 +181,33 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
}
+void GPUParticles3D::set_enable_trail(bool p_enabled) {
+ trail_enabled = p_enabled;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update_configuration_warnings();
+}
+void GPUParticles3D::set_trail_length(float p_seconds) {
+ ERR_FAIL_COND(p_seconds < 0.001);
+ trail_length = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+}
+
+bool GPUParticles3D::is_trail_enabled() const {
+ return trail_enabled;
+}
+float GPUParticles3D::get_trail_length() const {
+ return trail_length;
+}
+
GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const {
return draw_order;
}
void GPUParticles3D::set_draw_passes(int p_count) {
ERR_FAIL_COND(p_count < 1);
+ for (int i = p_count; i < draw_passes.size(); i++) {
+ set_draw_pass_mesh(i, Ref<Mesh>());
+ }
draw_passes.resize(p_count);
RS::get_singleton()->particles_set_draw_passes(particles, p_count);
notify_property_list_changed();
@@ -199,8 +220,16 @@ int GPUParticles3D::get_draw_passes() const {
void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
ERR_FAIL_INDEX(p_pass, draw_passes.size());
+ if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
+ draw_passes.write[p_pass]->disconnect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings));
+ }
+
draw_passes.write[p_pass] = p_mesh;
+ if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
+ draw_passes.write[p_pass]->connect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings), varray(), CONNECT_DEFERRED);
+ }
+
RID mesh_rid;
if (p_mesh.is_valid()) {
mesh_rid = p_mesh->get_rid();
@@ -208,6 +237,7 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
+ _skinning_changed();
update_configuration_warnings();
}
@@ -235,6 +265,15 @@ bool GPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
+void GPUParticles3D::set_interpolate(bool p_enable) {
+ interpolate = p_enable;
+ RS::get_singleton()->particles_set_interpolate(particles, p_enable);
+}
+
+bool GPUParticles3D::get_interpolate() const {
+ return interpolate;
+}
+
TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
@@ -250,7 +289,7 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
meshes_found = true;
for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
anim_material_found = Object::cast_to<ShaderMaterial>(draw_passes[i]->surface_get_material(j).ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
}
if (anim_material_found) {
@@ -260,8 +299,10 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
}
anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
- anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
+ {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == BaseMaterial3D::BILLBOARD_PARTICLES);
+ }
if (!meshes_found) {
warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));
@@ -274,7 +315,57 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
if (!anim_material_found && process &&
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- warnings.push_back(TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
+ warnings.push_back(TTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
+ }
+ }
+
+ if (trail_enabled) {
+ int dp_count = 0;
+ bool missing_trails = false;
+ bool no_materials = false;
+
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ dp_count++;
+ }
+
+ if (draw_pass.is_valid()) {
+ int mats_found = 0;
+ for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ if (spat) {
+ mats_found++;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+ }
+
+ if (mats_found != draw_passes[i]->get_surface_count()) {
+ no_materials = true;
+ }
+ }
+ }
+
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ if (spat) {
+ no_materials = false;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+
+ if (dp_count && skin.is_valid()) {
+ warnings.push_back(TTR("Using Trail meshes with a skin causes Skin to override Trail poses. Suggest removing the Skin."));
+ } else if (dp_count == 0 && skin.is_null()) {
+ warnings.push_back(TTR("Trails active, but neither Trail meshes or a Skin were found."));
+ } else if (dp_count > 1) {
+ warnings.push_back(TTR("Only one Trail mesh is supported. If you want to use more than a single mesh, a Skin is needed (see documentation)."));
+ }
+
+ if ((dp_count || !skin.is_null()) && (missing_trails || no_materials)) {
+ warnings.push_back(TTR("Trails enabled, but one or more mesh materials are either missing or not set for trails rendering."));
}
}
@@ -366,6 +457,47 @@ void GPUParticles3D::_notification(int p_what) {
}
}
+void GPUParticles3D::_skinning_changed() {
+ Vector<Transform> xforms;
+ if (skin.is_valid()) {
+ xforms.resize(skin->get_bind_count());
+ for (int i = 0; i < skin->get_bind_count(); i++) {
+ xforms.write[i] = skin->get_bind_pose(i);
+ }
+ } else {
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ xforms.resize(draw_pass->get_builtin_bind_pose_count());
+ for (int j = 0; j < draw_pass->get_builtin_bind_pose_count(); j++) {
+ xforms.write[i] = draw_pass->get_builtin_bind_pose(j);
+ }
+ break;
+ }
+ }
+ }
+
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
+ update_configuration_warnings();
+}
+
+void GPUParticles3D::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+ _skinning_changed();
+}
+Ref<Skin> GPUParticles3D::get_skin() const {
+ return skin;
+}
+
+void GPUParticles3D::set_transform_align(TransformAlign p_align) {
+ ERR_FAIL_INDEX(uint32_t(p_align), 4);
+ transform_align = p_align;
+ RS::get_singleton()->particles_set_transform_align(particles, RS::ParticlesTransformAlign(transform_align));
+}
+GPUParticles3D::TransformAlign GPUParticles3D::get_transform_align() const {
+ return transform_align;
+}
+
void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles3D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles3D::set_amount);
@@ -378,6 +510,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles3D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles3D::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles3D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_interpolate", "enable"), &GPUParticles3D::set_interpolate);
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles3D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles3D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles3D::set_collision_base_size);
@@ -393,6 +526,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles3D::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles3D::get_fixed_fps);
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles3D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_interpolate"), &GPUParticles3D::get_interpolate);
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles3D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles3D::get_collision_base_size);
@@ -407,6 +541,9 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_passes"), &GPUParticles3D::get_draw_passes);
ClassDB::bind_method(D_METHOD("get_draw_pass_mesh", "pass"), &GPUParticles3D::get_draw_pass_mesh);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &GPUParticles3D::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &GPUParticles3D::get_skin);
+
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
@@ -415,6 +552,15 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
+ ClassDB::bind_method(D_METHOD("set_enable_trail", "enabled"), &GPUParticles3D::set_enable_trail);
+ ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
+
+ ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
+ ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles3D::get_trail_length);
+
+ ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
+ ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
@@ -426,6 +572,7 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
@@ -433,6 +580,10 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align");
+ ADD_GROUP("Trails", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_enable_trail", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,4,0.01"), "set_trail_length", "get_trail_length");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
@@ -440,6 +591,7 @@ void GPUParticles3D::_bind_methods() {
for (int i = 0; i < MAX_DRAW_PASSES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "draw_pass_" + itos(i + 1), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_draw_pass_mesh", "get_draw_pass_mesh", i);
}
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "draw_skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
@@ -452,6 +604,11 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
BIND_CONSTANT(MAX_DRAW_PASSES);
+
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_DISABLED);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY);
}
GPUParticles3D::GPUParticles3D() {
@@ -462,17 +619,20 @@ GPUParticles3D::GPUParticles3D() {
set_one_shot(false);
set_amount(8);
set_lifetime(1);
- set_fixed_fps(0);
+ set_fixed_fps(30);
set_fractional_delta(true);
+ set_interpolate(true);
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
+ set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
set_use_local_coordinates(true);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
set_collision_base_size(0.01);
+ set_transform_align(TRANSFORM_ALIGN_DISABLED);
}
GPUParticles3D::~GPUParticles3D() {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index b9e2b5ccef..1f9cea79b6 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -34,6 +34,7 @@
#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/material.h"
+#include "scene/resources/skin.h"
class GPUParticles3D : public GeometryInstance3D {
private:
@@ -46,6 +47,13 @@ public:
DRAW_ORDER_VIEW_DEPTH,
};
+ enum TransformAlign {
+ TRANSFORM_ALIGN_DISABLED,
+ TRANSFORM_ALIGN_Z_BILLBOARD,
+ TRANSFORM_ALIGN_Y_TO_VELOCITY,
+ TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY
+ };
+
enum {
MAX_DRAW_PASSES = 4
};
@@ -64,17 +72,26 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
+ bool interpolate = true;
NodePath sub_emitter;
float collision_base_size;
+ bool trail_enabled = false;
+ float trail_length = 0.3;
+
+ TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED;
+
Ref<Material> process_material;
DrawOrder draw_order;
Vector<Ref<Mesh>> draw_passes;
+ Ref<Skin> skin;
void _attach_sub_emitter();
+ void _skinning_changed();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -96,6 +113,8 @@ public:
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
void set_collision_base_size(float p_ratio);
+ void set_enable_trail(bool p_enabled);
+ void set_trail_length(float p_seconds);
bool is_emitting() const;
int get_amount() const;
@@ -109,6 +128,8 @@ public:
Ref<Material> get_process_material() const;
float get_speed_scale() const;
float get_collision_base_size() const;
+ bool is_trail_enabled() const;
+ float get_trail_length() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -116,6 +137,9 @@ public:
void set_fractional_delta(bool p_enable);
bool get_fractional_delta() const;
+ void set_interpolate(bool p_enable);
+ bool get_interpolate() const;
+
void set_draw_order(DrawOrder p_order);
DrawOrder get_draw_order() const;
@@ -130,6 +154,12 @@ public:
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ void set_transform_align(TransformAlign p_align);
+ TransformAlign get_transform_align() const;
+
void restart();
enum EmitFlags {
@@ -148,6 +178,7 @@ public:
};
VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+VARIANT_ENUM_CAST(GPUParticles3D::TransformAlign)
VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags)
#endif // PARTICLES_H
diff --git a/scene/3d/lightmapper.cpp b/scene/3d/lightmapper.cpp
index c17ac52aa2..9e5078ba95 100644
--- a/scene/3d/lightmapper.cpp
+++ b/scene/3d/lightmapper.cpp
@@ -39,6 +39,15 @@ Ref<LightmapDenoiser> LightmapDenoiser::create() {
return Ref<LightmapDenoiser>();
}
+LightmapRaycaster *(*LightmapRaycaster::create_function)() = nullptr;
+
+Ref<LightmapRaycaster> LightmapRaycaster::create() {
+ if (create_function) {
+ return Ref<LightmapRaycaster>(create_function());
+ }
+ return Ref<LightmapRaycaster>();
+}
+
Lightmapper::CreateFunc Lightmapper::create_custom = nullptr;
Lightmapper::CreateFunc Lightmapper::create_gpu = nullptr;
Lightmapper::CreateFunc Lightmapper::create_cpu = nullptr;
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index a07a964c01..f63515f666 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -34,6 +34,16 @@
#include "scene/resources/mesh.h"
#include "servers/rendering/rendering_device.h"
+#if !defined(__aligned)
+
+#if defined(_WIN32) && defined(_MSC_VER)
+#define __aligned(...) __declspec(align(__VA_ARGS__))
+#else
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#endif
+
class LightmapDenoiser : public Reference {
GDCLASS(LightmapDenoiser, Reference)
protected:
@@ -44,6 +54,73 @@ public:
static Ref<LightmapDenoiser> create();
};
+class LightmapRaycaster : public Reference {
+ GDCLASS(LightmapRaycaster, Reference)
+protected:
+ static LightmapRaycaster *(*create_function)();
+
+public:
+ // compatible with embree3 rays
+ struct __aligned(16) Ray {
+ const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
+
+ /*! Default construction does nothing. */
+ _FORCE_INLINE_ Ray() :
+ geomID(INVALID_GEOMETRY_ID) {}
+
+ /*! Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far. */
+ _FORCE_INLINE_ Ray(const Vector3 &org,
+ const Vector3 &dir,
+ float tnear = 0.0f,
+ float tfar = INFINITY) :
+ org(org),
+ tnear(tnear),
+ dir(dir),
+ time(0.0f),
+ tfar(tfar),
+ mask(-1),
+ u(0.0),
+ v(0.0),
+ primID(INVALID_GEOMETRY_ID),
+ geomID(INVALID_GEOMETRY_ID),
+ instID(INVALID_GEOMETRY_ID) {}
+
+ /*! Tests if we hit something. */
+ _FORCE_INLINE_ explicit operator bool() const { return geomID != INVALID_GEOMETRY_ID; }
+
+ public:
+ Vector3 org; //!< Ray origin + tnear
+ float tnear; //!< Start of ray segment
+ Vector3 dir; //!< Ray direction + tfar
+ float time; //!< Time of this ray for motion blur.
+ float tfar; //!< End of ray segment
+ unsigned int mask; //!< used to mask out objects during traversal
+ unsigned int id; //!< ray ID
+ unsigned int flags; //!< ray flags
+
+ Vector3 normal; //!< Not normalized geometry normal
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+ unsigned int primID; //!< primitive ID
+ unsigned int geomID; //!< geometry ID
+ unsigned int instID; //!< instance ID
+ };
+
+ virtual bool intersect(Ray &p_ray) = 0;
+
+ virtual void intersect(Vector<Ray> &r_rays) = 0;
+
+ virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) = 0;
+ virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) = 0;
+ virtual void commit() = 0;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) = 0;
+ virtual void clear_mesh_filter() = 0;
+
+ static Ref<LightmapRaycaster> create();
+};
+
class Lightmapper : public Reference {
GDCLASS(Lightmapper, Reference)
public:
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 7623ede0fc..27d5487a1a 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -271,6 +271,41 @@ void MeshInstance3D::create_convex_collision() {
}
}
+Node *MeshInstance3D::create_multiple_convex_collisions_node() {
+ if (mesh.is_null()) {
+ return nullptr;
+ }
+
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+ if (!shapes.size()) {
+ return nullptr;
+ }
+
+ StaticBody3D *static_body = memnew(StaticBody3D);
+ for (int i = 0; i < shapes.size(); i++) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shapes[i]);
+ static_body->add_child(cshape);
+ }
+ return static_body;
+}
+
+void MeshInstance3D::create_multiple_convex_collisions() {
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_multiple_convex_collisions_node());
+ ERR_FAIL_COND(!static_body);
+ static_body->set_name(String(get_name()) + "_col");
+
+ add_child(static_body);
+ if (get_owner()) {
+ static_body->set_owner(get_owner());
+ int count = static_body->get_child_count();
+ for (int i = 0; i < count; i++) {
+ CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(i));
+ cshape->set_owner(get_owner());
+ }
+ }
+}
+
void MeshInstance3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
_resolve_skeleton_path();
@@ -321,6 +356,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
void MeshInstance3D::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
surface_override_materials.resize(mesh->get_surface_count());
+ update_gizmo();
}
void MeshInstance3D::create_debug_tangents() {
@@ -417,6 +453,8 @@ void MeshInstance3D::_bind_methods() {
ClassDB::set_method_flags("MeshInstance3D", "create_trimesh_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance3D::create_convex_collision);
ClassDB::set_method_flags("MeshInstance3D", "create_convex_collision", METHOD_FLAGS_DEFAULT);
+ ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance3D::create_multiple_convex_collisions);
+ ClassDB::set_method_flags("MeshInstance3D", "create_multiple_convex_collisions", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance3D::create_debug_tangents);
ClassDB::set_method_flags("MeshInstance3D", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 8aec227337..9dea5804e0 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -86,6 +86,9 @@ public:
Node *create_convex_collision_node();
void create_convex_collision();
+ Node *create_multiple_convex_collisions_node();
+ void create_multiple_convex_collisions();
+
void create_debug_tangents();
virtual AABB get_aabb() const override;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 4f5e56e227..64cfe4dca7 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -111,12 +111,7 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
- if (!target_reached) {
- if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
- target_reached = true;
- }
- }
+ _check_distance_to_target();
}
} break;
}
@@ -314,6 +309,7 @@ void NavigationAgent3D::update_navigation() {
while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < target_desired_distance) {
nav_path_index += 1;
if (nav_path_index == navigation_path.size()) {
+ _check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
emit_signal("navigation_finished");
@@ -322,3 +318,12 @@ void NavigationAgent3D::update_navigation() {
}
}
}
+
+void NavigationAgent3D::_check_distance_to_target() {
+ if (!target_reached) {
+ if (distance_to_target() < target_desired_distance) {
+ emit_signal("target_reached");
+ target_reached = true;
+ }
+ }
+}
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 814c0714e8..56da2d1acf 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -147,6 +147,7 @@ public:
private:
void update_navigation();
+ void _check_distance_to_target();
};
#endif
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
new file mode 100644
index 0000000000..d3a256db34
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* occluder_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "occluder_instance_3d.h"
+#include "core/core_string_names.h"
+#include "scene/3d/mesh_instance_3d.h"
+
+RID Occluder3D::get_rid() const {
+ if (!occluder.is_valid()) {
+ occluder = RS::get_singleton()->occluder_create();
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ return occluder;
+}
+
+void Occluder3D::set_vertices(PackedVector3Array p_vertices) {
+ vertices = p_vertices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedVector3Array Occluder3D::get_vertices() const {
+ return vertices;
+}
+
+void Occluder3D::set_indices(PackedInt32Array p_indices) {
+ indices = p_indices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedInt32Array Occluder3D::get_indices() const {
+ return indices;
+}
+
+void Occluder3D::_update_changes() {
+ aabb = AABB();
+
+ const Vector3 *ptr = vertices.ptr();
+ for (int i = 0; i < vertices.size(); i++) {
+ aabb.expand_to(ptr[i]);
+ }
+
+ debug_lines.clear();
+ debug_mesh.unref();
+
+ emit_changed();
+}
+
+Vector<Vector3> Occluder3D::get_debug_lines() const {
+ if (!debug_lines.is_empty()) {
+ return debug_lines;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return Vector<Vector3>();
+ }
+
+ for (int i = 0; i < indices.size() / 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ int a = indices[i * 3 + j];
+ int b = indices[i * 3 + (j + 1) % 3];
+ ERR_FAIL_INDEX_V_MSG(a, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ ERR_FAIL_INDEX_V_MSG(b, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ debug_lines.push_back(vertices[a]);
+ debug_lines.push_back(vertices[b]);
+ }
+ }
+ return debug_lines;
+}
+
+Ref<ArrayMesh> Occluder3D::get_debug_mesh() const {
+ if (debug_mesh.is_valid()) {
+ return debug_mesh;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return debug_mesh;
+ }
+
+ Array arrays;
+ arrays.resize(Mesh::ARRAY_MAX);
+ arrays[Mesh::ARRAY_VERTEX] = vertices;
+ arrays[Mesh::ARRAY_INDEX] = indices;
+
+ debug_mesh.instance();
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ return debug_mesh;
+}
+
+AABB Occluder3D::get_aabb() const {
+ return aabb;
+}
+
+void Occluder3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &Occluder3D::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &Occluder3D::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("set_indices", "indices"), &Occluder3D::set_indices);
+ ClassDB::bind_method(D_METHOD("get_indices"), &Occluder3D::get_indices);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_indices", "get_indices");
+}
+
+Occluder3D::Occluder3D() {
+}
+
+Occluder3D::~Occluder3D() {
+ if (occluder.is_valid()) {
+ RS::get_singleton()->free(occluder);
+ }
+}
+/////////////////////////////////////////////////
+
+AABB OccluderInstance3D::get_aabb() const {
+ if (occluder.is_valid()) {
+ return occluder->get_aabb();
+ }
+ return AABB();
+}
+
+Vector<Face3> OccluderInstance3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
+void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
+ if (occluder == p_occluder) {
+ return;
+ }
+
+ if (occluder.is_valid()) {
+ occluder->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ }
+
+ occluder = p_occluder;
+
+ if (occluder.is_valid()) {
+ set_base(occluder->get_rid());
+ occluder->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ } else {
+ set_base(RID());
+ }
+
+ update_gizmo();
+}
+
+void OccluderInstance3D::_occluder_changed() {
+ update_gizmo();
+}
+
+Ref<Occluder3D> OccluderInstance3D::get_occluder() const {
+ return occluder;
+}
+
+void OccluderInstance3D::set_bake_mask(uint32_t p_mask) {
+ bake_mask = p_mask;
+}
+
+uint32_t OccluderInstance3D::get_bake_mask() const {
+ return bake_mask;
+}
+
+void OccluderInstance3D::set_bake_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_bake_mask(bake_mask | (1 << p_layer));
+ } else {
+ set_bake_mask(bake_mask & (~(1 << p_layer)));
+ }
+}
+
+bool OccluderInstance3D::get_bake_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (bake_mask & (1 << p_layer));
+}
+
+bool OccluderInstance3D::_bake_material_check(Ref<Material> p_material) {
+ StandardMaterial3D *standard_mat = Object::cast_to<StandardMaterial3D>(p_material.ptr());
+ if (standard_mat && standard_mat->get_transparency() != StandardMaterial3D::TRANSPARENCY_DISABLED) {
+ return false;
+ }
+ return true;
+}
+
+void OccluderInstance3D::_bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ if (mi && mi->is_visible_in_tree()) {
+ Ref<Mesh> mesh = mi->get_mesh();
+ bool valid = true;
+
+ if (mesh.is_null()) {
+ valid = false;
+ }
+
+ if (valid && !_bake_material_check(mi->get_material_override())) {
+ valid = false;
+ }
+
+ if ((mi->get_layer_mask() & bake_mask) == 0) {
+ valid = false;
+ }
+
+ if (valid) {
+ Transform global_to_local = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ if (mi->get_surface_override_material(i).is_valid()) {
+ if (!_bake_material_check(mi->get_surface_override_material(i))) {
+ continue;
+ }
+ } else {
+ if (!_bake_material_check(mesh->surface_get_material(i))) {
+ continue;
+ }
+ }
+
+ Array arrays = mesh->surface_get_arrays(i);
+
+ int vertex_offset = r_vertices.size();
+ PackedVector3Array vertices = arrays[Mesh::ARRAY_VERTEX];
+ r_vertices.resize(r_vertices.size() + vertices.size());
+
+ Vector3 *vtx_ptr = r_vertices.ptrw();
+ for (int j = 0; j < vertices.size(); j++) {
+ vtx_ptr[vertex_offset + j] = global_to_local.xform(vertices[j]);
+ }
+
+ int index_offset = r_indices.size();
+ PackedInt32Array indices = arrays[Mesh::ARRAY_INDEX];
+ r_indices.resize(r_indices.size() + indices.size());
+
+ int *idx_ptr = r_indices.ptrw();
+ for (int j = 0; j < indices.size(); j++) {
+ idx_ptr[index_offset + j] = vertex_offset + indices[j];
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ if (!child->get_owner()) {
+ continue; //maybe a helper
+ }
+
+ _bake_node(child, r_vertices, r_indices);
+ }
+}
+
+OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String p_occluder_path) {
+ if (p_occluder_path == "") {
+ if (get_occluder().is_null()) {
+ return BAKE_ERROR_NO_SAVE_PATH;
+ }
+ }
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ _bake_node(p_from_node, vertices, indices);
+
+ if (vertices.is_empty() || indices.is_empty()) {
+ return BAKE_ERROR_NO_MESHES;
+ }
+
+ Ref<Occluder3D> occ;
+ if (get_occluder().is_valid()) {
+ occ = get_occluder();
+ } else {
+ occ.instance();
+ occ->set_path(p_occluder_path);
+ }
+
+ occ->set_vertices(vertices);
+ occ->set_indices(indices);
+ set_occluder(occ);
+
+ return BAKE_ERROR_OK;
+}
+
+void OccluderInstance3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &OccluderInstance3D::set_bake_mask);
+ ClassDB::bind_method(D_METHOD("get_bake_mask"), &OccluderInstance3D::get_bake_mask);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_bit", "layer", "enabled"), &OccluderInstance3D::set_bake_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_bit", "layer"), &OccluderInstance3D::get_bake_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_occluder", "occluder"), &OccluderInstance3D::set_occluder);
+ ClassDB::bind_method(D_METHOD("get_occluder"), &OccluderInstance3D::get_occluder);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "Occluder3D"), "set_occluder", "get_occluder");
+ ADD_GROUP("Bake", "bake_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
+}
+
+OccluderInstance3D::OccluderInstance3D() {
+}
+
+OccluderInstance3D::~OccluderInstance3D() {
+}
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
new file mode 100644
index 0000000000..4bb468274d
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* occluder_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUDER_INSTANCE_3D_H
+#define OCCLUDER_INSTANCE_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+
+class Occluder3D : public Resource {
+ GDCLASS(Occluder3D, Resource);
+ RES_BASE_EXTENSION("occ");
+
+ mutable RID occluder;
+ mutable Ref<ArrayMesh> debug_mesh;
+ mutable Vector<Vector3> debug_lines;
+ AABB aabb;
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ void _update_changes();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_vertices(PackedVector3Array p_vertices);
+ PackedVector3Array get_vertices() const;
+
+ void set_indices(PackedInt32Array p_indices);
+ PackedInt32Array get_indices() const;
+
+ Vector<Vector3> get_debug_lines() const;
+ Ref<ArrayMesh> get_debug_mesh() const;
+ AABB get_aabb() const;
+
+ virtual RID get_rid() const override;
+ Occluder3D();
+ ~Occluder3D();
+};
+
+class OccluderInstance3D : public VisualInstance3D {
+ GDCLASS(OccluderInstance3D, Node3D);
+
+private:
+ Ref<Occluder3D> occluder;
+ uint32_t bake_mask = 0xFFFFFFFF;
+
+ void _occluder_changed();
+
+ bool _bake_material_check(Ref<Material> p_material);
+ void _bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices);
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum BakeError {
+ BAKE_ERROR_OK,
+ BAKE_ERROR_NO_SAVE_PATH,
+ BAKE_ERROR_NO_MESHES,
+ };
+
+ void set_occluder(const Ref<Occluder3D> &p_occluder);
+ Ref<Occluder3D> get_occluder() const;
+
+ virtual AABB get_aabb() const override;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
+ void set_bake_mask(uint32_t p_mask);
+ uint32_t get_bake_mask() const;
+
+ void set_bake_mask_bit(int p_layer, bool p_enable);
+ bool get_bake_mask_bit(int p_layer) const;
+ BakeError bake(Node *p_from_node, String p_occluder_path = "");
+
+ OccluderInstance3D();
+ ~OccluderInstance3D();
+};
+
+#endif
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 66f3e539a2..95638ce514 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -61,6 +61,7 @@ uint32_t RayCast3D::get_collision_mask() const {
}
void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -71,6 +72,7 @@ void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool RayCast3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 98ac6aa65e..dc4deb0570 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -85,11 +85,11 @@ void SoftBodyRenderingServerHandler::commit_changes() {
}
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
@@ -496,6 +496,7 @@ uint32_t SoftBody3D::get_collision_layer() const {
}
void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -506,10 +507,12 @@ void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool SoftBody3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t layer = get_collision_layer();
if (p_value) {
layer |= 1 << p_bit;
@@ -520,6 +523,7 @@ void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
}
bool SoftBody3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 394c67e873..d81b09b86c 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -338,6 +338,15 @@ GeometryInstance3D::GIMode GeometryInstance3D::get_gi_mode() const {
return gi_mode;
}
+void GeometryInstance3D::set_ignore_occlusion_culling(bool p_enabled) {
+ ignore_occlusion_culling = p_enabled;
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, ignore_occlusion_culling);
+}
+
+bool GeometryInstance3D::is_ignoring_occlusion_culling() {
+ return ignore_occlusion_culling;
+}
+
void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override);
@@ -345,21 +354,24 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance3D::set_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance3D::get_cast_shadows_setting);
+ ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
+ ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+
ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance3D::set_lod_max_hysteresis);
ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance3D::get_lod_max_hysteresis);
ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance3D::set_lod_max_distance);
ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance3D::get_lod_max_distance);
- ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
-
ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance3D::set_lod_min_hysteresis);
ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance3D::get_lod_min_hysteresis);
ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance3D::set_lod_min_distance);
ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance3D::get_lod_min_distance);
+ ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
+
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
@@ -369,8 +381,8 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode);
ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode);
- ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
- ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+ ClassDB::bind_method(D_METHOD("set_ignore_occlusion_culling", "ignore_culling"), &GeometryInstance3D::set_ignore_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_ignoring_occlusion_culling"), &GeometryInstance3D::is_ignoring_occlusion_culling);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
@@ -381,6 +393,7 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 7fed8095ef..68d29ef81e 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -120,6 +120,7 @@ private:
float extra_cull_margin = 0.0;
LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
GIMode gi_mode = GI_MODE_DISABLED;
+ bool ignore_occlusion_culling = false;
const StringName *_instance_uniform_get_remap(const StringName p_name) const;
@@ -167,6 +168,9 @@ public:
void set_custom_aabb(AABB aabb);
+ void set_ignore_occlusion_culling(bool p_enabled);
+ bool is_ignoring_occlusion_culling();
+
GeometryInstance3D();
};