Blender V5.0
node_shader_util.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
8
9#include <optional>
10
11#include "DNA_node_types.h"
12#include "DNA_space_types.h"
13
14#include "BLI_math_vector.h"
15#include "BLI_string.h"
16
17#include "BKE_context.hh"
18#include "BKE_node_runtime.hh"
19
21
22#include "node_shader_util.hh"
23
25
26#include "RE_engine.h"
27
28#include "node_exec.hh"
29
31 const bNodeTree *ntree,
32 const char **r_disabled_hint)
33{
34 if (!STREQ(ntree->idname, "ShaderNodeTree")) {
35 *r_disabled_hint = RPT_("Not a shader node tree");
36 return false;
37 }
38 return true;
39}
40
41static bool sh_geo_poll_default(const blender::bke::bNodeType * /*ntype*/,
42 const bNodeTree *ntree,
43 const char **r_disabled_hint)
44{
45 if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
46 *r_disabled_hint = RPT_("Not a shader or geometry node tree");
47 return false;
48 }
49 return true;
50}
51
52static bool common_poll_default(const blender::bke::bNodeType * /*ntype*/,
53 const bNodeTree *ntree,
54 const char **r_disabled_hint)
55{
56 if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree", "CompositorNodeTree")) {
57 *r_disabled_hint = RPT_("Not a shader, geometry, or compositor node tree");
58 return false;
59 }
60 return true;
61}
62
64 std::string idname,
65 const std::optional<int16_t> legacy_type)
66{
67 blender::bke::node_type_base(*ntype, idname, legacy_type);
68
72}
73
75 std::string idname,
76 const std::optional<int16_t> legacy_type)
77{
78 blender::bke::node_type_base(*ntype, idname, legacy_type);
79
83}
84
86 std::string idname,
87 const std::optional<int16_t> legacy_type)
88{
89 sh_node_type_base(ntype, idname, legacy_type);
92}
93
95{
96 const SpaceNode *snode = CTX_wm_space_node(C);
97 return snode->shaderfrom == SNODE_SHADER_LINESTYLE;
98}
99
101{
102 const SpaceNode *snode = CTX_wm_space_node(C);
103 return snode->shaderfrom == SNODE_SHADER_WORLD;
104}
105
107{
108 const SpaceNode *snode = CTX_wm_space_node(C);
109 return snode->shaderfrom == SNODE_SHADER_OBJECT;
110}
111
113{
115 return false;
116 }
117 const RenderEngineType *engine_type = CTX_data_engine_type(C);
118 return STREQ(engine_type->idname, "CYCLES");
119}
120
122{
124 return false;
125 }
126 const RenderEngineType *engine_type = CTX_data_engine_type(C);
127 return STREQ(engine_type->idname, "BLENDER_EEVEE") ||
128 STREQ(engine_type->idname, "BLENDER_EEVEE");
129}
130
131/* ****** */
132
133static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
134{
135 const float *from = ns->vec;
136
137 if (type_in == SOCK_FLOAT) {
138 if (ns->sockettype == SOCK_FLOAT) {
139 *in = *from;
140 }
141 else {
142 *in = (from[0] + from[1] + from[2]) / 3.0f;
143 }
144 }
145 else if (type_in == SOCK_VECTOR) {
146 if (ns->sockettype == SOCK_FLOAT) {
147 in[0] = from[0];
148 in[1] = from[0];
149 in[2] = from[0];
150 }
151 else {
152 copy_v3_v3(in, from);
153 }
154 }
155 else { /* type_in==SOCK_RGBA */
156 if (ns->sockettype == SOCK_RGBA) {
157 copy_v4_v4(in, from);
158 }
159 else if (ns->sockettype == SOCK_FLOAT) {
160 in[0] = from[0];
161 in[1] = from[0];
162 in[2] = from[0];
163 in[3] = 1.0f;
164 }
165 else {
166 copy_v3_v3(in, from);
167 in[3] = 1.0f;
168 }
169 }
170}
171
173{
174 memset(gs, 0, sizeof(*gs));
175
176 if (ns == nullptr) {
177 /* node_get_stack() will generate nullptr bNodeStack pointers
178 * for unknown/unsupported types of sockets. */
179 zero_v4(gs->vec);
180 gs->link = nullptr;
181 gs->type = GPU_NONE;
182 gs->hasinput = false;
183 gs->hasoutput = false;
184 gs->sockettype = type;
185 }
186 else {
187 nodestack_get_vec(gs->vec, type, ns);
188 gs->link = (GPUNodeLink *)ns->data;
189
190 if (type == SOCK_FLOAT) {
191 gs->type = GPU_FLOAT;
192 }
193 else if (type == SOCK_INT) {
194 gs->type = GPU_FLOAT; /* HACK: Support as float. */
195 }
196 else if (type == SOCK_BOOLEAN) {
197 gs->type = GPU_FLOAT; /* HACK: Support as float. */
198 }
199 else if (type == SOCK_VECTOR) {
200 gs->type = GPU_VEC3;
201 }
202 else if (type == SOCK_RGBA) {
203 gs->type = GPU_VEC4;
204 }
205 else if (type == SOCK_SHADER) {
206 gs->type = GPU_CLOSURE;
207 }
208 else {
209 gs->type = GPU_NONE;
210 }
211
212 gs->hasinput = ns->hasinput && ns->data;
213 /* XXX Commented out the ns->data check here, as it seems it's not always set,
214 * even though there *is* a valid connection/output... But that might need
215 * further investigation.
216 */
217 gs->hasoutput = ns->hasoutput /*&& ns->data*/;
218 gs->sockettype = ns->sockettype;
219 }
220}
221
223{
224 copy_v4_v4(ns->vec, gs->vec);
225 ns->data = gs->link;
226 ns->sockettype = gs->sockettype;
227}
228
230{
231 int i;
232 LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
233 node_gpu_stack_from_data(&gs[i], socket->type, ns[i]);
234 }
235
236 gs[i].end = true;
237}
238
240{
241 int i = 0;
242 LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
243 if (ELEM(
245 {
246 node_data_from_gpu_stack(ns[i], &gs[i]);
247 i++;
248 }
249 }
250}
251
252bool blender::bke::node_supports_active_flag(const bNode &node, int sub_activity)
253{
255 switch (sub_activity) {
257 return node.typeinfo->nclass == NODE_CLASS_TEXTURE;
260 }
261 return false;
262}
263
264static bNode *node_get_active(bNodeTree *ntree, int sub_activity)
265{
267 /* this is the node we texture paint and draw in textured draw */
268 bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
269 bool hasgroup = false;
270
271 if (!ntree) {
272 return nullptr;
273 }
274
275 for (bNode *node : ntree->all_nodes()) {
276 if (node->flag & sub_activity) {
277 activetexnode = node;
278 /* if active we can return immediately */
279 if (node->flag & NODE_ACTIVE) {
280 return node;
281 }
282 }
283 else if (!inactivenode && blender::bke::node_supports_active_flag(*node, sub_activity)) {
284 inactivenode = node;
285 }
286 else if (node->type_legacy == NODE_GROUP) {
287 if (node->flag & NODE_ACTIVE) {
288 activegroup = node;
289 }
290 else {
291 hasgroup = true;
292 }
293 }
294 }
295
296 /* first, check active group for textures */
297 if (activegroup) {
298 bNode *tnode = node_get_active((bNodeTree *)activegroup->id, sub_activity);
299 /* active node takes priority, so ignore any other possible nodes here */
300 if (tnode) {
301 return tnode;
302 }
303 }
304
305 if (activetexnode) {
306 return activetexnode;
307 }
308
309 if (hasgroup) {
310 /* node active texture node in this tree, look inside groups */
311 for (bNode *node : ntree->all_nodes()) {
312 if (node->type_legacy == NODE_GROUP) {
313 bNode *tnode = node_get_active((bNodeTree *)node->id, sub_activity);
314 if (tnode && ((tnode->flag & sub_activity) || !inactivenode)) {
315 return tnode;
316 }
317 }
318 }
319 }
320
321 return inactivenode;
322}
323
324namespace blender::bke {
325
330
335} // namespace blender::bke
336
338 GPUMaterial *mat,
339 bNode *output_node,
340 const int *depth_level)
341{
342 bNodeExec *nodeexec;
343 bNode *node;
344 int n;
345 bNodeStack *stack;
346 bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
347 bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
348 GPUNodeStack gpuin[MAX_SOCKET + 1], gpuout[MAX_SOCKET + 1];
349 bool do_it;
350
351 stack = exec->stack;
352
353 for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
354 node = nodeexec->node;
355
356 if (depth_level && node->runtime->tmp_flag != *depth_level) {
357 continue;
358 }
359
360 do_it = false;
361 /* for groups, only execute outputs for edited group */
362 if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
363 if ((output_node != nullptr) && (node == output_node)) {
364 do_it = true;
365 }
366 }
367 else {
368 do_it = node->runtime->need_exec;
369 node->runtime->need_exec = 0;
370 }
371
372 if (do_it) {
373 BLI_assert(!depth_level || node->runtime->tmp_flag >= 0);
374 if (node->typeinfo->gpu_fn) {
375 node_get_stack(node, stack, nsin, nsout);
376 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
377 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
378 if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) {
379 data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
380 }
381 }
382 }
383 }
384}
385
387{
388 GPU_link(mat, "differentiate_texco", *link, link);
389}
390
392{
393 if (!*link) {
394 *link = GPU_attribute(mat, CD_ORCO, "");
395 node_shader_gpu_bump_tex_coord(mat, node, link);
396 }
397}
398
400 bNode *node,
402 GPUNodeStack * /*out*/)
403{
404 NodeTexBase *base = (NodeTexBase *)node->storage;
405 TexMapping *texmap = &base->tex_mapping;
406 float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
407 float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
408
409 if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
410 static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
411 static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
412 GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
413
414 tmin = GPU_uniform((domin) ? texmap->min : min);
415 tmax = GPU_uniform((domax) ? texmap->max : max);
416 tmat0 = GPU_uniform((float *)texmap->mat[0]);
417 tmat1 = GPU_uniform((float *)texmap->mat[1]);
418 tmat2 = GPU_uniform((float *)texmap->mat[2]);
419 tmat3 = GPU_uniform((float *)texmap->mat[3]);
420
421 GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
422
423 if (texmap->type == TEXMAP_TYPE_NORMAL) {
424 GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);
425 }
426 }
427}
428
430{
432 data->r[0] = xyz_to_rgb[0][0];
433 data->r[1] = xyz_to_rgb[1][0];
434 data->r[2] = xyz_to_rgb[2][0];
435 data->g[0] = xyz_to_rgb[0][1];
436 data->g[1] = xyz_to_rgb[1][1];
437 data->g[2] = xyz_to_rgb[2][1];
438 data->b[0] = xyz_to_rgb[0][2];
439 data->b[1] = xyz_to_rgb[1][2];
440 data->b[2] = xyz_to_rgb[2][2];
441}
442
444{
445 return socket.link || socket.vec[0] > 1e-5f;
446}
448{
449 return socket.link || socket.vec[0] < 1.0f || socket.vec[1] < 1.0f || socket.vec[2] < 1.0f;
450}
452{
453 return socket.link || socket.vec[0] > 1e-5f || socket.vec[1] > 1e-5f || socket.vec[2] > 1e-5f;
454}
SpaceNode * CTX_wm_space_node(const bContext *C)
RenderEngineType * CTX_data_engine_type(const bContext *C)
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:448
#define NODE_GROUP
Definition BKE_node.hh:811
#define MAX_SOCKET
Definition BKE_node.hh:28
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:457
#define SH_NODE_TEX_IMAGE
#define SH_NODE_ATTRIBUTE
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v4(float r[4])
#define STR_ELEM(...)
Definition BLI_string.h:661
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
@ NODE_ACTIVE
@ NODE_ACTIVE_TEXTURE
@ NODE_ACTIVE_PAINT_CANVAS
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_SHADER
@ SOCK_FLOAT
@ SOCK_RGBA
@ SNODE_SHADER_WORLD
@ SNODE_SHADER_LINESTYLE
@ SNODE_SHADER_OBJECT
@ TEXMAP_TYPE_NORMAL
@ TEXMAP_CLIP_MIN
@ TEXMAP_UNIT_MATRIX
@ TEXMAP_CLIP_MAX
@ GPU_VEC4
@ GPU_NONE
@ GPU_CLOSURE
@ GPU_VEC3
@ GPU_FLOAT
GPUNodeLink * GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name)
bool GPU_link(GPUMaterial *mat, const char *name,...)
GPUNodeLink * GPU_uniform(const float *num)
blender::float3x3 IMB_colormanagement_get_xyz_to_scene_linear()
#define C
Definition RandGen.cpp:29
BMesh const char void * data
#define in
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4685
bNode * node_get_active_texture(bNodeTree &ntree)
void node_type_base(bNodeType &ntype, std::string idname, std::optional< int16_t > legacy_type=std::nullopt)
Definition node.cc:5099
bNode * node_get_active_paint_canvas(bNodeTree &ntree)
bool node_supports_active_flag(const bNode &node, int sub_activity)
Does the given node supports the sub active flag.
void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
MatBase< float, 3, 3 > float3x3
color xyz_to_rgb(float x, float y, float z)
Definition node_color.h:73
void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
Definition node_exec.cc:38
bool line_style_shader_nodes_poll(const bContext *C)
void sh_geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
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)
static bool common_poll_default(const blender::bke::bNodeType *, const bNodeTree *ntree, const char **r_disabled_hint)
void sh_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
bool node_socket_not_white(const GPUNodeStack &socket)
bool object_cycles_shader_nodes_poll(const bContext *C)
static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data)
bool object_shader_nodes_poll(const bContext *C)
bool object_eevee_shader_nodes_poll(const bContext *C)
static bool sh_geo_poll_default(const blender::bke::bNodeType *, const bNodeTree *ntree, const char **r_disabled_hint)
bool node_socket_not_black(const GPUNodeStack &socket)
bool world_shader_nodes_poll(const bContext *C)
static bNode * node_get_active(bNodeTree *ntree, int sub_activity)
bool node_socket_not_zero(const GPUNodeStack &socket)
static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
void common_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_gpu_stack_from_data(GPUNodeStack *gs, int type, bNodeStack *ns)
void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node, const int *depth_level)
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
bool sh_node_poll_default(const blender::bke::bNodeType *, const bNodeTree *ntree, const char **r_disabled_hint)
void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *, GPUNodeLink **link)
static void exec(void *data, int, bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
bool node_insert_link_default(blender::bke::NodeInsertLinkParams &)
Definition node_util.cc:266
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
GPUNodeLink * link
TexMapping tex_mapping
char idname[64]
Definition RE_engine.h:73
float mat[4][4]
bNodeExecData data
Definition node_exec.hh:25
bNode * node
Definition node_exec.hh:24
float vec[4]
char idname[64]
bNodeTypeHandle * typeinfo
ListBase inputs
int16_t type_legacy
bNodeRuntimeHandle * runtime
void * storage
ListBase outputs
Defines a node type.
Definition BKE_node.hh:238
bool(* insert_link)(NodeInsertLinkParams &params)
Definition BKE_node.hh:333
bool(* poll)(const bNodeType *ntype, const bNodeTree *nodetree, const char **r_disabled_hint)
Definition BKE_node.hh:321
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251