This path merges the Musgrave and Noise Texture nodes into a single combined Noise Texture node. The reasoning is that both nodes intrinsically do the same thing, which is the layering of Perlin noise derivatives to produce fractal noise. So the patch de-duplicates code and unifies the use of fractal noise for the end use. Since the Noise node had a Distortion input and a Color output, while the Musgrave node did not, those are now available to the Musgrave types as new functionalities. The Dimension input of the Musgrave node is analogous to the Roughness input of the Noise node, so both inputs were unified to follow the same behavior of the Roughness input, which is arguable more intuitive to control. Similarly, the Detail input was slightly different across both nodes, since the Noise node evaluated one extra layer of noise. This was also unified to follow the behavior of the Noise node. The patch, coincidentally fixes an unreported bug causing repeated output for certain noise types and another floating precision bug #112180. The versioning code implemented with this patch ensures backward compatibility for both the Musgrave and Noise Texture nodes. When opening older Blender files in Blender 4.1 the output of both nodes are guaranteed to always be exactly identical to that of Blender files created before the nodes were merged in all cases. Forward compatibility with Blender 4.0 is implemented by #114236. Forward compatibility with Blender 3.6 LTS is implemented by #115015. Pull Request: #111187
301 lines
10 KiB
Plaintext
301 lines
10 KiB
Plaintext
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
#include "node_noise.h"
|
|
#include "stdcycles.h"
|
|
#include "vector2.h"
|
|
#include "vector4.h"
|
|
|
|
#define vector3 point
|
|
|
|
#define NOISE_SELECT(T) \
|
|
float noise_select(T p, \
|
|
float detail, \
|
|
float roughness, \
|
|
float lacunarity, \
|
|
float offset, \
|
|
float gain, \
|
|
string type, \
|
|
int use_normalize) \
|
|
{ \
|
|
if (type == "multifractal") { \
|
|
return noise_multi_fractal(p, detail, roughness, lacunarity); \
|
|
} \
|
|
else if (type == "fBM") { \
|
|
return noise_fbm(p, detail, roughness, lacunarity, use_normalize); \
|
|
} \
|
|
else if (type == "hybrid_multifractal") { \
|
|
return noise_hybrid_multi_fractal(p, detail, roughness, lacunarity, offset, gain); \
|
|
} \
|
|
else if (type == "ridged_multifractal") { \
|
|
return noise_ridged_multi_fractal(p, detail, roughness, lacunarity, offset, gain); \
|
|
} \
|
|
else if (type == "hetero_terrain") { \
|
|
return noise_hetero_terrain(p, detail, roughness, lacunarity, offset); \
|
|
} \
|
|
else { \
|
|
error("Unknown Type!"); \
|
|
return 0.0; \
|
|
} \
|
|
}
|
|
|
|
/* The following offset functions generate random offsets to be added to texture
|
|
* coordinates to act as a seed since the noise functions don't have seed values.
|
|
* A seed value is needed for generating distortion textures and color outputs.
|
|
* The offset's components are in the range [100, 200], not too high to cause
|
|
* bad precision and not too small to be noticeable. We use float seed because
|
|
* OSL only support float hashes.
|
|
*/
|
|
|
|
float random_float_offset(float seed)
|
|
{
|
|
return 100.0 + noise("hash", seed) * 100.0;
|
|
}
|
|
|
|
vector2 random_vector2_offset(float seed)
|
|
{
|
|
return vector2(100.0 + noise("hash", seed, 0.0) * 100.0,
|
|
100.0 + noise("hash", seed, 1.0) * 100.0);
|
|
}
|
|
|
|
vector3 random_vector3_offset(float seed)
|
|
{
|
|
return vector3(100.0 + noise("hash", seed, 0.0) * 100.0,
|
|
100.0 + noise("hash", seed, 1.0) * 100.0,
|
|
100.0 + noise("hash", seed, 2.0) * 100.0);
|
|
}
|
|
|
|
vector4 random_vector4_offset(float seed)
|
|
{
|
|
return vector4(100.0 + noise("hash", seed, 0.0) * 100.0,
|
|
100.0 + noise("hash", seed, 1.0) * 100.0,
|
|
100.0 + noise("hash", seed, 2.0) * 100.0,
|
|
100.0 + noise("hash", seed, 3.0) * 100.0);
|
|
}
|
|
|
|
/* Noise Select */
|
|
|
|
NOISE_SELECT(float)
|
|
NOISE_SELECT(vector2)
|
|
NOISE_SELECT(vector3)
|
|
NOISE_SELECT(vector4)
|
|
|
|
float noise_texture(float co,
|
|
float detail,
|
|
float roughness,
|
|
float lacunarity,
|
|
float offset,
|
|
float gain,
|
|
float distortion,
|
|
string type,
|
|
int use_normalize,
|
|
output color Color)
|
|
{
|
|
float p = co;
|
|
if (distortion != 0.0) {
|
|
p += safe_snoise(p + random_float_offset(0.0)) * distortion;
|
|
}
|
|
|
|
float value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, use_normalize);
|
|
Color = color(value,
|
|
noise_select(p + random_float_offset(1.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize),
|
|
noise_select(p + random_float_offset(2.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize));
|
|
return value;
|
|
}
|
|
|
|
float noise_texture(vector2 co,
|
|
float detail,
|
|
float roughness,
|
|
float lacunarity,
|
|
float offset,
|
|
float gain,
|
|
float distortion,
|
|
string type,
|
|
int use_normalize,
|
|
output color Color)
|
|
{
|
|
vector2 p = co;
|
|
if (distortion != 0.0) {
|
|
p += vector2(safe_snoise(p + random_vector2_offset(0.0)) * distortion,
|
|
safe_snoise(p + random_vector2_offset(1.0)) * distortion);
|
|
}
|
|
|
|
float value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, use_normalize);
|
|
Color = color(value,
|
|
noise_select(p + random_vector2_offset(2.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize),
|
|
noise_select(p + random_vector2_offset(3.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize));
|
|
return value;
|
|
}
|
|
|
|
float noise_texture(vector3 co,
|
|
float detail,
|
|
float roughness,
|
|
float lacunarity,
|
|
float offset,
|
|
float gain,
|
|
float distortion,
|
|
string type,
|
|
int use_normalize,
|
|
output color Color)
|
|
{
|
|
vector3 p = co;
|
|
if (distortion != 0.0) {
|
|
p += vector3(safe_snoise(p + random_vector3_offset(0.0)) * distortion,
|
|
safe_snoise(p + random_vector3_offset(1.0)) * distortion,
|
|
safe_snoise(p + random_vector3_offset(2.0)) * distortion);
|
|
}
|
|
|
|
float value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, use_normalize);
|
|
Color = color(value,
|
|
noise_select(p + random_vector3_offset(3.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize),
|
|
noise_select(p + random_vector3_offset(4.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize));
|
|
return value;
|
|
}
|
|
|
|
float noise_texture(vector4 co,
|
|
float detail,
|
|
float roughness,
|
|
float lacunarity,
|
|
float offset,
|
|
float gain,
|
|
float distortion,
|
|
string type,
|
|
int use_normalize,
|
|
output color Color)
|
|
{
|
|
vector4 p = co;
|
|
if (distortion != 0.0) {
|
|
p += vector4(safe_snoise(p + random_vector4_offset(0.0)) * distortion,
|
|
safe_snoise(p + random_vector4_offset(1.0)) * distortion,
|
|
safe_snoise(p + random_vector4_offset(2.0)) * distortion,
|
|
safe_snoise(p + random_vector4_offset(3.0)) * distortion);
|
|
}
|
|
|
|
float value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, use_normalize);
|
|
Color = color(value,
|
|
noise_select(p + random_vector4_offset(4.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize),
|
|
noise_select(p + random_vector4_offset(5.0),
|
|
detail,
|
|
roughness,
|
|
lacunarity,
|
|
offset,
|
|
gain,
|
|
type,
|
|
use_normalize));
|
|
return value;
|
|
}
|
|
|
|
shader node_noise_texture(int use_mapping = 0,
|
|
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
|
string dimensions = "3D",
|
|
string type = "fBM",
|
|
int use_normalize = 1,
|
|
vector3 Vector = vector3(0, 0, 0),
|
|
float W = 0.0,
|
|
float Scale = 5.0,
|
|
float Detail = 2.0,
|
|
float Roughness = 0.5,
|
|
float Offset = 0.0,
|
|
float Gain = 1.0,
|
|
float Lacunarity = 2.0,
|
|
float Distortion = 0.0,
|
|
output float Fac = 0.0,
|
|
output color Color = 0.0)
|
|
{
|
|
vector3 p = Vector;
|
|
if (use_mapping)
|
|
p = transform(mapping, p);
|
|
|
|
float detail = clamp(Detail, 0.0, 15.0);
|
|
float roughness = max(Roughness, 0.0);
|
|
|
|
p *= Scale;
|
|
float w = W * Scale;
|
|
|
|
if (dimensions == "1D") {
|
|
Fac = noise_texture(
|
|
w, detail, roughness, Lacunarity, Offset, Gain, Distortion, type, use_normalize, Color);
|
|
}
|
|
else if (dimensions == "2D") {
|
|
Fac = noise_texture(vector2(p[0], p[1]),
|
|
detail,
|
|
roughness,
|
|
Lacunarity,
|
|
Offset,
|
|
Gain,
|
|
Distortion,
|
|
type,
|
|
use_normalize,
|
|
Color);
|
|
}
|
|
else if (dimensions == "3D") {
|
|
Fac = noise_texture(
|
|
p, detail, roughness, Lacunarity, Offset, Gain, Distortion, type, use_normalize, Color);
|
|
}
|
|
else if (dimensions == "4D") {
|
|
Fac = noise_texture(vector4(p[0], p[1], p[2], w),
|
|
detail,
|
|
roughness,
|
|
Lacunarity,
|
|
Offset,
|
|
Gain,
|
|
Distortion,
|
|
type,
|
|
use_normalize,
|
|
Color);
|
|
}
|
|
else {
|
|
error("Unknown Dimension!");
|
|
}
|
|
}
|