Blender  V2.93
Materials.cpp
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 
17 #include "Materials.h"
18 
20  : mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
21 {
22  bNodeTree *new_ntree = prepare_material_nodetree();
23  setShaderType();
24  if (new_ntree) {
25  shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
26  output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
27  add_link(shader_node, 0, output_node, 0);
28  }
29 }
30 
32  COLLADAFW::EffectCommon *ef,
33  Material *ma,
34  UidImageMap &uid_image_map)
35  : mContext(C), material(ma), effect(ef), uid_image_map(&uid_image_map)
36 {
37  prepare_material_nodetree();
38  setShaderType();
39 
40  std::map<std::string, bNode *> nmap;
41 #if 0
42  nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
43  nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
44  nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
45  nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
46  nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
47  nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
48  nmap["out"]->flag &= ~NODE_SELECT;
49 
50  add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
51  add_link(ntree, nmap["main"], 0, nmap["add"], 1);
52  add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
53  add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
54 
55  add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
56  /* experimental, probably not used. */
57  make_group(C, ntree, nmap);
58 #else
59  shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
60  output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
61  add_link(shader_node, 0, output_node, 0);
62 #endif
63 }
64 
65 void MaterialNode::setShaderType()
66 {
67 #if 0
68  COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
69  /* Currently we only support PBR based shaders */
70  /* TODO: simulate the effects with PBR */
71 
72  /* blinn */
73  if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
74  ma->spec_shader = MA_SPEC_BLINN;
75  ma->spec = ef->getShininess().getFloatValue();
76  }
77  /* phong */
78  else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
79  ma->spec_shader = MA_SPEC_PHONG;
80  ma->har = ef->getShininess().getFloatValue();
81  }
82  /* lambert */
83  else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
84  ma->diff_shader = MA_DIFF_LAMBERT;
85  }
86  /* default - lambert */
87  else {
88  ma->diff_shader = MA_DIFF_LAMBERT;
89  fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
90  }
91 #endif
92 }
93 
94 /* returns null if material already has a node tree */
95 bNodeTree *MaterialNode::prepare_material_nodetree()
96 {
97  if (material->nodetree) {
98  ntree = material->nodetree;
99  return nullptr;
100  }
101 
102  material->nodetree = ntreeAddTree(nullptr, "Shader Nodetree", "ShaderNodeTree");
103  material->use_nodes = true;
104  ntree = material->nodetree;
105  return ntree;
106 }
107 
109 {
110  ntreeUpdateTree(CTX_data_main(mContext), ntree);
111 }
112 
113 bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
114 {
115  bNode *node = nodeAddStaticNode(mContext, ntree, node_type);
116  if (node) {
117  if (label.length() > 0) {
118  strcpy(node->label, label.c_str());
119  }
120  node->locx = locx;
121  node->locy = locy;
122  node->flag |= NODE_SELECT;
123  }
124  node_map[label] = node;
125  return node;
126 }
127 
128 void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index)
129 {
130  bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
131  bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
132 
133  nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
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  if (cot.isColor()) {
222  COLLADAFW::Color col = cot.getColor();
223  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Base Color");
224  float *fcol = (float *)socket->default_value;
225 
226  fcol[0] = material->r = col.getRed();
227  fcol[1] = material->g = col.getGreen();
228  fcol[2] = material->b = col.getBlue();
229  fcol[3] = material->a = col.getAlpha();
230  }
231  else if (cot.isTexture()) {
232  bNode *texture_node = add_texture_node(cot, -300, locy, "Base Color");
233  if (texture_node != nullptr) {
234  add_link(texture_node, 0, shader_node, 0);
235  }
236  }
237 }
238 
240 {
242  if (shader == nullptr) {
243  return nullptr;
244  }
245 
246  bNodeSocket *in_socket = nodeFindSocket(shader, SOCK_IN, "Base Color");
247  if (in_socket == nullptr) {
248  return nullptr;
249  }
250 
251  bNodeLink *link = in_socket->link;
252  if (link == nullptr) {
253  return nullptr;
254  }
255 
256  bNode *texture = link->fromnode;
257  if (texture == nullptr) {
258  return nullptr;
259  }
260 
261  if (texture->type != SH_NODE_TEX_IMAGE) {
262  return nullptr;
263  }
264 
265  Image *image = (Image *)texture->id;
266  return image;
267 }
268 
270 {
271  bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
272  float *fcol = (float *)socket->default_value;
273  fcol[0] = col.getRed();
274  fcol[1] = col.getGreen();
275  fcol[2] = col.getBlue();
276 
277  return socket;
278 }
279 
280 void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot)
281 {
282  int locy = -300 * (node_map.size() - 2);
283  if (cot.isColor()) {
284  COLLADAFW::Color col = cot.getColor();
285  bNode *node = add_node(SH_NODE_RGB, -300, locy, "Ambient");
286  set_color(node, col);
287  /* TODO: Connect node */
288  }
289  /* texture */
290  else if (cot.isTexture()) {
291  add_texture_node(cot, -300, locy, "Ambient");
292  /* TODO: Connect node */
293  }
294 }
295 
296 void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot)
297 {
298  int locy = -300 * (node_map.size() - 2);
299  if (cot.isColor()) {
300  COLLADAFW::Color col = cot.getColor();
301  bNode *node = add_node(SH_NODE_RGB, -300, locy, "Reflective");
302  set_color(node, col);
303  /* TODO: Connect node */
304  }
305  /* texture */
306  else if (cot.isTexture()) {
307  add_texture_node(cot, -300, locy, "Reflective");
308  /* TODO: Connect node */
309  }
310 }
311 
312 void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
313 {
314  int locy = -300 * (node_map.size() - 2);
315  if (cot.isColor()) {
316  COLLADAFW::Color col = cot.getColor();
317  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission");
318  float *fcol = (float *)socket->default_value;
319 
320  fcol[0] = col.getRed();
321  fcol[1] = col.getGreen();
322  fcol[2] = col.getBlue();
323  fcol[3] = col.getAlpha();
324  }
325  // texture
326  else if (cot.isTexture()) {
327  bNode *texture_node = add_texture_node(cot, -300, locy, "Emission");
328  if (texture_node != nullptr) {
329  add_link(texture_node, 0, shader_node, 0);
330  }
331  }
332 
333  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission Strength");
334  if (socket) {
335  *(float *)socket->default_value = 1.0f;
336  }
337 }
338 
339 void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot)
340 {
341  if (effect == nullptr) {
342  return;
343  }
344 
345  int locy = -300 * (node_map.size() - 2);
346  if (cot.isColor()) {
347  COLLADAFW::Color col = effect->getTransparent().getColor();
348  float alpha = effect->getTransparency().getFloatValue();
349 
350  if (col.isValid()) {
351  alpha *= col.getAlpha(); /* Assuming A_ONE opaque mode */
352  }
353 
354  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
355  ((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
356  }
357  /* texture */
358  else if (cot.isTexture()) {
359  add_texture_node(cot, -300, locy, "Alpha");
360  /* TODO: Connect node */
361  }
362 }
363 
364 void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
365 {
366  int locy = -300 * (node_map.size() - 2);
367  if (cot.isColor()) {
368  COLLADAFW::Color col = cot.getColor();
369  bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular");
370  set_color(node, col);
371  /* TODO: Connect node */
372  }
373  /* texture */
374  else if (cot.isTexture()) {
375  add_texture_node(cot, -300, locy, "Specular");
376  /* TODO: Connect node */
377  }
378 }
379 
380 bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot,
381  int locx,
382  int locy,
383  std::string label)
384 {
385  if (effect == nullptr) {
386  return nullptr;
387  }
388 
389  UidImageMap &image_map = *uid_image_map;
390 
391  COLLADAFW::Texture ctex = cot.getTexture();
392 
393  COLLADAFW::SamplerPointerArray &samp_array = effect->getSamplerPointerArray();
394  COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
395 
396  const COLLADAFW::UniqueId &ima_uid = sampler->getSourceImage();
397 
398  if (image_map.find(ima_uid) == image_map.end()) {
399  fprintf(stderr, "Couldn't find an image by UID.\n");
400  return nullptr;
401  }
402 
403  Image *ima = image_map[ima_uid];
404  bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
405  texture_node->id = &ima->id;
406  return texture_node;
407 }
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
#define SH_NODE_MIX_SHADER
Definition: BKE_node.h:999
struct bNode * ntreeFindType(const struct bNodeTree *ntree, int type)
#define SH_NODE_BSDF_PRINCIPLED
Definition: BKE_node.h:1058
#define SH_NODE_EMISSION
Definition: BKE_node.h:1009
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree)
Definition: node.cc:4262
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2189
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:2529
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2004
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ SOCK_IN
#define NODE_SELECT
static bNodeSocket * set_color(bNode *node, COLLADAFW::Color col)
Definition: Materials.cpp:269
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer SH_NODE_ADD_SHADER
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Texture
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction SH_NODE_BSDF_TRANSPARENT
Group SH_NODE_RGB
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Sky Noise Wave Voronoi Brick Texture Vector Combine Vertex Color
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume SH_NODE_TEX_IMAGE
Group RGB to Bright Vector Camera Vector Combine SH_NODE_OUTPUT_MATERIAL
#define C
Definition: RandGen.cpp:39
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:364
void update_material_nodetree()
Definition: Materials.cpp:108
void set_ior(COLLADAFW::FloatOrParam &val)
Definition: Materials.cpp:158
void set_reflective(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:296
void set_emission(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:312
Image * get_diffuse_image()
Definition: Materials.cpp:239
MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map)
Definition: Materials.cpp:31
void set_opacity(COLLADAFW::ColorOrTexture &cot)
Definition: Materials.cpp:339
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:280
std::map< std::string, Image * > KeyImageMap
Definition: collada_utils.h:70
std::map< COLLADAFW::UniqueId, Image * > UidImageMap
Definition: collada_utils.h:69
OperationNode * node
const char * label
Material material
static CCL_NAMESPACE_BEGIN const double alpha
uint col
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
struct bNodeTree * nodetree
struct bNodeLink * link
void * default_value
ListBase inputs
struct ID * id
ListBase outputs
ShaderType
Definition: svm_types.h:511