Blender V4.3
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
9#include "DNA_node_types.h"
10#include "DNA_space_types.h"
11
12#include "BLI_math_vector.h"
13#include "BLI_string.h"
14
15#include "BKE_context.hh"
16#include "BKE_node_runtime.hh"
17
19
20#include "node_shader_util.hh"
21
23
24#include "RE_engine.h"
25
26#include "node_exec.hh"
27
29 const bNodeTree *ntree,
30 const char **r_disabled_hint)
31{
32 if (!STREQ(ntree->idname, "ShaderNodeTree")) {
33 *r_disabled_hint = RPT_("Not a shader node tree");
34 return false;
35 }
36 return true;
37}
38
39static bool sh_fn_poll_default(const blender::bke::bNodeType * /*ntype*/,
40 const bNodeTree *ntree,
41 const char **r_disabled_hint)
42{
43 if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
44 *r_disabled_hint = RPT_("Not a shader or geometry node tree");
45 return false;
46 }
47 return true;
48}
49
50void sh_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
51{
52 blender::bke::node_type_base(ntype, type, name, nclass);
53
57}
58
59void sh_fn_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
60{
61 sh_node_type_base(ntype, type, name, nclass);
62 ntype->poll = sh_fn_poll_default;
64}
65
67{
68 const SpaceNode *snode = CTX_wm_space_node(C);
69 return snode->shaderfrom == SNODE_SHADER_LINESTYLE;
70}
71
73{
74 const SpaceNode *snode = CTX_wm_space_node(C);
75 return snode->shaderfrom == SNODE_SHADER_WORLD;
76}
77
79{
80 const SpaceNode *snode = CTX_wm_space_node(C);
81 return snode->shaderfrom == SNODE_SHADER_OBJECT;
82}
83
85{
87 return false;
88 }
89 const RenderEngineType *engine_type = CTX_data_engine_type(C);
90 return STREQ(engine_type->idname, "CYCLES");
91}
92
94{
96 return false;
97 }
98 const RenderEngineType *engine_type = CTX_data_engine_type(C);
99 return STREQ(engine_type->idname, "BLENDER_EEVEE") ||
100 STREQ(engine_type->idname, "BLENDER_EEVEE_NEXT");
101}
102
103/* ****** */
104
105static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
106{
107 const float *from = ns->vec;
108
109 if (type_in == SOCK_FLOAT) {
110 if (ns->sockettype == SOCK_FLOAT) {
111 *in = *from;
112 }
113 else {
114 *in = (from[0] + from[1] + from[2]) / 3.0f;
115 }
116 }
117 else if (type_in == SOCK_VECTOR) {
118 if (ns->sockettype == SOCK_FLOAT) {
119 in[0] = from[0];
120 in[1] = from[0];
121 in[2] = from[0];
122 }
123 else {
124 copy_v3_v3(in, from);
125 }
126 }
127 else { /* type_in==SOCK_RGBA */
128 if (ns->sockettype == SOCK_RGBA) {
129 copy_v4_v4(in, from);
130 }
131 else if (ns->sockettype == SOCK_FLOAT) {
132 in[0] = from[0];
133 in[1] = from[0];
134 in[2] = from[0];
135 in[3] = 1.0f;
136 }
137 else {
138 copy_v3_v3(in, from);
139 in[3] = 1.0f;
140 }
141 }
142}
143
145{
146 memset(gs, 0, sizeof(*gs));
147
148 if (ns == nullptr) {
149 /* node_get_stack() will generate nullptr bNodeStack pointers
150 * for unknown/unsupported types of sockets. */
151 zero_v4(gs->vec);
152 gs->link = nullptr;
153 gs->type = GPU_NONE;
154 gs->hasinput = false;
155 gs->hasoutput = false;
156 gs->sockettype = type;
157 }
158 else {
159 nodestack_get_vec(gs->vec, type, ns);
160 gs->link = (GPUNodeLink *)ns->data;
161
162 if (type == SOCK_FLOAT) {
163 gs->type = GPU_FLOAT;
164 }
165 else if (type == SOCK_INT) {
166 gs->type = GPU_FLOAT; /* HACK: Support as float. */
167 }
168 else if (type == SOCK_BOOLEAN) {
169 gs->type = GPU_FLOAT; /* HACK: Support as float. */
170 }
171 else if (type == SOCK_VECTOR) {
172 gs->type = GPU_VEC3;
173 }
174 else if (type == SOCK_RGBA) {
175 gs->type = GPU_VEC4;
176 }
177 else if (type == SOCK_SHADER) {
178 gs->type = GPU_CLOSURE;
179 }
180 else {
181 gs->type = GPU_NONE;
182 }
183
184 gs->hasinput = ns->hasinput && ns->data;
185 /* XXX Commented out the ns->data check here, as it seems it's not always set,
186 * even though there *is* a valid connection/output... But that might need
187 * further investigation.
188 */
189 gs->hasoutput = ns->hasoutput /*&& ns->data*/;
190 gs->sockettype = ns->sockettype;
191 }
192}
193
195{
196 copy_v4_v4(ns->vec, gs->vec);
197 ns->data = gs->link;
198 ns->sockettype = gs->sockettype;
199}
200
202{
203 int i;
204 LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
205 node_gpu_stack_from_data(&gs[i], socket->type, ns[i]);
206 }
207
208 gs[i].end = true;
209}
210
212{
213 int i = 0;
214 LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
215 if (ELEM(
217 {
218 node_data_from_gpu_stack(ns[i], &gs[i]);
219 i++;
220 }
221 }
222}
223
224bool blender::bke::node_supports_active_flag(const bNode *node, int sub_activity)
225{
227 switch (sub_activity) {
229 return node->typeinfo->nclass == NODE_CLASS_TEXTURE;
231 return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_ATTRIBUTE);
232 }
233 return false;
234}
235
236static bNode *node_get_active(bNodeTree *ntree, int sub_activity)
237{
239 /* this is the node we texture paint and draw in textured draw */
240 bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
241 bool hasgroup = false;
242
243 if (!ntree) {
244 return nullptr;
245 }
246
247 for (bNode *node : ntree->all_nodes()) {
248 if (node->flag & sub_activity) {
249 activetexnode = node;
250 /* if active we can return immediately */
251 if (node->flag & NODE_ACTIVE) {
252 return node;
253 }
254 }
255 else if (!inactivenode && blender::bke::node_supports_active_flag(node, sub_activity)) {
256 inactivenode = node;
257 }
258 else if (node->type == NODE_GROUP) {
259 if (node->flag & NODE_ACTIVE) {
260 activegroup = node;
261 }
262 else {
263 hasgroup = true;
264 }
265 }
266 }
267
268 /* first, check active group for textures */
269 if (activegroup) {
270 bNode *tnode = node_get_active((bNodeTree *)activegroup->id, sub_activity);
271 /* active node takes priority, so ignore any other possible nodes here */
272 if (tnode) {
273 return tnode;
274 }
275 }
276
277 if (activetexnode) {
278 return activetexnode;
279 }
280
281 if (hasgroup) {
282 /* node active texture node in this tree, look inside groups */
283 for (bNode *node : ntree->all_nodes()) {
284 if (node->type == NODE_GROUP) {
285 bNode *tnode = node_get_active((bNodeTree *)node->id, sub_activity);
286 if (tnode && ((tnode->flag & sub_activity) || !inactivenode)) {
287 return tnode;
288 }
289 }
290 }
291 }
292
293 return inactivenode;
294}
295
296namespace blender::bke {
297
302
307} // namespace blender::bke
308
309void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node, int *depth_level)
310{
311 bNodeExec *nodeexec;
312 bNode *node;
313 int n;
314 bNodeStack *stack;
315 bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
316 bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
317 GPUNodeStack gpuin[MAX_SOCKET + 1], gpuout[MAX_SOCKET + 1];
318 bool do_it;
319
320 stack = exec->stack;
321
322 for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
323 node = nodeexec->node;
324
325 if (depth_level && node->runtime->tmp_flag != *depth_level) {
326 continue;
327 }
328
329 do_it = false;
330 /* for groups, only execute outputs for edited group */
331 if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
332 if ((output_node != nullptr) && (node == output_node)) {
333 do_it = true;
334 }
335 }
336 else {
337 do_it = node->runtime->need_exec;
338 node->runtime->need_exec = 0;
339 }
340
341 if (do_it) {
342 BLI_assert(!depth_level || node->runtime->tmp_flag >= 0);
343 if (node->typeinfo->gpu_fn) {
344 node_get_stack(node, stack, nsin, nsout);
345 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
346 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
347 if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) {
348 data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
349 }
350 }
351 }
352 }
353}
354
356{
357 GPU_link(mat, "differentiate_texco", *link, link);
358}
359
361{
362 if (!*link) {
363 *link = GPU_attribute(mat, CD_ORCO, "");
364 node_shader_gpu_bump_tex_coord(mat, node, link);
365 }
366}
367
369 bNode *node,
370 GPUNodeStack *in,
371 GPUNodeStack * /*out*/)
372{
373 NodeTexBase *base = (NodeTexBase *)node->storage;
374 TexMapping *texmap = &base->tex_mapping;
375 float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
376 float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
377
378 if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
379 static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
380 static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
381 GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
382
383 tmin = GPU_uniform((domin) ? texmap->min : min);
384 tmax = GPU_uniform((domax) ? texmap->max : max);
385 tmat0 = GPU_uniform((float *)texmap->mat[0]);
386 tmat1 = GPU_uniform((float *)texmap->mat[1]);
387 tmat2 = GPU_uniform((float *)texmap->mat[2]);
388 tmat3 = GPU_uniform((float *)texmap->mat[3]);
389
390 GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
391
392 if (texmap->type == TEXMAP_TYPE_NORMAL) {
393 GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);
394 }
395 }
396}
397
399{
401 data->r[0] = xyz_to_rgb[0][0];
402 data->r[1] = xyz_to_rgb[1][0];
403 data->r[2] = xyz_to_rgb[2][0];
404 data->g[0] = xyz_to_rgb[0][1];
405 data->g[1] = xyz_to_rgb[1][1];
406 data->g[2] = xyz_to_rgb[2][1];
407 data->b[0] = xyz_to_rgb[0][2];
408 data->b[1] = xyz_to_rgb[1][2];
409 data->b[2] = xyz_to_rgb[2][2];
410}
411
413{
414 return socket.link || socket.vec[0] > 1e-5f;
415}
417{
418 return socket.link || socket.vec[0] < 1.0f || socket.vec[1] < 1.0f || socket.vec[2] < 1.0f;
419}
421{
422 return socket.link || socket.vec[0] > 1e-5f || socket.vec[1] > 1e-5f || socket.vec[2] > 1e-5f;
423}
SpaceNode * CTX_wm_space_node(const bContext *C)
RenderEngineType * CTX_data_engine_type(const bContext *C)
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:405
#define SH_NODE_TEX_IMAGE
Definition BKE_node.hh:930
#define NODE_GROUP
Definition BKE_node.hh:800
#define MAX_SOCKET
Definition BKE_node.hh:29
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:414
#define BLI_assert(a)
Definition BLI_assert.h:50
#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:653
#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_CLIP_MIN
@ TEXMAP_UNIT_MATRIX
@ TEXMAP_CLIP_MAX
@ TEXMAP_TYPE_NORMAL
GPUNodeLink * GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name)
@ GPU_VEC4
@ GPU_NONE
@ GPU_CLOSURE
@ GPU_VEC3
@ GPU_FLOAT
bool GPU_link(GPUMaterial *mat, const char *name,...)
GPUNodeLink * GPU_uniform(const float *num)
blender::float3x3 IMB_colormanagement_get_xyz_to_scene_linear()
OperationNode * node
StackEntry * from
bNode * node_get_active_texture(bNodeTree *ntree)
bool node_supports_active_flag(const bNode *node, int sub_active)
Does the given node supports the sub active flag.
bNode * node_get_active_paint_canvas(bNodeTree *ntree)
bNode * node_get_active(bNodeTree *ntree)
Definition node.cc:3849
void node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
Definition node.cc:4325
void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
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:37
void sh_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
bool line_style_shader_nodes_poll(const bContext *C)
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 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)
void sh_fn_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
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)
bool node_socket_not_black(const GPUNodeStack &socket)
static bool sh_fn_poll_default(const blender::bke::bNodeType *, const bNodeTree *ntree, const char **r_disabled_hint)
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 node_gpu_stack_from_data(GPUNodeStack *gs, int type, bNodeStack *ns)
void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node, 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(bNodeTree *, bNode *, bNodeLink *)
Definition node_util.cc:281
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
eGPUType type
GPUNodeLink * link
TexMapping tex_mapping
char idname[64]
Definition RE_engine.h:78
float mat[4][4]
bNodeExecData data
Definition node_exec.hh:29
bNode * node
Definition node_exec.hh:28
float vec[4]
char idname[64]
bNodeRuntimeHandle * runtime
Defines a node type.
Definition BKE_node.hh:218
bool(* poll)(const bNodeType *ntype, const bNodeTree *nodetree, const char **r_disabled_hint)
Definition BKE_node.hh:299
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:309
float max