1
0
mirror of https://github.com/godotengine/godot synced 2024-07-03 06:53:36 +00:00

[Noise/NoiseTexture2D] Allow disabling normalization

This commit is contained in:
Hendrik Brucker 2023-01-29 14:56:10 +01:00
parent d01ac9c736
commit d44eb95e93
6 changed files with 76 additions and 37 deletions

View File

@ -17,8 +17,10 @@
<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 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].
</description>
</method>
<method name="get_noise_1d" qualifiers="const">
@ -66,8 +68,10 @@
<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 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].
</description>
</method>
</methods>

View File

@ -44,6 +44,10 @@
<member name="noise" type="Noise" setter="set_noise" getter="get_noise">
The instance of the [Noise] object.
</member>
<member name="normalize" type="bool" setter="set_normalize" getter="is_normalized" default="true">
If [code]true[/code], the noise image coming from the noise generator is normalized to the range [code]0.0[/code] to [code]1.0[/code].
Turning normalization off can affect the contrast and allows you to generate non repeating tileable noise textures.
</member>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
If [code]true[/code], a seamless texture is requested from the [Noise] resource.

View File

@ -32,7 +32,7 @@
#include <float.h>
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 {
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 {
ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
int skirt_width = MAX(1, p_width * p_blend_skirt);
@ -40,7 +40,7 @@ Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, b
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, p_in_3d_space);
Ref<Image> src = get_image(src_width, src_height, 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);
@ -58,7 +58,7 @@ 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 {
Ref<Image> Noise::get_image(int p_width, int p_height, 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;
@ -66,38 +66,49 @@ Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_
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 = 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, 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];
if (p_normalize) {
// Get all values and identify min/max values.
Vector<real_t> values;
values.resize(p_width * p_height);
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, 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 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));
}
// 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 (p_invert) {
ivalue = 255 - ivalue;
}
wd8[x] = value;
wd8[x] = ivalue;
}
}
} 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, 0.0) : 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;
}
}
}
@ -113,6 +124,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", "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));
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));
}

View File

@ -233,8 +233,8 @@ 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, 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;
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 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;
};
#endif // NOISE_H

View File

@ -76,6 +76,9 @@ void NoiseTexture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture2D::set_bump_strength);
ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture2D::get_bump_strength);
ClassDB::bind_method(D_METHOD("set_normalize", "normalize"), &NoiseTexture2D::set_normalize);
ClassDB::bind_method(D_METHOD("is_normalized"), &NoiseTexture2D::is_normalized);
ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture2D::set_color_ramp);
ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture2D::get_color_ramp);
@ -91,6 +94,7 @@ void NoiseTexture2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "seamless_blend_skirt", PROPERTY_HINT_RANGE, "0,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::BOOL, "normalize"), "set_normalize", "is_normalized");
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");
}
@ -156,9 +160,9 @@ Ref<Image> NoiseTexture2D::_generate_texture() {
Ref<Image> new_image;
if (seamless) {
new_image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt);
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, invert, in_3d_space);
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);
@ -349,6 +353,18 @@ void NoiseTexture2D::set_color_ramp(const Ref<Gradient> &p_gradient) {
_queue_update();
}
void NoiseTexture2D::set_normalize(bool p_normalize) {
if (normalize == p_normalize) {
return;
}
normalize = p_normalize;
_queue_update();
}
bool NoiseTexture2D::is_normalized() const {
return normalize;
}
Ref<Gradient> NoiseTexture2D::get_color_ramp() const {
return color_ramp;
}

View File

@ -59,6 +59,7 @@ private:
real_t seamless_blend_skirt = 0.1;
bool as_normal_map = false;
float bump_strength = 8.0;
bool normalize = true;
Ref<Gradient> color_ramp;
Ref<Noise> noise;
@ -105,6 +106,9 @@ public:
void set_bump_strength(float p_bump_strength);
float get_bump_strength();
void set_normalize(bool p_normalize);
bool is_normalized() const;
void set_color_ramp(const Ref<Gradient> &p_gradient);
Ref<Gradient> get_color_ramp() const;