Blender  V3.3
usd_reader_material.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 NVIDIA Corporation. All rights reserved. */
3 
4 #include "usd_reader_material.h"
5 
6 #include "BKE_image.h"
7 #include "BKE_lib_id.h"
8 #include "BKE_main.h"
9 #include "BKE_material.h"
10 #include "BKE_node.h"
11 #include "BKE_node_tree_update.h"
12 
13 #include "BLI_math_vector.h"
14 #include "BLI_string.h"
15 
16 #include "DNA_material_types.h"
17 
18 #include <pxr/base/gf/vec3f.h>
19 #include <pxr/usd/usdShade/material.h>
20 #include <pxr/usd/usdShade/shader.h>
21 
22 #include <iostream>
23 #include <vector>
24 
25 namespace usdtokens {
26 
27 /* Parameter names. */
28 static const pxr::TfToken a("a", pxr::TfToken::Immortal);
29 static const pxr::TfToken b("b", pxr::TfToken::Immortal);
30 static const pxr::TfToken clearcoat("clearcoat", pxr::TfToken::Immortal);
31 static const pxr::TfToken clearcoatRoughness("clearcoatRoughness", pxr::TfToken::Immortal);
32 static const pxr::TfToken diffuseColor("diffuseColor", pxr::TfToken::Immortal);
33 static const pxr::TfToken emissiveColor("emissiveColor", pxr::TfToken::Immortal);
34 static const pxr::TfToken file("file", pxr::TfToken::Immortal);
35 static const pxr::TfToken g("g", pxr::TfToken::Immortal);
36 static const pxr::TfToken ior("ior", pxr::TfToken::Immortal);
37 static const pxr::TfToken metallic("metallic", pxr::TfToken::Immortal);
38 static const pxr::TfToken normal("normal", pxr::TfToken::Immortal);
39 static const pxr::TfToken occlusion("occlusion", pxr::TfToken::Immortal);
40 static const pxr::TfToken opacity("opacity", pxr::TfToken::Immortal);
41 static const pxr::TfToken opacityThreshold("opacityThreshold", pxr::TfToken::Immortal);
42 static const pxr::TfToken r("r", pxr::TfToken::Immortal);
43 static const pxr::TfToken result("result", pxr::TfToken::Immortal);
44 static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal);
45 static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal);
46 static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal);
47 static const pxr::TfToken sourceColorSpace("sourceColorSpace", pxr::TfToken::Immortal);
48 static const pxr::TfToken specularColor("specularColor", pxr::TfToken::Immortal);
49 static const pxr::TfToken st("st", pxr::TfToken::Immortal);
50 static const pxr::TfToken varname("varname", pxr::TfToken::Immortal);
51 
52 /* Color space names. */
53 static const pxr::TfToken raw("raw", pxr::TfToken::Immortal);
54 static const pxr::TfToken RAW("RAW", pxr::TfToken::Immortal);
55 
56 /* USD shader names. */
57 static const pxr::TfToken UsdPreviewSurface("UsdPreviewSurface", pxr::TfToken::Immortal);
58 static const pxr::TfToken UsdPrimvarReader_float2("UsdPrimvarReader_float2",
59  pxr::TfToken::Immortal);
60 static const pxr::TfToken UsdUVTexture("UsdUVTexture", pxr::TfToken::Immortal);
61 } // namespace usdtokens
62 
63 /* Add a node of the given type at the given location coordinates. */
64 static bNode *add_node(
65  const bContext *C, bNodeTree *ntree, const int type, const float locx, const float locy)
66 {
67  bNode *new_node = nodeAddStaticNode(C, ntree, type);
68 
69  if (new_node) {
70  new_node->locx = locx;
71  new_node->locy = locy;
72  }
73 
74  return new_node;
75 }
76 
77 /* Connect the output socket of node 'source' to the input socket of node 'dest'. */
78 static void link_nodes(
79  bNodeTree *ntree, bNode *source, const char *sock_out, bNode *dest, const char *sock_in)
80 {
81  bNodeSocket *source_socket = nodeFindSocket(source, SOCK_OUT, sock_out);
82 
83  if (!source_socket) {
84  std::cerr << "PROGRAMMER ERROR: Couldn't find output socket " << sock_out << std::endl;
85  return;
86  }
87 
88  bNodeSocket *dest_socket = nodeFindSocket(dest, SOCK_IN, sock_in);
89 
90  if (!dest_socket) {
91  std::cerr << "PROGRAMMER ERROR: Couldn't find input socket " << sock_in << std::endl;
92  return;
93  }
94 
95  nodeAddLink(ntree, source, source_socket, dest, dest_socket);
96 }
97 
98 /* Returns true if the given shader may have opacity < 1.0, based
99  * on heuristics. */
100 static bool needs_blend(const pxr::UsdShadeShader &usd_shader)
101 {
102  if (!usd_shader) {
103  return false;
104  }
105 
106  bool needs_blend = false;
107 
108  if (pxr::UsdShadeInput opacity_input = usd_shader.GetInput(usdtokens::opacity)) {
109 
110  if (opacity_input.HasConnectedSource()) {
111  needs_blend = true;
112  }
113  else {
114  pxr::VtValue val;
115  if (opacity_input.GetAttr().HasAuthoredValue() && opacity_input.GetAttr().Get(&val)) {
116  float opacity = val.Get<float>();
117  needs_blend = opacity < 1.0f;
118  }
119  }
120  }
121 
122  return needs_blend;
123 }
124 
125 /* Returns the given shader's opacityThreshold input value, if this input has an
126  * authored value. Otherwise, returns the given default value. */
127 static float get_opacity_threshold(const pxr::UsdShadeShader &usd_shader,
128  float default_value = 0.0f)
129 {
130  if (!usd_shader) {
131  return default_value;
132  }
133 
134  pxr::UsdShadeInput opacity_threshold_input = usd_shader.GetInput(usdtokens::opacityThreshold);
135 
136  if (!opacity_threshold_input) {
137  return default_value;
138  }
139 
140  pxr::VtValue val;
141  if (opacity_threshold_input.GetAttr().HasAuthoredValue() &&
142  opacity_threshold_input.GetAttr().Get(&val)) {
143  return val.Get<float>();
144  }
145 
146  return default_value;
147 }
148 
149 static pxr::TfToken get_source_color_space(const pxr::UsdShadeShader &usd_shader)
150 {
151  if (!usd_shader) {
152  return pxr::TfToken();
153  }
154 
155  pxr::UsdShadeInput color_space_input = usd_shader.GetInput(usdtokens::sourceColorSpace);
156 
157  if (!color_space_input) {
158  return pxr::TfToken();
159  }
160 
161  pxr::VtValue color_space_val;
162  if (color_space_input.Get(&color_space_val) && color_space_val.IsHolding<pxr::TfToken>()) {
163  return color_space_val.Get<pxr::TfToken>();
164  }
165 
166  return pxr::TfToken();
167 }
168 
169 /* Attempts to return in r_preview_surface the UsdPreviewSurface shader source
170  * of the given material. Returns true if a UsdPreviewSurface source was found
171  * and returns false otherwise. */
172 static bool get_usd_preview_surface(const pxr::UsdShadeMaterial &usd_material,
173  pxr::UsdShadeShader &r_preview_surface)
174 {
175  if (!usd_material) {
176  return false;
177  }
178 
179  if (pxr::UsdShadeShader surf_shader = usd_material.ComputeSurfaceSource()) {
180  /* Check if we have a UsdPreviewSurface shader. */
181  pxr::TfToken shader_id;
182  if (surf_shader.GetShaderId(&shader_id) && shader_id == usdtokens::UsdPreviewSurface) {
183  r_preview_surface = surf_shader;
184  return true;
185  }
186  }
187 
188  return false;
189 }
190 
191 /* Set the Blender material's viewport display color, metallic and roughness
192  * properties from the given USD preview surface shader's inputs. */
193 static void set_viewport_material_props(Material *mtl, const pxr::UsdShadeShader &usd_preview)
194 {
195  if (!(mtl && usd_preview)) {
196  return;
197  }
198 
199  if (pxr::UsdShadeInput diffuse_color_input = usd_preview.GetInput(usdtokens::diffuseColor)) {
200  pxr::VtValue val;
201  if (diffuse_color_input.GetAttr().HasAuthoredValue() &&
202  diffuse_color_input.GetAttr().Get(&val) && val.IsHolding<pxr::GfVec3f>()) {
203  pxr::GfVec3f color = val.UncheckedGet<pxr::GfVec3f>();
204  mtl->r = color[0];
205  mtl->g = color[1];
206  mtl->b = color[2];
207  }
208  }
209 
210  if (pxr::UsdShadeInput metallic_input = usd_preview.GetInput(usdtokens::metallic)) {
211  pxr::VtValue val;
212  if (metallic_input.GetAttr().HasAuthoredValue() && metallic_input.GetAttr().Get(&val) &&
213  val.IsHolding<float>()) {
214  mtl->metallic = val.Get<float>();
215  }
216  }
217 
218  if (pxr::UsdShadeInput roughness_input = usd_preview.GetInput(usdtokens::roughness)) {
219  pxr::VtValue val;
220  if (roughness_input.GetAttr().HasAuthoredValue() && roughness_input.GetAttr().Get(&val) &&
221  val.IsHolding<float>()) {
222  mtl->roughness = val.Get<float>();
223  }
224  }
225 }
226 
227 namespace blender::io::usd {
228 
229 namespace {
230 
231 /* Compute the x- and y-coordinates for placing a new node in an unoccupied region of
232  * the column with the given index. Returns the coordinates in r_locx and r_locy and
233  * updates the column-occupancy information in r_ctx. */
234 void compute_node_loc(const int column, float *r_locx, float *r_locy, NodePlacementContext *r_ctx)
235 {
236  if (!(r_locx && r_locy && r_ctx)) {
237  return;
238  }
239 
240  (*r_locx) = r_ctx->origx - column * r_ctx->horizontal_step;
241 
242  if (column >= r_ctx->column_offsets.size()) {
243  r_ctx->column_offsets.push_back(0.0f);
244  }
245 
246  (*r_locy) = r_ctx->origy - r_ctx->column_offsets[column];
247 
248  /* Record the y-offset of the occupied region in
249  * the column, including padding. */
250  r_ctx->column_offsets[column] += r_ctx->vertical_step + 10.0f;
251 }
252 
253 } // namespace
254 
256  : params_(params), bmain_(bmain)
257 {
258 }
259 
260 Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_material) const
261 {
262  if (!(bmain_ && usd_material)) {
263  return nullptr;
264  }
265 
266  std::string mtl_name = usd_material.GetPrim().GetName().GetString();
267 
268  /* Create the material. */
269  Material *mtl = BKE_material_add(bmain_, mtl_name.c_str());
270  id_us_min(&mtl->id);
271 
272  /* Get the UsdPreviewSurface shader source for the material,
273  * if there is one. */
274  pxr::UsdShadeShader usd_preview;
275  if (get_usd_preview_surface(usd_material, usd_preview)) {
276 
277  set_viewport_material_props(mtl, usd_preview);
278 
279  /* Optionally, create shader nodes to represent a UsdPreviewSurface. */
281  import_usd_preview(mtl, usd_preview);
282  }
283  }
284 
285  return mtl;
286 }
287 
289  const pxr::UsdShadeShader &usd_shader) const
290 {
291  if (!(bmain_ && mtl && usd_shader)) {
292  return;
293  }
294 
295  /* Create the Material's node tree containing the principled BSDF
296  * and output shaders. */
297 
298  /* Add the node tree. */
299  bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", "ShaderNodeTree");
300  mtl->nodetree = ntree;
301  mtl->use_nodes = true;
302 
303  /* Create the Principled BSDF shader node. */
304  bNode *principled = add_node(nullptr, ntree, SH_NODE_BSDF_PRINCIPLED, 0.0f, 300.0f);
305 
306  if (!principled) {
307  std::cerr << "ERROR: Couldn't create SH_NODE_BSDF_PRINCIPLED node for USD shader "
308  << usd_shader.GetPath() << std::endl;
309  return;
310  }
311 
312  /* Create the material output node. */
313  bNode *output = add_node(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL, 300.0f, 300.0f);
314 
315  if (!output) {
316  std::cerr << "ERROR: Couldn't create SH_NODE_OUTPUT_MATERIAL node for USD shader "
317  << usd_shader.GetPath() << std::endl;
318  return;
319  }
320 
321  /* Connect the Principled BSDF node to the output node. */
322  link_nodes(ntree, principled, "BSDF", output, "Surface");
323 
324  /* Recursively create the principled shader input networks. */
325  set_principled_node_inputs(principled, ntree, usd_shader);
326 
328 
330 
331  /* Optionally, set the material blend mode. */
332 
334  if (needs_blend(usd_shader)) {
335  float opacity_threshold = get_opacity_threshold(usd_shader, 0.0f);
336  if (opacity_threshold > 0.0f) {
337  mtl->blend_method = MA_BM_CLIP;
338  mtl->alpha_threshold = opacity_threshold;
339  }
340  else {
341  mtl->blend_method = MA_BM_BLEND;
342  }
343  }
344  }
345 }
346 
348  bNodeTree *ntree,
349  const pxr::UsdShadeShader &usd_shader) const
350 {
351  /* The context struct keeps track of the locations for adding
352  * input nodes. */
353  NodePlacementContext context(0.0f, 300.0);
354 
355  /* The column index (from right to left relative to the principled
356  * node) where we're adding the nodes. */
357  int column = 0;
358 
359  /* Recursively set the principled shader inputs. */
360 
361  if (pxr::UsdShadeInput diffuse_input = usd_shader.GetInput(usdtokens::diffuseColor)) {
362  set_node_input(diffuse_input, principled, "Base Color", ntree, column, &context);
363  }
364 
365  if (pxr::UsdShadeInput emissive_input = usd_shader.GetInput(usdtokens::emissiveColor)) {
366  set_node_input(emissive_input, principled, "Emission", ntree, column, &context);
367  }
368 
369  if (pxr::UsdShadeInput specular_input = usd_shader.GetInput(usdtokens::specularColor)) {
370  set_node_input(specular_input, principled, "Specular", ntree, column, &context);
371  }
372 
373  if (pxr::UsdShadeInput metallic_input = usd_shader.GetInput(usdtokens::metallic)) {
374  ;
375  set_node_input(metallic_input, principled, "Metallic", ntree, column, &context);
376  }
377 
378  if (pxr::UsdShadeInput roughness_input = usd_shader.GetInput(usdtokens::roughness)) {
379  set_node_input(roughness_input, principled, "Roughness", ntree, column, &context);
380  }
381 
382  if (pxr::UsdShadeInput clearcoat_input = usd_shader.GetInput(usdtokens::clearcoat)) {
383  set_node_input(clearcoat_input, principled, "Clearcoat", ntree, column, &context);
384  }
385 
386  if (pxr::UsdShadeInput clearcoat_roughness_input = usd_shader.GetInput(
389  clearcoat_roughness_input, principled, "Clearcoat Roughness", ntree, column, &context);
390  }
391 
392  if (pxr::UsdShadeInput opacity_input = usd_shader.GetInput(usdtokens::opacity)) {
393  set_node_input(opacity_input, principled, "Alpha", ntree, column, &context);
394  }
395 
396  if (pxr::UsdShadeInput ior_input = usd_shader.GetInput(usdtokens::ior)) {
397  set_node_input(ior_input, principled, "IOR", ntree, column, &context);
398  }
399 
400  if (pxr::UsdShadeInput normal_input = usd_shader.GetInput(usdtokens::normal)) {
401  set_node_input(normal_input, principled, "Normal", ntree, column, &context);
402  }
403 }
404 
405 void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
406  bNode *dest_node,
407  const char *dest_socket_name,
408  bNodeTree *ntree,
409  const int column,
410  NodePlacementContext *r_ctx) const
411 {
412  if (!(usd_input && dest_node && r_ctx)) {
413  return;
414  }
415 
416  if (usd_input.HasConnectedSource()) {
417  /* The USD shader input has a connected source shader. Follow the connection
418  * and attempt to convert the connected USD shader to a Blender node. */
419  follow_connection(usd_input, dest_node, dest_socket_name, ntree, column, r_ctx);
420  }
421  else {
422  /* Set the destination node socket value from the USD shader input value. */
423 
424  bNodeSocket *sock = nodeFindSocket(dest_node, SOCK_IN, dest_socket_name);
425  if (!sock) {
426  std::cerr << "ERROR: couldn't get destination node socket " << dest_socket_name << std::endl;
427  return;
428  }
429 
430  pxr::VtValue val;
431  if (!usd_input.Get(&val)) {
432  std::cerr << "ERROR: couldn't get value for usd shader input "
433  << usd_input.GetPrim().GetPath() << std::endl;
434  return;
435  }
436 
437  switch (sock->type) {
438  case SOCK_FLOAT:
439  if (val.IsHolding<float>()) {
440  ((bNodeSocketValueFloat *)sock->default_value)->value = val.UncheckedGet<float>();
441  }
442  else if (val.IsHolding<pxr::GfVec3f>()) {
443  pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>();
444  float average = (v3f[0] + v3f[1] + v3f[2]) / 3.0f;
445  ((bNodeSocketValueFloat *)sock->default_value)->value = average;
446  }
447  break;
448  case SOCK_RGBA:
449  if (val.IsHolding<pxr::GfVec3f>()) {
450  pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>();
451  copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, v3f.data());
452  }
453  break;
454  case SOCK_VECTOR:
455  if (val.IsHolding<pxr::GfVec3f>()) {
456  pxr::GfVec3f v3f = val.UncheckedGet<pxr::GfVec3f>();
457  copy_v3_v3(((bNodeSocketValueVector *)sock->default_value)->value, v3f.data());
458  }
459  else if (val.IsHolding<pxr::GfVec2f>()) {
460  pxr::GfVec2f v2f = val.UncheckedGet<pxr::GfVec2f>();
461  copy_v2_v2(((bNodeSocketValueVector *)sock->default_value)->value, v2f.data());
462  }
463  break;
464  default:
465  std::cerr << "WARNING: unexpected type " << sock->idname << " for destination node socket "
466  << dest_socket_name << std::endl;
467  break;
468  }
469  }
470 }
471 
472 void USDMaterialReader::follow_connection(const pxr::UsdShadeInput &usd_input,
473  bNode *dest_node,
474  const char *dest_socket_name,
475  bNodeTree *ntree,
476  int column,
477  NodePlacementContext *r_ctx) const
478 {
479  if (!(usd_input && dest_node && dest_socket_name && ntree && r_ctx)) {
480  return;
481  }
482 
483  pxr::UsdShadeConnectableAPI source;
484  pxr::TfToken source_name;
485  pxr::UsdShadeAttributeType source_type;
486 
487  usd_input.GetConnectedSource(&source, &source_name, &source_type);
488 
489  if (!(source && source.GetPrim().IsA<pxr::UsdShadeShader>())) {
490  return;
491  }
492 
493  pxr::UsdShadeShader source_shader(source.GetPrim());
494 
495  if (!source_shader) {
496  return;
497  }
498 
499  pxr::TfToken shader_id;
500  if (!source_shader.GetShaderId(&shader_id)) {
501  std::cerr << "ERROR: couldn't get shader id for source shader "
502  << source_shader.GetPrim().GetPath() << std::endl;
503  return;
504  }
505 
506  /* For now, only convert UsdUVTexture and UsdPrimvarReader_float2 inputs. */
507  if (shader_id == usdtokens::UsdUVTexture) {
508 
509  if (strcmp(dest_socket_name, "Normal") == 0) {
510 
511  /* The normal texture input requires creating a normal map node. */
512  float locx = 0.0f;
513  float locy = 0.0f;
514  compute_node_loc(column + 1, &locx, &locy, r_ctx);
515 
516  bNode *normal_map = add_node(nullptr, ntree, SH_NODE_NORMAL_MAP, locx, locy);
517 
518  /* Currently, the Normal Map node has Tangent Space as the default,
519  * which is what we need, so we don't need to explicitly set it. */
520 
521  /* Connect the Normal Map to the Normal input. */
522  link_nodes(ntree, normal_map, "Normal", dest_node, "Normal");
523 
524  /* Now, create the Texture Image node input to the Normal Map "Color" input. */
526  source_shader, source_name, normal_map, "Color", ntree, column + 2, r_ctx);
527  }
528  else {
530  source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx);
531  }
532  }
533  else if (shader_id == usdtokens::UsdPrimvarReader_float2) {
535  source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx);
536  }
537 }
538 
539 void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_shader,
540  const pxr::TfToken &usd_source_name,
541  bNode *dest_node,
542  const char *dest_socket_name,
543  bNodeTree *ntree,
544  const int column,
545  NodePlacementContext *r_ctx) const
546 {
547  if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_ || !r_ctx) {
548  return;
549  }
550 
551  float locx = 0.0f;
552  float locy = 0.0f;
553  compute_node_loc(column, &locx, &locy, r_ctx);
554 
555  /* Create the Texture Image node. */
556  bNode *tex_image = add_node(nullptr, ntree, SH_NODE_TEX_IMAGE, locx, locy);
557 
558  if (!tex_image) {
559  std::cerr << "ERROR: Couldn't create SH_NODE_TEX_IMAGE for node input " << dest_socket_name
560  << std::endl;
561  return;
562  }
563 
564  /* Load the texture image. */
565  load_tex_image(usd_shader, tex_image);
566 
567  /* Connect to destination node input. */
568 
569  /* Get the source socket name. */
570  std::string source_socket_name = usd_source_name == usdtokens::a ? "Alpha" : "Color";
571 
572  link_nodes(ntree, tex_image, source_socket_name.c_str(), dest_node, dest_socket_name);
573 
574  /* Connect the texture image node "Vector" input. */
575  if (pxr::UsdShadeInput st_input = usd_shader.GetInput(usdtokens::st)) {
576  set_node_input(st_input, tex_image, "Vector", ntree, column, r_ctx);
577  }
578 }
579 
580 void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
581  bNode *tex_image) const
582 {
583  if (!(usd_shader && tex_image && tex_image->type == SH_NODE_TEX_IMAGE)) {
584  return;
585  }
586 
587  /* Try to load the texture image. */
588  pxr::UsdShadeInput file_input = usd_shader.GetInput(usdtokens::file);
589 
590  if (!file_input) {
591  std::cerr << "WARNING: Couldn't get file input for USD shader " << usd_shader.GetPath()
592  << std::endl;
593  return;
594  }
595 
596  pxr::VtValue file_val;
597  if (!file_input.Get(&file_val) || !file_val.IsHolding<pxr::SdfAssetPath>()) {
598  std::cerr << "WARNING: Couldn't get file input value for USD shader " << usd_shader.GetPath()
599  << std::endl;
600  return;
601  }
602 
603  const pxr::SdfAssetPath &asset_path = file_val.Get<pxr::SdfAssetPath>();
604  std::string file_path = asset_path.GetResolvedPath();
605  if (file_path.empty()) {
606  std::cerr << "WARNING: Couldn't resolve image asset '" << asset_path
607  << "' for Texture Image node." << std::endl;
608  return;
609  }
610 
611  const char *im_file = file_path.c_str();
613  if (!image) {
614  std::cerr << "WARNING: Couldn't open image file '" << im_file << "' for Texture Image node."
615  << std::endl;
616  return;
617  }
618 
619  tex_image->id = &image->id;
620 
621  /* Set texture color space.
622  * TODO(makowalski): For now, just checking for RAW color space,
623  * assuming sRGB otherwise, but more complex logic might be
624  * required if the color space is "auto". */
625 
626  pxr::TfToken color_space = get_source_color_space(usd_shader);
627 
628  if (color_space.IsEmpty()) {
629  color_space = file_input.GetAttr().GetColorSpace();
630  }
631 
632  if (ELEM(color_space, usdtokens::RAW, usdtokens::raw)) {
633  STRNCPY(image->colorspace_settings.name, "Raw");
634  }
635 }
636 
638  const pxr::UsdShadeShader &usd_shader,
639  const pxr::TfToken & /* usd_source_name */,
640  bNode *dest_node,
641  const char *dest_socket_name,
642  bNodeTree *ntree,
643  const int column,
644  NodePlacementContext *r_ctx) const
645 {
646  if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_ || !r_ctx) {
647  return;
648  }
649 
650  float locx = 0.0f;
651  float locy = 0.0f;
652  compute_node_loc(column, &locx, &locy, r_ctx);
653 
654  /* Create the UV Map node. */
655  bNode *uv_map = add_node(nullptr, ntree, SH_NODE_UVMAP, locx, locy);
656 
657  if (!uv_map) {
658  std::cerr << "ERROR: Couldn't create SH_NODE_UVMAP for node input " << dest_socket_name
659  << std::endl;
660  return;
661  }
662 
663  /* Set the texmap name. */
664  pxr::UsdShadeInput varname_input = usd_shader.GetInput(usdtokens::varname);
665  if (varname_input) {
666  pxr::VtValue varname_val;
667  if (varname_input.Get(&varname_val) && varname_val.IsHolding<pxr::TfToken>()) {
668  std::string varname = varname_val.Get<pxr::TfToken>().GetString();
669  if (!varname.empty()) {
670  NodeShaderUVMap *storage = (NodeShaderUVMap *)uv_map->storage;
671  BLI_strncpy(storage->uv_map, varname.c_str(), sizeof(storage->uv_map));
672  }
673  }
674  }
675 
676  /* Connect to destination node input. */
677  link_nodes(ntree, uv_map, "UV", dest_node, dest_socket_name);
678 }
679 
680 } // namespace blender::io::usd
struct Image * BKE_image_load_exists(struct Main *bmain, const char *filepath)
void id_us_min(struct ID *id)
Definition: lib_id.c:313
General operations, lookup, etc. for materials.
struct Material * BKE_material_add(struct Main *bmain, const char *name)
Definition: material.c:289
#define SH_NODE_UVMAP
Definition: BKE_node.h:1158
#define SH_NODE_BSDF_PRINCIPLED
Definition: BKE_node.h:1164
#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 nodeSetActive(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:3644
void BKE_ntree_update_main_tree(struct Main *bmain, struct bNodeTree *ntree, struct NodeTreeUpdateExtraParams *params)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define ELEM(...)
@ MA_BM_CLIP
@ MA_BM_BLEND
@ SOCK_OUT
@ SOCK_IN
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_RGBA
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
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 A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a 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 SH_NODE_NORMAL_MAP
#define C
Definition: RandGen.cpp:25
Material * add_material(const pxr::UsdShadeMaterial &usd_material) const
void set_node_input(const pxr::UsdShadeInput &usd_input, bNode *dest_node, const char *dest_socket_name, bNodeTree *ntree, int column, NodePlacementContext *r_ctx) const
USDMaterialReader(const USDImportParams &params, Main *bmain)
void convert_usd_primvar_reader_float2(const pxr::UsdShadeShader &usd_shader, const pxr::TfToken &usd_source_name, bNode *dest_node, const char *dest_socket_name, bNodeTree *ntree, int column, NodePlacementContext *r_ctx) const
void convert_usd_uv_texture(const pxr::UsdShadeShader &usd_shader, const pxr::TfToken &usd_source_name, bNode *dest_node, const char *dest_socket_name, bNodeTree *ntree, int column, NodePlacementContext *r_ctx) const
void import_usd_preview(Material *mtl, const pxr::UsdShadeShader &usd_shader) const
void follow_connection(const pxr::UsdShadeInput &usd_input, bNode *dest_node, const char *dest_socket_name, bNodeTree *ntree, int column, NodePlacementContext *r_ctx) const
void load_tex_image(const pxr::UsdShadeShader &usd_shader, bNode *tex_image) const
void set_principled_node_inputs(bNode *principled_node, bNodeTree *ntree, const pxr::UsdShadeShader &usd_shader) const
SyclQueue void * dest
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
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_device_inline float average(const float2 &a)
Definition: math_float2.h:170
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static const pxr::TfToken opacity("opacity", pxr::TfToken::Immortal)
static const pxr::TfToken UsdPreviewSurface("UsdPreviewSurface", pxr::TfToken::Immortal)
static const pxr::TfToken sourceColorSpace("sourceColorSpace", pxr::TfToken::Immortal)
static const pxr::TfToken clearcoat("clearcoat", pxr::TfToken::Immortal)
static const pxr::TfToken varname("varname", pxr::TfToken::Immortal)
static const pxr::TfToken emissiveColor("emissiveColor", pxr::TfToken::Immortal)
static const pxr::TfToken RAW("RAW", pxr::TfToken::Immortal)
static const pxr::TfToken r("r", pxr::TfToken::Immortal)
static const pxr::TfToken UsdUVTexture("UsdUVTexture", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken ior("ior", pxr::TfToken::Immortal)
static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal)
static const pxr::TfToken result("result", pxr::TfToken::Immortal)
static const pxr::TfToken raw("raw", pxr::TfToken::Immortal)
static const pxr::TfToken g("g", pxr::TfToken::Immortal)
static const pxr::TfToken occlusion("occlusion", pxr::TfToken::Immortal)
static const pxr::TfToken clearcoatRoughness("clearcoatRoughness", pxr::TfToken::Immortal)
static const pxr::TfToken file("file", pxr::TfToken::Immortal)
static const pxr::TfToken opacityThreshold("opacityThreshold", pxr::TfToken::Immortal)
static const pxr::TfToken normal("normal", pxr::TfToken::Immortal)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
static const pxr::TfToken metallic("metallic", pxr::TfToken::Immortal)
static const pxr::TfToken diffuseColor("diffuseColor", pxr::TfToken::Immortal)
static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal)
static const pxr::TfToken specularColor("specularColor", pxr::TfToken::Immortal)
static const pxr::TfToken a("a", pxr::TfToken::Immortal)
static const pxr::TfToken UsdPrimvarReader_float2("UsdPrimvarReader_float2", pxr::TfToken::Immortal)
Definition: BKE_main.h:121
struct bNodeTree * nodetree
float alpha_threshold
bool set_material_blend
Definition: usd.h:65
bool import_usd_preview
Definition: usd.h:64
void * default_value
char idname[64]
float locy
struct ID * id
float locx
short type
void * storage
static float get_opacity_threshold(const pxr::UsdShadeShader &usd_shader, float default_value=0.0f)
static pxr::TfToken get_source_color_space(const pxr::UsdShadeShader &usd_shader)
static bool needs_blend(const pxr::UsdShadeShader &usd_shader)
static bool get_usd_preview_surface(const pxr::UsdShadeMaterial &usd_material, pxr::UsdShadeShader &r_preview_surface)
static void link_nodes(bNodeTree *ntree, bNode *source, const char *sock_out, bNode *dest, const char *sock_in)
static void set_viewport_material_props(Material *mtl, const pxr::UsdShadeShader &usd_preview)
static bNode * add_node(const bContext *C, bNodeTree *ntree, const int type, const float locx, const float locy)