297 create_translator(
doc, source, target, source_version =
"", target_version =
"", mappings =
null, output_doc) {
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;
322 if (nodedef.getNodeString() === target) {
323 if (target_version ===
"" || nodedef.getVersionString() === target_version) {
324 target_nodedef = nodedef;
328 if (!source_nodedef || !target_nodedef) {
329 if (!source_nodedef) {
330 console.warn(`Source nodedef not found
for '${source}' with version
'${source_version}'`);
332 if (!target_nodedef) {
333 console.warn(`Target nodedef not found
for '${target}' with version
'${target_version}'`);
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;
348 console.log(`> Creating Translator NodeDef: ${nodename} from
'${source}' to
'${target}'`);
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);
366 let comment = translator_nodedef.addChildOfCategory(
"comment");
367 comment.setDocString(`Inputs (inputs from source
'${source}')`);
368 let inputs = source_nodedef.getActiveInputs();
370 for (let input of inputs) {
372 let nodedef_input = translator_nodedef.addInput(input.getName(), input.getType());
373 if (input.hasValueString()) {
374 nodedef_input.setValueString(input.getValueString(), input.getType());
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());
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());
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());
415 return translator_nodedef;
425 let trans_nodedefs = [];
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);
434 trans_doc.copyContentFrom(definitions);
437 console.log(
'No output document specified for translators');
438 return trans_nodedefs;
441 let source_bsdf = this.physlib_category;
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) {
449 let target_bsdf = bsdf.getNodeString();
451 if (remapping && Object.keys(remapping).length > 0) {
452 let trans_nodedef = this.
create_translator(trans_doc, source_bsdf, target_bsdf,
"",
"", remapping, output_doc);
454 console.log(`> Created translator to BSDF: ${bsdf_name}`);
455 trans_nodedefs.push(trans_nodedef);
459 return trans_nodedefs;
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');
486 doc = this.
mx.createDocument();
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');
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");
515 console.log(
'> Map keys to definition for materials:', this.
materials.length);
517 this.map_keys_to_definition(mat, ndef);
521 console.log(
'> No materials to map keys to definition');
533 let definitions = this.get_definitions();
535 doc_mat = this.
mx.createDocument();
539 doc_mat.setDataLibrary(definitions);
542 let matName = mat[
'name'];
543 if (filter_list && !filter_list.includes(matName)) {
547 let shaderName = doc_mat.createValidChildName(matName +
'_SHD_PBM');
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)) {
556 if (key ===
'name') {
557 let new_name = doc_mat.createValidChildName(String(value));
558 shaderNode.setName(new_name);
560 let input = shaderNode.addInputFromNodeDef(key);
563 if (Array.isArray(value)) {
564 value = value.map(x => String(x)).join(
', ');
566 input.setValueString(String(value), input.getType());
569 if (key ===
'description') {
570 doc_string = String(value);
572 if (doc_string.length > 0) {
573 shaderNode.setDocString(doc_string);
577 shaderNode.setAttribute(
'uiname', matName);
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());
613 console.warn(`- No translator found from
'${source_bxdf}' to
'${target_bxdf}' for node
'${node.getName()}'`);
617 let replace_name = node.getName();
618 let target_node_name =
doc.createValidChildName(`${replace_name}_${target_bxdf}_SPB`);
621 let downstream_ports = node.getDownstreamPorts()
622 for (let port of downstream_ports) {
624 let downstream_node = port.getParent();
625 let downstream_input = downstream_node.getInput(port.getName());
626 if (downstream_input) {
628 downstream_input.setNodeName(target_node_name);
632 let targetNode =
doc.addChildOfCategory(target_bxdf, target_node_name);
634 console.warn(`- Failed to create target node of category
'${target_bxdf}' for node
'${node.getName()}'`);
637 targetNode.setType(
"surfaceshader");
646 let translationNode =
doc.addNodeInstance(nodedef,
647 targetNode.getName() +
"_translator");
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);
660 const impl = nodedef.getImplementation();
661 for (let output of nodedef.getActiveOutputs()) {
664 const impl_output = impl.getOutput(output.getName());
665 if (!impl_output.getConnectedNode()) {
669 let target_input_name = output.getName();
671 if (target_input_name.endsWith(
'_out')) {
672 target_input_name = target_input_name.slice(0, -4);
675 let translationOutput = translationNode.addOutput(output.getName(), output.getType());
676 translationOutput.copyContentFrom(output);
678 let target_input = targetNode.addInputFromNodeDef(target_input_name);
680 console.info(` - Warning: Target node
'${targetNode.getName()}' has no input named
'${target_input_name}' for output
'${output.getName()}'`);
683 target_input.setNodeName(translationNode.getName());
684 target_input.setOutputString(translationOutput.getName());
685 target_input.removeAttribute(
'value');
691 doc.removeNode(replace_name);
693 return {
'translationNode': translationNode,
'targetNode': targetNode };
703 console.log(
'> Generate for shading model:', shadingModel,
'materials filer:',
materialNames);
705 if (!this.physlib || force) {
709 console.log(
'> Created Physically Based MaterialX definition library...');
712 let translated_doc =
null;
713 let untranslated_doc =
null;
714 if (!this.physlib_materials || !this.physlib_translators || force) {
716 this.physlib_translators = this.
mx.createDocument();
720 let filter_list =
null;
724 untranslated_doc = this.physlib_materials;
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()) {
739 if (node.getCategory() ==
'physbased_pbr_surface')
741 console.log(
'> Translate specified material:', node.getName());
742 let result = this.
translate_node(translated_doc,
'physbased_pbr_surface', shadingModel, node)
751 if (!(shadingModel in this.translated_materials) || force) {
753 const category = this.get_physlib_category()
754 console.log(
'> Translating all materials from', category,
'to', shadingModel);
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')
763 let result = this.
translate_node(translated_doc,
'physbased_pbr_surface', shadingModel, node)
766 this.translated_materials[shadingModel] = translated_doc;
769 translated_doc = this.translated_materials[shadingModel];
773 let def_string = this.
mx.writeToXmlString(this.physlib);
775 let trans_string = this.
mx.writeToXmlString(this.physlib_translators);
777 let mat_string = this.
mx.writeToXmlString(untranslated_doc);
779 let mat_trans_string = this.
mx.writeToXmlString(translated_doc);
781 return {
'bsdf': def_string,
782 'bsdf_trans': trans_string,
783 'bsdf_materials': mat_string,
784 'bsdf_trans_materials': mat_trans_string };
1059 console.error(
'MaterialX module is not loaded');
1064 console.warn(
'No Physically Based Materials to convert');
1068 if (Object.keys(remapKeys).length === 0)
1076 let refDoc = this.
mx.createDocument();
1077 refDoc.importLibrary(this.
stdlib);
1078 const refNode = refDoc.addNode(shaderCategory,
'refShader', this.
mx.SURFACE_SHADER_TYPE_STRING);
1080 console.warn(
'MaterialX JS API missing addInputsFromNodeDef()');
1083 this.
doc = this.
mx.createDocument();
1089 for (let i = 0; i < this.
materials.length; i++) {
1091 let matName = mat[
'name'];
1096 let shaderNode =
null;
1098 if (!skipGeneration)
1100 if (shaderPreFix.length > 0) {
1101 matName = shaderPreFix +
'_' + matName;
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);
1108 const category = mat[
'category'];
1109 const group = mat[
'group'];
1111 if (category && category.length > 0) {
1112 uifolder = category[0];
1114 if (group && group.length > 0) {
1115 if (uifolder.length > 0) {
1118 uifolder += group[0];
1120 if (uifolder.length > 0) {
1121 shaderNode.setAttribute(
'uifolder', uifolder);
1124 if (mat[
'description'].length > 0) {
1125 docString +=
'Description: ' + mat[
'description'];
1130 const refString = mat[
'reference'];
1131 if (refString.length > 0) {
1132 if (docString.length > 0) {
1135 docString +=
'Reference: ' + refString[0];
1137 let referenceItem = { name: matName, reference: refString[0] };
1139 references.push(referenceItem);
1142 references.sort((a, b) => a.name.localeCompare(b.name));
1147 if (docString.length > 0) {
1148 shaderNode.setDocString(docString);
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());
1160 const skipKeys = [
'name',
"density",
"category",
"description",
"sources",
"tags",
"reference"];
1162 let metallness =
null;
1163 let roughness =
null;
1164 let transmission_color =
null;
1165 let transmission =
null;
1166 Object.entries(mat).forEach(([key, value]) => {
1168 if (!skipKeys.includes(key)) {
1172 if (key ==
'metalness') {
1176 if (key ==
'roughness') {
1180 if (key ==
'transmission') {
1181 transmission = value;
1184 if (key ==
'color') {
1185 transmission_color = value;
1190 if (remapKeys[key]) {
1191 key = remapKeys[key];
1194 let refInput = refNode.getInput(key);
1196 refInput = refNode.addInputFromNodeDef(key);
1198 const input = shaderNode.addInput(key);
1199 input.copyContentFrom(refInput);
1202 if (Array.isArray(value)) {
1203 value = value.join(
',');
1206 else if (typeof value ===
'number') {
1207 value = value.toString();
1212 input.setValueString(value, refInput.getType());
1221 if (transmission !==
null && metallness !==
null && roughness !==
null && transmission_color !==
null)
1223 if (metallness == 0 && roughness == 0)
1225 if (remapKeys[
'transmission_color']) {
1226 let inputName = remapKeys[
'transmission_color'];
1227 let input = shaderNode.addInput(inputName);
1229 let value = transmission_color.join(
',');
1231 input.setValueString(value,
'color3');