Blender V4.3
node_shader_tex_white_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
7#include "BLI_noise.hh"
8
10
11#include "NOD_multi_function.hh"
12
13#include "UI_interface.hh"
14#include "UI_resources.hh"
15
17
19{
20 b.is_function_node();
21 b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f).implicit_field(
23 b.add_input<decl::Float>("W")
24 .min(-10000.0f)
25 .max(10000.0f)
26 .make_available([](bNode &node) {
27 /* Default to 1 instead of 4, because it is faster. */
28 node.custom1 = 1;
29 })
30 .description("Value used as seed in 1D and 4D dimensions");
31 b.add_output<decl::Float>("Value");
32 b.add_output<decl::Color>("Color");
33}
34
36{
37 uiItemR(layout, ptr, "noise_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
38}
39
40static void node_shader_init_tex_white_noise(bNodeTree * /*ntree*/, bNode *node)
41{
42 node->custom1 = 3;
43}
44
45static const char *gpu_shader_get_name(const int dimensions)
46{
47 BLI_assert(dimensions >= 1 && dimensions <= 4);
48 return std::array{"node_white_noise_1d",
49 "node_white_noise_2d",
50 "node_white_noise_3d",
51 "node_white_noise_4d"}[dimensions - 1];
52}
53
55 bNode *node,
56 bNodeExecData * /*execdata*/,
57 GPUNodeStack *in,
58 GPUNodeStack *out)
59{
60 const char *name = gpu_shader_get_name(node->custom1);
61 return GPU_stack_link(mat, node, name, in, out);
62}
63
65{
66 bNodeSocket *sockVector = bke::node_find_socket(node, SOCK_IN, "Vector");
67 bNodeSocket *sockW = bke::node_find_socket(node, SOCK_IN, "W");
68
69 bke::node_set_socket_availability(ntree, sockVector, node->custom1 != 1);
70 bke::node_set_socket_availability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4);
71}
72
73class WhiteNoiseFunction : public mf::MultiFunction {
74 private:
75 int dimensions_;
76
77 public:
78 WhiteNoiseFunction(int dimensions) : dimensions_(dimensions)
79 {
80 BLI_assert(dimensions >= 1 && dimensions <= 4);
81 static std::array<mf::Signature, 4> signatures{
86 };
87 this->set_signature(&signatures[dimensions - 1]);
88 }
89
90 static mf::Signature create_signature(int dimensions)
91 {
92 mf::Signature signature;
93 mf::SignatureBuilder builder{"WhiteNoise", signature};
94
95 if (ELEM(dimensions, 2, 3, 4)) {
96 builder.single_input<float3>("Vector");
97 }
98 if (ELEM(dimensions, 1, 4)) {
99 builder.single_input<float>("W");
100 }
101
102 builder.single_output<float>("Value", mf::ParamFlag::SupportsUnusedOutput);
103 builder.single_output<ColorGeometry4f>("Color", mf::ParamFlag::SupportsUnusedOutput);
104
105 return signature;
106 }
107
108 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
109 {
110 int param = ELEM(dimensions_, 2, 3, 4) + ELEM(dimensions_, 1, 4);
111
112 MutableSpan<float> r_value = params.uninitialized_single_output_if_required<float>(param++,
113 "Value");
115 params.uninitialized_single_output_if_required<ColorGeometry4f>(param++, "Color");
116
117 const bool compute_value = !r_value.is_empty();
118 const bool compute_color = !r_color.is_empty();
119
120 switch (dimensions_) {
121 case 1: {
122 const VArray<float> &w = params.readonly_single_input<float>(0, "W");
123 if (compute_color) {
124 mask.foreach_index([&](const int64_t i) {
126 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
127 });
128 }
129 if (compute_value) {
130 mask.foreach_index(
131 [&](const int64_t i) { r_value[i] = noise::hash_float_to_float(w[i]); });
132 }
133 break;
134 }
135 case 2: {
136 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
137 if (compute_color) {
138 mask.foreach_index([&](const int64_t i) {
140 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
141 });
142 }
143 if (compute_value) {
144 mask.foreach_index([&](const int64_t i) {
145 r_value[i] = noise::hash_float_to_float(float2(vector[i].x, vector[i].y));
146 });
147 }
148 break;
149 }
150 case 3: {
151 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
152 if (compute_color) {
153 mask.foreach_index([&](const int64_t i) {
155 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
156 });
157 }
158 if (compute_value) {
159 mask.foreach_index(
160 [&](const int64_t i) { r_value[i] = noise::hash_float_to_float(vector[i]); });
161 }
162 break;
163 }
164 case 4: {
165 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
166 const VArray<float> &w = params.readonly_single_input<float>(1, "W");
167 if (compute_color) {
168 mask.foreach_index([&](const int64_t i) {
170 float4(vector[i].x, vector[i].y, vector[i].z, w[i]));
171 r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
172 });
173 }
174 if (compute_value) {
175 mask.foreach_index([&](const int64_t i) {
176 r_value[i] = noise::hash_float_to_float(
177 float4(vector[i].x, vector[i].y, vector[i].z, w[i]));
178 });
179 }
180 break;
181 }
182 }
183 }
184};
185
187{
188 const bNode &node = builder.node();
190}
191
193#ifdef WITH_MATERIALX
194{
195 /* MaterialX cellnoise node rounds float value of texture coordinate.
196 * Therefore it changes at different integer coordinates.
197 * The simple trick would be to multiply the texture coordinate by a large number. */
198 const float LARGE_NUMBER = 10000.0f;
199
200 NodeItem noise = empty();
201 NodeItem vector = empty();
202 NodeItem w = empty();
203
204 int dimension = node_->custom1;
205 switch (dimension) {
206 case 1:
207 w = get_input_value("W", NodeItem::Type::Vector2);
208 noise = create_node(
209 "cellnoise2d", NodeItem::Type::Float, {{"texcoord", w * val(LARGE_NUMBER)}});
210 break;
211 case 2:
212 vector = get_input_link("Vector", NodeItem::Type::Vector2);
213 if (!vector) {
214 vector = texcoord_node();
215 }
216 noise = create_node(
217 "cellnoise2d", NodeItem::Type::Float, {{"texcoord", vector * val(LARGE_NUMBER)}});
218 break;
219 case 3:
220 vector = get_input_link("Vector", NodeItem::Type::Vector3);
221 if (!vector) {
222 vector = texcoord_node(NodeItem::Type::Vector3);
223 }
224 noise = create_node(
225 "cellnoise3d", NodeItem::Type::Float, {{"position", vector * val(LARGE_NUMBER)}});
226 break;
227 case 4:
228 vector = get_input_link("Vector", NodeItem::Type::Vector3);
229 if (!vector) {
230 vector = texcoord_node(NodeItem::Type::Vector3);
231 }
232 w = get_input_value("W", NodeItem::Type::Float);
233 noise = create_node(
234 "cellnoise3d", NodeItem::Type::Float, {{"position", (vector + w) * val(LARGE_NUMBER)}});
235 break;
236 default:
238 break;
239 }
240
241 if (STREQ(socket_out_->name, "Value")) {
242 return noise;
243 }
244
245 /* NOTE: cellnoise node doesn't have colored output, so we create hsvtorgb node and put
246 * noise in first (Hue) channel to generate color. */
247 NodeItem combine = create_node("combine3",
248 NodeItem::Type::Color3,
249 {{"in1", noise}, {"in2", val(1.0f)}, {"in3", val(0.5f)}});
250 return create_node("hsvtorgb", NodeItem::Type::Color3, {{"in", combine}});
251}
252#endif
254
255} // namespace blender::nodes::node_shader_tex_white_noise_cc
256
258{
260
261 static blender::bke::bNodeType ntype;
262
263 sh_fn_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE);
264 ntype.declare = file_ns::sh_node_tex_white_noise_declare;
265 ntype.draw_buttons = file_ns::node_shader_buts_white_noise;
266 ntype.initfunc = file_ns::node_shader_init_tex_white_noise;
267 ntype.gpu_fn = file_ns::gpu_shader_tex_white_noise;
268 ntype.updatefunc = file_ns::node_shader_update_tex_white_noise;
269 ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
270 ntype.materialx_fn = file_ns::node_shader_materialx;
271
273}
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:414
#define SH_NODE_TEX_WHITE_NOISE
Definition BKE_node.hh:987
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ELEM(...)
#define STREQ(a, b)
@ SOCK_IN
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a vector
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 & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr bool is_empty() const
Definition BLI_span.hh:510
void set_signature(const Signature *signature)
void make_available(bNode &node) const
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 mask, const float4 a)
void node_set_socket_availability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
Definition node.cc:3911
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
void position(const bNode &, void *r_value)
static const char * gpu_shader_get_name(const int dimensions)
static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
static void node_shader_buts_white_noise(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node)
static int gpu_shader_tex_white_noise(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
static void node_shader_init_tex_white_noise(bNodeTree *, bNode *node)
float hash_float_to_float(float k)
Definition noise.cc:188
float3 hash_float_to_float3(float k)
Definition noise.cc:225
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
#define NODE_SHADER_MATERIALX_BEGIN
#define NODE_SHADER_MATERIALX_END
void register_node_type_sh_tex_white_noise()
void sh_fn_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
#define min(a, b)
Definition sort.c:32
__int64 int64_t
Definition stdint.h:89
int16_t custom1
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