Blender V4.3
node_shader_tex_noise.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "node_shader_util.hh"
6#include "node_util.hh"
7
8#include "BKE_texture.h"
9
10#include "BLI_noise.hh"
11
12#include "NOD_multi_function.hh"
13
14#include "RNA_access.hh"
15
16#include "UI_interface.hh"
17#include "UI_resources.hh"
18
20
22
24{
25 b.is_function_node();
26 b.add_input<decl::Vector>("Vector").implicit_field(implicit_field_inputs::position);
27 b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
28 /* Default to 1 instead of 4, because it is much faster. */
29 node_storage(node).dimensions = 1;
30 });
31 b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f).description(
32 "Scale of the base noise octave");
33 b.add_input<decl::Float>("Detail").min(0.0f).max(15.0f).default_value(2.0f).description(
34 "The number of noise octaves. Higher values give more detailed noise but increase render "
35 "time");
36 b.add_input<decl::Float>("Roughness")
37 .min(0.0f)
38 .max(1.0f)
39 .default_value(0.5f)
40 .subtype(PROP_FACTOR)
41 .description(
42 "Blend factor between an octave and its previous one. A value of zero corresponds to "
43 "zero detail");
44 b.add_input<decl::Float>("Lacunarity")
45 .min(0.0f)
46 .max(1000.0f)
47 .default_value(2.0f)
48 .description(
49 "The difference between the scale of each two consecutive octaves. Larger values "
50 "corresponds to larger scale for higher octaves");
51 b.add_input<decl::Float>("Offset")
52 .min(-1000.0f)
53 .max(1000.0f)
54 .default_value(0.0f)
55 .make_available([](bNode &node) { node_storage(node).type = SHD_NOISE_RIDGED_MULTIFRACTAL; })
56 .description(
57 "An added offset to each octave, determines the level where the highest octave will "
58 "appear");
59 b.add_input<decl::Float>("Gain")
60 .min(0.0f)
61 .max(1000.0f)
62 .default_value(1.0f)
63 .make_available([](bNode &node) { node_storage(node).type = SHD_NOISE_RIDGED_MULTIFRACTAL; })
64 .description("An extra multiplier to tune the magnitude of octaves");
65 b.add_input<decl::Float>("Distortion")
66 .min(-1000.0f)
67 .max(1000.0f)
68 .default_value(0.0f)
69 .description("Amount of distortion");
70 b.add_output<decl::Float>("Fac").no_muted_links();
71 b.add_output<decl::Color>("Color").no_muted_links();
72}
73
75{
76 uiItemR(layout, ptr, "noise_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
77 uiItemR(layout, ptr, "noise_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
78 if (ELEM(RNA_enum_get(ptr, "noise_type"), SHD_NOISE_FBM)) {
79 uiItemR(layout, ptr, "normalize", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
80 }
81}
82
83static void node_shader_init_tex_noise(bNodeTree * /*ntree*/, bNode *node)
84{
85 NodeTexNoise *tex = MEM_cnew<NodeTexNoise>(__func__);
87 BKE_texture_colormapping_default(&tex->base.color_mapping);
88 tex->dimensions = 3;
90 tex->normalize = true;
91
92 node->storage = tex;
93}
94
95static const char *gpu_shader_get_name(const int dimensions, const int type)
96{
97 BLI_assert(dimensions > 0 && dimensions < 5);
98 BLI_assert(type >= 0 && type < 5);
99
100 switch (type) {
102 return std::array{"node_noise_tex_multi_fractal_1d",
103 "node_noise_tex_multi_fractal_2d",
104 "node_noise_tex_multi_fractal_3d",
105 "node_noise_tex_multi_fractal_4d"}[dimensions - 1];
106 case SHD_NOISE_FBM:
107 return std::array{"node_noise_tex_fbm_1d",
108 "node_noise_tex_fbm_2d",
109 "node_noise_tex_fbm_3d",
110 "node_noise_tex_fbm_4d"}[dimensions - 1];
112 return std::array{"node_noise_tex_hybrid_multi_fractal_1d",
113 "node_noise_tex_hybrid_multi_fractal_2d",
114 "node_noise_tex_hybrid_multi_fractal_3d",
115 "node_noise_tex_hybrid_multi_fractal_4d"}[dimensions - 1];
117 return std::array{"node_noise_tex_ridged_multi_fractal_1d",
118 "node_noise_tex_ridged_multi_fractal_2d",
119 "node_noise_tex_ridged_multi_fractal_3d",
120 "node_noise_tex_ridged_multi_fractal_4d"}[dimensions - 1];
122 return std::array{"node_noise_tex_hetero_terrain_1d",
123 "node_noise_tex_hetero_terrain_2d",
124 "node_noise_tex_hetero_terrain_3d",
125 "node_noise_tex_hetero_terrain_4d"}[dimensions - 1];
126 }
127 return nullptr;
128}
129
131 bNode *node,
132 bNodeExecData * /*execdata*/,
133 GPUNodeStack *in,
134 GPUNodeStack *out)
135{
136 node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
137 node_shader_gpu_tex_mapping(mat, node, in, out);
138
139 const NodeTexNoise &storage = node_storage(*node);
140 float normalize = storage.normalize;
141
142 const char *name = gpu_shader_get_name(storage.dimensions, storage.type);
143 return GPU_stack_link(mat, node, name, in, out, GPU_constant(&normalize));
144}
145
147{
148 bNodeSocket *sockVector = bke::node_find_socket(node, SOCK_IN, "Vector");
149 bNodeSocket *sockW = bke::node_find_socket(node, SOCK_IN, "W");
150 bNodeSocket *inOffsetSock = bke::node_find_socket(node, SOCK_IN, "Offset");
151 bNodeSocket *inGainSock = bke::node_find_socket(node, SOCK_IN, "Gain");
152
153 const NodeTexNoise &storage = node_storage(*node);
154 bke::node_set_socket_availability(ntree, sockVector, storage.dimensions != 1);
156 ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4);
158 inOffsetSock,
159 storage.type != SHD_NOISE_MULTIFRACTAL &&
160 storage.type != SHD_NOISE_FBM);
162 inGainSock,
165}
166
168 private:
169 int dimensions_;
170 int type_;
171 bool normalize_;
172
173 public:
207
208 static mf::Signature create_signature(int dimensions, int type)
209 {
211 mf::SignatureBuilder builder{"Noise", signature};
212
213 if (ELEM(dimensions, 2, 3, 4)) {
214 builder.single_input<float3>("Vector");
215 }
216 if (ELEM(dimensions, 1, 4)) {
217 builder.single_input<float>("W");
218 }
219
220 builder.single_input<float>("Scale");
221 builder.single_input<float>("Detail");
222 builder.single_input<float>("Roughness");
223 builder.single_input<float>("Lacunarity");
224 if (ELEM(type,
228 {
229 builder.single_input<float>("Offset");
230 }
232 builder.single_input<float>("Gain");
233 }
234 builder.single_input<float>("Distortion");
235
236 builder.single_output<float>("Fac", mf::ParamFlag::SupportsUnusedOutput);
237 builder.single_output<ColorGeometry4f>("Color", mf::ParamFlag::SupportsUnusedOutput);
238
239 return signature;
240 }
241
242 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
243 {
244 int param = ELEM(dimensions_, 2, 3, 4) + ELEM(dimensions_, 1, 4);
245 const VArray<float> &scale = params.readonly_single_input<float>(param++, "Scale");
246 const VArray<float> &detail = params.readonly_single_input<float>(param++, "Detail");
247 const VArray<float> &roughness = params.readonly_single_input<float>(param++, "Roughness");
248 const VArray<float> &lacunarity = params.readonly_single_input<float>(param++, "Lacunarity");
249 /* Initialize to any other variable when unused to avoid unnecessary conditionals. */
250 const VArray<float> &offset = ELEM(type_,
254 params.readonly_single_input<float>(param++, "Offset") :
255 scale;
256 /* Initialize to any other variable when unused to avoid unnecessary conditionals. */
257 const VArray<float> &gain = ELEM(type_,
260 params.readonly_single_input<float>(param++, "Gain") :
261 scale;
262 const VArray<float> &distortion = params.readonly_single_input<float>(param++, "Distortion");
263
264 MutableSpan<float> r_factor = params.uninitialized_single_output_if_required<float>(param++,
265 "Fac");
267 params.uninitialized_single_output_if_required<ColorGeometry4f>(param++, "Color");
268
269 const bool compute_factor = !r_factor.is_empty();
270 const bool compute_color = !r_color.is_empty();
271
272 switch (dimensions_) {
273 case 1: {
274 const VArray<float> &w = params.readonly_single_input<float>(0, "W");
275 if (compute_factor) {
276 mask.foreach_index([&](const int64_t i) {
277 const float position = w[i] * scale[i];
278 r_factor[i] = noise::perlin_fractal_distorted(position,
279 math::clamp(detail[i], 0.0f, 15.0f),
280 math::max(roughness[i], 0.0f),
281 lacunarity[i],
282 offset[i],
283 gain[i],
284 distortion[i],
285 type_,
286 normalize_);
287 });
288 }
289 if (compute_color) {
290 mask.foreach_index([&](const int64_t i) {
291 const float position = w[i] * scale[i];
293 position,
294 math::clamp(detail[i], 0.0f, 15.0f),
295 math::max(roughness[i], 0.0f),
296 lacunarity[i],
297 offset[i],
298 gain[i],
299 distortion[i],
300 type_,
301 normalize_);
302 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
303 });
304 }
305 break;
306 }
307 case 2: {
308 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
309 if (compute_factor) {
310 mask.foreach_index([&](const int64_t i) {
311 const float2 position = float2(vector[i] * scale[i]);
312 r_factor[i] = noise::perlin_fractal_distorted(position,
313 math::clamp(detail[i], 0.0f, 15.0f),
314 math::max(roughness[i], 0.0f),
315 lacunarity[i],
316 offset[i],
317 gain[i],
318 distortion[i],
319 type_,
320 normalize_);
321 });
322 }
323 if (compute_color) {
324 mask.foreach_index([&](const int64_t i) {
325 const float2 position = float2(vector[i] * scale[i]);
327 position,
328 math::clamp(detail[i], 0.0f, 15.0f),
329 math::max(roughness[i], 0.0f),
330 lacunarity[i],
331 offset[i],
332 gain[i],
333 distortion[i],
334 type_,
335 normalize_);
336 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
337 });
338 }
339 break;
340 }
341 case 3: {
342 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
343 if (compute_factor) {
344 mask.foreach_index([&](const int64_t i) {
345 const float3 position = vector[i] * scale[i];
346 r_factor[i] = noise::perlin_fractal_distorted(position,
347 math::clamp(detail[i], 0.0f, 15.0f),
348 math::max(roughness[i], 0.0f),
349 lacunarity[i],
350 offset[i],
351 gain[i],
352 distortion[i],
353 type_,
354 normalize_);
355 });
356 }
357 if (compute_color) {
358 mask.foreach_index([&](const int64_t i) {
359 const float3 position = vector[i] * scale[i];
361 position,
362 math::clamp(detail[i], 0.0f, 15.0f),
363 math::max(roughness[i], 0.0f),
364 lacunarity[i],
365 offset[i],
366 gain[i],
367 distortion[i],
368 type_,
369 normalize_);
370 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
371 });
372 }
373 break;
374 }
375 case 4: {
376 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
377 const VArray<float> &w = params.readonly_single_input<float>(1, "W");
378 if (compute_factor) {
379 mask.foreach_index([&](const int64_t i) {
380 const float3 position_vector = vector[i] * scale[i];
381 const float position_w = w[i] * scale[i];
382 const float4 position{
383 position_vector[0], position_vector[1], position_vector[2], position_w};
384 r_factor[i] = noise::perlin_fractal_distorted(position,
385 math::clamp(detail[i], 0.0f, 15.0f),
386 math::max(roughness[i], 0.0f),
387 lacunarity[i],
388 offset[i],
389 gain[i],
390 distortion[i],
391 type_,
392 normalize_);
393 });
394 }
395 if (compute_color) {
396 mask.foreach_index([&](const int64_t i) {
397 const float3 position_vector = vector[i] * scale[i];
398 const float position_w = w[i] * scale[i];
399 const float4 position{
400 position_vector[0], position_vector[1], position_vector[2], position_w};
402 position,
403 math::clamp(detail[i], 0.0f, 15.0f),
404 math::max(roughness[i], 0.0f),
405 lacunarity[i],
406 offset[i],
407 gain[i],
408 distortion[i],
409 type_,
410 normalize_);
411 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
412 });
413 }
414 break;
415 }
416 }
417 }
418
420 {
421 ExecutionHints hints;
422 hints.allocates_array = false;
423 hints.min_grain_size = 100;
424 return hints;
425 }
426};
427
429{
430 const NodeTexNoise &storage = node_storage(builder.node());
432 storage.dimensions, storage.type, storage.normalize);
433}
434
436#ifdef WITH_MATERIALX
437{
438 /* NOTE: Some inputs aren't supported by MaterialX. */
439 NodeItem scale = get_input_value("Scale", NodeItem::Type::Float);
440 NodeItem detail = get_input_default("Detail", NodeItem::Type::Float);
441 NodeItem lacunarity = get_input_value("Lacunarity", NodeItem::Type::Float);
442
443 NodeItem position = create_node("position", NodeItem::Type::Vector3);
444 position = position * scale;
445
446 return create_node("fractal3d",
447 STREQ(socket_out_->identifier, "Fac") ? NodeItem::Type::Float :
448 NodeItem::Type::Color3,
449 {{"position", position},
450 {"octaves", val(int(detail.value->asA<float>()))},
451 {"lacunarity", lacunarity}});
452}
453#endif
455
456} // namespace blender::nodes::node_shader_tex_noise_cc
457
459{
461
462 static blender::bke::bNodeType ntype;
463
465 ntype.declare = file_ns::sh_node_tex_noise_declare;
466 ntype.draw_buttons = file_ns::node_shader_buts_tex_noise;
467 ntype.initfunc = file_ns::node_shader_init_tex_noise;
470 ntype.gpu_fn = file_ns::node_shader_gpu_tex_noise;
471 ntype.updatefunc = file_ns::node_shader_update_tex_noise;
472 ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
473 ntype.materialx_fn = file_ns::node_shader_materialx;
474
476}
#define SH_NODE_TEX_NOISE
Definition BKE_node.hh:936
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:414
void BKE_texture_mapping_default(struct TexMapping *texmap, int type)
Definition texture.cc:247
void BKE_texture_colormapping_default(struct ColorMapping *colormap)
Definition texture.cc:350
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ELEM(...)
#define STREQ(a, b)
@ SOCK_IN
@ SHD_NOISE_HYBRID_MULTIFRACTAL
@ SHD_NOISE_FBM
@ SHD_NOISE_MULTIFRACTAL
@ SHD_NOISE_RIDGED_MULTIFRACTAL
@ SHD_NOISE_HETERO_TERRAIN
@ TEXMAP_TYPE_POINT
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_constant(const float *num)
@ PROP_FACTOR
Definition RNA_types.hh:154
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
void set_signature(const Signature *signature)
void make_available(bNode &node) const
static mf::Signature create_signature(int dimensions, int type)
NoiseFunction(int dimensions, int type, bool normalize)
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_set_socket_availability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
Definition node.cc:3911
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
bNodeSocket * node_find_socket(bNode *node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:1829
T clamp(const T &a, const T &min, const T &max)
T max(const T &a, const T &b)
void position(const bNode &, void *r_value)
static const char * gpu_shader_get_name(const int dimensions, const int type)
static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
static void node_shader_buts_tex_noise(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_shader_init_tex_noise(bNodeTree *, bNode *node)
static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node)
static int node_shader_gpu_tex_noise(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
float3 perlin_float3_fractal_distorted(float position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
Definition noise.cc:886
float perlin_fractal_distorted(T position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
Definition noise.cc:832
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
#define NODE_SHADER_MATERIALX_BEGIN
#define NODE_SHADER_MATERIALX_END
void register_node_type_sh_tex_noise()
void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *)
void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
void sh_fn_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
int RNA_enum_get(PointerRNA *ptr, const char *name)
#define min(a, b)
Definition sort.c:32
__int64 int64_t
Definition stdint.h:89
Defines a node type.
Definition BKE_node.hh:218
NodeMaterialXFunction materialx_fn
Definition BKE_node.hh:320
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:318
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:336
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:257
PointerRNA * ptr
Definition wm_files.cc:4126