summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/classes/ParticleProcessMaterial.xml11
-rw-r--r--editor/plugins/material_editor_plugin.cpp12
-rw-r--r--editor/plugins/material_editor_plugin.h2
-rw-r--r--editor/scene_tree_dock.cpp2
-rw-r--r--modules/noise/doc_classes/Noise.xml41
-rw-r--r--modules/noise/doc_classes/NoiseTexture3D.xml3
-rw-r--r--modules/noise/fastnoise_lite.cpp2
-rw-r--r--modules/noise/noise.cpp152
-rw-r--r--modules/noise/noise.h200
-rw-r--r--modules/noise/noise_texture_2d.cpp4
-rw-r--r--modules/noise/noise_texture_3d.cpp127
-rw-r--r--modules/noise/noise_texture_3d.h2
-rw-r--r--modules/noise/tests/test_fastnoise_lite.h6
-rw-r--r--platform/android/java_godot_lib_jni.cpp33
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp3
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/3d/collision_object_3d.cpp6
-rw-r--r--scene/3d/collision_polygon_3d.cpp6
-rw-r--r--scene/3d/collision_shape_3d.cpp6
-rw-r--r--scene/3d/light_3d.cpp3
-rw-r--r--scene/3d/physics_body_3d.cpp4
-rw-r--r--scene/gui/tab_container.cpp8
-rw-r--r--scene/resources/surface_tool.cpp18
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp50
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h13
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp14
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl204
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h10
28 files changed, 484 insertions, 462 deletions
diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index 6d549e1b67..5497effc75 100644
--- a/doc/classes/ParticleProcessMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -282,7 +282,8 @@
Minimum equivalent of [member tangential_accel_max].
</member>
<member name="turbulence_enabled" type="bool" setter="set_turbulence_enabled" getter="get_turbulence_enabled" default="false">
- Enables and disables Turbulence for the particle system.
+ If [code]true[/code], enables turbulence for the particle system. Turbulence can be used to vary particle movement according to its position (based on a 3D noise pattern). In 3D, [GPUParticlesAttractorVectorField3D] with [NoiseTexture3D] can be used as an alternative to turbulence that works in world space and with multiple particle systems reacting in the same way.
+ [b]Note:[/b] Enabling turbulence has a high performance cost on the GPU. Only enable turbulence on a few particle systems at once at most, and consider disabling it when targeting mobile/web platforms.
</member>
<member name="turbulence_influence_max" type="float" setter="set_param_max" getter="get_param_max" default="0.1">
Maximum turbulence influence on each particle.
@@ -296,11 +297,11 @@
Each particle's amount of turbulence will be influenced along this [CurveTexture] over its life time.
</member>
<member name="turbulence_initial_displacement_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
- Maximum displacement of each particles spawn position by the turbulence.
+ Maximum displacement of each particle's spawn position by the turbulence.
The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max].
</member>
<member name="turbulence_initial_displacement_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
- Minimum displacement of each particles spawn position by the turbulence.
+ Minimum displacement of each particle's spawn position by the turbulence.
The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max].
</member>
<member name="turbulence_noise_scale" type="float" setter="set_turbulence_noise_scale" getter="get_turbulence_noise_scale" default="9.0">
@@ -312,10 +313,10 @@
A value of [code]Vector3(0.0, 0.0, 0.0)[/code] will freeze the turbulence pattern in place.
</member>
<member name="turbulence_noise_speed_random" type="float" setter="set_turbulence_noise_speed_random" getter="get_turbulence_noise_speed_random" default="0.0">
- Use to influence the noise speed in a random pattern. This helps to break up visible movement patterns.
+ Use to influence the noise speed in a random pattern. This helps break up visible movement patterns.
</member>
<member name="turbulence_noise_strength" type="float" setter="set_turbulence_noise_strength" getter="get_turbulence_noise_strength" default="1.0">
- The turbulence noise strength. Increasing this will result in a stronger, more contrasting, noise pattern.
+ The turbulence noise strength. Increasing this will result in a stronger, more contrasting noise pattern.
</member>
</members>
<constants>
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 2fdebc7c7f..404711e074 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -164,9 +164,19 @@ void MaterialEditor::_button_pressed(Node *p_button) {
MaterialEditor::MaterialEditor() {
// canvas item
+ vc_2d = memnew(SubViewportContainer);
+ vc_2d->set_stretch(true);
+ add_child(vc_2d);
+ vc_2d->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
+
+ viewport_2d = memnew(SubViewport);
+ vc_2d->add_child(viewport_2d);
+ viewport_2d->set_disable_input(true);
+ viewport_2d->set_transparent_background(true);
+
layout_2d = memnew(HBoxContainer);
layout_2d->set_alignment(BoxContainer::ALIGNMENT_CENTER);
- add_child(layout_2d);
+ viewport_2d->add_child(layout_2d);
layout_2d->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
rect_instance = memnew(ColorRect);
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index deb1211c54..ac81bdc7c7 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -51,6 +51,8 @@ class MaterialEditor : public Control {
Vector2 rot;
+ SubViewportContainer *vc_2d = nullptr;
+ SubViewport *viewport_2d = nullptr;
HBoxContainer *layout_2d = nullptr;
ColorRect *rect_instance = nullptr;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 96166dab3f..9e231a41c3 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -276,6 +276,8 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
return;
}
+ instantiated_scene->set_unique_name_in_owner(base->is_unique_name_in_owner());
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Replace with Branch Scene"));
diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml
index a5cdb5bcbc..c075b5b629 100644
--- a/modules/noise/doc_classes/Noise.xml
+++ b/modules/noise/doc_classes/Noise.xml
@@ -15,13 +15,24 @@
<return type="Image" />
<param index="0" name="width" type="int" />
<param index="1" name="height" type="int" />
+ <param index="2" name="invert" type="bool" default="false" />
+ <param index="3" name="in_3d_space" type="bool" default="false" />
+ <param index="4" name="normalize" type="bool" default="true" />
+ <description>
+ Returns an [Image] containing 2D noise values.
+ [b]Note:[/b] With [param normalize] set to [code]false[/code], the default implementation expects the noise generator to return values in the range [code]-1.0[/code] to [code]1.0[/code].
+ </description>
+ </method>
+ <method name="get_image_3d" qualifiers="const">
+ <return type="Image[]" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
<param index="2" name="depth" type="int" />
<param index="3" name="invert" type="bool" default="false" />
- <param index="4" name="in_3d_space" type="bool" default="false" />
- <param index="5" name="normalize" type="bool" default="true" />
+ <param index="4" name="normalize" type="bool" default="true" />
<description>
- Returns a 2D [Image] noise image.
- Note: With [param normalize] set to [code]false[/code] the default implementation expects the noise generator to return values in the range [code]-1.0[/code] to [code]1.0[/code].
+ Returns an [Array] of [Image]s containing 3D noise values for use with [method ImageTexture3D.create].
+ [b]Note:[/b] With [param normalize] set to [code]false[/code], the default implementation expects the noise generator to return values in the range [code]-1.0[/code] to [code]1.0[/code].
</description>
</method>
<method name="get_noise_1d" qualifiers="const">
@@ -66,14 +77,26 @@
<return type="Image" />
<param index="0" name="width" type="int" />
<param index="1" name="height" type="int" />
+ <param index="2" name="invert" type="bool" default="false" />
+ <param index="3" name="in_3d_space" type="bool" default="false" />
+ <param index="4" name="skirt" type="float" default="0.1" />
+ <param index="5" name="normalize" type="bool" default="true" />
+ <description>
+ Returns an [Image] containing seamless 2D noise values.
+ [b]Note:[/b] With [param normalize] set to [code]false[/code], the default implementation expects the noise generator to return values in the range [code]-1.0[/code] to [code]1.0[/code].
+ </description>
+ </method>
+ <method name="get_seamless_image_3d" qualifiers="const">
+ <return type="Image[]" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
<param index="2" name="depth" type="int" />
<param index="3" name="invert" type="bool" default="false" />
- <param index="4" name="in_3d_space" type="bool" default="false" />
- <param index="5" name="skirt" type="float" default="0.1" />
- <param index="6" name="normalize" type="bool" default="true" />
+ <param index="4" name="skirt" type="float" default="0.1" />
+ <param index="5" name="normalize" type="bool" default="true" />
<description>
- Returns a seamless 2D [Image] noise image.
- Note: With [param normalize] set to [code]false[/code] the default implementation expects the noise generator to return values in the range [code]-1.0[/code] to [code]1.0[/code].
+ Returns an [Array] of [Image]s containing seamless 3D noise values for use with [method ImageTexture3D.create].
+ [b]Note:[/b] With [param normalize] set to [code]false[/code], the default implementation expects the noise generator to return values in the range [code]-1.0[/code] to [code]1.0[/code].
</description>
</method>
</methods>
diff --git a/modules/noise/doc_classes/NoiseTexture3D.xml b/modules/noise/doc_classes/NoiseTexture3D.xml
index 0b385d9b9c..7394e7ff08 100644
--- a/modules/noise/doc_classes/NoiseTexture3D.xml
+++ b/modules/noise/doc_classes/NoiseTexture3D.xml
@@ -5,13 +5,12 @@
</brief_description>
<description>
Uses [FastNoiseLite] or other libraries to fill the texture data of your desired size.
- The class uses [Thread]s to generate the texture data internally, so [method Texture3D.get_data] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data:
+ The class uses [Thread]s to generate the texture data internally, so [method Texture3D.get_data] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image:
[codeblock]
var texture = NoiseTexture3D.new()
texture.noise = FastNoiseLite.new()
await texture.changed
var data = texture.get_data()
- var image = data[0]
[/codeblock]
</description>
<tutorials>
diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp
index 224c082c0f..4aea98c4de 100644
--- a/modules/noise/fastnoise_lite.cpp
+++ b/modules/noise/fastnoise_lite.cpp
@@ -416,7 +416,7 @@ void FastNoiseLite::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".0001,1,.0001"), "set_frequency", "get_frequency");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset");
ADD_GROUP("Fractal", "fractal_");
diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp
index b8c1587ec3..1115d92f58 100644
--- a/modules/noise/noise.cpp
+++ b/modules/noise/noise.cpp
@@ -32,21 +32,40 @@
#include <float.h>
-Ref<Image> Noise::get_seamless_image(int p_width, int p_height, int p_depth, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt, bool p_normalize) const {
- ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
+Vector<Ref<Image>> Noise::_get_seamless_image(int p_width, int p_height, int p_depth, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt, bool p_normalize) const {
+ ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0 || p_depth <= 0, Vector<Ref<Image>>());
int skirt_width = MAX(1, p_width * p_blend_skirt);
int skirt_height = MAX(1, p_height * p_blend_skirt);
+ int skirt_depth = MAX(1, p_depth * p_blend_skirt);
int src_width = p_width + skirt_width;
int src_height = p_height + skirt_height;
+ int src_depth = p_depth + skirt_depth;
+
+ Vector<Ref<Image>> src = _get_image(src_width, src_height, src_depth, p_invert, p_in_3d_space, p_normalize);
+ bool grayscale = (src[0]->get_format() == Image::FORMAT_L8);
- Ref<Image> src = get_image(src_width, src_height, p_depth, p_invert, p_in_3d_space, p_normalize);
- bool grayscale = (src->get_format() == Image::FORMAT_L8);
if (grayscale) {
- return _generate_seamless_image<uint8_t>(src, p_width, p_height, p_invert, p_blend_skirt);
+ return _generate_seamless_image<uint8_t>(src, p_width, p_height, p_depth, p_invert, p_blend_skirt);
} else {
- return _generate_seamless_image<uint32_t>(src, p_width, p_height, p_invert, p_blend_skirt);
+ return _generate_seamless_image<uint32_t>(src, p_width, p_height, p_depth, p_invert, p_blend_skirt);
+ }
+}
+
+Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt, bool p_normalize) const {
+ Vector<Ref<Image>> images = _get_seamless_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_blend_skirt, p_normalize);
+ return images[0];
+}
+
+TypedArray<Image> Noise::get_seamless_image_3d(int p_width, int p_height, int p_depth, bool p_invert, real_t p_blend_skirt, bool p_normalize) const {
+ Vector<Ref<Image>> images = _get_seamless_image(p_width, p_height, p_depth, p_invert, true, p_blend_skirt, p_normalize);
+
+ TypedArray<Image> ret;
+ ret.resize(images.size());
+ for (int i = 0; i < images.size(); i++) {
+ ret[i] = images[i];
}
+ return ret;
}
// Template specialization for faster grayscale blending.
@@ -58,61 +77,104 @@ uint8_t Noise::_alpha_blend<uint8_t>(uint8_t p_bg, uint8_t p_fg, int p_alpha) co
return (uint8_t)((alpha * p_fg + inv_alpha * p_bg) >> 8);
}
-Ref<Image> Noise::get_image(int p_width, int p_height, int p_depth, bool p_invert, bool p_in_3d_space, bool p_normalize) const {
- ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
-
- Vector<uint8_t> data;
- data.resize(p_width * p_height);
+Vector<Ref<Image>> Noise::_get_image(int p_width, int p_height, int p_depth, bool p_invert, bool p_in_3d_space, bool p_normalize) const {
+ ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0 || p_depth <= 0, Vector<Ref<Image>>());
- uint8_t *wd8 = data.ptrw();
+ Vector<Ref<Image>> images;
+ images.resize(p_depth);
if (p_normalize) {
// Get all values and identify min/max values.
- Vector<real_t> values;
- values.resize(p_width * p_height);
+ LocalVector<real_t> values;
+ values.resize(p_width * p_height * p_depth);
+
real_t min_val = FLT_MAX;
real_t max_val = -FLT_MAX;
- for (int y = 0, i = 0; y < p_height; y++) {
- for (int x = 0; x < p_width; x++, i++) {
- values.set(i, p_in_3d_space ? get_noise_3d(x, y, p_depth) : get_noise_2d(x, y));
- if (values[i] > max_val) {
- max_val = values[i];
- }
- if (values[i] < min_val) {
- min_val = values[i];
+ int idx = 0;
+ for (int d = 0; d < p_depth; d++) {
+ for (int y = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++) {
+ values[idx] = p_in_3d_space ? get_noise_3d(x, y, d) : get_noise_2d(x, y);
+ if (values[idx] > max_val) {
+ max_val = values[idx];
+ }
+ if (values[idx] < min_val) {
+ min_val = values[idx];
+ }
+ idx++;
}
}
}
+ idx = 0;
// Normalize values and write to texture.
- uint8_t ivalue;
- for (int i = 0, x = 0; i < p_height; i++) {
- for (int j = 0; j < p_width; j++, x++) {
- if (max_val == min_val) {
- ivalue = 0;
- } else {
- ivalue = static_cast<uint8_t>(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255));
- }
-
- if (p_invert) {
- ivalue = 255 - ivalue;
+ for (int d = 0; d < p_depth; d++) {
+ Vector<uint8_t> data;
+ data.resize(p_width * p_height);
+
+ uint8_t *wd8 = data.ptrw();
+ uint8_t ivalue;
+
+ for (int y = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++) {
+ if (max_val == min_val) {
+ ivalue = 0;
+ } else {
+ ivalue = static_cast<uint8_t>(CLAMP((values[idx] - min_val) / (max_val - min_val) * 255.f, 0, 255));
+ }
+
+ if (p_invert) {
+ ivalue = 255 - ivalue;
+ }
+
+ wd8[x + y * p_width] = ivalue;
+ idx++;
}
-
- wd8[x] = ivalue;
}
+ Ref<Image> img = memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
+ images.write[d] = img;
}
} else {
// Without normalization, the expected range of the noise function is [-1, 1].
- uint8_t ivalue;
- for (int y = 0, i = 0; y < p_height; y++) {
- for (int x = 0; x < p_width; x++, i++) {
- float value = (p_in_3d_space ? get_noise_3d(x, y, p_depth) : get_noise_2d(x, y));
- ivalue = static_cast<uint8_t>(CLAMP(value * 127.5f + 127.5f, 0.0f, 255.0f));
- wd8[i] = p_invert ? (255 - ivalue) : ivalue;
+
+ for (int d = 0; d < p_depth; d++) {
+ Vector<uint8_t> data;
+ data.resize(p_width * p_height);
+
+ uint8_t *wd8 = data.ptrw();
+
+ uint8_t ivalue;
+ int idx = 0;
+ for (int y = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++) {
+ float value = (p_in_3d_space ? get_noise_3d(x, y, d) : get_noise_2d(x, y));
+ ivalue = static_cast<uint8_t>(CLAMP(value * 127.5f + 127.5f, 0.0f, 255.0f));
+ wd8[idx] = p_invert ? (255 - ivalue) : ivalue;
+ idx++;
+ }
}
+
+ Ref<Image> img = memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
+ images.write[d] = img;
}
}
- return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
+ return images;
+}
+
+Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, bool p_normalize) const {
+ Vector<Ref<Image>> images = _get_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_normalize);
+ return images[0];
+}
+
+TypedArray<Image> Noise::get_image_3d(int p_width, int p_height, int p_depth, bool p_invert, bool p_normalize) const {
+ Vector<Ref<Image>> images = _get_image(p_width, p_height, p_depth, p_invert, true, p_normalize);
+
+ TypedArray<Image> ret;
+ ret.resize(images.size());
+ for (int i = 0; i < images.size(); i++) {
+ ret[i] = images[i];
+ }
+ return ret;
}
void Noise::_bind_methods() {
@@ -124,6 +186,8 @@ void Noise::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv);
// Textures.
- ClassDB::bind_method(D_METHOD("get_image", "width", "height", "depth", "invert", "in_3d_space", "normalize"), &Noise::get_image, DEFVAL(false), DEFVAL(false), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "depth", "invert", "in_3d_space", "skirt", "normalize"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert", "in_3d_space", "normalize"), &Noise::get_image, DEFVAL(false), DEFVAL(false), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "in_3d_space", "skirt", "normalize"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_image_3d", "width", "height", "depth", "invert", "normalize"), &Noise::get_image_3d, DEFVAL(false), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_seamless_image_3d", "width", "height", "depth", "invert", "skirt", "normalize"), &Noise::get_seamless_image_3d, DEFVAL(false), DEFVAL(0.1), DEFVAL(true));
}
diff --git a/modules/noise/noise.h b/modules/noise/noise.h
index 856bef8c31..6c49c12bc2 100644
--- a/modules/noise/noise.h
+++ b/modules/noise/noise.h
@@ -32,6 +32,7 @@
#define NOISE_H
#include "core/io/image.h"
+#include "core/variant/typed_array.h"
class Noise : public Resource {
GDCLASS(Noise, Resource);
@@ -81,7 +82,7 @@ class Noise : public Resource {
};
template <typename T>
- Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) const {
+ Vector<Ref<Image>> _generate_seamless_image(Vector<Ref<Image>> p_src, int p_width, int p_height, int p_depth, bool p_invert, real_t p_blend_skirt) const {
/*
To make a seamless image, we swap the quadrants so the edges are perfect matches.
We initially get a 10% larger image so we have an overlap we can use to blend over the seams.
@@ -101,7 +102,7 @@ class Noise : public Resource {
on Source it's translated to
corner of Q1/s3 unless the ALT_XY modulo moves it to Q4
*/
- ERR_FAIL_COND_V(p_blend_skirt < 0, Ref<Image>());
+ ERR_FAIL_COND_V(p_blend_skirt < 0, Vector<Ref<Image>>());
int skirt_width = MAX(1, p_width * p_blend_skirt);
int skirt_height = MAX(1, p_height * p_blend_skirt);
@@ -112,83 +113,139 @@ class Noise : public Resource {
int skirt_edge_x = half_width + skirt_width;
int skirt_edge_y = half_height + skirt_height;
- Vector<uint8_t> dest;
- dest.resize(p_width * p_height * Image::get_format_pixel_size(p_src->get_format()));
-
- img_buff<T> rd_src = {
- (T *)p_src->get_data().ptr(),
- src_width, src_height,
- half_width, half_height,
- p_width, p_height
- };
-
- // `wr` is setup for straight x/y coordinate array access.
- img_buff<T> wr = {
- (T *)dest.ptrw(),
- p_width, p_height,
- 0, 0, 0, 0
- };
- // `rd_dest` is a readable pointer to `wr`, i.e. what has already been written to the output buffer.
- img_buff<T> rd_dest = {
- (T *)dest.ptr(),
- p_width, p_height,
- 0, 0, 0, 0
- };
+ Image::Format format = p_src[0]->get_format();
+ int pixel_size = Image::get_format_pixel_size(format);
+
+ Vector<Ref<Image>> images;
+ images.resize(p_src.size());
+
+ // First blend across x and y for all slices.
+ for (int d = 0; d < images.size(); d++) {
+ Vector<uint8_t> dest;
+ dest.resize(p_width * p_height * pixel_size);
+
+ img_buff<T> rd_src = {
+ (T *)p_src[d]->get_data().ptr(),
+ src_width, src_height,
+ half_width, half_height,
+ p_width, p_height
+ };
+
+ // `wr` is setup for straight x/y coordinate array access.
+ img_buff<T> wr = {
+ (T *)dest.ptrw(),
+ p_width, p_height,
+ 0, 0, 0, 0
+ };
+ // `rd_dest` is a readable pointer to `wr`, i.e. what has already been written to the output buffer.
+ img_buff<T> rd_dest = {
+ (T *)dest.ptr(),
+ p_width, p_height,
+ 0, 0, 0, 0
+ };
+
+ // Swap the quadrants to make edges seamless.
+ for (int y = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++) {
+ // rd_src has a half offset and the shorter modulo ignores the skirt.
+ // It reads and writes in Q1-4 order (see map above), skipping the skirt.
+ wr(x, y) = rd_src(x, y, img_buff<T>::ALT_XY);
+ }
+ }
- // Swap the quadrants to make edges seamless.
- for (int y = 0; y < p_height; y++) {
- for (int x = 0; x < p_width; x++) {
- // rd_src has a half offset and the shorter modulo ignores the skirt.
- // It reads and writes in Q1-4 order (see map above), skipping the skirt.
- wr(x, y) = rd_src(x, y, img_buff<T>::ALT_XY);
+ // Blend the vertical skirt over the middle seam.
+ for (int x = half_width; x < skirt_edge_x; x++) {
+ int alpha = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(x - half_width) / float(skirt_width)));
+ for (int y = 0; y < p_height; y++) {
+ // Skip the center square
+ if (y == half_height) {
+ y = skirt_edge_y - 1;
+ } else {
+ // Starts reading at s2, ALT_Y skips s3, and continues with s1.
+ wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_Y), alpha);
+ }
+ }
}
- }
- // Blend the vertical skirt over the middle seam.
- for (int x = half_width; x < skirt_edge_x; x++) {
- int alpha = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(x - half_width) / float(skirt_width)));
- for (int y = 0; y < p_height; y++) {
- // Skip the center square
- if (y == half_height) {
- y = skirt_edge_y - 1;
- } else {
- // Starts reading at s2, ALT_Y skips s3, and continues with s1.
- wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_Y), alpha);
+ // Blend the horizontal skirt over the middle seam.
+ for (int y = half_height; y < skirt_edge_y; y++) {
+ int alpha = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(y - half_height) / float(skirt_height)));
+ for (int x = 0; x < p_width; x++) {
+ // Skip the center square
+ if (x == half_width) {
+ x = skirt_edge_x - 1;
+ } else {
+ // Starts reading at s4, skips s3, continues with s5.
+ wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_X), alpha);
+ }
}
}
- }
- // Blend the horizontal skirt over the middle seam.
- for (int y = half_height; y < skirt_edge_y; y++) {
- int alpha = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(y - half_height) / float(skirt_height)));
- for (int x = 0; x < p_width; x++) {
- // Skip the center square
- if (x == half_width) {
- x = skirt_edge_x - 1;
- } else {
- // Starts reading at s4, skips s3, continues with s5.
- wr(x, y) = _alpha_blend<T>(rd_dest(x, y), rd_src(x, y, img_buff<T>::ALT_X), alpha);
+ // Fill in the center square. Wr starts at the top left of Q4, which is the equivalent of the top left of s3, unless a modulo is used.
+ for (int y = half_height; y < skirt_edge_y; y++) {
+ for (int x = half_width; x < skirt_edge_x; x++) {
+ int xpos = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(x - half_width) / float(skirt_width)));
+ int ypos = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(y - half_height) / float(skirt_height)));
+
+ // Blend s3(Q1) onto s5(Q2) for the top half.
+ T top_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_X), rd_src(x, y, img_buff<T>::DEFAULT), xpos);
+ // Blend s1(Q3) onto Q4 for the bottom half.
+ T bottom_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_XY), rd_src(x, y, img_buff<T>::ALT_Y), xpos);
+ // Blend the top half onto the bottom half.
+ wr(x, y) = _alpha_blend<T>(bottom_blend, top_blend, ypos);
}
}
+ Ref<Image> image = memnew(Image(p_width, p_height, false, format, dest));
+ p_src.write[d].unref();
+ images.write[d] = image;
}
- // Fill in the center square. Wr starts at the top left of Q4, which is the equivalent of the top left of s3, unless a modulo is used.
- for (int y = half_height; y < skirt_edge_y; y++) {
- for (int x = half_width; x < skirt_edge_x; x++) {
- int xpos = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(x - half_width) / float(skirt_width)));
- int ypos = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(y - half_height) / float(skirt_height)));
-
- // Blend s3(Q1) onto s5(Q2) for the top half.
- T top_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_X), rd_src(x, y, img_buff<T>::DEFAULT), xpos);
- // Blend s1(Q3) onto Q4 for the bottom half.
- T bottom_blend = _alpha_blend<T>(rd_src(x, y, img_buff<T>::ALT_XY), rd_src(x, y, img_buff<T>::ALT_Y), xpos);
- // Blend the top half onto the bottom half.
- wr(x, y) = _alpha_blend<T>(bottom_blend, top_blend, ypos);
+ // Now blend across z.
+ if (p_depth > 1) {
+ int skirt_depth = MAX(1, p_depth * p_blend_skirt);
+ int half_depth = p_depth * 0.5;
+ int skirt_edge_z = half_depth + skirt_depth;
+
+ // Swap halves on depth.
+ for (int i = 0; i < half_depth; i++) {
+ Ref<Image> img = images[i];
+ images.write[i] = images[i + half_depth];
+ images.write[i + half_depth] = img;
}
+
+ Vector<Ref<Image>> new_images = images;
+ new_images.resize(p_depth);
+
+ // Scale seamless generation to third dimension.
+ for (int z = half_depth; z < skirt_edge_z; z++) {
+ int alpha = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(z - half_depth) / float(skirt_depth)));
+
+ Vector<uint8_t> img = images[z % p_depth]->get_data();
+ Vector<uint8_t> skirt = images[(z - half_depth) + p_depth]->get_data();
+
+ Vector<uint8_t> dest;
+ dest.resize(images[0]->get_width() * images[0]->get_height() * Image::get_format_pixel_size(images[0]->get_format()));
+
+ for (int i = 0; i < img.size(); i++) {
+ uint8_t fg, bg, out;
+
+ fg = skirt[i];
+ bg = img[i];
+
+ uint16_t a = alpha + 1;
+ uint16_t inv_a = 256 - alpha;
+
+ out = (uint8_t)((a * fg + inv_a * bg) >> 8);
+
+ dest.write[i] = out;
+ }
+
+ Ref<Image> new_image = memnew(Image(images[0]->get_width(), images[0]->get_height(), false, images[0]->get_format(), dest));
+ new_images.write[z % p_depth] = new_image;
+ }
+ return new_images;
}
- Ref<Image> image = memnew(Image(p_width, p_height, false, p_src->get_format(), dest));
- p_src.unref();
- return image;
+ return images;
}
template <typename T>
@@ -233,8 +290,13 @@ public:
virtual real_t get_noise_3dv(Vector3 p_v) const = 0;
virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const = 0;
- virtual Ref<Image> get_image(int p_width, int p_height, int p_depth, bool p_invert = false, bool p_in_3d_space = false, bool p_normalize = true) const;
- virtual Ref<Image> get_seamless_image(int p_width, int p_height, int p_depth, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1, bool p_normalize = true) const;
+ Vector<Ref<Image>> _get_image(int p_width, int p_height, int p_depth, bool p_invert = false, bool p_in_3d_space = false, bool p_normalize = true) const;
+ virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false, bool p_normalize = true) const;
+ virtual TypedArray<Image> get_image_3d(int p_width, int p_height, int p_depth, bool p_invert = false, bool p_normalize = true) const;
+
+ Vector<Ref<Image>> _get_seamless_image(int p_width, int p_height, int p_depth, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1, bool p_normalize = true) const;
+ virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1, bool p_normalize = true) const;
+ virtual TypedArray<Image> get_seamless_image_3d(int p_width, int p_height, int p_depth, bool p_invert = false, real_t p_blend_skirt = 0.1, bool p_normalize = true) const;
};
#endif // NOISE_H
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index a31f77a38d..e4b2e0b4ac 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -162,9 +162,9 @@ Ref<Image> NoiseTexture2D::_generate_texture() {
Ref<Image> new_image;
if (seamless) {
- new_image = ref_noise->get_seamless_image(size.x, size.y, 0, invert, in_3d_space, seamless_blend_skirt, normalize);
+ new_image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt, normalize);
} else {
- new_image = ref_noise->get_image(size.x, size.y, 0, invert, in_3d_space, normalize);
+ new_image = ref_noise->get_image(size.x, size.y, invert, in_3d_space, normalize);
}
if (color_ramp.is_valid()) {
new_image = _modulate_with_gradient(new_image, color_ramp);
diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp
index 58403397de..25d75b8ffb 100644
--- a/modules/noise/noise_texture_3d.cpp
+++ b/modules/noise/noise_texture_3d.cpp
@@ -44,7 +44,9 @@ NoiseTexture3D::~NoiseTexture3D() {
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
- noise_thread.wait_to_finish();
+ if (noise_thread.is_started()) {
+ noise_thread.wait_to_finish();
+ }
}
void NoiseTexture3D::_bind_methods() {
@@ -147,18 +149,9 @@ TypedArray<Image> NoiseTexture3D::_generate_texture() {
Vector<Ref<Image>> images;
if (seamless) {
- images = _get_seamless(width, height, depth, invert, seamless_blend_skirt);
+ images = ref_noise->_get_seamless_image(width, height, depth, invert, true, seamless_blend_skirt, normalize);
} else {
- images.resize(depth);
-
- for (int i = 0; i < images.size(); i++) {
- images.write[i] = ref_noise->get_image(width, height, i, invert, true, false);
- }
- }
-
- // Normalize on whole texture at once rather than on each image individually as it would result in visible artifacts on z (depth) axis.
- if (normalize) {
- images = _normalize(images);
+ images = ref_noise->_get_image(width, height, depth, invert, true, normalize);
}
if (color_ramp.is_valid()) {
@@ -177,116 +170,6 @@ TypedArray<Image> NoiseTexture3D::_generate_texture() {
return new_data;
}
-Vector<Ref<Image>> NoiseTexture3D::_get_seamless(int p_width, int p_height, int p_depth, bool p_invert, real_t p_blend_skirt) {
- // Prevent memdelete due to unref() on other thread.
- Ref<Noise> ref_noise = noise;
-
- if (ref_noise.is_null()) {
- return Vector<Ref<Image>>();
- }
-
- int skirt_depth = MAX(1, p_depth * p_blend_skirt);
- int src_depth = p_depth + skirt_depth;
-
- Vector<Ref<Image>> images;
- images.resize(src_depth);
-
- for (int i = 0; i < src_depth; i++) {
- images.write[i] = ref_noise->get_seamless_image(p_width, p_height, i, p_invert, true, p_blend_skirt, false);
- }
-
- int half_depth = p_depth * 0.5;
- int skirt_edge_z = half_depth + skirt_depth;
-
- // swap halves on depth.
- for (int i = 0; i < half_depth; i++) {
- Ref<Image> img = images[i];
- images.write[i] = images[i + half_depth];
- images.write[i + half_depth] = img;
- }
-
- Vector<Ref<Image>> new_images = images;
- new_images.resize(p_depth);
-
- // scale seamless generation to third dimension.
- for (int z = half_depth; z < skirt_edge_z; z++) {
- int alpha = 255 * (1 - Math::smoothstep(0.1f, 0.9f, float(z - half_depth) / float(skirt_depth)));
-
- Vector<uint8_t> img = images[z % p_depth]->get_data();
- Vector<uint8_t> skirt = images[(z - half_depth) + p_depth]->get_data();
-
- Vector<uint8_t> dest;
- dest.resize(images[0]->get_width() * images[0]->get_height() * Image::get_format_pixel_size(images[0]->get_format()));
-
- for (int i = 0; i < img.size(); i++) {
- uint8_t fg, bg, out;
-
- fg = skirt[i];
- bg = img[i];
-
- uint16_t a;
- uint16_t inv_a;
-
- a = alpha + 1;
- inv_a = 256 - alpha;
-
- out = (uint8_t)((a * fg + inv_a * bg) >> 8);
-
- dest.write[i] = out;
- }
-
- Ref<Image> new_image = memnew(Image(images[0]->get_width(), images[0]->get_height(), false, images[0]->get_format(), dest));
- new_images.write[z % p_depth] = new_image;
- }
-
- return new_images;
-}
-
-Vector<Ref<Image>> NoiseTexture3D::_normalize(Vector<Ref<Image>> p_images) {
- real_t min_val = FLT_MAX;
- real_t max_val = -FLT_MAX;
-
- int w = p_images[0]->get_width();
- int h = p_images[0]->get_height();
-
- for (int i = 0; i < p_images.size(); i++) {
- Vector<uint8_t> data = p_images[i]->get_data();
-
- for (int j = 0; j < data.size(); j++) {
- if (data[j] > max_val) {
- max_val = data[j];
- }
- if (data[j] < min_val) {
- min_val = data[j];
- }
- }
- }
-
- Vector<Ref<Image>> new_images;
- new_images.resize(p_images.size());
-
- for (int i = 0; i < p_images.size(); i++) {
- Vector<uint8_t> data = p_images[i]->get_data();
-
- for (int j = 0; j < data.size(); j++) {
- uint8_t value;
-
- if (max_val == min_val) {
- value = 0;
- } else {
- value = static_cast<uint8_t>(CLAMP((data[j] - min_val) / (max_val - min_val) * 255.f, 0, 255));
- }
-
- data.write[j] = value;
- }
-
- Ref<Image> new_image = memnew(Image(w, h, false, Image::FORMAT_L8, data));
- new_images.write[i] = new_image;
- }
-
- return new_images;
-}
-
Ref<Image> NoiseTexture3D::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
int w = p_image->get_width();
int h = p_image->get_height();
diff --git a/modules/noise/noise_texture_3d.h b/modules/noise/noise_texture_3d.h
index b5dab10321..397711ca98 100644
--- a/modules/noise/noise_texture_3d.h
+++ b/modules/noise/noise_texture_3d.h
@@ -68,8 +68,6 @@ private:
void _update_texture();
void _set_texture_data(const TypedArray<Image> &p_data);
- Vector<Ref<Image>> _get_seamless(int p_width, int p_height, int p_depth, bool p_invert, real_t p_blend_skirt);
- Vector<Ref<Image>> _normalize(Vector<Ref<Image>> p_images);
Ref<Image> _modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient);
protected:
diff --git a/modules/noise/tests/test_fastnoise_lite.h b/modules/noise/tests/test_fastnoise_lite.h
index db489c6672..0a435c6a5c 100644
--- a/modules/noise/tests/test_fastnoise_lite.h
+++ b/modules/noise/tests/test_fastnoise_lite.h
@@ -605,7 +605,7 @@ TEST_CASE("[FastNoiseLite] Generating seamless 2D images (11x11px) and compare t
noise.set_cellular_jitter(0.0);
SUBCASE("Blend skirt 0.0") {
- Ref<Image> img = noise.get_seamless_image(11, 11, 0, false, false, 0.0);
+ Ref<Image> img = noise.get_seamless_image(11, 11, false, false, 0.0);
Ref<Image> ref_img_1 = memnew(Image);
ref_img_1->set_data(11, 11, false, Image::FORMAT_L8, ref_img_1_data);
@@ -614,7 +614,7 @@ TEST_CASE("[FastNoiseLite] Generating seamless 2D images (11x11px) and compare t
}
SUBCASE("Blend skirt 0.1") {
- Ref<Image> img = noise.get_seamless_image(11, 11, 0, false, false, 0.1);
+ Ref<Image> img = noise.get_seamless_image(11, 11, false, false, 0.1);
Ref<Image> ref_img_2 = memnew(Image);
ref_img_2->set_data(11, 11, false, Image::FORMAT_L8, ref_img_2_data);
@@ -623,7 +623,7 @@ TEST_CASE("[FastNoiseLite] Generating seamless 2D images (11x11px) and compare t
}
SUBCASE("Blend skirt 1.0") {
- Ref<Image> img = noise.get_seamless_image(11, 11, 0, false, false, 0.1);
+ Ref<Image> img = noise.get_seamless_image(11, 11, false, false, 0.1);
Ref<Image> ref_img_3 = memnew(Image);
ref_img_3->set_data(11, 11, false, Image::FORMAT_L8, ref_img_3_data);
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 71339c9443..18091649e3 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -446,39 +446,29 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_NULL(obj);
- int res = env->PushLocalFrame(16);
- ERR_FAIL_COND(res != 0);
-
String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
+
Variant *vlist = (Variant *)alloca(sizeof(Variant) * count);
- Variant **vptr = (Variant **)alloca(sizeof(Variant *) * count);
+ const Variant **vptr = (const Variant **)alloca(sizeof(Variant *) * count);
+
for (int i = 0; i < count; i++) {
jobject jobj = env->GetObjectArrayElement(params, i);
- Variant v;
- if (jobj) {
- v = _jobject_to_variant(env, jobj);
- }
- memnew_placement(&vlist[i], Variant);
- vlist[i] = v;
+ ERR_FAIL_NULL(jobj);
+ memnew_placement(&vlist[i], Variant(_jobject_to_variant(env, jobj)));
vptr[i] = &vlist[i];
env->DeleteLocalRef(jobj);
}
Callable::CallError err;
- obj->callp(str_method, (const Variant **)vptr, count, err);
-
- env->PopLocalFrame(nullptr);
+ obj->callp(str_method, vptr, count, err);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_NULL(obj);
- int res = env->PushLocalFrame(16);
- ERR_FAIL_COND(res != 0);
-
String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
@@ -488,16 +478,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
for (int i = 0; i < count; i++) {
jobject jobj = env->GetObjectArrayElement(params, i);
- if (jobj) {
- args[i] = _jobject_to_variant(env, jobj);
- }
- env->DeleteLocalRef(jobj);
+ ERR_FAIL_NULL(jobj);
+ memnew_placement(&args[i], Variant(_jobject_to_variant(env, jobj)));
argptrs[i] = &args[i];
+ env->DeleteLocalRef(jobj);
}
- MessageQueue::get_singleton()->push_callp(obj, str_method, (const Variant **)argptrs, count);
-
- env->PopLocalFrame(nullptr);
+ MessageQueue::get_singleton()->push_callp(obj, str_method, argptrs, count);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) {
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 4bb90cb971..843c015d49 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -120,7 +120,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitS
for (int i = 0; i < count; i++) {
jobject j_param = env->GetObjectArrayElement(j_signal_params, i);
- variant_params[i] = _jobject_to_variant(env, j_param);
+ ERR_FAIL_NULL(j_param);
+ memnew_placement(&variant_params[i], Variant(_jobject_to_variant(env, j_param)));
args[i] = &variant_params[i];
env->DeleteLocalRef(j_param);
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index c678b4bf02..1b59351b30 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -907,9 +907,7 @@ void RigidBody2D::_notification(int p_what) {
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
+ update_configuration_warnings();
} break;
}
#endif
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 19d1b83cab..6d8d60dcaa 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -83,13 +83,9 @@ void CollisionObject3D::_notification(int p_what) {
_update_pickable();
} break;
-#ifdef TOOLS_ENABLED
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
+ update_configuration_warnings();
} break;
-#endif
case NOTIFICATION_TRANSFORM_CHANGED: {
if (only_update_transform_changes) {
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 53a61c1368..9a2ed00274 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -104,11 +104,7 @@ void CollisionPolygon3D::_notification(int p_what) {
if (parent) {
_update_in_shape_owner(true);
}
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
-#endif
+ update_configuration_warnings();
} break;
case NOTIFICATION_UNPARENTED: {
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index f1d918ad9b..b7f3b12c25 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -99,11 +99,7 @@ void CollisionShape3D::_notification(int p_what) {
if (parent) {
_update_in_shape_owner(true);
}
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
-#endif
+ update_configuration_warnings();
} break;
case NOTIFICATION_UNPARENTED: {
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 16c82bf6d2..18198b566e 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -284,6 +284,9 @@ void Light3D::_update_visibility() {
void Light3D::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ update_configuration_warnings();
+ } break;
case NOTIFICATION_VISIBILITY_CHANGED:
case NOTIFICATION_ENTER_TREE: {
_update_visibility();
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index b7d63258db..4be695d189 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -599,9 +599,7 @@ void RigidBody3D::_notification(int p_what) {
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
+ update_configuration_warnings();
} break;
}
#endif
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 818e19ab29..1b148defc1 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -564,12 +564,12 @@ void TabContainer::add_child_notify(Node *p_child) {
}
void TabContainer::move_child_notify(Node *p_child) {
+ Container::move_child_notify(p_child);
+
if (p_child == tab_bar) {
return;
}
- Container::move_child_notify(p_child);
-
Control *c = Object::cast_to<Control>(p_child);
if (c && !c->is_set_as_top_level()) {
int old_idx = -1;
@@ -588,12 +588,12 @@ void TabContainer::move_child_notify(Node *p_child) {
}
void TabContainer::remove_child_notify(Node *p_child) {
+ Container::remove_child_notify(p_child);
+
if (p_child == tab_bar) {
return;
}
- Container::remove_child_notify(p_child);
-
Control *c = Object::cast_to<Control>(p_child);
if (!c || c->is_set_as_top_level()) {
return;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index ccb3ddee45..5ef3e09e3d 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -985,9 +985,21 @@ void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_sur
}
ERR_FAIL_COND(shape_idx == -1);
ERR_FAIL_COND(shape_idx >= arr.size());
- Array mesh = arr[shape_idx];
- ERR_FAIL_COND(mesh.size() != RS::ARRAY_MAX);
- _create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format);
+ Array blendshape_mesh_arrays = arr[shape_idx];
+ ERR_FAIL_COND(blendshape_mesh_arrays.size() != RS::ARRAY_MAX);
+
+ Array source_mesh_arrays = p_existing->surface_get_arrays(p_surface);
+ ERR_FAIL_COND(source_mesh_arrays.size() != RS::ARRAY_MAX);
+
+ // Copy BlendShape vertex data over while keeping e.g. bones, weights, index from existing mesh intact.
+ source_mesh_arrays[RS::ARRAY_VERTEX] = blendshape_mesh_arrays[RS::ARRAY_VERTEX];
+ source_mesh_arrays[RS::ARRAY_NORMAL] = blendshape_mesh_arrays[RS::ARRAY_NORMAL];
+ source_mesh_arrays[RS::ARRAY_TANGENT] = blendshape_mesh_arrays[RS::ARRAY_TANGENT];
+
+ _create_list_from_arrays(source_mesh_arrays, &vertex_array, &index_array, format);
+
+ material = p_existing->surface_get_material(p_surface);
+ format = p_existing->surface_get_format(p_surface);
for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) {
if (format & custom_mask[j]) {
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 57da55db4d..78b785153f 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -388,6 +388,37 @@ Fog::FogShaderData::~FogShaderData() {
////////////////////////////////////////////////////////////////////////////////
// Volumetric Fog
+bool Fog::VolumetricFog::sync_gi_dependent_sets_validity(bool p_ensure_freed) {
+ bool null = gi_dependent_sets.copy_uniform_set.is_null();
+ bool valid = !null && RD::get_singleton()->uniform_set_is_valid(gi_dependent_sets.copy_uniform_set);
+
+#ifdef DEV_ENABLED
+ // It's all-or-nothing, or something else has changed that requires dev attention.
+ DEV_ASSERT(null == gi_dependent_sets.process_uniform_set_density.is_null());
+ DEV_ASSERT(null == gi_dependent_sets.process_uniform_set.is_null());
+ DEV_ASSERT(null == gi_dependent_sets.process_uniform_set2.is_null());
+ DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(gi_dependent_sets.process_uniform_set_density));
+ DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(gi_dependent_sets.process_uniform_set));
+ DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(gi_dependent_sets.process_uniform_set2));
+#endif
+
+ if (valid) {
+ if (p_ensure_freed) {
+ RD::get_singleton()->free(gi_dependent_sets.copy_uniform_set);
+ RD::get_singleton()->free(gi_dependent_sets.process_uniform_set_density);
+ RD::get_singleton()->free(gi_dependent_sets.process_uniform_set);
+ RD::get_singleton()->free(gi_dependent_sets.process_uniform_set2);
+ valid = false;
+ }
+ }
+
+ if (!valid && !null) {
+ gi_dependent_sets = {};
+ }
+
+ return valid;
+}
+
void Fog::VolumetricFog::init(const Vector3i &fog_size, RID p_sky_shader) {
width = fog_size.x;
height = fog_size.y;
@@ -464,17 +495,7 @@ Fog::VolumetricFog::~VolumetricFog() {
RD::get_singleton()->free(fog_uniform_set);
}
- // At this point, due to cascade deletions, the sets may no longer be valid, but still they must work as a group.
- gi_dependent_sets.valid = RD::get_singleton()->uniform_set_is_valid(gi_dependent_sets.process_uniform_set_density);
-#ifdef DEV_ENABLED
- gi_dependent_sets.assert_actual_validity();
-#endif
- if (gi_dependent_sets.valid) {
- RD::get_singleton()->free(gi_dependent_sets.copy_uniform_set);
- RD::get_singleton()->free(gi_dependent_sets.process_uniform_set_density);
- RD::get_singleton()->free(gi_dependent_sets.process_uniform_set);
- RD::get_singleton()->free(gi_dependent_sets.process_uniform_set2);
- }
+ sync_gi_dependent_sets_validity(true);
if (sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_uniform_set)) {
RD::get_singleton()->free(sdfgi_uniform_set);
@@ -717,10 +738,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->compute_list_end();
}
-#ifdef DEV_ENABLED
- fog->gi_dependent_sets.assert_actual_validity();
-#endif
- if (!fog->gi_dependent_sets.valid) {
+ if (!fog->sync_gi_dependent_sets_validity()) {
//re create uniform set if needed
Vector<RD::Uniform> uniforms;
Vector<RD::Uniform> copy_uniforms;
@@ -932,8 +950,6 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
uniforms.remove_at(8);
uniforms.write[7].set_id(0, aux7);
fog->gi_dependent_sets.process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
-
- fog->gi_dependent_sets.valid = true;
}
bool using_sdfgi = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env) > 0.0001 && RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_enabled(p_settings.env) && (p_settings.sdfgi.is_valid());
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 926da4026c..277389c596 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -303,21 +303,10 @@ public:
RID fog_uniform_set;
struct {
- bool valid = false;
RID copy_uniform_set;
RID process_uniform_set_density;
RID process_uniform_set;
RID process_uniform_set2;
-
-#ifdef DEV_ENABLED
- void assert_actual_validity() {
- // It's all-or-nothing, or something else has changed that requires dev attention.
- DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(copy_uniform_set));
- DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(process_uniform_set_density));
- DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(process_uniform_set));
- DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(process_uniform_set2));
- }
-#endif
} gi_dependent_sets;
RID sdfgi_uniform_set;
@@ -328,6 +317,8 @@ public:
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
virtual void free_data() override{};
+ bool sync_gi_dependent_sets_validity(bool p_ensure_freed = false);
+
void init(const Vector3i &fog_size, RID p_sky_shader);
~VolumetricFog();
};
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 52f09e1ccb..c2a018c7c6 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -3695,20 +3695,6 @@ void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBu
}
rbgi->uniform_set[v] = RID();
}
- if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
- Ref<Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
-
-#ifdef DEV_ENABLED
- fog->gi_dependent_sets.assert_actual_validity();
-#endif
- if (fog->gi_dependent_sets.valid) {
- RD::get_singleton()->free(fog->gi_dependent_sets.copy_uniform_set);
- RD::get_singleton()->free(fog->gi_dependent_sets.process_uniform_set_density);
- RD::get_singleton()->free(fog->gi_dependent_sets.process_uniform_set);
- RD::get_singleton()->free(fog->gi_dependent_sets.process_uniform_set2);
- fog->gi_dependent_sets.valid = false;
- }
- }
}
if (p_voxel_gi_instances.size() > 0) {
diff --git a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
index 0828ffd921..b8c64d09f4 100644
--- a/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
@@ -55,109 +55,107 @@ void main() {
// Converted from compute shader which uses absolute coordinates.
// Could possibly simplify this
float face_size = float(params.face_size);
+ float inv_face_size = 1.0 / face_size;
+ vec2 id = floor(uv_interp);
- if (uv_interp.x < face_size && uv_interp.y < face_size) {
- float inv_face_size = 1.0 / face_size;
-
- float u0 = (uv_interp.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
- float u1 = (uv_interp.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
-
- float v0 = (uv_interp.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
- float v1 = (uv_interp.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
-
- float weights[4];
- weights[0] = calcWeight(u0, v0);
- weights[1] = calcWeight(u1, v0);
- weights[2] = calcWeight(u0, v1);
- weights[3] = calcWeight(u1, v1);
-
- const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
- for (int i = 0; i < 4; i++) {
- weights[i] = weights[i] * wsum + .125;
- }
-
- vec3 dir;
- vec4 color;
- switch (params.face_id) {
- case 0:
- get_dir_0(dir, u0, v0);
- color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
-
- get_dir_0(dir, u1, v0);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
-
- get_dir_0(dir, u0, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
-
- get_dir_0(dir, u1, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
- break;
- case 1:
- get_dir_1(dir, u0, v0);
- color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
-
- get_dir_1(dir, u1, v0);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
-
- get_dir_1(dir, u0, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
-
- get_dir_1(dir, u1, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
- break;
- case 2:
- get_dir_2(dir, u0, v0);
- color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
-
- get_dir_2(dir, u1, v0);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
-
- get_dir_2(dir, u0, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
-
- get_dir_2(dir, u1, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
- break;
- case 3:
- get_dir_3(dir, u0, v0);
- color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
-
- get_dir_3(dir, u1, v0);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
-
- get_dir_3(dir, u0, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
-
- get_dir_3(dir, u1, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
- break;
- case 4:
- get_dir_4(dir, u0, v0);
- color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
-
- get_dir_4(dir, u1, v0);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
-
- get_dir_4(dir, u0, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
-
- get_dir_4(dir, u1, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
- break;
- default:
- get_dir_5(dir, u0, v0);
- color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
-
- get_dir_5(dir, u1, v0);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
-
- get_dir_5(dir, u0, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
-
- get_dir_5(dir, u1, v1);
- color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
- break;
- }
- frag_color = color;
+ float u1 = (id.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
+ float u0 = (id.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
+
+ float v0 = (id.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
+ float v1 = (id.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
+
+ float weights[4];
+ weights[0] = calcWeight(u0, v0);
+ weights[1] = calcWeight(u1, v0);
+ weights[2] = calcWeight(u0, v1);
+ weights[3] = calcWeight(u1, v1);
+
+ const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
+ for (int i = 0; i < 4; i++) {
+ weights[i] = weights[i] * wsum + .125;
+ }
+
+ vec3 dir;
+ vec4 color;
+ switch (params.face_id) {
+ case 0:
+ get_dir_0(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_0(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_0(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_0(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 1:
+ get_dir_1(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_1(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_1(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_1(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 2:
+ get_dir_2(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_2(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_2(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_2(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 3:
+ get_dir_3(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_3(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_3(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_3(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 4:
+ get_dir_4(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_4(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_4(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_4(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ default:
+ get_dir_5(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_5(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_5(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_5(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
}
+ frag_color = color;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index c36d1ef503..3360358169 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -93,11 +93,11 @@ private:
struct ShadowTransform {
Projection camera;
Transform3D transform;
- float farplane;
- float split;
- float bias_scale;
- float shadow_texel_size;
- float range_begin;
+ float farplane = 0.0;
+ float split = 0.0;
+ float bias_scale = 0.0;
+ float shadow_texel_size = 0.0;
+ float range_begin = 0.0;
Rect2 atlas_rect;
Vector2 uv_scale;
};