Blender  V2.93
node_shader_map_range.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "node_shader_util.h"
25 
26 #include "BLI_math_base_safe.h"
27 
28 /* **************** Map Range ******************** */
30  {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
31  {SOCK_FLOAT, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
32  {SOCK_FLOAT, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
33  {SOCK_FLOAT, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
34  {SOCK_FLOAT, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
35  {SOCK_FLOAT, N_("Steps"), 4.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
36  {-1, ""},
37 };
39  {SOCK_FLOAT, N_("Result")},
40  {-1, ""},
41 };
42 
44 {
45  bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps");
47 }
48 
50 {
51  node->custom1 = true; /* use_clamp */
52  node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */
53 }
54 
55 static const char *gpu_shader_get_name(int mode)
56 {
57  switch (mode) {
59  return "map_range_linear";
61  return "map_range_stepped";
63  return "map_range_smoothstep";
65  return "map_range_smootherstep";
66  }
67 
68  return nullptr;
69 }
70 
72  bNode *node,
73  bNodeExecData *UNUSED(execdata),
74  GPUNodeStack *in,
75  GPUNodeStack *out)
76 {
77  const char *name = gpu_shader_get_name(node->custom2);
78 
79  int ret = 0;
80  if (name != nullptr) {
81  ret = GPU_stack_link(mat, node, name, in, out);
82  }
83  else {
84  ret = GPU_stack_link(mat, node, "map_range_linear", in, out);
85  }
86  if (ret && node->custom1 &&
88  GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link);
89  }
90  return ret;
91 }
92 
93 static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
94 {
95  signature->single_input<float>("Value");
96  signature->single_input<float>("From Min");
97  signature->single_input<float>("From Max");
98  signature->single_input<float>("To Min");
99  signature->single_input<float>("To Max");
100  if (use_steps) {
101  signature->single_input<float>("Steps");
102  }
103  signature->single_output<float>("Result");
104 }
105 
107  private:
108  bool clamp_;
109 
110  public:
111  MapRangeFunction(bool clamp) : clamp_(clamp)
112  {
114  this->set_signature(&signature);
115  }
116 
118  {
121  return signature.build();
122  }
123 
126  blender::fn::MFContext UNUSED(context)) const override
127  {
128  const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
129  const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
130  const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
131  const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
132  const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
133  blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
134 
135  for (int64_t i : mask) {
136  float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
137  results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
138  }
139 
140  if (clamp_) {
141  for (int64_t i : mask) {
142  results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
143  clamp_f(results[i], to_min[i], to_max[i]);
144  }
145  }
146  }
147 };
148 
150  private:
151  bool clamp_;
152 
153  public:
155  {
157  this->set_signature(&signature);
158  }
159 
161  {
162  blender::fn::MFSignatureBuilder signature{"Map Range Stepped"};
164  return signature.build();
165  }
166 
169  blender::fn::MFContext UNUSED(context)) const override
170  {
171  const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
172  const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
173  const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
174  const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
175  const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
176  const blender::VArray<float> &steps = params.readonly_single_input<float>(5, "Steps");
177  blender::MutableSpan<float> results = params.uninitialized_single_output<float>(6, "Result");
178 
179  for (int64_t i : mask) {
180  float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
181  factor = safe_divide(floorf(factor * (steps[i] + 1.0f)), steps[i]);
182  results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
183  }
184 
185  if (clamp_) {
186  for (int64_t i : mask) {
187  results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
188  clamp_f(results[i], to_min[i], to_max[i]);
189  }
190  }
191  }
192 };
193 
195  public:
197  {
199  this->set_signature(&signature);
200  }
201 
203  {
204  blender::fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
206  return signature.build();
207  }
208 
211  blender::fn::MFContext UNUSED(context)) const override
212  {
213  const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
214  const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
215  const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
216  const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
217  const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
218  blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
219 
220  for (int64_t i : mask) {
221  float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
222  factor = std::clamp(factor, 0.0f, 1.0f);
223  factor = (3.0f - 2.0f * factor) * (factor * factor);
224  results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
225  }
226  }
227 };
228 
230  public:
232  {
234  this->set_signature(&signature);
235  }
236 
238  {
239  blender::fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
241  return signature.build();
242  }
243 
246  blender::fn::MFContext UNUSED(context)) const override
247  {
248  const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
249  const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
250  const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
251  const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
252  const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
253  blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
254 
255  for (int64_t i : mask) {
256  float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
257  factor = std::clamp(factor, 0.0f, 1.0f);
258  factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
259  results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
260  }
261  }
262 };
263 
265 {
266  bNode &bnode = builder.bnode();
267  bool clamp = bnode.custom1 != 0;
268  int interpolation_type = bnode.custom2;
269 
270  switch (interpolation_type) {
271  case NODE_MAP_RANGE_LINEAR: {
272  if (clamp) {
273  static MapRangeFunction fn_with_clamp{true};
274  builder.set_matching_fn(fn_with_clamp);
275  }
276  else {
277  static MapRangeFunction fn_without_clamp{false};
278  builder.set_matching_fn(fn_without_clamp);
279  }
280  break;
281  }
282  case NODE_MAP_RANGE_STEPPED: {
283  if (clamp) {
284  static MapRangeSteppedFunction fn_stepped_with_clamp{true};
285  builder.set_matching_fn(fn_stepped_with_clamp);
286  }
287  else {
288  static MapRangeSteppedFunction fn_stepped_without_clamp{false};
289  builder.set_matching_fn(fn_stepped_without_clamp);
290  }
291  break;
292  }
295  builder.set_matching_fn(smoothstep);
296  break;
297  }
300  builder.set_matching_fn(smootherstep);
301  break;
302  }
303  default:
304  builder.set_not_implemented();
305  break;
306  }
307 }
308 
310 {
311  static bNodeType ntype;
312 
319 
320  nodeRegisterType(&ntype);
321 }
void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn)
Definition: node.cc:4645
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3726
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4623
#define SH_NODE_MAP_RANGE
Definition: BKE_node.h:1067
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4559
#define NODE_CLASS_CONVERTOR
Definition: BKE_node.h:341
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
MINLINE float clamp_f(float value, float min, float max)
MINLINE float safe_divide(float a, float b)
#define UNUSED(x)
#define ELEM(...)
#define N_(msgid)
@ SOCK_IN
@ NODE_MAP_RANGE_STEPPED
@ NODE_MAP_RANGE_SMOOTHERSTEP
@ NODE_MAP_RANGE_SMOOTHSTEP
@ NODE_MAP_RANGE_LINEAR
@ SOCK_FLOAT
bool GPU_link(GPUMaterial *mat, const char *name,...)
bool GPU_stack_link(GPUMaterial *mat, struct bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
@ PROP_NONE
Definition: RNA_types.h:113
void call(blender::IndexMask mask, blender::fn::MFParams params, blender::fn::MFContext UNUSED(context)) const override
static blender::fn::MFSignature create_signature()
static blender::fn::MFSignature create_signature()
void call(blender::IndexMask mask, blender::fn::MFParams params, blender::fn::MFContext UNUSED(context)) const override
void call(blender::IndexMask mask, blender::fn::MFParams params, blender::fn::MFContext UNUSED(context)) const override
static blender::fn::MFSignature create_signature()
void call(blender::IndexMask mask, blender::fn::MFParams params, blender::fn::MFContext UNUSED(context)) const override
static blender::fn::MFSignature create_signature()
void set_signature(const MFSignature *signature)
const MFSignature & signature() const
void set_matching_fn(const fn::MultiFunction &function)
OperationNode * node
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define floorf(x)
void register_node_type_sh_map_range(void)
static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
static const char * gpu_shader_get_name(int mode)
static bNodeSocketTemplate sh_node_map_range_in[]
static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node)
static bNodeSocketTemplate sh_node_map_range_out[]
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
static int gpu_shader_map_range(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
return ret
struct SELECTID_Context context
Definition: select_engine.c:47
static const int steps
Definition: sky_nishita.cpp:28
__int64 int64_t
Definition: stdint.h:92
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeExpandInMFNetworkFunction expand_in_mf_network
Definition: BKE_node.h:324
short custom1
short custom2
CCL_NAMESPACE_BEGIN ccl_device_inline float smootherstep(float edge0, float edge1, float x)
Definition: svm_map_range.h:21
ccl_device_inline float smoothstep(float edge0, float edge1, float x)
Definition: util_math.h:298
ccl_device_inline int clamp(int a, int mn, int mx)
Definition: util_math.h:283
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)