Browse Source

[Noise/NoiseTexture2D] Allow disabling normalization

Hendrik Brucker 2 years ago
parent
commit
d44eb95e93

+ 4 - 0
modules/noise/doc_classes/Noise.xml

@@ -17,8 +17,10 @@
 			<param index="1" name="height" type="int" />
 			<param index="1" name="height" type="int" />
 			<param index="2" name="invert" type="bool" default="false" />
 			<param index="2" name="invert" type="bool" default="false" />
 			<param index="3" name="in_3d_space" 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>
 			<description>
 				Returns a 2D [Image] noise image.
 				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>
 			</description>
 		</method>
 		</method>
 		<method name="get_noise_1d" qualifiers="const">
 		<method name="get_noise_1d" qualifiers="const">
@@ -66,8 +68,10 @@
 			<param index="2" name="invert" type="bool" default="false" />
 			<param index="2" name="invert" type="bool" default="false" />
 			<param index="3" name="in_3d_space" 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="4" name="skirt" type="float" default="0.1" />
+			<param index="5" name="normalize" type="bool" default="true" />
 			<description>
 			<description>
 				Returns a seamless 2D [Image] noise image.
 				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>
 			</description>
 		</method>
 		</method>
 	</methods>
 	</methods>

+ 4 - 0
modules/noise/doc_classes/NoiseTexture2D.xml

@@ -44,6 +44,10 @@
 		<member name="noise" type="Noise" setter="set_noise" getter="get_noise">
 		<member name="noise" type="Noise" setter="set_noise" getter="get_noise">
 			The instance of the [Noise] object.
 			The instance of the [Noise] object.
 		</member>
 		</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="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">
 		<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.
 			If [code]true[/code], a seamless texture is requested from the [Noise] resource.

+ 44 - 33
modules/noise/noise.cpp

@@ -32,7 +32,7 @@
 
 
 #include <float.h>
 #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>());
 	ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
 
 
 	int skirt_width = MAX(1, p_width * p_blend_skirt);
 	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_width = p_width + skirt_width;
 	int src_height = p_height + skirt_height;
 	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);
 	bool grayscale = (src->get_format() == Image::FORMAT_L8);
 	if (grayscale) {
 	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_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);
 	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>());
 	ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
 
 
 	Vector<uint8_t> data;
 	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();
 	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 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));
+		// 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;
+				}
+
+				wd8[x] = ivalue;
 			}
 			}
-			if (p_invert) {
-				value = 255 - value;
+		}
+	} 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;
 			}
 			}
-
-			wd8[x] = value;
 		}
 		}
 	}
 	}
 
 
@@ -113,6 +124,6 @@ void Noise::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv);
 	ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv);
 
 
 	// Textures.
 	// 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));
 }
 }

+ 2 - 2
modules/noise/noise.h

@@ -233,8 +233,8 @@ public:
 	virtual real_t get_noise_3dv(Vector3 p_v) const = 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 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
 #endif // NOISE_H

+ 18 - 2
modules/noise/noise_texture_2d.cpp

@@ -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("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("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("set_color_ramp", "gradient"), &NoiseTexture2D::set_color_ramp);
 	ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture2D::get_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::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::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::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, "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");
 	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;
 	Ref<Image> new_image;
 
 
 	if (seamless) {
 	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 {
 	} 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()) {
 	if (color_ramp.is_valid()) {
 		new_image = _modulate_with_gradient(new_image, color_ramp);
 		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();
 	_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 {
 Ref<Gradient> NoiseTexture2D::get_color_ramp() const {
 	return color_ramp;
 	return color_ramp;
 }
 }

+ 4 - 0
modules/noise/noise_texture_2d.h

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