summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/SCsub10
-rw-r--r--scene/3d/arvr_nodes.cpp2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp149
-rw-r--r--scene/3d/audio_stream_player_3d.h1
-rw-r--r--scene/3d/baked_lightmap.cpp20
-rw-r--r--scene/3d/baked_lightmap.h4
-rw-r--r--scene/3d/collision_object.cpp2
-rw-r--r--scene/3d/collision_shape.cpp2
-rw-r--r--scene/3d/cpu_particles.cpp27
-rw-r--r--scene/3d/cpu_particles.h4
-rw-r--r--scene/3d/gi_probe.cpp1
-rw-r--r--scene/3d/light.cpp24
-rw-r--r--scene/3d/light.h2
-rw-r--r--scene/3d/particles.cpp3
-rw-r--r--scene/3d/path.cpp2
-rw-r--r--scene/3d/physics_body.cpp2
-rw-r--r--scene/3d/remote_transform.cpp9
-rw-r--r--scene/3d/remote_transform.h2
-rw-r--r--scene/3d/soft_body.cpp3
-rw-r--r--scene/3d/sprite_3d.cpp22
-rw-r--r--scene/3d/vehicle_body.cpp68
-rw-r--r--scene/3d/vehicle_body.h11
-rw-r--r--scene/3d/visual_instance.cpp13
-rw-r--r--scene/3d/voxel_light_baker.cpp75
-rw-r--r--scene/3d/voxel_light_baker.h2
-rw-r--r--scene/3d/world_environment.cpp2
26 files changed, 342 insertions, 120 deletions
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index 200cf4316f..31a443bad1 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -3,10 +3,10 @@
Import('env')
if env['disable_3d']:
- env.scene_sources.append("3d/spatial.cpp")
- env.scene_sources.append("3d/skeleton.cpp")
- env.scene_sources.append("3d/particles.cpp")
- env.scene_sources.append("3d/visual_instance.cpp")
- env.scene_sources.append("3d/world_environment.cpp")
+ env.add_source_files(env.scene_sources, "spatial.cpp")
+ env.add_source_files(env.scene_sources, "skeleton.cpp")
+ env.add_source_files(env.scene_sources, "particles.cpp")
+ env.add_source_files(env.scene_sources, "visual_instance.cpp")
+ env.add_source_files(env.scene_sources, "world_environment.cpp")
else:
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index dfa8fce9be..263a2d8de6 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -61,7 +61,7 @@ String ARVRCamera::get_configuration_warning() const {
// must be child node of ARVROrigin!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin == NULL) {
- return TTR("ARVRCamera must have an ARVROrigin node as its parent");
+ return TTR("ARVRCamera must have an ARVROrigin node as its parent.");
};
return String();
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index ff28f60d4f..27f16f7601 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -35,6 +35,99 @@
#include "scene/3d/listener.h"
#include "scene/main/viewport.h"
+// Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004)
+// Speaker-Placement Correction Amplitude Panning (SPCAP)
+class Spcap {
+private:
+ struct Speaker {
+ Vector3 direction;
+ real_t effective_number_of_speakers; // precalculated
+ mutable real_t squared_gain; // temporary
+ };
+
+ PoolVector<Speaker> speakers;
+
+public:
+ Spcap(unsigned int speaker_count, const Vector3 *speaker_directions) {
+ this->speakers.resize(speaker_count);
+ PoolVector<Speaker>::Write w = this->speakers.write();
+ for (unsigned int speaker_num = 0; speaker_num < speaker_count; speaker_num++) {
+ w[speaker_num].direction = speaker_directions[speaker_num];
+ w[speaker_num].squared_gain = 0.0;
+ w[speaker_num].effective_number_of_speakers = 0.0;
+ for (unsigned int other_speaker_num = 0; other_speaker_num < speaker_count; other_speaker_num++) {
+ w[speaker_num].effective_number_of_speakers += 0.5 * (1.0 + w[speaker_num].direction.dot(w[other_speaker_num].direction));
+ }
+ }
+ }
+
+ unsigned int get_speaker_count() const {
+ return (unsigned int)this->speakers.size();
+ }
+
+ Vector3 get_speaker_direction(unsigned int index) const {
+ return this->speakers.read()[index].direction;
+ }
+
+ void calculate(const Vector3 &source_direction, real_t tightness, unsigned int volume_count, real_t *volumes) const {
+ PoolVector<Speaker>::Read r = this->speakers.read();
+ real_t sum_squared_gains = 0.0;
+ for (unsigned int speaker_num = 0; speaker_num < (unsigned int)this->speakers.size(); speaker_num++) {
+ real_t initial_gain = 0.5 * powf(1.0 + r[speaker_num].direction.dot(source_direction), tightness) / r[speaker_num].effective_number_of_speakers;
+ r[speaker_num].squared_gain = initial_gain * initial_gain;
+ sum_squared_gains += r[speaker_num].squared_gain;
+ }
+
+ for (unsigned int speaker_num = 0; speaker_num < MIN(volume_count, (unsigned int)this->speakers.size()); speaker_num++) {
+ volumes[speaker_num] = sqrtf(r[speaker_num].squared_gain / sum_squared_gains);
+ }
+ }
+};
+
+//TODO: hardcoded main speaker directions for 2, 3.1, 5.1 and 7.1 setups - these are simplified and could also be made configurable
+static const Vector3 speaker_directions[7] = {
+ Vector3(-1.0, 0.0, -1.0).normalized(), // front-left
+ Vector3(1.0, 0.0, -1.0).normalized(), // front-right
+ Vector3(0.0, 0.0, -1.0).normalized(), // center
+ Vector3(-1.0, 0.0, 1.0).normalized(), // rear-left
+ Vector3(1.0, 0.0, 1.0).normalized(), // rear-right
+ Vector3(-1.0, 0.0, 0.0).normalized(), // side-left
+ Vector3(1.0, 0.0, 0.0).normalized(), // side-right
+};
+
+void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, AudioStreamPlayer3D::Output &output) {
+ unsigned int speaker_count; // only main speakers (no LFE)
+ switch (AudioServer::get_singleton()->get_speaker_mode()) {
+ default: //fallthrough
+ case AudioServer::SPEAKER_MODE_STEREO: speaker_count = 2; break;
+ case AudioServer::SPEAKER_SURROUND_31: speaker_count = 3; break;
+ case AudioServer::SPEAKER_SURROUND_51: speaker_count = 5; break;
+ case AudioServer::SPEAKER_SURROUND_71: speaker_count = 7; break;
+ }
+
+ Spcap spcap(speaker_count, speaker_directions); //TODO: should only be created/recreated once the speaker mode / speaker positions changes
+ real_t volumes[7];
+ spcap.calculate(source_dir, tightness, speaker_count, volumes);
+
+ switch (AudioServer::get_singleton()->get_speaker_mode()) {
+ case AudioServer::SPEAKER_SURROUND_71:
+ output.vol[3].l = volumes[5]; // side-left
+ output.vol[3].r = volumes[6]; // side-right
+ //fallthrough
+ case AudioServer::SPEAKER_SURROUND_51:
+ output.vol[2].l = volumes[3]; // rear-left
+ output.vol[2].r = volumes[4]; // rear-right
+ //fallthrough
+ case AudioServer::SPEAKER_SURROUND_31:
+ output.vol[1].r = 1.0; // LFE - always full power
+ output.vol[1].l = volumes[2]; // center
+ //fallthrough
+ case AudioServer::SPEAKER_MODE_STEREO:
+ output.vol[0].r = volumes[1]; // front-right
+ output.vol[0].l = volumes[0]; // front-left
+ }
+}
+
void AudioStreamPlayer3D::_mix_audio() {
if (!stream_playback.is_valid() || !active ||
@@ -381,59 +474,11 @@ void AudioStreamPlayer3D::_notification(int p_what) {
output.filter_gain = Math::db2linear(db_att);
- Vector3 flat_pos = local_pos;
- flat_pos.y = 0;
- flat_pos.normalize();
+ //TODO: The lower the second parameter (tightness) the more the sound will "enclose" the listener (more undirected / playing from
+ // speakers not facing the source) - this could be made distance dependent.
+ _calc_output_vol(local_pos.normalized(), 4.0, output);
unsigned int cc = AudioServer::get_singleton()->get_channel_count();
- if (cc == 1) {
- // Stereo pair
- float c = flat_pos.x * 0.5 + 0.5;
-
- output.vol[0].l = 1.0 - c;
- output.vol[0].r = c;
- } else {
- Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
- float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
- float angle = Math::rad2deg(Math::acos(c));
- float av = angle * (flat_pos.x < 0 ? -1 : 1) / 180.0;
-
- if (cc >= 1) {
- // Stereo pair
- float fl = Math::abs(1.0 - Math::abs(-0.8 - av));
- float fr = Math::abs(1.0 - Math::abs(0.8 - av));
-
- output.vol[0].l = fl;
- output.vol[0].r = fr;
- }
-
- if (cc >= 2) {
- // Center pair
- float center = 1.0 - Math::sin(Math::acos(c));
-
- output.vol[1].l = center;
- output.vol[1].r = center;
- }
-
- if (cc >= 3) {
- // Side pair
- float sleft = Math::abs(1.0 - Math::abs(-0.4 - av));
- float sright = Math::abs(1.0 - Math::abs(0.4 - av));
-
- output.vol[2].l = sleft;
- output.vol[2].r = sright;
- }
-
- if (cc >= 4) {
- // Rear pair
- float rleft = Math::abs(1.0 - Math::abs(-0.2 - av));
- float rright = Math::abs(1.0 - Math::abs(0.2 - av));
-
- output.vol[3].l = rleft;
- output.vol[3].r = rright;
- }
- }
-
for (unsigned int k = 0; k < cc; k++) {
output.vol[k] *= multiplier;
}
@@ -974,7 +1019,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1"), "set_emission_angle", "get_emission_angle");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_angle_filter_attenuation_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_emission_angle_filter_attenuation_db", "get_emission_angle_filter_attenuation_db");
ADD_GROUP("Attenuation Filter", "attenuation_filter_");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "50,50000,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_attenuation_filter_db", "get_attenuation_filter_db");
ADD_GROUP("Doppler", "doppler_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 93954e758a..494aa70097 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -115,6 +115,7 @@ private:
bool stream_paused_fade_out;
StringName bus;
+ static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Output &output);
void _mix_audio();
static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_mix_audio(); }
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 2b12e78158..c5ff4dadbc 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -221,6 +221,15 @@ Vector3 BakedLightmap::get_extents() const {
return extents;
}
+void BakedLightmap::set_bake_default_texels_per_unit(const float &p_bake_texels_per_unit) {
+ bake_default_texels_per_unit = p_bake_texels_per_unit;
+ update_gizmo();
+}
+
+float BakedLightmap::get_bake_default_texels_per_unit() const {
+ return bake_default_texels_per_unit;
+}
+
void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plot_meshes, List<PlotLight> &plot_lights) {
MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node);
@@ -236,7 +245,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo
}
}
- if (all_have_uv2 && mesh->get_lightmap_size_hint() != Size2()) {
+ if (all_have_uv2) {
//READY TO BAKE! size hint could be computed if not found, actually..
AABB aabb = mesh->get_aabb();
@@ -463,7 +472,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
btd.text = RTR("Lighting Meshes: ") + mesh_name + " (" + itos(pmc) + "/" + itos(mesh_list.size()) + ")";
btd.pass = step;
btd.last_step = 0;
- err = baker.make_lightmap(E->get().local_xform, E->get().mesh, lm, _bake_time, &btd);
+ err = baker.make_lightmap(E->get().local_xform, E->get().mesh, bake_default_texels_per_unit, lm, _bake_time, &btd);
if (err != OK) {
bake_end_function();
if (err == ERR_SKIP)
@@ -473,7 +482,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
step += 100;
} else {
- err = baker.make_lightmap(E->get().local_xform, E->get().mesh, lm);
+ err = baker.make_lightmap(E->get().local_xform, E->get().mesh, bake_default_texels_per_unit, lm);
}
if (err == OK) {
@@ -790,6 +799,9 @@ void BakedLightmap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BakedLightmap::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &BakedLightmap::get_extents);
+ ClassDB::bind_method(D_METHOD("set_bake_default_texels_per_unit", "texels"), &BakedLightmap::set_bake_default_texels_per_unit);
+ ClassDB::bind_method(D_METHOD("get_bake_default_texels_per_unit"), &BakedLightmap::get_bake_default_texels_per_unit);
+
ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &BakedLightmap::set_propagation);
ClassDB::bind_method(D_METHOD("get_propagation"), &BakedLightmap::get_propagation);
@@ -814,6 +826,7 @@ void BakedLightmap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_hdr"), "set_hdr", "is_hdr");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "bake_extents"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_default_texels_per_unit"), "set_bake_default_texels_per_unit", "get_bake_default_texels_per_unit");
ADD_GROUP("Capture", "capture_");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size");
ADD_GROUP("Data", "");
@@ -836,6 +849,7 @@ void BakedLightmap::_bind_methods() {
BakedLightmap::BakedLightmap() {
extents = Vector3(10, 10, 10);
+ bake_default_texels_per_unit = 20;
bake_cell_size = 0.25;
capture_cell_size = 0.5;
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h
index bb3f84719a..3a9f4cf01d 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/baked_lightmap.h
@@ -119,6 +119,7 @@ private:
float bake_cell_size;
float capture_cell_size;
Vector3 extents;
+ float bake_default_texels_per_unit;
float propagation;
float energy;
BakeQuality bake_quality;
@@ -178,6 +179,9 @@ public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
+ void set_bake_default_texels_per_unit(const float &p_bake_texels_per_unit);
+ float get_bake_default_texels_per_unit() const;
+
void set_propagation(float p_propagation);
float get_propagation() const;
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index fc46cf5bdb..9d3e2983c4 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -371,7 +371,7 @@ String CollisionObject::get_configuration_warning() const {
if (shapes.empty()) {
if (warning == String()) {
- warning += "\n";
+ warning += "\n\n";
}
warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape or CollisionPolygon as a child to define its shape.");
}
diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp
index 219ea56681..2b030641eb 100644
--- a/scene/3d/collision_shape.cpp
+++ b/scene/3d/collision_shape.cpp
@@ -120,7 +120,7 @@ String CollisionShape::get_configuration_warning() const {
}
if (!shape.is_valid()) {
- return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it!");
+ return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it.");
}
if (shape->is_class("PlaneShape")) {
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 358c4bdb44..fc16bc36cb 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -92,6 +92,10 @@ void CPUParticles::set_randomness_ratio(float p_ratio) {
randomness_ratio = p_ratio;
}
+void CPUParticles::set_lifetime_randomness(float p_random) {
+
+ lifetime_randomness = p_random;
+}
void CPUParticles::set_use_local_coordinates(bool p_enable) {
local_coords = p_enable;
@@ -130,6 +134,10 @@ float CPUParticles::get_randomness_ratio() const {
return randomness_ratio;
}
+float CPUParticles::get_lifetime_randomness() const {
+
+ return lifetime_randomness;
+}
bool CPUParticles::get_use_local_coordinates() const {
@@ -583,6 +591,10 @@ void CPUParticles::_particles_process(float p_delta) {
}
}
+ if (p.time * (1.0 - explosiveness_ratio) > p.lifetime) {
+ restart = true;
+ }
+
if (restart) {
if (!emitting) {
@@ -636,6 +648,7 @@ void CPUParticles::_particles_process(float p_delta) {
p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
p.transform = Transform();
p.time = 0;
+ p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
p.base_color = Color(1, 1, 1, 1);
switch (emission_shape) {
@@ -643,7 +656,9 @@ void CPUParticles::_particles_process(float p_delta) {
//do none
} break;
case EMISSION_SHAPE_SPHERE: {
- p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius;
+ float s = 2.0 * Math::randf() - 1.0, t = 2.0 * Math_PI * Math::randf();
+ float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
+ p.transform.origin = Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s);
} break;
case EMISSION_SHAPE_BOX: {
p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_box_extents;
@@ -699,6 +714,8 @@ void CPUParticles::_particles_process(float p_delta) {
} else if (!p.active) {
continue;
+ } else if (p.time > p.lifetime) {
+ p.active = false;
} else {
uint32_t alt_seed = p.seed;
@@ -1057,9 +1074,6 @@ void CPUParticles::_notification(int p_what) {
_set_redraw(false);
}
- if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
- }
-
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
if (particles.size() == 0 || !is_visible_in_tree()) {
@@ -1219,6 +1233,7 @@ void CPUParticles::convert_from_particles(Node *p_particles) {
set_emission_box_extents(material->get_emission_box_extents());
set_gravity(material->get_gravity());
+ set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
@@ -1253,6 +1268,7 @@ void CPUParticles::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles::set_pre_process_time);
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles::set_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "random"), &CPUParticles::set_lifetime_randomness);
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles::set_fractional_delta);
@@ -1265,6 +1281,7 @@ void CPUParticles::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles::get_pre_process_time);
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles::get_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &CPUParticles::get_lifetime_randomness);
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles::get_fixed_fps);
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles::get_fractional_delta);
@@ -1288,6 +1305,7 @@ void CPUParticles::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Drawing", "");
@@ -1470,6 +1488,7 @@ CPUParticles::CPUParticles() {
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
+ set_lifetime_randomness(0);
set_use_local_coordinates(true);
set_draw_order(DRAW_ORDER_INDEX);
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index 517df8490d..71de56f59e 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -95,6 +95,7 @@ private:
float hue_rot_rand;
float anim_offset_rand;
float time;
+ float lifetime;
Color base_color;
uint32_t seed;
@@ -137,6 +138,7 @@ private:
float pre_process_time;
float explosiveness_ratio;
float randomness_ratio;
+ float lifetime_randomness;
float speed_scale;
bool local_coords;
int fixed_fps;
@@ -200,6 +202,7 @@ public:
void set_pre_process_time(float p_time);
void set_explosiveness_ratio(float p_ratio);
void set_randomness_ratio(float p_ratio);
+ void set_lifetime_randomness(float p_random);
void set_visibility_aabb(const AABB &p_aabb);
void set_use_local_coordinates(bool p_enable);
void set_speed_scale(float p_scale);
@@ -211,6 +214,7 @@ public:
float get_pre_process_time() const;
float get_explosiveness_ratio() const;
float get_randomness_ratio() const;
+ float get_lifetime_randomness() const;
AABB get_visibility_aabb() const;
bool get_use_local_coordinates() const;
float get_speed_scale() const;
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 414e932f61..a04f156d80 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -571,4 +571,5 @@ GIProbe::GIProbe() {
}
GIProbe::~GIProbe() {
+ VS::get_singleton()->free(gi_probe);
}
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 2e64872616..85ee925248 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -51,6 +51,7 @@ void Light::set_param(Param p_param, float p_value) {
if (p_param == PARAM_SPOT_ANGLE) {
_change_notify("spot_angle");
+ update_configuration_warning();
} else if (p_param == PARAM_RANGE) {
_change_notify("omni_range");
_change_notify("spot_range");
@@ -68,6 +69,10 @@ void Light::set_shadow(bool p_enable) {
shadow = p_enable;
VS::get_singleton()->light_set_shadow(light, p_enable);
+
+ if (type == VisualServer::LIGHT_SPOT) {
+ update_configuration_warning();
+ }
}
bool Light::has_shadow() const {
@@ -195,9 +200,6 @@ void Light::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
_update_visibility();
}
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- }
}
void Light::set_editor_only(bool p_editor_only) {
@@ -408,7 +410,7 @@ DirectionalLight::DirectionalLight() :
set_param(PARAM_SHADOW_NORMAL_BIAS, 0.8);
set_param(PARAM_SHADOW_BIAS, 0.1);
- set_param(PARAM_SHADOW_MAX_DISTANCE, 200);
+ set_param(PARAM_SHADOW_MAX_DISTANCE, 100);
set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25);
set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);
@@ -465,6 +467,20 @@ OmniLight::OmniLight() :
set_shadow_detail(SHADOW_DETAIL_HORIZONTAL);
}
+String SpotLight::get_configuration_warning() const {
+ String warning = Light::get_configuration_warning();
+
+ if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
+ if (warning != String()) {
+ warning += "\n\n";
+ }
+
+ warning += TTR("A SpotLight with an angle wider than 90 degrees cannot cast shadows.");
+ }
+
+ return warning;
+}
+
void SpotLight::_bind_methods() {
ADD_GROUP("Spot", "spot_");
diff --git a/scene/3d/light.h b/scene/3d/light.h
index ddd5bc6b3a..5d365758b5 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -221,6 +221,8 @@ protected:
static void _bind_methods();
public:
+ virtual String get_configuration_warning() const;
+
SpotLight() :
Light(VisualServer::LIGHT_SPOT) {}
};
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 2bcd0eaa46..a6ccdb5791 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -257,7 +257,7 @@ String Particles::get_configuration_warning() const {
SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(draw_passes[i]->surface_get_material(j).ptr());
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES);
}
- if (meshes_found && anim_material_found) break;
+ if (anim_material_found) break;
}
}
@@ -411,6 +411,7 @@ Particles::Particles() {
particles = VS::get_singleton()->particles_create();
set_base(particles);
+ one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
set_emitting(true);
set_one_shot(false);
set_amount(8);
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 84078911cb..d55c795d38 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -270,7 +270,7 @@ String PathFollow::get_configuration_warning() const {
} else {
Path *path = Object::cast_to<Path>(get_parent());
if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
- return TTR("PathFollow ROTATION_ORIENTED requires \"Up Vector\" enabled in its parent Path's Curve resource.");
+ return TTR("PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path's Curve resource.");
}
}
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index d3aad7000d..2f8b2ecc5c 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -934,7 +934,7 @@ String RigidBody::get_configuration_warning() const {
if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (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(2).length() - 1.0) > 0.05)) {
if (warning != String()) {
- warning += "\n";
+ warning += "\n\n";
}
warning += TTR("Size changes to RigidBody (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
}
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
index add77e0272..76b0b0c92f 100644
--- a/scene/3d/remote_transform.cpp
+++ b/scene/3d/remote_transform.cpp
@@ -105,7 +105,7 @@ void RemoteTransform::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
+ case NOTIFICATION_ENTER_TREE: {
_update_cache();
@@ -174,10 +174,14 @@ bool RemoteTransform::get_update_scale() const {
return update_remote_scale;
}
+void RemoteTransform::force_update_cache() {
+ _update_cache();
+}
+
String RemoteTransform::get_configuration_warning() const {
if (!has_node(remote_node) || !Object::cast_to<Spatial>(get_node(remote_node))) {
- return TTR("Path property must point to a valid Spatial node to work.");
+ return TTR("The \"Remote Path\" property must point to a valid Spatial or Spatial-derived node to work.");
}
return String();
@@ -187,6 +191,7 @@ void RemoteTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_remote_node", "path"), &RemoteTransform::set_remote_node);
ClassDB::bind_method(D_METHOD("get_remote_node"), &RemoteTransform::get_remote_node);
+ ClassDB::bind_method(D_METHOD("force_update_cache"), &RemoteTransform::force_update_cache);
ClassDB::bind_method(D_METHOD("set_use_global_coordinates", "use_global_coordinates"), &RemoteTransform::set_use_global_coordinates);
ClassDB::bind_method(D_METHOD("get_use_global_coordinates"), &RemoteTransform::get_use_global_coordinates);
diff --git a/scene/3d/remote_transform.h b/scene/3d/remote_transform.h
index b737a4f858..07e01284e5 100644
--- a/scene/3d/remote_transform.h
+++ b/scene/3d/remote_transform.h
@@ -68,6 +68,8 @@ public:
void set_update_scale(const bool p_update);
bool get_update_scale() const;
+ void force_update_cache();
+
virtual String get_configuration_warning() const;
RemoteTransform();
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index a9d96292a1..386e127f8b 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -73,7 +73,7 @@ void SoftBodyVisualServerHandler::open() {
}
void SoftBodyVisualServerHandler::close() {
- write_buffer = PoolVector<uint8_t>::Write();
+ write_buffer.release();
}
void SoftBodyVisualServerHandler::commit_changes() {
@@ -712,6 +712,7 @@ SoftBody::SoftBody() :
}
SoftBody::~SoftBody() {
+ PhysicsServer::get_singleton()->free(physics_rid);
}
void SoftBody::reset_softbody_pin() {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 9f73484b6a..b39762fde8 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -254,7 +254,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
facesw[j] = vtx;
}
- facesw = PoolVector<Vector3>::Write();
+ facesw.release();
triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
triangle_mesh->create(faces);
@@ -558,7 +558,7 @@ Rect2 Sprite3D::get_region_rect() const {
void Sprite3D::set_frame(int p_frame) {
- ERR_FAIL_INDEX(p_frame, vframes * hframes);
+ ERR_FAIL_INDEX(p_frame, int64_t(vframes) * hframes);
if (frame != p_frame)
@@ -628,10 +628,9 @@ Rect2 Sprite3D::get_item_rect() const {
void Sprite3D::_validate_property(PropertyInfo &property) const {
if (property.name == "frame") {
-
- property.hint = PROPERTY_HINT_SPRITE_FRAME;
-
+ property.hint = PROPERTY_HINT_RANGE;
property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
}
@@ -659,7 +658,7 @@ void Sprite3D::_bind_methods() {
ADD_GROUP("Animation", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
@@ -851,14 +850,11 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
}
if (property.name == "frame") {
-
property.hint = PROPERTY_HINT_RANGE;
-
- if (frames->has_animation(animation)) {
+ if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) {
property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
- } else {
- property.hint_string = "0,0,0";
}
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
}
@@ -1061,7 +1057,7 @@ StringName AnimatedSprite3D::get_animation() const {
String AnimatedSprite3D::get_configuration_warning() const {
if (frames.is_null()) {
- return TTR("A SpriteFrames resource must be created or set in the 'Frames' property in order for AnimatedSprite3D to display frames.");
+ return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
}
return String();
@@ -1091,7 +1087,7 @@ void AnimatedSprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
}
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index 89e96e0227..98e68cfbda 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -272,6 +272,20 @@ void VehicleWheel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm);
+ ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleWheel::set_engine_force);
+ ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleWheel::get_engine_force);
+
+ ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleWheel::set_brake);
+ ClassDB::bind_method(D_METHOD("get_brake"), &VehicleWheel::get_brake);
+
+ ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleWheel::set_steering);
+ ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel::get_steering);
+
+ ADD_GROUP("Per-Wheel Motion", "");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
+ ADD_GROUP("VehicleBody Motion", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering");
ADD_GROUP("Wheel", "wheel_");
@@ -288,6 +302,34 @@ void VehicleWheel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation");
}
+void VehicleWheel::set_engine_force(float p_engine_force) {
+
+ m_engineForce = p_engine_force;
+}
+
+float VehicleWheel::get_engine_force() const {
+
+ return m_engineForce;
+}
+
+void VehicleWheel::set_brake(float p_brake) {
+
+ m_brake = p_brake;
+}
+float VehicleWheel::get_brake() const {
+
+ return m_brake;
+}
+
+void VehicleWheel::set_steering(float p_steering) {
+
+ m_steering = p_steering;
+}
+float VehicleWheel::get_steering() const {
+
+ return m_steering;
+}
+
void VehicleWheel::set_use_as_traction(bool p_enable) {
engine_traction = p_enable;
@@ -374,10 +416,7 @@ void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) {
Vector3 fwd = up.cross(right);
fwd = fwd.normalized();
- //rotate around steering over de wheelAxleWS
- real_t steering = wheel.steers ? m_steeringValue : 0.0;
-
- Basis steeringMat(up, steering);
+ Basis steeringMat(up, wheel.m_steering);
Basis rotatingMat(right, wheel.m_rotation);
@@ -723,12 +762,11 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
real_t rollingFriction = 0.f;
if (wheelInfo.m_raycastInfo.m_isInContact) {
- if (engine_force != 0.f && wheelInfo.engine_traction) {
- rollingFriction = -engine_force * s->get_step();
+ if (wheelInfo.m_engineForce != 0.f) {
+ rollingFriction = -wheelInfo.m_engineForce * s->get_step();
} else {
real_t defaultRollingFrictionImpulse = 0.f;
- float cbrake = MAX(wheelInfo.m_brake, brake);
- real_t maxImpulse = cbrake ? cbrake : defaultRollingFrictionImpulse;
+ real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
btVehicleWheelContactPoint contactPt(s, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel], maxImpulse);
rollingFriction = _calc_rolling_friction(contactPt);
}
@@ -886,6 +924,11 @@ void VehicleBody::_direct_state_changed(Object *p_state) {
void VehicleBody::set_engine_force(float p_engine_force) {
engine_force = p_engine_force;
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel &wheelInfo = *wheels[i];
+ if (wheelInfo.engine_traction)
+ wheelInfo.m_engineForce = p_engine_force;
+ }
}
float VehicleBody::get_engine_force() const {
@@ -896,6 +939,10 @@ float VehicleBody::get_engine_force() const {
void VehicleBody::set_brake(float p_brake) {
brake = p_brake;
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel &wheelInfo = *wheels[i];
+ wheelInfo.m_brake = p_brake;
+ }
}
float VehicleBody::get_brake() const {
@@ -905,6 +952,11 @@ float VehicleBody::get_brake() const {
void VehicleBody::set_steering(float p_steering) {
m_steeringValue = p_steering;
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel &wheelInfo = *wheels[i];
+ if (wheelInfo.steers)
+ wheelInfo.m_steering = p_steering;
+ }
}
float VehicleBody::get_steering() const {
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
index 9e3fe72282..914bfd54bd 100644
--- a/scene/3d/vehicle_body.h
+++ b/scene/3d/vehicle_body.h
@@ -70,7 +70,7 @@ class VehicleWheel : public Spatial {
real_t m_deltaRotation;
real_t m_rpm;
real_t m_rollInfluence;
- //real_t m_engineForce;
+ real_t m_engineForce;
real_t m_brake;
real_t m_clippedInvContactDotSuspension;
@@ -137,6 +137,15 @@ public:
float get_rpm() const;
+ void set_engine_force(float p_engine_force);
+ float get_engine_force() const;
+
+ void set_brake(float p_brake);
+ float get_brake() const;
+
+ void set_steering(float p_steering);
+ float get_steering() const;
+
String get_configuration_warning() const;
VehicleWheel();
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 5141c84803..d1de0c56a7 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -215,17 +215,6 @@ float GeometryInstance::get_lod_max_hysteresis() const {
}
void GeometryInstance::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_WORLD) {
-
- if (flags[FLAG_USE_BAKED_LIGHT]) {
- }
-
- } else if (p_what == NOTIFICATION_EXIT_WORLD) {
-
- if (flags[FLAG_USE_BAKED_LIGHT]) {
- }
- }
}
void GeometryInstance::set_flag(Flags p_flag, bool p_value) {
@@ -236,8 +225,6 @@ void GeometryInstance::set_flag(Flags p_flag, bool p_value) {
flags[p_flag] = p_value;
VS::get_singleton()->instance_geometry_set_flag(get_instance(), (VS::InstanceFlags)p_flag, p_value);
- if (p_flag == FLAG_USE_BAKED_LIGHT) {
- }
}
bool GeometryInstance::get_flag(Flags p_flag) const {
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 5fa8c43f9f..8e09930aed 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -1792,19 +1792,82 @@ void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
}
}
-Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) {
+Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, float default_texels_per_unit, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) {
//transfer light information to a lightmap
Ref<Mesh> mesh = p_mesh;
- int width = mesh->get_lightmap_size_hint().x;
- int height = mesh->get_lightmap_size_hint().y;
-
//step 1 - create lightmap
+ int width;
+ int height;
Vector<LightMap> lightmap;
- lightmap.resize(width * height);
-
Transform xform = to_cell_space * p_xform;
+ if (mesh->get_lightmap_size_hint() == Size2()) {
+ double area = 0;
+ double uv_area = 0;
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ Array arrays = mesh->surface_get_arrays(i);
+ PoolVector<Vector3> vertices = arrays[Mesh::ARRAY_VERTEX];
+ PoolVector<Vector2> uv2 = arrays[Mesh::ARRAY_TEX_UV2];
+ PoolVector<int> indices = arrays[Mesh::ARRAY_INDEX];
+
+ ERR_FAIL_COND_V(vertices.size() == 0, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(uv2.size() == 0, ERR_INVALID_PARAMETER);
+
+ int vc = vertices.size();
+ PoolVector<Vector3>::Read vr = vertices.read();
+ PoolVector<Vector2>::Read u2r = uv2.read();
+ PoolVector<int>::Read ir;
+ int ic = 0;
+
+ if (indices.size()) {
+ ic = indices.size();
+ ir = indices.read();
+ }
+
+ int faces = ic ? ic / 3 : vc / 3;
+ for (int j = 0; j < faces; j++) {
+ Vector3 vertex[3];
+ Vector2 uv[3];
+
+ for (int k = 0; k < 3; k++) {
+ int idx = ic ? ir[j * 3 + k] : j * 3 + k;
+ vertex[k] = xform.xform(vr[idx]);
+ uv[k] = u2r[idx];
+ }
+
+ Vector3 p1 = vertex[0];
+ Vector3 p2 = vertex[1];
+ Vector3 p3 = vertex[2];
+ double a = p1.distance_to(p2);
+ double b = p2.distance_to(p3);
+ double c = p3.distance_to(p1);
+ double halfPerimeter = (a + b + c) / 2.0;
+ area += sqrt(halfPerimeter * (halfPerimeter - a) * (halfPerimeter - b) * (halfPerimeter - c));
+
+ Vector2 uv_p1 = uv[0];
+ Vector2 uv_p2 = uv[1];
+ Vector2 uv_p3 = uv[2];
+ double uv_a = uv_p1.distance_to(uv_p2);
+ double uv_b = uv_p2.distance_to(uv_p3);
+ double uv_c = uv_p3.distance_to(uv_p1);
+ double uv_halfPerimeter = (uv_a + uv_b + uv_c) / 2.0;
+ uv_area += sqrt(uv_halfPerimeter * (uv_halfPerimeter - uv_a) * (uv_halfPerimeter - uv_b) * (uv_halfPerimeter - uv_c));
+ }
+ }
+
+ if (uv_area < 0.0001f) {
+ uv_area = 1.0;
+ }
+
+ int pixels = (ceil((1.0 / sqrt(uv_area)) * sqrt(area * default_texels_per_unit)));
+ width = height = CLAMP(pixels, 2, 4096);
+ } else {
+ width = mesh->get_lightmap_size_hint().x;
+ height = mesh->get_lightmap_size_hint().y;
+ }
+
+ lightmap.resize(width * height);
//step 2 plot faces to lightmap
for (int i = 0; i < mesh->get_surface_count(); i++) {
diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h
index 295e099d47..2e2efc62ff 100644
--- a/scene/3d/voxel_light_baker.h
+++ b/scene/3d/voxel_light_baker.h
@@ -177,7 +177,7 @@ public:
PoolVector<float> light;
};
- Error make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float) = NULL, void *p_bake_time_ud = NULL);
+ Error make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, float default_texels_per_unit, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float) = NULL, void *p_bake_time_ud = NULL);
PoolVector<int> create_gi_probe_data();
Ref<MultiMesh> create_debug_multimesh(DebugMode p_mode = DEBUG_ALBEDO);
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index 3cd43cbf5b..8d46b4161d 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -80,7 +80,7 @@ Ref<Environment> WorldEnvironment::get_environment() const {
String WorldEnvironment::get_configuration_warning() const {
if (!environment.is_valid()) {
- return TTR("WorldEnvironment needs an Environment resource.");
+ return TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
}
if (/*!is_visible_in_tree() ||*/ !is_inside_tree())