diff options
author | Hendrik Brucker <hendrik.brucker@mail.de> | 2022-04-19 19:48:25 +0200 |
---|---|---|
committer | Hendrik Brucker <hendrik.brucker@mail.de> | 2022-04-19 19:49:48 +0200 |
commit | bde6fc9c8217d59be0783dde8b404251e6239ea3 (patch) | |
tree | a78be343b9922a2612f1d3c41d3574476dc44c6b /modules | |
parent | 3ca45148668b8c25883371c7bf39490a943f0de5 (diff) |
Restructure and refine the noise module
Diffstat (limited to 'modules')
-rw-r--r-- | modules/noise/SCsub | 1 | ||||
-rw-r--r-- | modules/noise/doc_classes/FastNoiseLite.xml | 8 | ||||
-rw-r--r-- | modules/noise/doc_classes/Noise.xml | 18 | ||||
-rw-r--r-- | modules/noise/doc_classes/NoiseTexture.xml | 11 | ||||
-rw-r--r-- | modules/noise/editor/noise_editor_plugin.cpp | 149 | ||||
-rw-r--r-- | modules/noise/editor/noise_editor_plugin.h | 49 | ||||
-rw-r--r-- | modules/noise/fastnoise_lite.cpp | 237 | ||||
-rw-r--r-- | modules/noise/fastnoise_lite.h | 63 | ||||
-rw-r--r-- | modules/noise/noise.cpp | 52 | ||||
-rw-r--r-- | modules/noise/noise.h | 16 | ||||
-rw-r--r-- | modules/noise/noise_texture.cpp | 95 | ||||
-rw-r--r-- | modules/noise/noise_texture.h | 20 | ||||
-rw-r--r-- | modules/noise/register_types.cpp | 9 |
13 files changed, 487 insertions, 241 deletions
diff --git a/modules/noise/SCsub b/modules/noise/SCsub index 3e8395b9b1..1430aa0c4e 100644 --- a/modules/noise/SCsub +++ b/modules/noise/SCsub @@ -27,6 +27,7 @@ env.modules_sources += thirdparty_obj module_obj = [] env_noise.add_source_files(module_obj, "*.cpp") +env_noise.add_source_files(module_obj, "editor/*.cpp") env.modules_sources += module_obj # Needed to force rebuilding the module files when the thirdparty library is updated. diff --git a/modules/noise/doc_classes/FastNoiseLite.xml b/modules/noise/doc_classes/FastNoiseLite.xml index b6d91850c4..6ca4ba2d46 100644 --- a/modules/noise/doc_classes/FastNoiseLite.xml +++ b/modules/noise/doc_classes/FastNoiseLite.xml @@ -16,12 +16,9 @@ <member name="cellular_jitter" type="float" setter="set_cellular_jitter" getter="get_cellular_jitter" default="0.45"> Maximum distance a point can move off of its grid position. Set to [code]0[/code] for an even grid. </member> - <member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="0"> + <member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="1"> Return type from cellular noise calculations. See [enum CellularReturnType]. </member> - <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> - A [Gradient] which is used to map the luminance of each pixel to a color value. - </member> <member name="domain_warp_amplitude" type="float" setter="set_domain_warp_amplitude" getter="get_domain_warp_amplitude" default="30.0"> Sets the maximum warp distance from the origin. </member> @@ -69,9 +66,6 @@ <member name="frequency" type="float" setter="set_frequency" getter="get_frequency" default="0.01"> The frequency for all noise types. Low frequency results in smooth noise while high frequency results in rougher, more granular noise. </member> - <member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false"> - Determines whether the noise image returned by [method Noise.get_image] is calculated in 3d space. May result in reduced contrast. - </member> <member name="noise_type" type="int" setter="set_noise_type" getter="get_noise_type" enum="FastNoiseLite.NoiseType" default="1"> The noise algorithm used. See [enum NoiseType]. </member> diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml index db0dec18d2..5af204575c 100644 --- a/modules/noise/doc_classes/Noise.xml +++ b/modules/noise/doc_classes/Noise.xml @@ -11,23 +11,24 @@ <tutorials> </tutorials> <methods> - <method name="get_image"> + <method name="get_image" qualifiers="const"> <return type="Image" /> <argument index="0" name="width" type="int" /> <argument index="1" name="height" type="int" /> <argument index="2" name="invert" type="bool" default="false" /> + <argument index="3" name="in_3d_space" type="bool" default="false" /> <description> Returns a 2D [Image] noise image. </description> </method> - <method name="get_noise_1d"> + <method name="get_noise_1d" qualifiers="const"> <return type="float" /> <argument index="0" name="x" type="float" /> <description> Returns the 1D noise value at the given (x) coordinate. </description> </method> - <method name="get_noise_2d"> + <method name="get_noise_2d" qualifiers="const"> <return type="float" /> <argument index="0" name="x" type="float" /> <argument index="1" name="y" type="float" /> @@ -35,14 +36,14 @@ Returns the 2D noise value at the given position. </description> </method> - <method name="get_noise_2dv"> + <method name="get_noise_2dv" qualifiers="const"> <return type="float" /> <argument index="0" name="v" type="Vector2" /> <description> Returns the 2D noise value at the given position. </description> </method> - <method name="get_noise_3d"> + <method name="get_noise_3d" qualifiers="const"> <return type="float" /> <argument index="0" name="x" type="float" /> <argument index="1" name="y" type="float" /> @@ -51,19 +52,20 @@ Returns the 3D noise value at the given position. </description> </method> - <method name="get_noise_3dv"> + <method name="get_noise_3dv" qualifiers="const"> <return type="float" /> <argument index="0" name="v" type="Vector3" /> <description> Returns the 3D noise value at the given position. </description> </method> - <method name="get_seamless_image"> + <method name="get_seamless_image" qualifiers="const"> <return type="Image" /> <argument index="0" name="width" type="int" /> <argument index="1" name="height" type="int" /> <argument index="2" name="invert" type="bool" default="false" /> - <argument index="3" name="skirt" type="float" default="0.1" /> + <argument index="3" name="in_3d_space" type="bool" default="false" /> + <argument index="4" name="skirt" type="float" default="0.1" /> <description> Returns a seamless 2D [Image] noise image. </description> diff --git a/modules/noise/doc_classes/NoiseTexture.xml b/modules/noise/doc_classes/NoiseTexture.xml index 63630eccde..62a223b387 100644 --- a/modules/noise/doc_classes/NoiseTexture.xml +++ b/modules/noise/doc_classes/NoiseTexture.xml @@ -24,9 +24,20 @@ <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0"> Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer. </member> + <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> + A [Gradient] which is used to map the luminance of each pixel to a color value. + </member> + <member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="is_generating_mipmaps" default="true"> + Determines whether mipmaps are generated for this texture. + Enabling this results in less texture aliasing, but the noise texture generation may take longer. + Requires (anisotropic) mipmap filtering to be enabled for a material to have an effect. + </member> <member name="height" type="int" setter="set_height" getter="get_height" default="512"> Height of the generated texture. </member> + <member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false"> + Determines whether the noise image is calculated in 3D space. May result in reduced contrast. + </member> <member name="invert" type="bool" setter="set_invert" getter="get_invert" default="false"> If [code]true[/code], inverts the noise texture. White becomes black, black becomes white. </member> diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp new file mode 100644 index 0000000000..32c3f0aad4 --- /dev/null +++ b/modules/noise/editor/noise_editor_plugin.cpp @@ -0,0 +1,149 @@ +/*************************************************************************/ +/* noise_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "noise_editor_plugin.h" + +#ifdef TOOLS_ENABLED + +#include "editor/editor_scale.h" + +#include "modules/noise/noise.h" +#include "modules/noise/noise_texture.h" + +class NoisePreview : public Control { + GDCLASS(NoisePreview, Control) + + static const int PREVIEW_HEIGHT = 150; + static const int PADDING_3D_SPACE_SWITCH = 2; + + Ref<Noise> _noise; + Size2i _preview_texture_size; + + TextureRect *_texture_rect = nullptr; + Button *_3d_space_switch = nullptr; + +public: + NoisePreview() { + set_custom_minimum_size(Size2(0, EDSCALE * PREVIEW_HEIGHT)); + + _texture_rect = memnew(TextureRect); + _texture_rect->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + _texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED); + add_child(_texture_rect); + + _3d_space_switch = memnew(Button); + _3d_space_switch->set_text(TTR("3D")); + _3d_space_switch->set_tooltip(TTR("Toggles whether the noise preview is computed in 3D space.")); + _3d_space_switch->set_toggle_mode(true); + _3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH); + _3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH); + _3d_space_switch->connect("pressed", callable_mp(this, &NoisePreview::_on_3d_button_pressed)); + add_child(_3d_space_switch); + } + + void set_noise(Ref<Noise> noise) { + if (_noise == noise) { + return; + } + _noise = noise; + if (_noise.is_valid()) { + if (_noise->has_meta("_preview_in_3d_space_")) { + _3d_space_switch->set_pressed(true); + } + + update_preview(); + } + } + +private: + void _on_3d_button_pressed() { + if (_3d_space_switch->is_pressed()) { + _noise->set_meta("_preview_in_3d_space_", true); + } else { + _noise->remove_meta("_preview_in_3d_space_"); + } + } + + void _notification(int p_what) { + switch (p_what) { + case NOTIFICATION_RESIZED: { + _preview_texture_size = get_size(); + update_preview(); + } break; + } + } + + void update_preview() { + if (MIN(_preview_texture_size.width, _preview_texture_size.height) > 0) { + Ref<NoiseTexture> tex; + tex.instantiate(); + tex->set_width(_preview_texture_size.width); + tex->set_height(_preview_texture_size.height); + tex->set_in_3d_space(_3d_space_switch->is_pressed()); + tex->set_noise(_noise); + _texture_rect->set_texture(tex); + } + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +class NoiseEditorInspectorPlugin : public EditorInspectorPlugin { + GDCLASS(NoiseEditorInspectorPlugin, EditorInspectorPlugin) +public: + bool can_handle(Object *p_object) override { + return Object::cast_to<Noise>(p_object) != nullptr; + } + + void parse_begin(Object *p_object) override { + Noise *noise_ptr = Object::cast_to<Noise>(p_object); + if (noise_ptr) { + Ref<Noise> noise(noise_ptr); + + NoisePreview *viewer = memnew(NoisePreview); + viewer->set_noise(noise); + add_custom_control(viewer); + } + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +String NoiseEditorPlugin::get_name() const { + return Noise::get_class_static(); +} + +NoiseEditorPlugin::NoiseEditorPlugin() { + Ref<NoiseEditorInspectorPlugin> plugin; + plugin.instantiate(); + add_inspector_plugin(plugin); +} + +#endif // TOOLS_ENABLED diff --git a/modules/noise/editor/noise_editor_plugin.h b/modules/noise/editor/noise_editor_plugin.h new file mode 100644 index 0000000000..55a01deb2d --- /dev/null +++ b/modules/noise/editor/noise_editor_plugin.h @@ -0,0 +1,49 @@ +/*************************************************************************/ +/* noise_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NOISE_EDITOR_PLUGIN_H +#define NOISE_EDITOR_PLUGIN_H + +#ifdef TOOLS_ENABLED + +#include "editor/editor_plugin.h" + +class NoiseEditorPlugin : public EditorPlugin { + GDCLASS(NoiseEditorPlugin, EditorPlugin) + +public: + String get_name() const override; + + NoiseEditorPlugin(); +}; + +#endif // TOOLS_ENABLED + +#endif // NOISE_EDITOR_PLUGIN_H diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp index 9497fe6a7e..a8d38dee62 100644 --- a/modules/noise/fastnoise_lite.cpp +++ b/modules/noise/fastnoise_lite.cpp @@ -31,31 +31,29 @@ #include "fastnoise_lite.h" FastNoiseLite::FastNoiseLite() { - // Most defaults copied from the library. - set_noise_type(TYPE_SIMPLEX_SMOOTH); - set_seed(0); - set_frequency(0.01); - set_in_3d_space(false); - - set_fractal_type(FRACTAL_FBM); - set_fractal_octaves(5); - set_fractal_lacunarity(2.0); - set_fractal_gain(0.5); - set_fractal_weighted_strength(0.0); - set_fractal_ping_pong_strength(2.0); - - set_cellular_distance_function(DISTANCE_EUCLIDEAN); - set_cellular_return_type(RETURN_CELL_VALUE); - set_cellular_jitter(0.45); - - set_domain_warp_enabled(false); - set_domain_warp_type(DOMAIN_WARP_SIMPLEX); - set_domain_warp_amplitude(30.0); - set_domain_warp_frequency(0.05); - set_domain_warp_fractal_type(DOMAIN_WARP_FRACTAL_PROGRESSIVE); - set_domain_warp_fractal_octaves(5); - set_domain_warp_fractal_lacunarity(6); - set_domain_warp_fractal_gain(0.5); + _noise.SetNoiseType((_FastNoiseLite::NoiseType)noise_type); + _noise.SetSeed(seed); + _noise.SetFrequency(frequency); + + _noise.SetFractalType((_FastNoiseLite::FractalType)fractal_type); + _noise.SetFractalOctaves(fractal_octaves); + _noise.SetFractalLacunarity(fractal_lacunarity); + _noise.SetFractalGain(fractal_gain); + _noise.SetFractalWeightedStrength(fractal_weighted_strength); + _noise.SetFractalPingPongStrength(fractal_ping_pong_strength); + + _noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)cellular_distance_function); + _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)cellular_return_type); + _noise.SetCellularJitter(cellular_jitter); + + _domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)domain_warp_type); + _domain_warp_noise.SetSeed(seed); + _domain_warp_noise.SetDomainWarpAmp(domain_warp_amplitude); + _domain_warp_noise.SetFrequency(domain_warp_frequency); + _domain_warp_noise.SetFractalType(_FastNoiseLite::FractalType_None); + _domain_warp_noise.SetFractalOctaves(domain_warp_fractal_octaves); + _domain_warp_noise.SetFractalLacunarity(domain_warp_fractal_lacunarity); + _domain_warp_noise.SetFractalGain(domain_warp_fractal_gain); } FastNoiseLite::~FastNoiseLite() { @@ -77,6 +75,7 @@ FastNoiseLite::NoiseType FastNoiseLite::get_noise_type() const { void FastNoiseLite::set_seed(int p_seed) { seed = p_seed; _noise.SetSeed(p_seed); + _domain_warp_noise.SetSeed(p_seed); emit_changed(); } @@ -94,14 +93,6 @@ real_t FastNoiseLite::get_frequency() const { return frequency; } -void FastNoiseLite::set_in_3d_space(bool p_enable) { - in_3d_space = p_enable; - emit_changed(); -} -bool FastNoiseLite::is_in_3d_space() const { - return in_3d_space; -} - void FastNoiseLite::set_offset(Vector3 p_offset) { offset = p_offset; emit_changed(); @@ -111,46 +102,6 @@ Vector3 FastNoiseLite::get_offset() const { return offset; } -void FastNoiseLite::set_color_ramp(const Ref<Gradient> &p_gradient) { - color_ramp = p_gradient; - if (color_ramp.is_valid()) { - color_ramp->connect(SNAME("changed"), callable_mp(this, &FastNoiseLite::_changed)); - emit_changed(); - } -} - -Ref<Gradient> FastNoiseLite::get_color_ramp() const { - return color_ramp; -} - -// Noise functions. - -real_t FastNoiseLite::get_noise_1d(real_t p_x) { - return get_noise_2d(p_x, 0.0); -} - -real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) { - return get_noise_2d(p_v.x, p_v.y); -} - -real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) { - if (domain_warp_enabled) { - _domain_warp_noise.DomainWarp(p_x, p_y); - } - return _noise.GetNoise(p_x + offset.x, p_y + offset.y); -} - -real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) { - return get_noise_3d(p_v.x, p_v.y, p_v.z); -} - -real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) { - if (domain_warp_enabled) { - _domain_warp_noise.DomainWarp(p_x, p_y, p_z); - } - return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z); -} - // Fractal. void FastNoiseLite::set_fractal_type(FractalType p_type) { @@ -204,12 +155,12 @@ real_t FastNoiseLite::get_fractal_weighted_strength() const { } void FastNoiseLite::set_fractal_ping_pong_strength(real_t p_ping_pong_strength) { - fractal_pinp_pong_strength = p_ping_pong_strength; + fractal_ping_pong_strength = p_ping_pong_strength; _noise.SetFractalPingPongStrength(p_ping_pong_strength); emit_changed(); } real_t FastNoiseLite::get_fractal_ping_pong_strength() const { - return fractal_pinp_pong_strength; + return fractal_ping_pong_strength; } // Cellular. @@ -237,7 +188,6 @@ real_t FastNoiseLite::get_cellular_jitter() const { void FastNoiseLite::set_cellular_return_type(CellularReturnType p_ret) { cellular_return_type = p_ret; _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)p_ret); - emit_changed(); } @@ -345,68 +295,32 @@ real_t FastNoiseLite::get_domain_warp_fractal_gain() const { return domain_warp_fractal_gain; } -// Textures. +// Noise interface functions. -Ref<Image> FastNoiseLite::get_image(int p_width, int p_height, bool p_invert) { - bool grayscale = color_ramp.is_null(); - - Vector<uint8_t> data; - data.resize(p_width * p_height * (grayscale ? 1 : 4)); - - uint8_t *wd8 = data.ptrw(); +real_t FastNoiseLite::get_noise_1d(real_t p_x) const { + return get_noise_2d(p_x, 0.0); +} - // Get all values and identify min/max values. - Vector<real_t> values; - values.resize(p_width * p_height); - real_t min_val = 100; - real_t max_val = -100; +real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const { + return get_noise_2d(p_v.x, p_v.y); +} - for (int y = 0, i = 0; y < p_height; y++) { - for (int x = 0; x < p_width; x++, i++) { - values.set(i, is_in_3d_space() ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y)); - if (values[i] > max_val) { - max_val = values[i]; - } - if (values[i] < min_val) { - min_val = values[i]; - } - } +real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const { + if (domain_warp_enabled) { + _domain_warp_noise.DomainWarp(p_x, p_y); } + return _noise.GetNoise(p_x + offset.x, p_y + offset.y); +} - // Normalize values and write to texture. - uint8_t value; - for (int i = 0, x = 0; i < p_height; i++) { - for (int j = 0; j < p_width; j++, x++) { - if (max_val == min_val) { - value = 0; - } else { - value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255)); - } - if (p_invert) { - value = 255 - value; - } - if (grayscale) { - wd8[x] = value; - } else { - float luminance = value / 255.0; - Color ramp_color = color_ramp->get_color_at_offset(luminance); - wd8[x * 4 + 0] = uint8_t(CLAMP(ramp_color.r * 255, 0, 255)); - wd8[x * 4 + 1] = uint8_t(CLAMP(ramp_color.g * 255, 0, 255)); - wd8[x * 4 + 2] = uint8_t(CLAMP(ramp_color.b * 255, 0, 255)); - wd8[x * 4 + 3] = uint8_t(CLAMP(ramp_color.a * 255, 0, 255)); - } - } - } - if (grayscale) { - return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data)); - } else { - return memnew(Image(p_width, p_height, false, Image::FORMAT_RGBA8, data)); - } +real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const { + return get_noise_3d(p_v.x, p_v.y, p_v.z); } -Ref<Image> FastNoiseLite::get_seamless_image(int p_width, int p_height, bool p_invert, real_t p_blend_skirt) { - // Just return parent function. This is here only so Godot will properly document this function. - return Noise::get_seamless_image(p_width, p_height, p_invert, p_blend_skirt); +real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const { + if (domain_warp_enabled) { + _domain_warp_noise.DomainWarp(p_x, p_y, p_z); + } + return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z); } void FastNoiseLite::_changed() { @@ -418,108 +332,103 @@ void FastNoiseLite::_bind_methods() { ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoiseLite::set_noise_type); ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoiseLite::get_noise_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type"); ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLite::set_seed); ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLite::get_seed); - ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); ClassDB::bind_method(D_METHOD("set_frequency", "freq"), &FastNoiseLite::set_frequency); ClassDB::bind_method(D_METHOD("get_frequency"), &FastNoiseLite::get_frequency); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency"); - - ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &FastNoiseLite::set_in_3d_space); - ClassDB::bind_method(D_METHOD("is_in_3d_space"), &FastNoiseLite::is_in_3d_space); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space"); ClassDB::bind_method(D_METHOD("set_offset", "offset"), &FastNoiseLite::set_offset); ClassDB::bind_method(D_METHOD("get_offset"), &FastNoiseLite::get_offset); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,1"), "set_offset", "get_offset"); - - ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &FastNoiseLite::set_color_ramp); - ClassDB::bind_method(D_METHOD("get_color_ramp"), &FastNoiseLite::get_color_ramp); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); // Fractal. - ADD_GROUP("Fractal", "fractal_"); ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoiseLite::set_fractal_type); ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoiseLite::get_fractal_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type"); ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octave_count"), &FastNoiseLite::set_fractal_octaves); ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLite::get_fractal_octaves); - ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves"); ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"), &FastNoiseLite::set_fractal_lacunarity); ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoiseLite::get_fractal_lacunarity); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity"); ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoiseLite::set_fractal_gain); ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoiseLite::get_fractal_gain); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain"); ClassDB::bind_method(D_METHOD("set_fractal_weighted_strength", "weighted_strength"), &FastNoiseLite::set_fractal_weighted_strength); ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoiseLite::get_fractal_weighted_strength); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength"); ClassDB::bind_method(D_METHOD("set_fractal_ping_pong_strength", "ping_pong_strength"), &FastNoiseLite::set_fractal_ping_pong_strength); ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoiseLite::get_fractal_ping_pong_strength); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength"); // Cellular. - ADD_GROUP("Cellular", "cellular_"); ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "func"), &FastNoiseLite::set_cellular_distance_function); ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoiseLite::get_cellular_distance_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function"); ClassDB::bind_method(D_METHOD("set_cellular_jitter", "jitter"), &FastNoiseLite::set_cellular_jitter); ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoiseLite::get_cellular_jitter); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter"); ClassDB::bind_method(D_METHOD("set_cellular_return_type", "ret"), &FastNoiseLite::set_cellular_return_type); ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoiseLite::get_cellular_return_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type"); // Domain warp. - ADD_GROUP("Domain Warp", "domain_warp_"); - ClassDB::bind_method(D_METHOD("set_domain_warp_enabled", "domain_warp_enabled"), &FastNoiseLite::set_domain_warp_enabled); ClassDB::bind_method(D_METHOD("is_domain_warp_enabled"), &FastNoiseLite::is_domain_warp_enabled); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled"); ClassDB::bind_method(D_METHOD("set_domain_warp_type", "domain_warp_type"), &FastNoiseLite::set_domain_warp_type); ClassDB::bind_method(D_METHOD("get_domain_warp_type"), &FastNoiseLite::get_domain_warp_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type"); ClassDB::bind_method(D_METHOD("set_domain_warp_amplitude", "domain_warp_amplitude"), &FastNoiseLite::set_domain_warp_amplitude); ClassDB::bind_method(D_METHOD("get_domain_warp_amplitude"), &FastNoiseLite::get_domain_warp_amplitude); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude"); ClassDB::bind_method(D_METHOD("set_domain_warp_frequency", "domain_warp_frequency"), &FastNoiseLite::set_domain_warp_frequency); ClassDB::bind_method(D_METHOD("get_domain_warp_frequency"), &FastNoiseLite::get_domain_warp_frequency); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency"); ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_type", "domain_warp_fractal_type"), &FastNoiseLite::set_domain_warp_fractal_type); ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_type"), &FastNoiseLite::get_domain_warp_fractal_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type"); ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_octaves", "domain_warp_octave_count"), &FastNoiseLite::set_domain_warp_fractal_octaves); ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_octaves"), &FastNoiseLite::get_domain_warp_fractal_octaves); - ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves"); ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_lacunarity", "domain_warp_lacunarity"), &FastNoiseLite::set_domain_warp_fractal_lacunarity); ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_lacunarity"), &FastNoiseLite::get_domain_warp_fractal_lacunarity); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity"); ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_gain", "domain_warp_gain"), &FastNoiseLite::set_domain_warp_fractal_gain); ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_gain"), &FastNoiseLite::get_domain_warp_fractal_gain); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain"); ClassDB::bind_method(D_METHOD("_changed"), &FastNoiseLite::_changed); + 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::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset"); + + ADD_GROUP("Fractal", "fractal_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength"); + + ADD_GROUP("Cellular", "cellular_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type"); + + ADD_GROUP("Domain Warp", "domain_warp_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain"); + BIND_ENUM_CONSTANT(TYPE_VALUE); BIND_ENUM_CONSTANT(TYPE_VALUE_CUBIC); BIND_ENUM_CONSTANT(TYPE_PERLIN); diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h index 4635e26d28..0a4251868b 100644 --- a/modules/noise/fastnoise_lite.h +++ b/modules/noise/fastnoise_lite.h @@ -99,36 +99,33 @@ private: _FastNoiseLite _domain_warp_noise; Vector3 offset; - NoiseType noise_type; - Ref<Gradient> color_ramp; + NoiseType noise_type = TYPE_SIMPLEX_SMOOTH; - int seed; - real_t frequency; - bool in_3d_space; + int seed = 0; + real_t frequency = 0.01; // Fractal specific. - FractalType fractal_type; - int fractal_octaves; - real_t fractal_lacunarity; - real_t fractal_gain; - real_t fractal_weighted_strength; - real_t fractal_pinp_pong_strength; + FractalType fractal_type = FRACTAL_FBM; + int fractal_octaves = 5; + real_t fractal_lacunarity = 2; + real_t fractal_gain = 0.5; + real_t fractal_weighted_strength = 0; + real_t fractal_ping_pong_strength = 2; // Cellular specific. - CellularDistanceFunction cellular_distance_function; - CellularReturnType cellular_return_type; - real_t cellular_jitter; + CellularDistanceFunction cellular_distance_function = DISTANCE_EUCLIDEAN; + CellularReturnType cellular_return_type = RETURN_DISTANCE; + real_t cellular_jitter = 0.45; // Domain warp specific. - bool domain_warp_enabled; - DomainWarpType domain_warp_type; - real_t domain_warp_frequency; - real_t domain_warp_amplitude; - - DomainWarpFractalType domain_warp_fractal_type; - int domain_warp_fractal_octaves; - real_t domain_warp_fractal_lacunarity; - real_t domain_warp_fractal_gain; + bool domain_warp_enabled = false; + DomainWarpType domain_warp_type = DOMAIN_WARP_SIMPLEX; + real_t domain_warp_amplitude = 30.0; + real_t domain_warp_frequency = 0.05; + DomainWarpFractalType domain_warp_fractal_type = DOMAIN_WARP_FRACTAL_PROGRESSIVE; + int domain_warp_fractal_octaves = 5; + real_t domain_warp_fractal_lacunarity = 6; + real_t domain_warp_fractal_gain = 0.5; public: FastNoiseLite(); @@ -145,15 +142,9 @@ public: void set_frequency(real_t p_freq); real_t get_frequency() const; - void set_in_3d_space(bool p_enable); - bool is_in_3d_space() const; - void set_offset(Vector3 p_offset); Vector3 get_offset() const; - void set_color_ramp(const Ref<Gradient> &p_gradient); - Ref<Gradient> get_color_ramp() const; - // Fractal specific. void set_fractal_type(FractalType p_type); @@ -212,17 +203,13 @@ public: real_t get_domain_warp_fractal_gain() const; // Interface methods. + real_t get_noise_1d(real_t p_x) const override; - Ref<Image> get_image(int p_width, int p_height, bool p_invert = false) override; - Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, real_t p_blend_skirt = 0.1) override; - - real_t get_noise_1d(real_t p_x) override; - - real_t get_noise_2dv(Vector2 p_v) override; - real_t get_noise_2d(real_t p_x, real_t p_y) override; + real_t get_noise_2dv(Vector2 p_v) const override; + real_t get_noise_2d(real_t p_x, real_t p_y) const override; - real_t get_noise_3dv(Vector3 p_v) override; - real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) override; + real_t get_noise_3dv(Vector3 p_v) const override; + real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const override; void _changed(); }; diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp index 430e8c87cf..ad3df0a016 100644 --- a/modules/noise/noise.cpp +++ b/modules/noise/noise.cpp @@ -30,13 +30,13 @@ #include "noise.h" -Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, real_t 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) const { int skirt_width = p_width * p_blend_skirt; int skirt_height = p_height * p_blend_skirt; int src_width = p_width + skirt_width; int src_height = p_height + skirt_height; - Ref<Image> src = get_image(src_width, src_height, p_invert); + Ref<Image> src = get_image(src_width, src_height, p_invert, p_in_3d_space); 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); @@ -54,6 +54,50 @@ 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, bool p_invert, bool p_in_3d_space) const { + Vector<uint8_t> data; + data.resize(p_width * p_height); + + uint8_t *wd8 = data.ptrw(); + + // Get all values and identify min/max values. + Vector<real_t> values; + values.resize(p_width * p_height); + real_t min_val = 1000; + real_t max_val = -1000; + + 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, 0.0) : get_noise_2d(x, y)); + if (values[i] > max_val) { + max_val = values[i]; + } + if (values[i] < min_val) { + min_val = values[i]; + } + } + } + + // Normalize values and write to texture. + uint8_t value; + for (int i = 0, x = 0; i < p_height; i++) { + for (int j = 0; j < p_width; j++, x++) { + if (max_val == min_val) { + value = 0; + } else { + value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255)); + } + if (p_invert) { + value = 255 - value; + } + + wd8[x] = value; + } + } + + return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data)); +} + void Noise::_bind_methods() { // Noise functions. ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &Noise::get_noise_1d); @@ -63,6 +107,6 @@ 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", "invert"), &Noise::get_image, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(0.1)); + ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert", "in_3d_space"), &Noise::get_image, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "in_3d_space", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1)); } diff --git a/modules/noise/noise.h b/modules/noise/noise.h index 853c24b485..8083334388 100644 --- a/modules/noise/noise.h +++ b/modules/noise/noise.h @@ -81,7 +81,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) { + Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, 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. @@ -225,16 +225,16 @@ public: // Virtual destructor so we can delete any Noise derived object when referenced as a Noise*. virtual ~Noise() {} - virtual real_t get_noise_1d(real_t p_x) = 0; + virtual real_t get_noise_1d(real_t p_x) const = 0; - virtual real_t get_noise_2dv(Vector2 p_v) = 0; - virtual real_t get_noise_2d(real_t p_x, real_t p_y) = 0; + virtual real_t get_noise_2dv(Vector2 p_v) const = 0; + virtual real_t get_noise_2d(real_t p_x, real_t p_y) const = 0; - virtual real_t get_noise_3dv(Vector3 p_v) = 0; - virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) = 0; + 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, bool p_invert = false) = 0; - virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, real_t p_blend_skirt = 0.1); + virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false) 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) const; }; #endif // NOISE_H diff --git a/modules/noise/noise_texture.cpp b/modules/noise/noise_texture.cpp index 276335797a..2b35e00906 100644 --- a/modules/noise/noise_texture.cpp +++ b/modules/noise/noise_texture.cpp @@ -47,15 +47,22 @@ NoiseTexture::~NoiseTexture() { } void NoiseTexture::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture); + ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture); + ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done); + ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture::set_width); ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture::set_height); - ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise); - ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise); - ClassDB::bind_method(D_METHOD("set_invert", "invert"), &NoiseTexture::set_invert); ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture::get_invert); + ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &NoiseTexture::set_in_3d_space); + ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture::is_in_3d_space); + + ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture::set_generate_mipmaps); + ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture::is_generating_mipmaps); + ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless); ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless); @@ -68,17 +75,22 @@ void NoiseTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength); ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength); - ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture); - ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture); - ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done); + ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture::set_color_ramp); + ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture::get_color_ramp); + + ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise); + ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise); ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert"), "set_invert", "get_invert"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "is_generating_mipmaps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "seamless"), "set_seamless", "get_seamless"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "seamless_blend_skirt", PROPERTY_HINT_RANGE, "0.05,1,0.001"), "set_seamless_blend_skirt", "get_seamless_blend_skirt"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normal_map"), "set_as_normal_map", "is_normal_map"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise"); } @@ -143,18 +155,42 @@ Ref<Image> NoiseTexture::_generate_texture() { Ref<Image> image; if (seamless) { - image = ref_noise->get_seamless_image(size.x, size.y, invert, seamless_blend_skirt); + image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt); } else { - image = ref_noise->get_image(size.x, size.y, invert); + image = ref_noise->get_image(size.x, size.y, invert, in_3d_space); + } + if (color_ramp.is_valid()) { + image = _modulate_with_gradient(image, color_ramp); } - if (as_normal_map) { image->bump_map_to_normal_map(bump_strength); } + if (generate_mipmaps) { + image->generate_mipmaps(); + } return image; } +Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) { + int width = p_image->get_width(); + int height = p_image->get_height(); + + Ref<Image> new_image; + new_image.instantiate(); + new_image->create(width, height, false, Image::FORMAT_RGBA8); + + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + Color pixel_color = p_image->get_pixel(col, row); + Color ramp_color = color_ramp->get_color_at_offset(pixel_color.get_luminance()); + new_image->set_pixel(col, row, ramp_color); + } + } + + return new_image; +} + void NoiseTexture::_update_texture() { bool use_thread = true; if (first_time) { @@ -227,6 +263,29 @@ bool NoiseTexture::get_invert() const { return invert; } +void NoiseTexture::set_in_3d_space(bool p_enable) { + if (p_enable == in_3d_space) { + return; + } + in_3d_space = p_enable; + _queue_update(); +} +bool NoiseTexture::is_in_3d_space() const { + return in_3d_space; +} + +void NoiseTexture::set_generate_mipmaps(bool p_enable) { + if (p_enable == generate_mipmaps) { + return; + } + generate_mipmaps = p_enable; + _queue_update(); +} + +bool NoiseTexture::is_generating_mipmaps() const { + return generate_mipmaps; +} + void NoiseTexture::set_seamless(bool p_seamless) { if (p_seamless == seamless) { return; @@ -278,6 +337,24 @@ float NoiseTexture::get_bump_strength() { return bump_strength; } +void NoiseTexture::set_color_ramp(const Ref<Gradient> &p_gradient) { + if (p_gradient == color_ramp) { + return; + } + if (color_ramp.is_valid()) { + color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update)); + } + color_ramp = p_gradient; + if (color_ramp.is_valid()) { + color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update)); + } + _queue_update(); +} + +Ref<Gradient> NoiseTexture::get_color_ramp() const { + return color_ramp; +} + int NoiseTexture::get_width() const { return size.x; } diff --git a/modules/noise/noise_texture.h b/modules/noise/noise_texture.h index 2a94df39d4..6c088562a1 100644 --- a/modules/noise/noise_texture.h +++ b/modules/noise/noise_texture.h @@ -51,15 +51,18 @@ private: mutable RID texture; uint32_t flags = 0; - Ref<Noise> noise; + Size2i size = Size2i(512, 512); bool invert = false; - Vector2i size = Vector2i(512, 512); - Vector2 noise_offset; + bool in_3d_space = false; + bool generate_mipmaps = true; bool seamless = false; real_t seamless_blend_skirt = 0.1; bool as_normal_map = false; float bump_strength = 8.0; + Ref<Gradient> color_ramp; + Ref<Noise> noise; + void _thread_done(const Ref<Image> &p_image); static void _thread_function(void *p_ud); @@ -68,6 +71,8 @@ private: void _update_texture(); void _set_texture_image(const Ref<Image> &p_image); + Ref<Image> _modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient); + protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; @@ -82,6 +87,12 @@ public: void set_invert(bool p_invert); bool get_invert() const; + void set_in_3d_space(bool p_enable); + bool is_in_3d_space() const; + + void set_generate_mipmaps(bool p_enable); + bool is_generating_mipmaps() const; + void set_seamless(bool p_seamless); bool get_seamless(); @@ -94,6 +105,9 @@ public: void set_bump_strength(float p_bump_strength); float get_bump_strength(); + void set_color_ramp(const Ref<Gradient> &p_gradient); + Ref<Gradient> get_color_ramp() const; + int get_width() const override; int get_height() const override; diff --git a/modules/noise/register_types.cpp b/modules/noise/register_types.cpp index 81bb0317c1..3623da3bb9 100644 --- a/modules/noise/register_types.cpp +++ b/modules/noise/register_types.cpp @@ -34,10 +34,19 @@ #include "noise.h" #include "noise_texture.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_plugin.h" +#include "editor/noise_editor_plugin.h" +#endif + void register_noise_types() { GDREGISTER_CLASS(NoiseTexture); GDREGISTER_ABSTRACT_CLASS(Noise); GDREGISTER_CLASS(FastNoiseLite); + +#ifdef TOOLS_ENABLED + EditorPlugins::add_by_type<NoiseEditorPlugin>(); +#endif } void unregister_noise_types() { |