MaterialXMaterials 1.39.5
Utilities for retrieving materials from remote servers
Loading...
Searching...
No Matches
JsPhysicallyBasedMaterialLoader Class Reference

Javascript class for querying materials from the Physically Based database and creating MaterialX materials. More...

Public Member Functions

 constructor (mtlx_module=null, mtlx_stdlib=null)
 Constructor for the PhysicallyBasedMaterialLoader.
 getJSON ()
 Get the Physically Based Materials as JSON.
 getJSONMaterialNames ()
 Get list of the Physically Based Material names.
 getMaterialXDocument ()
 Get the MaterialX document.
 validateDocument ()
 Validate the MaterialX document.
 getInputRemapping (shadingModel)
 Get the remapping keys for a given shading model.
 getInputRemappingMap ()
 Get remmapping map.
 get_physlib ()
 get_physlib_definition ()
 get_physlib_category ()
 get_physlib_definition_name ()
 get_physlib_implementation_name ()
 get_physlib_materials ()
 get_definitions ()
 map_keys_to_definition (mat, ndef)
 find_all_bxdf (doc)
 derive_translator_name_from_targets (source, target)
 create_translator (doc, source, target, source_version="", target_version="", mappings=null, output_doc)
 create_all_translators (definitions, output_doc=null)
 add_copyright_comment (doc, shaderCategory, embedDate=false)
 create_definition (doc=null)
 create_definition_materials (doc_mat, filter_list=null)
 find_translator (doc, source, target)
 translate_node (doc, source_bxdf, target_bxdf, node)
 initialize_definitions_and_materials (shadingModel='standard_surface', materialNames=[], force=false)
 setDefaultRemapKeys ()
 Set the default remapping keys for different shading models : glTF, OpenPBR, and Autodesk Standard Surface.
 initializeInputRemapping ()
 Initialize the input remapping for different shading models.
 loadMaterialX ()
 Load the MaterialX module.
async getPhysicallyBasedMaterials ()
 Get the Physically Based Materials from the API.
 loadStandardLibraries ()
 Load the MaterialX standard libraries.
 skipLibraryElement (element)
 Predicate to skip library elements.
 getMaterialXString ()
 Get the MaterialX document as a string.
 addComment (doc, commentString)
 Add a comment to the MaterialX document.
 getReferenceList ()
 Return a sorted list reference names mapped reference images.
 add_copyright_docstring (doc, shaderCategory='')
 Add copyright docstring to the MaterialX document.
 convertToMaterialX (shaderCategory, references, addAllInputs=false, materialNames=[], remapKeys={}, shaderPreFix='')
 Convert the Physically Based Materials to MaterialX.

Public Attributes

 url = ''
 URL to fetch the Physically Based Materials.
 headers = {}
 Headers for the fetch operation.
 materials = null
 List of Physically Based Materials.
 materialNames = []
 List of Physically Based Material names.
 mxMaterialNames = []
 List of MaterialX Material names.
 mx = null
 MaterialX module.
 doc = null
 Working MaterialX document.
 stdlib = null
 MaterialX standard libraries.
 remapMap = {}
 Remap keys for input values for different shading models.

Detailed Description

Javascript class for querying materials from the Physically Based database and creating MaterialX materials.

Definition at line 8 of file JsMaterialXPhysicallyBased.js.

Member Function Documentation

◆ add_copyright_comment()

JsPhysicallyBasedMaterialLoader::add_copyright_comment ( doc,
shaderCategory,
embedDate = false )

Definition at line 462 of file JsMaterialXPhysicallyBased.js.

462 {
463
464 // Add header comments
465 this.addComment(doc, 'Physically Based Materials from https://api.physicallybased.info ');
466 this.addComment(doc, ' Content Author: Anton Palmqvist, https://antonpalmqvist.com/ ');
467 this.addComment(doc, ` Content processsed via REST API and mapped to MaterialX V${this.mx.getVersionString()} `);
468 if (shaderCategory) {
469 this.addComment(doc, ` Target Shading Model: ${shaderCategory} `);
470 }
471 this.addComment(doc, ' Utility Author: Bernard Kwok. kwokcb@gmail.com ');
472 if (embedDate) {
473 const now = new Date();
474 const dt_string = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0') + ':' + String(now.getSeconds()).padStart(2, '0');
475 this.addComment(doc, ` Generated on: ${dt_string} `);
476 }
477 }
addComment(doc, commentString)
Add a comment to the MaterialX document.

◆ add_copyright_docstring()

JsPhysicallyBasedMaterialLoader::add_copyright_docstring ( doc,
shaderCategory = '' )

Add copyright docstring to the MaterialX document.

Parameters
docMaterialX document
shaderCategory- MaterialX shader category (optional)

Definition at line 1033 of file JsMaterialXPhysicallyBased.js.

1034 {
1035 // Add document level accreditation
1036 let docString = 'Physically Based Materials from https://api.physicallybased.info.\n'
1037 docString += ' Content Author: Anton Palmqvist, https://antonpalmqvist.com/ \n'
1038 docString += ` Content processsed via REST API and mapped to MaterialX V${this.mx.getVersionString()} \n`
1039 if (shaderCategory.length > 0) {
1040 docString += ` Target Shading Model: ${shaderCategory} \n`
1041 }
1042 docString += ' Utility Author: Bernard Kwok. kwokcb@gmail.com '
1043 doc.setDocString(docString);
1044 }

◆ addComment()

JsPhysicallyBasedMaterialLoader::addComment ( doc,
commentString )

Add a comment to the MaterialX document.

Parameters
doc- MaterialX document
commentString- Comment string to add

Definition at line 994 of file JsMaterialXPhysicallyBased.js.

995 {
996 let comment = doc.addChildOfCategory('comment')
997 comment.setDocString(commentString)
998 }

◆ constructor()

JsPhysicallyBasedMaterialLoader::constructor ( mtlx_module = null,
mtlx_stdlib = null )

Constructor for the PhysicallyBasedMaterialLoader.

Returns
{void}

Definition at line 60 of file JsMaterialXPhysicallyBased.js.

61 {
62 this.url = 'https://api.physicallybased.info/materials';
63 this.headers = { 'Accept': 'application/json' };
64
65 this.materials = null;
66 this.materialNames = [];
67
68 this.mxMaterialNames = [];
69 this.mx = null;
70 if (mtlx_module) {
71 this.mx = mtlx_module;
72 }
73 this.stdlib = null;
74 if (mtlx_stdlib) {
75 this.stdlib = mtlx_stdlib;
76 }
77 this.doc = null;
78
80
81 this.physlib = null;
82 // PhysicallyBased MaterialX surface definition name
83 this.physlib_definition_name = "ND_PhysicallyBasedMaterial";
84 // PhysicallyBased MaterialX surface implementation (nodegraph) name
85 this.physlib_implementation_name = "NG_PhysicallyBasedMaterial";
86 // PhysicallyBased MaterialX surface category
87 this.physlib_category = "physbased_pbr_surface"
88 // Document containing PhysicallyBased materials using PhysicallyBasedMaterial definition
89 this.physlib_materials = null
90 // Document containing PhysicallyBased MaterialX translators
91 this.physlib_translators = null
92 // All MaterialX definitions (standard library + PhysicallyBased definition + translators)
93 this.all_lib = null;
94 // Translated materials keyed by shading model
95 this.translated_materials = {};
96 }
initializeInputRemapping()
Initialize the input remapping for different shading models.
materials
List of Physically Based Materials.
materialNames
List of Physically Based Material names.
mxMaterialNames
List of MaterialX Material names.
headers
Headers for the fetch operation.
url
URL to fetch the Physically Based Materials.

◆ convertToMaterialX()

JsPhysicallyBasedMaterialLoader::convertToMaterialX ( shaderCategory,
references,
addAllInputs = false,
materialNames = [],
remapKeys = {},
shaderPreFix = '' )

Convert the Physically Based Materials to MaterialX.

Parameters
shaderCategory- MaterialX shader category
addAllInputs- Add all inputs from node definitions
materialNames- List of material names to convert. If empty all materials are converted
remapKeys- Remap keys to MaterialX shader inputs. If not specified the default remap keys are used if any.
shaderPreFix- Prefix for the shader name. Default is empty
references- List of references found. (returned). Each reference is a object: { name: string, reference: string }
Returns
True if the conversion is successful. False otherwise

Definition at line 1056 of file JsMaterialXPhysicallyBased.js.

1056 {}, shaderPreFix = '')
1057 {
1058 if (!this.mx) {
1059 console.error('MaterialX module is not loaded');
1060 return false;
1061 }
1062
1063 if (!this.materials) {
1064 console.warn('No Physically Based Materials to convert');
1065 return false;
1066 }
1067
1068 if (Object.keys(remapKeys).length === 0)
1069 {
1070 remapKeys = this.getInputRemapping(shaderCategory);
1071 }
1072 //console.log('Using remap keys for shading model:', shaderCategory, remapKeys);
1073
1074 // Create a dummy doc with the surface shader with all inputs
1075 // as reference
1076 let refDoc = this.mx.createDocument();
1077 refDoc.importLibrary(this.stdlib);
1078 const refNode = refDoc.addNode(shaderCategory, 'refShader', this.mx.SURFACE_SHADER_TYPE_STRING);
1079 if (addAllInputs) {
1080 console.warn('MaterialX JS API missing addInputsFromNodeDef()');
1081 //refNode.addInputsFromNodeDef() -- This is missing from the JS API.
1082 }
1083 this.doc = this.mx.createDocument();
1084
1085 // Add document level accreditation
1086 this.add_copyright_docstring(this.doc, shaderCategory);
1087
1088 // Add properties to the material
1089 for (let i = 0; i < this.materials.length; i++) {
1090 const mat = this.materials[i];
1091 let matName = mat['name'];
1092
1093 // Filter by material name(s)
1094 let skipGeneration = materialNames.length > 0 && !materialNames.includes(matName);
1095
1096 let shaderNode = null;
1097 let docString = ''
1098 if (!skipGeneration)
1099 {
1100 if (shaderPreFix.length > 0) {
1101 matName = shaderPreFix + '_' + matName;
1102 }
1103
1104 const shaderName = this.doc.createValidChildName(matName + '_' + shaderCategory + '_SPB');
1105 this.addComment(this.doc, ' Generated shader: ' + matName + ' ');
1106 shaderNode = this.doc.addNode(shaderCategory, shaderName, this.mx.SURFACE_SHADER_TYPE_STRING);
1107
1108 const category = mat['category'];
1109 const group = mat['group'];
1110 let uifolder = '';
1111 if (category && category.length > 0) {
1112 uifolder = category[0];
1113 }
1114 if (group && group.length > 0) {
1115 if (uifolder.length > 0) {
1116 uifolder += '/';
1117 }
1118 uifolder += group[0];
1119 }
1120 if (uifolder.length > 0) {
1121 shaderNode.setAttribute('uifolder', uifolder);
1122 }
1123
1124 if (mat['description'].length > 0) {
1125 docString += 'Description: ' + mat['description'];
1126 }
1127 }
1128
1129 // Always want to build the reference
1130 const refString = mat['reference'];
1131 if (refString.length > 0) {
1132 if (docString.length > 0) {
1133 docString += '. ';
1134 }
1135 docString += 'Reference: ' + refString[0];
1136
1137 let referenceItem = { name: matName, reference: refString[0] };
1138 //console.log('Add Reference:', referenceItem);
1139 references.push(referenceItem);
1140 }
1141 // Sort references by name
1142 references.sort((a, b) => a.name.localeCompare(b.name));
1143
1144 if (!shaderNode) {
1145 continue;
1146 }
1147 if (docString.length > 0) {
1148 shaderNode.setDocString(docString);
1149 }
1150
1151 // Create a new material
1152 const materialName = this.doc.createValidChildName(matName + '_' + shaderCategory + '_MPB');
1153 this.addComment(this.doc, ' Generated material: ' + matName + ' ');
1154 const materialNode = this.doc.addNode(this.mx.SURFACE_MATERIAL_NODE_STRING, materialName, this.mx.MATERIAL_TYPE_STRING);
1155 const shaderInput = materialNode.addInput(this.mx.SURFACE_SHADER_TYPE_STRING, this.mx.SURFACE_SHADER_TYPE_STRING);
1156 shaderInput.setAttribute(MTLX_NODE_NAME_ATTRIBUTE, shaderNode.getName());
1157
1158 // Warning this is a bit bespoke for remapping keys
1159 // to Autodesk Standard Surface shader inputs
1160 const skipKeys = ['name', "density", "category", "description", "sources", "tags", "reference"];
1161
1162 let metallness = null;
1163 let roughness = null;
1164 let transmission_color = null;
1165 let transmission = null;
1166 Object.entries(mat).forEach(([key, value]) => {
1167
1168 if (!skipKeys.includes(key)) {
1169
1170 //console.log(`-- Processing key: "${key}" with value:`, value);
1171
1172 if (key == 'metalness') {
1173 metallness = value;
1174 //console.log('Metalness:', metallness);
1175 }
1176 if (key == 'roughness') {
1177 roughness = value;
1178 //console.log('Roughness:', roughness);
1179 }
1180 if (key == 'transmission') {
1181 transmission = value;
1182 //console.log('Transmission:', transmission);
1183 }
1184 if (key == 'color') {
1185 transmission_color = value;
1186 //console.log('Color:', color);
1187 }
1188
1189 //console.log(`-- Remapping key "${key}" to "${remapKeys[key]}"`);
1190 if (remapKeys[key]) {
1191 key = remapKeys[key];
1192 }
1193
1194 let refInput = refNode.getInput(key);
1195 if (!refInput)
1196 refInput = refNode.addInputFromNodeDef(key);
1197 if (refInput) {
1198 const input = shaderNode.addInput(key);
1199 input.copyContentFrom(refInput);
1200 if (input) {
1201 // Convert number vector to string
1202 if (Array.isArray(value)) {
1203 value = value.join(',');
1204 }
1205 // Convert number to string
1206 else if (typeof value === 'number') {
1207 value = value.toString();
1208 }
1209 // Note: This API has side-effects as the
1210 // type is set to "string" when the value is set. Thus
1211 // we must explicitly set the type here.
1212 input.setValueString(value, refInput.getType());
1213 }
1214 }
1215 else {
1216 //console.log('>> Could not map input:', key, 'to node definition')
1217 }
1218 }
1219 });
1220
1221 if (transmission !== null && metallness !== null && roughness !== null && transmission_color !== null)
1222 {
1223 if (metallness == 0 && roughness == 0)
1224 {
1225 if (remapKeys['transmission_color']) {
1226 let inputName = remapKeys['transmission_color'];
1227 let input = shaderNode.addInput(inputName);
1228 if (input) {
1229 let value = transmission_color.join(',');
1230 //console.log(`Add "${inputName}": "${value}"`);
1231 input.setValueString(value, 'color3');
1232 }
1233 }
1234 }
1235 };
1236 }
1237 return true;
1238 }
getInputRemapping(shadingModel)
Get the remapping keys for a given shading model.
add_copyright_docstring(doc, shaderCategory='')
Add copyright docstring to the MaterialX document.

◆ create_all_translators()

JsPhysicallyBasedMaterialLoader::create_all_translators ( definitions,
output_doc = null )

Create translators for all supported shading models.

Parameters
{object}definitions - The source document containing Physically Based MaterialX definitions.
{object}output_doc - The document to add the translators to. If null, use the source doc.
Returns
{object[]} A list of created translator definitions.

Definition at line 418 of file JsMaterialXPhysicallyBased.js.

418 {
425 let trans_nodedefs = [];
426 // Create temporary doc with all standard library definitions
427 //let result = this.create_working_document();
428 let trans_doc = this.mx.createDocument();
429 let stdlib_defs = this.stdlib.getNodeDefs();
430 console.log('> --------------------->>>>>>>>>> Use stdlib', stdlib_defs.length, 'definitions');
431 trans_doc.setDataLibrary(this.stdlib);
432
433 // Add Physically Based Material definitions to the temporary document
434 trans_doc.copyContentFrom(definitions);
435 this.add_copyright_docstring(output_doc, '');
436 if (!output_doc) {
437 console.log('No output document specified for translators');
438 return trans_nodedefs;
439 }
440 // Source BSDF is always physbased_pbr_surface
441 let source_bsdf = this.physlib_category;
442 // Iterate over all target BSDFs
443 let bsdfs = this.find_all_bxdf(trans_doc);
444 for (let bsdf of bsdfs) {
445 let bsdf_name = bsdf.getNodeString();
446 if (bsdf_name === this.physlib_category) {
447 continue;
448 }
449 let target_bsdf = bsdf.getNodeString();
450 let remapping = this.getInputRemapping(target_bsdf);
451 if (remapping && Object.keys(remapping).length > 0) {
452 let trans_nodedef = this.create_translator(trans_doc, source_bsdf, target_bsdf, "", "", remapping, output_doc);
453 if (trans_nodedef) {
454 console.log(`> Created translator to BSDF: ${bsdf_name}`);
455 trans_nodedefs.push(trans_nodedef);
456 }
457 }
458 }
459 return trans_nodedefs;
460 }
create_translator(doc, source, target, source_version="", target_version="", mappings=null, output_doc)

◆ create_definition()

JsPhysicallyBasedMaterialLoader::create_definition ( doc = null)

Create a NodeDef for the Physically Based Material inputs

Parameters
{object|null}doc - The MaterialX document to add the NodeDef to. If null, a new document will be created.
Returns
{object} The MaterialX document with the created definition.

Definition at line 479 of file JsMaterialXPhysicallyBased.js.

479 {
485 if (!doc) {
486 doc = this.mx.createDocument();
488 }
489
490 // Create placeholder nodegraph
491 let graph = doc.addNodeGraph(this.get_physlib_implementation_name());
492 graph.setNodeDefString(this.get_physlib_definition_name());
493 let node = graph.addNode('oren_nayar_diffuse_bsdf', 'oren_nayar_diffuse_bsdf', 'BSDF');
494 let node_in = node.addInput('color', 'color3');
495 node_in.setInterfaceName('color');
496 let node_in_rough = node.addInput('roughness', 'float');
497 node_in_rough.setInterfaceName('roughness');
498 node.addOutput('out', 'BSDF');
499 node = graph.addNode('surface', 'surface', 'surfaceshader');
500 node_in = node.addInput('bsdf', 'BSDF');
501 node_in.setAttribute('out', 'out');
502 node_in.setNodeName('oren_nayar_diffuse_bsdf');
503 let node_out = graph.addOutput('out', 'surfaceshader');
504 node_out.setNodeName('surface');
505
506 // Create definition template
507 let ndef = doc.addNodeDef(this.get_physlib_definition_name(), 'surfaceshader');
508 ndef.setNodeString(this.physlib_category);
509 ndef.setNodeGroup("pbr");
510 ndef.setDocString("Node definitions for PhysicallyBased Material");
511 ndef.setVersionString("1.0");
512 ndef.setAttribute("isdefaultversion", "true");
513
514 if (this.materials) {
515 console.log('> Map keys to definition for materials:', this.materials.length);
516 for (let mat of this.materials) {
517 this.map_keys_to_definition(mat, ndef);
518 }
519 }
520 else {
521 console.log('> No materials to map keys to definition');
522 }
523 return doc;
524 }

◆ create_definition_materials()

JsPhysicallyBasedMaterialLoader::create_definition_materials ( doc_mat,
filter_list = null )

Create a MaterialX document containing Physically Based MaterialX materials

Parameters
{object|null}doc_mat - The MaterialX document to add the materials to
{string[]|null}filter_list - A list of material names to filter. If null, all materials will be processed.
Returns
{object} The MaterialX document containing the materials

Definition at line 526 of file JsMaterialXPhysicallyBased.js.

526 {
533 let definitions = this.get_definitions();
534 if (!doc_mat) {
535 doc_mat = this.mx.createDocument();
536 this.add_copyright_docstring(doc_mat, '');
537 }
538 // Reference the library definitions into the material document
539 doc_mat.setDataLibrary(definitions);
540 for (let mat of this.materials) {
541
542 let matName = mat['name'];
543 if (filter_list && !filter_list.includes(matName)) {
544 continue;
545 }
546
547 let shaderName = doc_mat.createValidChildName(matName + '_SHD_PBM');
548 //console.log('************* Create material for:', mat['name'], '-> shader name:', shaderName, filter_list);
549
550 let shaderNode = doc_mat.addNode(this.physlib_category, shaderName, this.mx.SURFACE_SHADER_TYPE_STRING);
551 for (let [key, value] of Object.entries(mat)) {
552 if (!value){
553 continue;
554 }
555
556 if (key === 'name') {
557 let new_name = doc_mat.createValidChildName(String(value));
558 shaderNode.setName(new_name);
559 }
560 let input = shaderNode.addInputFromNodeDef(key);
561 if (input) {
562 //console.log('> Add input for key:', key, 'value:', value, 'input:', input.getName());
563 if (Array.isArray(value)) {
564 value = value.map(x => String(x)).join(', ');
565 }
566 input.setValueString(String(value), input.getType());
567 // Add doc string
568 let doc_string = '';
569 if (key === 'description') {
570 doc_string = String(value);
571 }
572 if (doc_string.length > 0) {
573 shaderNode.setDocString(doc_string);
574 }
575 }
576 }
577 shaderNode.setAttribute('uiname', matName);
578
579 // Create a new material
580 let materialName = doc_mat.createValidChildName(matName + '_MAT_PBM');
581 let materialNode = doc_mat.addNode(this.mx.SURFACE_MATERIAL_NODE_STRING, materialName, this.mx.MATERIAL_TYPE_STRING);
582 let shaderInput = materialNode.addInput(this.mx.SURFACE_SHADER_TYPE_STRING, this.mx.SURFACE_SHADER_TYPE_STRING);
583 shaderInput.setAttribute(MTLX_NODE_NAME_ATTRIBUTE, shaderNode.getName());
584 }
585 return doc_mat;
586 }

◆ create_translator()

JsPhysicallyBasedMaterialLoader::create_translator ( doc,
source,
target,
source_version = "",
target_version = "",
mappings = null,
output_doc )

Create a translator nodedef and nodegraph from source to target definitions.

Parameters
{object}doc - The source document containing the definition.
{string}source - The source definition category.
{string}target - The target definition category.
{string}source_version - The source version string. If empty, use the first source definition version found.
{string}target_version - The target version string. If empty, use the first target definition version found.
{object}mappings - A dictionary mapping source input names to target input names.
{object}output_doc - The document to add the translator to. If null, use the source doc.
Returns
{object|null} The created translator definition.

Definition at line 297 of file JsMaterialXPhysicallyBased.js.

297 {
309 if (!output_doc) {
310 return null;
311 }
312 // Get source and target nodedefs
313 let nodedefs = this.find_all_bxdf(doc);
314 let source_nodedef = null;
315 let target_nodedef = null;
316 for (let nodedef of nodedefs) {
317 if (nodedef.getNodeString() === source) {
318 if (source_version === "" || nodedef.getVersionString() === source_version) {
319 source_nodedef = nodedef;
320 }
321 }
322 if (nodedef.getNodeString() === target) {
323 if (target_version === "" || nodedef.getVersionString() === target_version) {
324 target_nodedef = nodedef;
325 }
326 }
327 }
328 if (!source_nodedef || !target_nodedef) {
329 if (!source_nodedef) {
330 console.warn(`Source nodedef not found for '${source}' with version '${source_version}'`);
331 }
332 if (!target_nodedef) {
333 console.warn(`Target nodedef not found for '${target}' with version '${target_version}'`);
334 }
335 return null;
336 }
337 //console.log('******* Source nodedef:\n', this.mx.prettyPrint(source_nodedef));
338
339 // 1. Add a new nodedef for the translator
340 let derived_name = this.derive_translator_name_from_targets(source, target);
341 let nodename = derived_name.startsWith("ND_") ? derived_name.substring(3) : derived_name;
342 let translator_nodedef = output_doc.getNodeDef(derived_name);
343 if (translator_nodedef) {
344 console.log(`> Translator NodeDef already exists: ${target_nodedef.getName()}`);
345 return translator_nodedef;
346 }
347 else {
348 console.log(`> Creating Translator NodeDef: ${nodename} from '${source}' to '${target}'`);
349 }
350
351 translator_nodedef = output_doc.addNodeDef(derived_name);
352 translator_nodedef.removeOutput("out");
353 translator_nodedef.setNodeString(nodename);
354 translator_nodedef.setNodeGroup("translation");
355 translator_nodedef.setDocString(`Translator from '${source}' to '${target}'`);
356 let version1 = source_nodedef.getVersionString();
357 if (!version1) version1 = "1.0";
358 translator_nodedef.setAttribute('source_version', version1);
359 translator_nodedef.setAttribute('source', source);
360 let version2 = target_nodedef.getVersionString();
361 if (!version2) version2 = "1.0";
362 translator_nodedef.setAttribute('target_version', version2);
363 translator_nodedef.setAttribute('target', target);
364
365 // Add inputs from source as inputs to the translator
366 let comment = translator_nodedef.addChildOfCategory("comment");
367 comment.setDocString(`Inputs (inputs from source '${source}')`);
368 let inputs = source_nodedef.getActiveInputs();
369 //console.log('>>>>>>>>>>>>>> ADD Inputs from source nodedef:', inputs.length);
370 for (let input of inputs) {
371 //console.log('-------------------------- Input:', input.getName(), input.getType());
372 let nodedef_input = translator_nodedef.addInput(input.getName(), input.getType());
373 if (input.hasValueString()) {
374 nodedef_input.setValueString(input.getValueString(), input.getType());
375 }
376 }
377
378 // Add inputs from target as outputs to the translator
379 comment = translator_nodedef.addChildOfCategory("comment");
380 comment.setDocString(`Outputs (inputs from target '${target}' with '_out' suffix)`);
381 for (let input of target_nodedef.getActiveInputs()) {
382 let output_name = input.getName() + "_out";
383 translator_nodedef.addOutput(output_name, input.getType());
384 }
385 // 2. Create a new functional nodegraph
386 comment = output_doc.addChildOfCategory("comment");
387 comment.setDocString(`NodeGraph implementation for translator '${nodename}'`);
388 let nodegraph_id = 'NG_' + nodename;
389 let nodegraph = output_doc.addNodeGraph(nodegraph_id);
390 nodegraph.setNodeDefString(derived_name);
391 nodegraph.setDocString(`NodeGraph implementation of translator from '${source}' to '${target}'`);
392 nodegraph.setAttribute('source_version', version1);
393 nodegraph.setAttribute('source', source);
394 nodegraph.setAttribute('target_version', version2);
395 nodegraph.setAttribute('target', target);
396 for (let output of translator_nodedef.getActiveOutputs()) {
397 nodegraph.addOutput(output.getName(), output.getType());
398 }
399 if (mappings) {
400 for (let [source_input_name, target_input_name] of Object.entries(mappings)) {
401 let source_input = translator_nodedef.getInput(source_input_name);
402 let output_name = target_input_name + "_out";
403 let target_output = nodegraph.getOutput(output_name);
404 if (source_input && target_output) {
405 let dot_name = nodegraph.createValidChildName(target_input_name);
406 let comment = nodegraph.addChildOfCategory("comment");
407 comment.setDocString(`Routing source input: '${source_input_name}' to target input: '${target_input_name}'`);
408 let dot_node = nodegraph.addNode('dot', dot_name);
409 let dot_input = dot_node.addInput('in', source_input.getType());
410 dot_input.setInterfaceName(source_input.getName());
411 target_output.setNodeName(dot_node.getName());
412 }
413 }
414 }
415 return translator_nodedef;
416 }

◆ derive_translator_name_from_targets()

JsPhysicallyBasedMaterialLoader::derive_translator_name_from_targets ( source,
target )

Definition at line 292 of file JsMaterialXPhysicallyBased.js.

293 {
294 return `ND_${source}_to_${target}`;
295 }

◆ find_all_bxdf()

JsPhysicallyBasedMaterialLoader::find_all_bxdf ( doc)

Definition at line 279 of file JsMaterialXPhysicallyBased.js.

279 {
280 // Scan all nodedefs with output type of "surfaceshader"
281 let bxdfs = [];
282 for (let nodedef of doc.getNodeDefs()) {
283 if (nodedef.getType() === "surfaceshader") {
284 if (nodedef.getNodeString() !== "convert" && nodedef.getNodeString() !== "surface" && nodedef.getNodeGroup() === "pbr") {
285 bxdfs.push(nodedef);
286 }
287 }
288 }
289 return bxdfs;
290 }

◆ find_translator()

JsPhysicallyBasedMaterialLoader::find_translator ( doc,
source,
target )

Find a translator nodedef from source to target in the document.

Parameters
{object}doc - The MaterialX document to search.
{string}source - The source definition category.
{string}target - The target definition category.
Returns
{object|null} The translator nodedef if found, otherwise null.

Definition at line 588 of file JsMaterialXPhysicallyBased.js.

588 {
596 let derived_name = this.derive_translator_name_from_targets(source, target);
597 let translator_nodedef = doc.getNodeDef(derived_name);
598 return translator_nodedef;
599 }

◆ get_definitions()

JsPhysicallyBasedMaterialLoader::get_definitions ( )

Definition at line 200 of file JsMaterialXPhysicallyBased.js.

200 {
201 // Get a combined MaterialX document containing the standard library and Physically Based MaterialX definition and translators.
202 if (!this.all_lib) {
203 this.all_lib = this.mx.createDocument();
204 this.all_lib.copyContentFrom(this.stdlib);
205 if (this.physlib) {
206 this.all_lib.copyContentFrom(this.physlib);
207 }
208 if (this.physlib_translators) {
209 this.all_lib.copyContentFrom(this.physlib_translators);
210 }
211 }
212 return this.all_lib;
213 }

◆ get_physlib()

JsPhysicallyBasedMaterialLoader::get_physlib ( )

Definition at line 167 of file JsMaterialXPhysicallyBased.js.

167 {
168 // Get the Physically Based MaterialX definition library.
169 return this.physlib;
170 }

◆ get_physlib_category()

JsPhysicallyBasedMaterialLoader::get_physlib_category ( )

Definition at line 180 of file JsMaterialXPhysicallyBased.js.

180 {
181 // Get the Physically Based MaterialX surface category.
182 return this.physlib_category;
183 }

◆ get_physlib_definition()

JsPhysicallyBasedMaterialLoader::get_physlib_definition ( )

Definition at line 172 of file JsMaterialXPhysicallyBased.js.

172 {
173 // Get the Physically Based MaterialX definition NodeDef.
174 if (this.physlib) {
175 return this.physlib.getNodeDef(this.get_physlib_definition_name());
176 }
177 return null;
178 }

◆ get_physlib_definition_name()

JsPhysicallyBasedMaterialLoader::get_physlib_definition_name ( )

Definition at line 185 of file JsMaterialXPhysicallyBased.js.

185 {
186 // Get the Physically Based MaterialX definition name.
187 return this.physlib_definition_name;
188 }

◆ get_physlib_implementation_name()

JsPhysicallyBasedMaterialLoader::get_physlib_implementation_name ( )

Definition at line 190 of file JsMaterialXPhysicallyBased.js.

190 {
191 // Get the Physically Based MaterialX implementation (nodegraph) name.
192 return this.physlib_implementation_name;
193 }

◆ get_physlib_materials()

JsPhysicallyBasedMaterialLoader::get_physlib_materials ( )

Definition at line 195 of file JsMaterialXPhysicallyBased.js.

195 {
196 // Get the Physically Based MaterialX materials document.
197 return this.physlib_materials;
198 }

◆ getInputRemapping()

JsPhysicallyBasedMaterialLoader::getInputRemapping ( shadingModel)

Get the remapping keys for a given shading model.

Parameters
shadingModel- Shading model to get the remapping keys
Returns
Remapping keys for the shading model. Empty object if not found

Definition at line 146 of file JsMaterialXPhysicallyBased.js.

147 {
148 if (shadingModel in this.remapMap) {
149 return this.remapMap[shadingModel];
150 }
151 else
152 {
153 console.log('>> No remap keys for shading model:', shadingModel);
154 }
155 return {};
156 }
remapMap
Remap keys for input values for different shading models.

◆ getInputRemappingMap()

JsPhysicallyBasedMaterialLoader::getInputRemappingMap ( )

Get remmapping map.

Returns
{object} - Remapping map

Definition at line 162 of file JsMaterialXPhysicallyBased.js.

163 {
164 return this.remapMap;
165 }

◆ getJSON()

JsPhysicallyBasedMaterialLoader::getJSON ( )

Get the Physically Based Materials as JSON.

Returns
{object[]} - List of Physically Based Materials

Definition at line 102 of file JsMaterialXPhysicallyBased.js.

103 {
104 return this.materials
105 }

◆ getJSONMaterialNames()

JsPhysicallyBasedMaterialLoader::getJSONMaterialNames ( )

Get list of the Physically Based Material names.

Definition at line 110 of file JsMaterialXPhysicallyBased.js.

111 {
112 return this.materialNames
113 }

◆ getMaterialXDocument()

JsPhysicallyBasedMaterialLoader::getMaterialXDocument ( )

Get the MaterialX document.

Definition at line 118 of file JsMaterialXPhysicallyBased.js.

119 {
120 return this.doc;
121 }

◆ getMaterialXString()

JsPhysicallyBasedMaterialLoader::getMaterialXString ( )

Get the MaterialX document as a string.

Returns
{string} - MaterialX document as a string. Empty string if no document

Definition at line 971 of file JsMaterialXPhysicallyBased.js.

972 {
973 if (!this.doc) {
974 console.error('No MaterialX document to convert');
975 return '';
976 }
977
978 // Create write options
979 const writeOptions = new this.mx.XmlWriteOptions();
980 writeOptions.writeXIncludeEnable = false;
981 //writeOptions.writeXIncludes = false;
982 writeOptions.elementPredicate = this.skipLibraryElement;
983
984 // Convert the MaterialX document to a string
985 const mtlx = this.mx.writeToXmlString(this.doc, writeOptions);
986 return mtlx;
987 }
skipLibraryElement(element)
Predicate to skip library elements.

◆ getPhysicallyBasedMaterials()

async JsPhysicallyBasedMaterialLoader::getPhysicallyBasedMaterials ( )

Get the Physically Based Materials from the API.

Returns
{object[]} - List of Physically Based Materials in JSON format

Definition at line 898 of file JsMaterialXPhysicallyBased.js.

899 {
900 try {
901 // Re-initialize cached information
902 this.materials = null
903 this.materialNames = [];
904 this.physlib = null;
905 this.physlib_materials = null;
906 this.physlib_translators = null;
907 this.translated_materials = {};
908
909 const response = await fetch(this.url, {
910 method: 'GET',
911 headers: this.headers
912 });
913
914 if (!response.ok) {
915 throw new Error('Network response was not ok ' + response.statusText);
916 }
917
918 this.materials = await response.json();
919 for (let i = 0; i < this.materials.length; i++) {
920 this.materialNames.push(this.materials[i]['name']);
921 }
922 return this.materials;
923 } catch (error) {
924 console.error('There has been a problem with your fetch operation:', error);
925 }
926
927 return null;
928 }

◆ getReferenceList()

JsPhysicallyBasedMaterialLoader::getReferenceList ( )

Return a sorted list reference names mapped reference images.

Returns
{object[]} - List of references.

Definition at line 1005 of file JsMaterialXPhysicallyBased.js.

1006 {
1007 let references = [];
1008 if (this.materials) {
1009 for (let i = 0; i < this.materials.length; i++) {
1010 const mat = this.materials[i];
1011 const matName = mat['name'];
1012 const refString = mat['reference'];
1013 const tags = mat['tags'];
1014 const category = mat['category'];
1015 if (refString.length > 0)
1016 {
1017 let referenceItem = { name: matName, reference: refString[0], tags: tags, category: category };
1018 //console.log('Add Reference:', referenceItem);
1019 references.push(referenceItem);
1020 }
1021 }
1022 // Sort references by name
1023 references.sort((a, b) => a.name.localeCompare(b.name));
1024 }
1025 return references;
1026 }

◆ initialize_definitions_and_materials()

JsPhysicallyBasedMaterialLoader::initialize_definitions_and_materials ( shadingModel = 'standard_surface',
materialNames = [],
force = false )

Initialize Physically Based MaterialX definitions, materials, remappings, and translators.

Returns
{void}

Definition at line 697 of file JsMaterialXPhysicallyBased.js.

697 {
702
703 console.log('> Generate for shading model:', shadingModel, 'materials filer:', materialNames);
704
705 if (!this.physlib || force) {
706
707 // Create Physically Based MaterialX definition library
708 this.physlib = this.create_definition(null);
709 console.log('> Created Physically Based MaterialX definition library...');
710 }
711
712 let translated_doc = null;
713 let untranslated_doc = null;
714 if (!this.physlib_materials || !this.physlib_translators || force) {
715 // Create all translators
716 this.physlib_translators = this.mx.createDocument();
717 this.create_all_translators(this.physlib, this.physlib_translators);
718
719 // Create Physically Based MaterialX materials library
720 let filter_list = null;
721 this.physlib_materials = this.create_definition_materials(null, filter_list);
722 }
723
724 untranslated_doc = this.physlib_materials;
725
726 if (materialNames.length > 0) {
727
728 // Translate specified materials
729 //
730 untranslated_doc = this.create_definition_materials(null, materialNames);
731 translated_doc = this.mx.createDocument();
732 translated_doc.copyContentFrom(untranslated_doc);
733 translated_doc.setDataLibrary(this.get_definitions());
734 const category = this.get_physlib_category()
735 for (const node of translated_doc.getNodes()) {
736 if (materialNames.length > 0 && !materialNames.includes(node.getName())) {
737 continue;
738 }
739 if (node.getCategory() == 'physbased_pbr_surface')
740 {
741 console.log('> Translate specified material:', node.getName());
742 let result = this.translate_node(translated_doc, 'physbased_pbr_surface', shadingModel, node)
743 }
744 }
745
746 }
747 else
748 {
749 // Translate all material
750 //
751 if (!(shadingModel in this.translated_materials) || force) {
752
753 const category = this.get_physlib_category()
754 console.log('> Translating all materials from', category, 'to', shadingModel);
755
756 // Create translated materials for specified shader model
757 translated_doc = this.mx.createDocument();
758 translated_doc.copyContentFrom(this.physlib_materials);
759 translated_doc.setDataLibrary(this.get_definitions());
760 for (const node of translated_doc.getNodes()) {
761 if (node.getCategory() == 'physbased_pbr_surface')
762 {
763 let result = this.translate_node(translated_doc, 'physbased_pbr_surface', shadingModel, node)
764 }
765 }
766 this.translated_materials[shadingModel] = translated_doc;
767 }
768 else {
769 translated_doc = this.translated_materials[shadingModel];
770 }
771 }
772
773 let def_string = this.mx.writeToXmlString(this.physlib);
774 //console.log('> Physically Based MaterialX Definition Library:\n', def_string);
775 let trans_string = this.mx.writeToXmlString(this.physlib_translators);
776 //console.log('> Physically Based MaterialX Translators Library:\n', trans_string);
777 let mat_string = this.mx.writeToXmlString(untranslated_doc);
778 //console.log('> Physically Based MaterialX Materials Library:\n', mat_string);
779 let mat_trans_string = this.mx.writeToXmlString(translated_doc);
780
781 return { 'bsdf': def_string,
782 'bsdf_trans': trans_string,
783 'bsdf_materials': mat_string,
784 'bsdf_trans_materials': mat_trans_string };
785 }
create_definition_materials(doc_mat, filter_list=null)
create_all_translators(definitions, output_doc=null)

◆ initializeInputRemapping()

JsPhysicallyBasedMaterialLoader::initializeInputRemapping ( )

Initialize the input remapping for different shading models.

Returns
{void}

Definition at line 846 of file JsMaterialXPhysicallyBased.js.

847 {
848 console.log('Initializing input remapping for Physically Based Materials...');
849 this.remapMap = null;
850
851 const remapKeyURL = 'https://raw.githubusercontent.com/kwokcb/materialxMaterials/refs/heads/main/src/materialxMaterials/data/PhysicallyBasedMaterialX/PhysicallyBasedToMtlxMappings.json';
852
853 fetch(remapKeyURL)
854 .then((response) =>
855 {
856 if (!response.ok) {
857 console.warn(`HTTP error! Status: ${response.status}`);
858 return null;
859 }
860 return response.json();
861 })
862 .then((data) => {
863 if (data) {
864 this.remapMap = data;
865 console.log('- Remap keys loaded from repo:', this.remapMap);
866 } else {
867 console.log('- No remap keys from repo. Using default remap keys.');
868 this.setDefaultRemapKeys();
869 }
870 })
871 .catch((error) => {
872 console.log('- Error loading remap keys:', error);
873 this.setDefaultRemapKeys();
874 console.warn('- Using default remap keys.', this.remapMap);
875 });
876 }
setDefaultRemapKeys()
Set the default remapping keys for different shading models : glTF, OpenPBR, and Autodesk Standard Su...

◆ loadMaterialX()

JsPhysicallyBasedMaterialLoader::loadMaterialX ( )

Load the MaterialX module.

Returns
{Promise} - Promise to load the MaterialX module

Definition at line 882 of file JsMaterialXPhysicallyBased.js.

883 {
884 return new Promise((resolve, reject) => {
885 MaterialX().then((mtlx) => {
886 this.mx = mtlx;
887 resolve();
888 }).catch((error) => {
889 reject(error);
890 });
891 });
892 }

◆ loadStandardLibraries()

JsPhysicallyBasedMaterialLoader::loadStandardLibraries ( )

Load the MaterialX standard libraries.

Returns
{void}

Definition at line 934 of file JsMaterialXPhysicallyBased.js.

935 {
936 if (!this.mx) {
937 // Call the asynchronous function and then perform additional logic
938 this.loadMaterialX().then(() => {
939
940 this.esslgenerator = new this.mx.EsslShaderGenerator.create();
941 this.esslgenContext = new this.mx.GenContext(this.esslgenerator);
942 this.stdlib = this.mx.loadStandardLibraries(this.esslgenContext);
943 let children = this.stdlib.getChildren();
944 for (let i = 0; i < children.length; i++) {
945 let child = children[i];
946 child.setSourceUri('STDLIB_ELEMENT');
947 }
948
949 let nodedefs = this.stdlib.getNodeDefs();
950 console.log("MaterialX is loaded. With ", nodedefs.length, "definitions.");
951 }).catch((error) => {
952 console.error("Error loading MaterialX:", error);
953 });
954 }
955 }

◆ map_keys_to_definition()

JsPhysicallyBasedMaterialLoader::map_keys_to_definition ( mat,
ndef )

Definition at line 215 of file JsMaterialXPhysicallyBased.js.

215 {
216 // Map a key to a NodeDef input
217 for (let [key, value] of Object.entries(mat)) {
218 let uifolder = null;
219 if (!ndef.getInput(key)) {
220 //if (key === 'name') {
221 // Skip as these will be node instance names
222 // continue;
223 //}
224
225 let input_type = "string";
226 if (key.toLowerCase().includes('color')) {
227 input_type = "color3";
228 value = "1,1,1";
229 } else if (typeof value === 'number' && !Number.isInteger(value)) {
230 input_type = "float";
231 value = "0.0";
232 } else if (typeof value === 'number' && Number.isInteger(value)) {
233 input_type = "float";
234 value = "0.0";
235 } else if (key === 'category') {
236 // category handling (optional)
237 } else if (["sources", "reference", "tags", "group"].includes(key)) {
238 value = '';
239 }
240 //console.log(`> Add key as input: ${key}. Type: ${typeof value}. input_type: ${input_type}, value: ${value}`);
241 let input = ndef.addInput(key, input_type);
242 if (input) {
243 if (value !== undefined && value !== null) {
244 if (Array.isArray(value)) {
245 let value_list = value.map(x => String(x));
246 let is_number_list = value.every(x => typeof x === 'number');
247 if (is_number_list) {
248 if (value_list.length > 4) {
249 input_type = 'string'; // floatarray will cause errors in shader generation!
250 } else if (value_list.length > 3) {
251 input_type = 'vector4';
252 } else if (value_list.length > 2) {
253 input_type = 'vector3';
254 } else if (value_list.length > 1) {
255 input_type = 'vector2';
256 } else {
257 input_type = 'float';
258 }
259 value_list = value_list.map(() => '0.0');
260 }
261 value = value_list.join(', ');
262 }
263 input.setValueString(String(value));
264 input.setType(input_type);
265 }
266 // Split camel case names and separate by space, e.g. specularColor -> Specular Color
267 let uiname = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()).trim();
268 input.setAttribute("uiname", uiname);
269 uifolder = 'Base';
270 if (["description", "sources", "reference", "tags"].includes(key)) {
271 uifolder = 'Metadata';
272 }
273 input.setAttribute("uifolder", uifolder);
274 }
275 }
276 }
277 }

◆ setDefaultRemapKeys()

JsPhysicallyBasedMaterialLoader::setDefaultRemapKeys ( )

Set the default remapping keys for different shading models : glTF, OpenPBR, and Autodesk Standard Surface.

Returns
{void}

Definition at line 792 of file JsMaterialXPhysicallyBased.js.

793 {
794 const standard_surface_remapKeys = {
795 "color": "base_color",
796 "specularColor": "specular_color",
797 "roughness": "specular_roughness",
798 "metalness": "metalness",
799 "ior": "specular_IOR",
800 "subsurfaceRadius": "subsurface_radius",
801 "transmission": "transmission",
802 "transmission_color": "transmission_color",
803 "transmissionDispersion": "transmission_dispersion",
804 "thinFilmThickness": "thin_film_thickness",
805 "thinFilmIor": "thin_film_IOR"
806 };
807
808 const openpbr_remapKeys = {
809 "color": "base_color",
810 "specularColor": "specular_color",
811 "roughness": "specular_roughness",
812 "metalness": "base_metalness",
813 "ior": "specular_ior",
814 "subsurfaceRadius": "subsurface_radius",
815 "transmission": "transmission_weight",
816 "transmission_color": "transmission_color",
817 "transmissionDispersion": "transmission_dispersion_abbe_number",
818 "thinFilmThickness": "thin_film_thickness",
819 "thinFilmIor": "thin_film_ior"
820 };
821
822 const gltf_remapKeys = {
823 "color": "base_color",
824 "specularColor": "specular_color",
825 "roughness": "roughness",
826 "metalness": "metallic",
827 "ior": "ior",
828 "transmission": "transmission",
829 "transmission_color": "attenuation_color",
830 "thinFilmThickness": "iridescence_thickness",
831 "thinFilmIor": "iridescence_ior"
832 };
833
834 this.remapMap = {
835 'standard_surface': standard_surface_remapKeys,
836 'gltf_pbr': gltf_remapKeys,
837 'open_pbr_surface': openpbr_remapKeys
838 };
839 }

◆ skipLibraryElement()

JsPhysicallyBasedMaterialLoader::skipLibraryElement ( element)

Predicate to skip library elements.

Parameters
element- MaterialX element
Returns
True if the element is a library element. False otherwise

Definition at line 962 of file JsMaterialXPhysicallyBased.js.

963 {
964 return !elem.hasSourceUri()
965 }

◆ translate_node()

JsPhysicallyBasedMaterialLoader::translate_node ( doc,
source_bxdf,
target_bxdf,
node )

Translate a shader node of source_bxdf to target_bxdf using ungrouped nodes. This function creates a target node and a translation node based on the translator nodedef, then makes upstream and downstream connections.

Parameters
{object}doc - The document to operate on.
{string}source_bxdf - The source BXDF shading model name.
{string}target_bxdf - The target BXDF shading model name.
{object}node - The source shader node to translate.
Returns
{object|null} An object with 'translationNode' and 'targetNode' if successful, null otherwise.

Definition at line 601 of file JsMaterialXPhysicallyBased.js.

601 {
611 let nodedef = this.find_translator(doc, source_bxdf, target_bxdf);
612 if (!nodedef) {
613 console.warn(`- No translator found from '${source_bxdf}' to '${target_bxdf}' for node '${node.getName()}'`);
614 return null;
615 }
616 // Create a target node of the target_bxdf category.
617 let replace_name = node.getName();
618 let target_node_name = doc.createValidChildName(`${replace_name}_${target_bxdf}_SPB`);
619
620 // Cleanup dowstream connections
621 let downstream_ports = node.getDownstreamPorts()
622 for (let port of downstream_ports) {
623 //console.log('Scan downstream port:', port.getName(), 'of node:', port.getParent().getName());
624 let downstream_node = port.getParent();
625 let downstream_input = downstream_node.getInput(port.getName());
626 if (downstream_input) {
627 //console.log(` - Reconnecting downstream node '${downstream_node.getName()}' input '${downstream_input.getName()}' from '${node.getName()}' to target node '${target_node_name}'`);
628 downstream_input.setNodeName(target_node_name);
629 }
630 }
631
632 let targetNode = doc.addChildOfCategory(target_bxdf, target_node_name);
633 if (!targetNode) {
634 console.warn(`- Failed to create target node of category '${target_bxdf}' for node '${node.getName()}'`);
635 return null;
636 }
637 targetNode.setType("surfaceshader");
638 // WARNING: addInputsFromNodeDef() is missing from MaterialX JS API as of 1.39.5 !
639 //targetNode.addInputsFromNodeDef();
640 //const targetNodeDef = targetNode.getNodeDef();
641 //for (let input of targetNodeDef.getActiveInputs()) {
642 // let targetInput = targetNode.addInputFromNodeDef(input.getName());
643 //}
644
645 // Create a translation node based on the translator nodedef.
646 let translationNode = doc.addNodeInstance(nodedef,
647 targetNode.getName() + "_translator");
648
649 // Copy over inputs from the source node to the translation node.
650 let num_overrides = 0;
651 for (let input of node.getActiveInputs()) {
652 let translationInput = translationNode.addInputFromNodeDef(input.getName());
653 if (translationInput) {
654 translationInput.copyContentFrom(input);
655 num_overrides += 1;
656 }
657 }
658
659 // Connect translation outputs to target inputs.
660 const impl = nodedef.getImplementation();
661 for (let output of nodedef.getActiveOutputs()) {
662
663 // Avoid adding ports which do not route an input data
664 const impl_output = impl.getOutput(output.getName());
665 if (!impl_output.getConnectedNode()) {
666 continue;
667 }
668
669 let target_input_name = output.getName();
670 // Remove trailing '_out' from name
671 if (target_input_name.endsWith('_out')) {
672 target_input_name = target_input_name.slice(0, -4);
673 }
674
675 let translationOutput = translationNode.addOutput(output.getName(), output.getType());
676 translationOutput.copyContentFrom(output);
677
678 let target_input = targetNode.addInputFromNodeDef(target_input_name);
679 if (!target_input) {
680 console.info(` - Warning: Target node '${targetNode.getName()}' has no input named '${target_input_name}' for output '${output.getName()}'`);
681 continue;
682 } else {
683 target_input.setNodeName(translationNode.getName());
684 target_input.setOutputString(translationOutput.getName());
685 target_input.removeAttribute('value');
686 }
687 }
688
689
690 // Remove original node
691 doc.removeNode(replace_name);
692
693 return { 'translationNode': translationNode, 'targetNode': targetNode };
694 }

◆ validateDocument()

JsPhysicallyBasedMaterialLoader::validateDocument ( )

Validate the MaterialX document.

Returns
{[boolean, errors]} - True if the document is valid. False otherwise

Definition at line 127 of file JsMaterialXPhysicallyBased.js.

128 {
129 if (this.doc) {
130 let errors = {}
131 let errorString = ''
132 var valid = this.doc.validate(errors);
133 if (!valid) {
134 errorString = errors.message;
135 }
136 return [valid, errorString]
137 }
138 return [false, 'No MaterialX document'];
139 }

Member Data Documentation

◆ doc

JsPhysicallyBasedMaterialLoader::doc = null

Working MaterialX document.

Definition at line 43 of file JsMaterialXPhysicallyBased.js.

◆ headers

JsPhysicallyBasedMaterialLoader::headers = {}

Headers for the fetch operation.

Definition at line 18 of file JsMaterialXPhysicallyBased.js.

18{};

◆ materialNames

JsPhysicallyBasedMaterialLoader::materialNames = []

List of Physically Based Material names.

Definition at line 28 of file JsMaterialXPhysicallyBased.js.

◆ materials

JsPhysicallyBasedMaterialLoader::materials = null

List of Physically Based Materials.

Definition at line 23 of file JsMaterialXPhysicallyBased.js.

◆ mx

JsPhysicallyBasedMaterialLoader::mx = null

MaterialX module.

Definition at line 38 of file JsMaterialXPhysicallyBased.js.

◆ mxMaterialNames

JsPhysicallyBasedMaterialLoader::mxMaterialNames = []

List of MaterialX Material names.

Definition at line 33 of file JsMaterialXPhysicallyBased.js.

◆ remapMap

JsPhysicallyBasedMaterialLoader::remapMap = {}

Remap keys for input values for different shading models.

Definition at line 53 of file JsMaterialXPhysicallyBased.js.

53{};

◆ stdlib

JsPhysicallyBasedMaterialLoader::stdlib = null

MaterialX standard libraries.

Definition at line 48 of file JsMaterialXPhysicallyBased.js.

◆ url

JsPhysicallyBasedMaterialLoader::url = ''

URL to fetch the Physically Based Materials.

Definition at line 13 of file JsMaterialXPhysicallyBased.js.


The documentation for this class was generated from the following file: