Blender  V3.3
Materials.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "Materials.h"
4 
5 #include "BKE_node_tree_update.h"
6 
8  : mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
9 {
10  bNodeTree *new_ntree = prepare_material_nodetree();
11  setShaderType();
12  if (new_ntree) {
13  shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
14  output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
15  add_link(shader_node, 0, output_node, 0);
16  }
17 }
18 
20  COLLADAFW::EffectCommon *ef,
21  Material *ma,
22  UidImageMap &uid_image_map)
23  : mContext(C), material(ma), effect(ef), uid_image_map(&uid_image_map)
24 {
25  prepare_material_nodetree();
26  setShaderType();
27 
28  std::map<std::string, bNode *> nmap;
29 #if 0
30  nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
31  nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
32  nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
33  nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
34  nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
35  nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
36  nmap["out"]->flag &= ~NODE_SELECT;
37 
38  add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
39  add_link(ntree, nmap["main"], 0, nmap["add"], 1);
40  add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
41  add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
42 
43  add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
44  /* experimental, probably not used. */
45  make_group(C, ntree, nmap);
46 #else
47  shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
48  output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
49  add_link(shader_node, 0, output_node, 0);
50 #endif
51 }
52 
53 void MaterialNode::setShaderType()
54 {
55 #if 0
56  COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
57  /* Currently we only support PBR based shaders */
58  /* TODO: simulate the effects with PBR */
59 
60  /* blinn */
61  if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
62  ma->spec_shader = MA_SPEC_BLINN;
63  ma->spec = ef->getShininess().getFloatValue();
64  }
65  /* phong */
66  else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
67  ma->spec_shader = MA_SPEC_PHONG;
68  ma->har = ef->getShininess().getFloatValue();
69  }
70  /* lambert */
71  else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
72  ma->diff_shader = MA_DIFF_LAMBERT;
73  }
74  /* default - lambert */
75  else {
76  ma->diff_shader = MA_DIFF_LAMBERT;
77  fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
78  }
79 #endif
80 }
81 
82 bNodeTree *MaterialNode::prepare_material_nodetree()
83 {
84  if (material->nodetree) {
85  ntree = material->nodetree;
86  return nullptr;
87  }
88 
89  material->nodetree = ntreeAddTree(nullptr, "Shader Nodetree", "ShaderNodeTree");
90  material->use_nodes = true;
91  ntree = material->nodetree;
92  return ntree;
93 }
94 
96 {
97  BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr);
98 }
99 
100 bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
101 {
102  bNode *node = nodeAddStaticNode(mContext, ntree, node_type);
103  if (node) {
104  if (label.length() > 0) {
105  strcpy(node->label, label.c_str());
106  }
107  node->locx = locx;
108  node->locy = locy;
109  node->flag |= NODE_SELECT;
110  }
111  node_map[label] = node;
112  return node;
113 }
114 
115 void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index)
116 {
117  bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
118  bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
119 
120  nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
121 }
122 
123 void MaterialNode::add_link(bNode *from_node,
124  const char *from_label,
125  bNode *to_node,
126  const char *to_label)
127 {
128  bNodeSocket *from_socket = nodeFindSocket(from_node, SOCK_OUT, from_label);
129  bNodeSocket *to_socket = nodeFindSocket(to_node, SOCK_IN, to_label);
130 
131  if (from_socket && to_socket) {
132  nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
133  }
134 }
135 
136 void MaterialNode::set_reflectivity(COLLADAFW::FloatOrParam &val)
137 {
138  float reflectivity = val.getFloatValue();
139  if (reflectivity >= 0) {
140  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Metallic");
141  ((bNodeSocketValueFloat *)socket->default_value)->value = reflectivity;
142  material->metallic = reflectivity;
143  }
144 }
145 
146 #if 0
147 /* needs rework to be done for 2.81 */
148 void MaterialNode::set_shininess(COLLADAFW::FloatOrParam &val)
149 {
150  float roughness = val.getFloatValue();
151  if (roughness >= 0) {
152  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Roughness");
153  ((bNodeSocketValueFloat *)socket->default_value)->value = roughness;
154  }
155 }
156 #endif
157 
158 void MaterialNode::set_ior(COLLADAFW::FloatOrParam &val)
159 {
160  float ior = val.getFloatValue();
161  if (ior < 0) {
162  fprintf(stderr,
163  "IOR of negative value is not allowed for materials (using Blender default value "
164  "instead)");
165  return;
166  }
167 
168  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "IOR");
169  ((bNodeSocketValueFloat *)socket->default_value)->value = ior;
170 }
171 
172 void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
173  COLLADAFW::ColorOrTexture &cot,
174  COLLADAFW::FloatOrParam &val)
175 {
176  /* Handling the alpha value according to the Collada 1.4 reference guide
177  * see page 7-5 Determining Transparency (Opacity)
178  */
179 
180  if (effect == nullptr) {
181  return;
182  }
183 
184  if (cot.isColor() || !cot.isValid()) {
185  /* transparent_cot is either a color or not defined */
186 
187  float transparent_alpha;
188  if (cot.isValid()) {
189  COLLADAFW::Color col = cot.getColor();
190  transparent_alpha = col.getAlpha();
191  }
192  else {
193  /* no transparent color defined */
194  transparent_alpha = 1;
195  }
196 
197  float transparency_alpha = val.getFloatValue();
198  if (transparency_alpha < 0) {
199  /* transparency is not defined */
200  transparency_alpha = 1; /* set to opaque */
201  }
202 
203  float alpha = transparent_alpha * transparency_alpha;
204  if (mode == COLLADAFW::EffectCommon::RGB_ZERO) {
205  alpha = 1 - alpha;
206  }
207 
208  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
209  ((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
210  material->a = alpha;
211  }
212  else if (cot.isTexture()) {
213  int locy = -300 * (node_map.size() - 2);
214  add_texture_node(cot, -300, locy, "Alpha");
215  }
216 }
217 
218 void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot)
219 {
220  int locy = -300 * (node_map.size() - 2);
221 
222  if (cot.isTexture()) {
223  bNode *texture_node = add_texture_node(cot, -300, locy, "Base Color");
224  if (texture_node != nullptr) {
225  add_link(texture_node, 0, shader_node, 0);
226  }
227  }
228  else {
229  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Base Color");
230  float *fcol = (float *)socket->default_value;
231 
232  if (cot.isColor()) {
233  COLLADAFW::Color col = cot.getColor();
234  fcol[0] = material->r = col.getRed();
235  fcol[1] = material->g = col.getGreen();
236  fcol[2] = material->b = col.getBlue();
237  fcol[3] = material->a = col.getAlpha();
238  }
239  else {
240  /* no diffuse term = same as black */
241  fcol[0] = material->r = 0.0f;
242  fcol[1] = material->g = 0.0f;
243  fcol[2] = material->b = 0.0f;
244  fcol[3] = material->a = 1.0f;
245  }
246  }
247 }
248 
250 {
251  bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
252  if (shader == nullptr) {
253  return nullptr;
254  }
255 
256  bNodeSocket *in_socket = nodeFindSocket(shader, SOCK_IN, "Base Color");
257  if (in_socket == nullptr) {
258  return nullptr;
259  }
260 
261  bNodeLink *link = in_socket->link;
262  if (link == nullptr) {
263  return nullptr;
264  }
265 
266  bNode *texture = link->fromnode;
267  if (texture == nullptr) {
268  return nullptr;
269  }
270 
271  if (texture->type != SH_NODE_TEX_IMAGE) {
272  return nullptr;
273  }
274 
275  Image *image = (Image *)texture->id;
276  return image;
277 }
278 
280 {
281  bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
282  float *fcol = (float *)socket->default_value;
283  fcol[0] = col.getRed();
284  fcol[1] = col.getGreen();
285  fcol[2] = col.getBlue();
286 
287  return socket;
288 }
289 
290 void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot)
291 {
292  int locy = -300 * (node_map.size() - 2);
293  if (cot.isColor()) {
294  COLLADAFW::Color col = cot.getColor();
295  bNode *node = add_node(SH_NODE_RGB, -300, locy, "Ambient");
296  set_color(node, col);
297  /* TODO: Connect node */
298  }
299  /* texture */
300  else if (cot.isTexture()) {
301  add_texture_node(cot, -300, locy, "Ambient");
302  /* TODO: Connect node */
303  }
304 }
305 
306 void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot)
307 {
308  int locy = -300 * (node_map.size() - 2);
309  if (cot.isColor()) {
310  COLLADAFW::Color col = cot.getColor();
311  bNode *node = add_node(SH_NODE_RGB, -300, locy, "Reflective");
312  set_color(node, col);
313  /* TODO: Connect node */
314  }
315  /* texture */
316  else if (cot.isTexture()) {
317  add_texture_node(cot, -300, locy, "Reflective");
318  /* TODO: Connect node */
319  }
320 }
321 
322 void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
323 {
324  int locy = -300 * (node_map.size() - 2);
325  if (cot.isColor()) {
326  COLLADAFW::Color col = cot.getColor();
327  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission");
328  float *fcol = (float *)socket->default_value;
329 
330  fcol[0] = col.getRed();
331  fcol[1] = col.getGreen();
332  fcol[2] = col.getBlue();
333  fcol[3] = col.getAlpha();
334  }
335  // texture
336  else if (cot.isTexture()) {
337  bNode *texture_node = add_texture_node(cot, -300, locy, "Emission");
338  if (texture_node != nullptr) {
339  add_link(texture_node, "Color", shader_node, "Emission");
340  }
341  }
342 
343  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission Strength");
344  if (socket) {
345  *(float *)socket->default_value = 1.0f;
346  }
347 }
348 
349 void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot)
350 {
351  if (effect == nullptr) {
352  return;
353  }
354 
355  int locy = -300 * (node_map.size() - 2);
356  if (cot.isColor()) {
357  COLLADAFW::Color col = effect->getTransparent().getColor();
358  float alpha = effect->getTransparency().getFloatValue();
359 
360  if (col.isValid()) {
361  alpha *= col.getAlpha(); /* Assuming A_ONE opaque mode */
362  }
363 
364  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
365  ((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
366  }
367  /* texture */
368  else if (cot.isTexture()) {
369  add_texture_node(cot, -300, locy, "Alpha");
370  /* TODO: Connect node */
371  }
372 }
373 
374 void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
375 {
376  bool has_specularity = true;
377  int locy = -300 * (node_map.size() - 2);
378  if (cot.isColor()) {
379  COLLADAFW::Color col = cot.getColor();
380 
381  if (col.getRed() == 0 && col.getGreen() == 0 && col.getBlue() == 0) {
382  has_specularity = false;
383  }
384  else {
385  bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular");
386  set_color(node, col);
387  /* TODO: Connect node */
388  }
389  }
390  else if (cot.isTexture()) {
391  add_texture_node(cot, -300, locy, "Specular");
392  /* TODO: Connect node */
393  }
394  else {
395  /* no specular term) */
396  has_specularity = false;
397  }
398 
399  if (!has_specularity) {
400  /* If specularity is black or not defined reset the Specular value to 0
401  * TODO: This is a solution only for a corner case. We must find a better
402  * way to handle specularity in general. Also note that currently we
403  * do not export specularity values, see EffectExporter::operator() */
404  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Specular");
405  ((bNodeSocketValueFloat *)socket->default_value)->value = 0.0f;
406  }
407 }
408 
409 bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot,
410  int locx,
411  int locy,
412  std::string label)
413 {
414  if (effect == nullptr) {
415  return nullptr;
416  }
417 
418  UidImageMap &image_map = *uid_image_map;
419 
420  COLLADAFW::Texture ctex = cot.getTexture();
421 
422  COLLADAFW::SamplerPointerArray &samp_array = effect->getSamplerPointerArray();
423  COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
424 
425  const COLLADAFW::UniqueId &ima_uid = sampler->getSourceImage();
426 
427  if (image_map.find(ima_uid) == image_map.end()) {
428  fprintf(stderr, "Couldn't find an image by UID.\n");
429  return nullptr;
430  }
431 
432  Image *ima = image_map[ima_uid];
433  bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
434  texture_node->id = &ima->id;
435  return texture_node;
436 }
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
#define SH_NODE_MIX_SHADER
Definition: BKE_node.h:1105
struct bNode * ntreeFindType(const struct bNodeTree *ntree, int type)
#define SH_NODE_BSDF_PRINCIPLED
Definition: BKE_node.h:1164
#define SH_NODE_EMISSION
Definition: BKE_node.h:1115
#define SH_NODE_ADD_SHADER
Definition: BKE_node.h:1127
#define SH_NODE_BSDF_TRANSPARENT
Definition: BKE_node.h:1113
#define SH_NODE_OUTPUT_MATERIAL
Definition: BKE_node.h:1101
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2296
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
struct bNodeTree * ntreeAddTree(struct Main *bmain, const char *name, const char *idname)
Definition: node.cc:2674
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2151
void BKE_ntree_update_main_tree(struct Main *bmain, struct bNodeTree *ntree, struct NodeTreeUpdateExtraParams *params)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ SOCK_OUT
@ SOCK_IN
#define NODE_SELECT
static bNodeSocket * set_color(bNode *node, COLLADAFW::Color col)
Definition: Materials.cpp:279
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 Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise 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 or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color or the default fallback if none is specified Separate Split a vector into its and Z components Generates normals with round corners and may slow down renders Vector Displace the surface along an arbitrary direction White Return a random value or color based on an input seed Float Map an input float to a curve and outputs a float value Separate Color
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 Texture
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 SH_NODE_TEX_IMAGE
Group Output data from inside of a node group SH_NODE_RGB
#define C
Definition: RandGen.cpp:25
void set_reflectivity(COLLADAFW::FloatOrParam &val)
Definition: Materials.cpp:136
void set_shininess(COLLADAFW::FloatOrParam &val)
void set_specular(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:374
void update_material_nodetree()
Definition: Materials.cpp:95
void set_ior(COLLADAFW::FloatOrParam &val)
Definition: Materials.cpp:158
void set_reflective(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:306
void set_emission(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:322
Image * get_diffuse_image()
Definition: Materials.cpp:249
MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map)
Definition: Materials.cpp:19
void set_opacity(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:349
void set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode, COLLADAFW::ColorOrTexture &cot, COLLADAFW::FloatOrParam &val)
Definition: Materials.cpp:172
void set_diffuse(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:218
void set_ambient(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:290
std::map< std::string, Image * > KeyImageMap
Definition: collada_utils.h:56
std::map< COLLADAFW::UniqueId, Image * > UidImageMap
Definition: collada_utils.h:55
OperationNode * node
const char * label
Material material
depth_tx sampler(1, ImageType::FLOAT_2D, "combined_tx") .sampler(2
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
uint col
ShaderType
static const pxr::TfToken ior("ior", pxr::TfToken::Immortal)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
struct bNodeTree * nodetree
struct bNodeLink * link
void * default_value
ListBase inputs
struct ID * id
short type
ListBase outputs