Blender V5.0
node_shader_tex_brick.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 <algorithm>
6
7#include "node_shader_util.hh"
8#include "node_util.hh"
9
10#include "BKE_texture.h"
11
12#include "BLI_math_vector.h"
14
15#include "NOD_multi_function.hh"
16
18#include "UI_resources.hh"
19
21
23{
24 b.is_function_node();
25 b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f).implicit_field(
27 b.add_input<decl::Color>("Color1")
28 .default_value({0.8f, 0.8f, 0.8f, 1.0f})
29 .description("Color of the first reference brick");
30 b.add_input<decl::Color>("Color2")
31 .default_value({0.2f, 0.2f, 0.2f, 1.0f})
32 .description("Color of the second reference brick");
33 b.add_input<decl::Color>("Mortar")
34 .default_value({0.0f, 0.0f, 0.0f, 1.0f})
35 .no_muted_links()
36 .description("Color of the area between bricks");
37 b.add_input<decl::Float>("Scale")
38 .min(-1000.0f)
39 .max(1000.0f)
40 .default_value(5.0f)
41 .no_muted_links()
42 .description("Scale of the texture");
43 b.add_input<decl::Float>("Mortar Size")
44 .min(0.0f)
45 .max(0.125f)
46 .default_value(0.02f)
47 .no_muted_links()
48 .description(
49 "Size of the filling between the bricks (known as \"mortar\"). "
50 "0 means no mortar");
51 b.add_input<decl::Float>("Mortar Smooth")
52 .min(0.0f)
53 .max(1.0f)
54 .default_value(0.1f)
55 .no_muted_links()
56 .description(
57 "Blurs/softens the edge between the mortar and the bricks. "
58 "This can be useful with a texture and displacement textures");
59 b.add_input<decl::Float>("Bias").min(-1.0f).max(1.0f).no_muted_links().description(
60 "The color variation between Color1 and Color2. "
61 "Values of -1 and 1 only use one of the two colors. "
62 "Values in between mix the colors");
63 b.add_input<decl::Float>("Brick Width")
64 .min(0.01f)
65 .max(100.0f)
66 .default_value(0.5f)
67 .no_muted_links()
68 .description("Ratio of brick's width relative to the texture scale");
69 b.add_input<decl::Float>("Row Height")
70 .min(0.01f)
71 .max(100.0f)
72 .default_value(0.25f)
73 .no_muted_links()
74 .description("Ratio of brick's row height relative to the texture scale");
75 b.add_output<decl::Color>("Color");
76 b.add_output<decl::Float>("Factor", "Fac");
77}
78
80{
82
83 col = &layout->column(true);
84 col->prop(
85 ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
86 col->prop(ptr, "offset_frequency", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Frequency"), ICON_NONE);
87
88 col = &layout->column(true);
89 col->prop(ptr, "squash", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Squash"), ICON_NONE);
90 col->prop(ptr, "squash_frequency", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Frequency"), ICON_NONE);
91}
92
93static void node_shader_init_tex_brick(bNodeTree * /*ntree*/, bNode *node)
94{
98
99 tex->offset = 0.5f;
100 tex->squash = 1.0f;
101 tex->offset_freq = 2;
102 tex->squash_freq = 2;
103
104 node->storage = tex;
105}
106
108 bNode *node,
109 bNodeExecData * /*execdata*/,
112{
113 node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
115 NodeTexBrick *tex = (NodeTexBrick *)node->storage;
116 float offset_freq = tex->offset_freq;
117 float squash_freq = tex->squash_freq;
118 return GPU_stack_link(mat,
119 node,
120 "node_tex_brick",
121 in,
122 out,
123 GPU_uniform(&tex->offset),
124 GPU_constant(&offset_freq),
125 GPU_uniform(&tex->squash),
126 GPU_constant(&squash_freq));
127}
128
129class BrickFunction : public mf::MultiFunction {
130 private:
131 const float offset_;
132 const int offset_freq_;
133 const float squash_;
134 const int squash_freq_;
135
136 public:
137 BrickFunction(const float offset,
138 const int offset_freq,
139 const float squash,
140 const int squash_freq)
141 : offset_(offset), offset_freq_(offset_freq), squash_(squash), squash_freq_(squash_freq)
142 {
143 static const mf::Signature signature = []() {
144 mf::Signature signature;
145 mf::SignatureBuilder builder{"BrickTexture", signature};
146 builder.single_input<float3>("Vector");
147 builder.single_input<ColorGeometry4f>("Color1");
148 builder.single_input<ColorGeometry4f>("Color2");
149 builder.single_input<ColorGeometry4f>("Mortar");
150 builder.single_input<float>("Scale");
151 builder.single_input<float>("Mortar Size");
152 builder.single_input<float>("Mortar Smooth");
153 builder.single_input<float>("Bias");
154 builder.single_input<float>("Brick Width");
155 builder.single_input<float>("Row Height");
156 builder.single_output<ColorGeometry4f>("Color", mf::ParamFlag::SupportsUnusedOutput);
157 builder.single_output<float>("Fac", mf::ParamFlag::SupportsUnusedOutput);
158 return signature;
159 }();
160 this->set_signature(&signature);
161 }
162
163 /* Fast integer noise. */
164 static float brick_noise(uint n)
165 {
166 n = (n + 1013) & 0x7fffffff;
167 n = (n >> 13) ^ n;
168 const uint nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
169 return 0.5f * (float(nn) / 1073741824.0f);
170 }
171
172 static float smoothstepf(const float f)
173 {
174 const float ff = f * f;
175 return (3.0f * ff - 2.0f * ff * f);
176 }
177
179 float mortar_size,
180 float mortar_smooth,
181 float bias,
182 float brick_width,
183 float row_height,
184 float offset_amount,
185 int offset_frequency,
186 float squash_amount,
187 int squash_frequency)
188 {
189 float offset = 0.0f;
190
191 const int rownum = int(floorf(p.y / row_height));
192
193 if (offset_frequency && squash_frequency) {
194 brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount;
195 offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount);
196 }
197
198 const int bricknum = int(floorf((p.x + offset) / brick_width));
199
200 const float x = (p.x + offset) - brick_width * bricknum;
201 const float y = p.y - row_height * rownum;
202
203 const float tint = clamp_f(
204 brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias, 0.0f, 1.0f);
205 float min_dist = std::min({x, y, brick_width - x, row_height - y});
206
207 float mortar;
208 if (min_dist >= mortar_size) {
209 mortar = 0.0f;
210 }
211 else if (mortar_smooth == 0.0f) {
212 mortar = 1.0f;
213 }
214 else {
215 min_dist = 1.0f - min_dist / mortar_size;
216 mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f;
217 }
218
219 return float2(tint, mortar);
220 }
221
222 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
223 {
224 const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
225 const VArray<ColorGeometry4f> &color1_values = params.readonly_single_input<ColorGeometry4f>(
226 1, "Color1");
227 const VArray<ColorGeometry4f> &color2_values = params.readonly_single_input<ColorGeometry4f>(
228 2, "Color2");
229 const VArray<ColorGeometry4f> &mortar_values = params.readonly_single_input<ColorGeometry4f>(
230 3, "Mortar");
231 const VArray<float> &scale = params.readonly_single_input<float>(4, "Scale");
232 const VArray<float> &mortar_size = params.readonly_single_input<float>(5, "Mortar Size");
233 const VArray<float> &mortar_smooth = params.readonly_single_input<float>(6, "Mortar Smooth");
234 const VArray<float> &bias = params.readonly_single_input<float>(7, "Bias");
235 const VArray<float> &brick_width = params.readonly_single_input<float>(8, "Brick Width");
236 const VArray<float> &row_height = params.readonly_single_input<float>(9, "Row Height");
237
239 params.uninitialized_single_output_if_required<ColorGeometry4f>(10, "Color");
240 MutableSpan<float> r_fac = params.uninitialized_single_output_if_required<float>(11, "Fac");
241
242 const bool store_fac = !r_fac.is_empty();
243 const bool store_color = !r_color.is_empty();
244
245 mask.foreach_index([&](const int64_t i) {
246 const float2 f2 = brick(vector[i] * scale[i],
247 mortar_size[i],
248 mortar_smooth[i],
249 bias[i],
250 brick_width[i],
251 row_height[i],
252 offset_,
253 offset_freq_,
254 squash_,
255 squash_freq_);
256
257 float4 color_data, color1, color2, mortar;
258 copy_v4_v4(color_data, color1_values[i]);
259 copy_v4_v4(color1, color1_values[i]);
260 copy_v4_v4(color2, color2_values[i]);
261 copy_v4_v4(mortar, mortar_values[i]);
262 const float tint = f2.x;
263 const float f = f2.y;
264
265 if (f != 1.0f) {
266 const float facm = 1.0f - tint;
267 color_data = color1 * facm + color2 * tint;
268 }
269
270 if (store_color) {
271 color_data = color_data * (1.0f - f) + mortar * f;
272 copy_v4_v4(r_color[i], color_data);
273 }
274 if (store_fac) {
275 r_fac[i] = f;
276 }
277 });
278 }
279};
280
282{
283 const bNode &node = builder.node();
284 NodeTexBrick *tex = (NodeTexBrick *)node.storage;
285
287 tex->offset, tex->offset_freq, tex->squash, tex->squash_freq);
288}
289
290} // namespace blender::nodes::node_shader_tex_brick_cc
291
293{
295
296 static blender::bke::bNodeType ntype;
297
298 common_node_type_base(&ntype, "ShaderNodeTexBrick", SH_NODE_TEX_BRICK);
299 ntype.ui_name = "Brick Texture";
300 ntype.ui_description = "Generate a procedural texture producing bricks";
301 ntype.enum_name_legacy = "TEX_BRICK";
303 ntype.declare = file_ns::sh_node_tex_brick_declare;
304 ntype.draw_buttons = file_ns::node_shader_buts_tex_brick;
306 ntype.initfunc = file_ns::node_shader_init_tex_brick;
309 ntype.gpu_fn = file_ns::node_shader_gpu_tex_brick;
310 ntype.build_multi_function = file_ns::sh_node_brick_build_multi_function;
312
314}
constexpr int NODE_DEFAULT_MAX_WIDTH
Definition BKE_node.hh:1250
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:457
#define SH_NODE_TEX_BRICK
void BKE_texture_mapping_default(struct TexMapping *texmap, int type)
Definition texture.cc:234
void BKE_texture_colormapping_default(struct ColorMapping *colormap)
Definition texture.cc:337
MINLINE float clamp_f(float value, float min, float max)
MINLINE void copy_v4_v4(float r[4], const float a[4])
unsigned int uint
#define IFACE_(msgid)
@ NODE_DEFAULT_INPUT_POSITION_FIELD
@ 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)
GPUNodeLink * GPU_uniform(const float *num)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
@ UI_ITEM_R_SLIDER
long long int int64_t
void set_signature(const Signature *signature)
BrickFunction(const float offset, const int offset_freq, const float squash, const int squash_freq)
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
static float2 brick(float3 p, float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, int offset_frequency, float squash_amount, int squash_frequency)
nullptr float
uint col
#define in
#define out
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5384
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
void node_type_size_preset(bNodeType &ntype, eNodeSizePreset size)
Definition node.cc:5396
static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder)
static void node_shader_buts_tex_brick(uiLayout *layout, bContext *, PointerRNA *ptr)
static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
static void node_shader_init_tex_brick(bNodeTree *, bNode *node)
static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
void register_node_type_sh_tex_brick()
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 common_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
#define floorf
#define min(a, b)
Definition sort.cc:36
TexMapping tex_mapping
ColorMapping color_mapping
NodeTexBase base
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:342
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:351
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeDeclareFunction declare
Definition BKE_node.hh:362
uiLayout & column(bool align)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238