MaterialXLab API  0.0.1
APIs For MaterialXLab Libraries
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.
 
 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.
 
 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

◆ addComment()

JsPhysicallyBasedMaterialLoader::addComment ( doc,
commentString )

Add a comment to the MaterialX document.

Parameters
doc- MaterialX document
commentString- Comment string to add

Definition at line 351 of file JsMaterialXPhysicallyBased.js.

352 {
353 let comment = doc.addChildOfCategory('comment')
354 comment.setDocString(commentString)
355 }

◆ 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 }
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 395 of file JsMaterialXPhysicallyBased.js.

395 {}, shaderPreFix = '')
396 {
397 if (!this.mx) {
398 console.error('MaterialX module is not loaded');
399 return false;
400 }
401
402 if (!this.materials) {
403 console.warn('No Physically Based Materials to convert');
404 return false;
405 }
406
407 if (Object.keys(remapKeys).length === 0)
408 {
409 remapKeys = this.getInputRemapping(shaderCategory);
410 }
411 //console.log('Using remap keys for shading model:', shaderCategory, remapKeys);
412
413 // Create a dummy doc with the surface shader with all inputs
414 // as reference
415 let refDoc = this.mx.createDocument();
416 refDoc.importLibrary(this.stdlib);
417 const refNode = refDoc.addNode(shaderCategory, 'refShader', this.mx.SURFACE_SHADER_TYPE_STRING);
418 if (addAllInputs) {
419 console.warn('MaterialX JS API missing addInputsFromNodeDef()');
420 //refNode.addInputsFromNodeDef() -- This is missing from the JS API.
421 }
422 this.doc = this.mx.createDocument();
423
424 // Add document level accreditation
425 let docString = 'Physically Based Materials from https://api.physicallybased.info.\n'
426 docString += ' Content Author: Anton Palmqvist, https://antonpalmqvist.com/ \n'
427 docString += ` Content processsed via REST API and mapped to MaterialX V${this.mx.getVersionString()} \n`
428 docString += ` Target Shading Model: ${shaderCategory} \n`
429 docString += ' Utility Author: Bernard Kwok. kwokcb@gmail.com '
430 this.doc.setDocString(docString);
431
432 // Add properties to the material
433 for (let i = 0; i < this.materials.length; i++) {
434 const mat = this.materials[i];
435 let matName = mat['name'];
436
437 // Filter by material name(s)
438 let skipGeneration = materialNames.length > 0 && !materialNames.includes(matName);
439
440 let shaderNode = null;
441 if (!skipGeneration)
442 {
443 if (shaderPreFix.length > 0) {
444 matName = shaderPreFix + '_' + matName;
445 }
446
447 const shaderName = this.doc.createValidChildName(matName + '_' + shaderCategory + '_SPB');
448 this.addComment(this.doc, ' Generated shader: ' + matName + ' ');
449 shaderNode = this.doc.addNode(shaderCategory, shaderName, this.mx.SURFACE_SHADER_TYPE_STRING);
450
451 const category = mat['category'];
452 const group = mat['group'];
453 let uifolder = '';
454 if (category && category.length > 0) {
455 uifolder = category[0];
456 }
457 if (group && group.length > 0) {
458 if (uifolder.length > 0) {
459 uifolder += '/';
460 }
461 uifolder += group[0];
462 }
463 if (uifolder.length > 0) {
464 shaderNode.setAttribute('uifolder', uifolder);
465 }
466
467 let docString = ''
468 if (mat['description'].length > 0) {
469 docString += 'Description: ' + mat['description'];
470 }
471 }
472
473 // Always want to build the ference
474 const refString = mat['reference'];
475 if (refString.length > 0) {
476 if (docString.length > 0) {
477 docString += '. ';
478 }
479 docString += 'Reference: ' + refString[0];
480
481 let referenceItem = { name: matName, reference: refString[0] };
482 //console.log('Add Reference:', referenceItem);
483 references.push(referenceItem);
484 }
485 // Sort references by name
486 references.sort((a, b) => a.name.localeCompare(b.name));
487
488 if (!shaderNode) {
489 continue;
490 }
491 if (docString.length > 0) {
492 shaderNode.setDocString(docString);
493 }
494
495 // Create a new material
496 const materialName = this.doc.createValidChildName(matName + '_' + shaderCategory + '_MPB');
497 this.addComment(this.doc, ' Generated material: ' + matName + ' ');
498 const materialNode = this.doc.addNode(this.mx.SURFACE_MATERIAL_NODE_STRING, materialName, this.mx.MATERIAL_TYPE_STRING);
499 const shaderInput = materialNode.addInput(this.mx.SURFACE_SHADER_TYPE_STRING, this.mx.SURFACE_SHADER_TYPE_STRING);
500 shaderInput.setAttribute(MTLX_NODE_NAME_ATTRIBUTE, shaderNode.getName());
501
502 // Warning this is a bit bespoke for remapping keys
503 // to Autodesk Standard Surface shader inputs
504 const skipKeys = ['name', "density", "category", "description", "sources", "tags", "reference"];
505
506 let metallness = null;
507 let roughness = null;
508 let transmission_color = null;
509 let transmission = null;
510 Object.entries(mat).forEach(([key, value]) => {
511
512 if (!skipKeys.includes(key)) {
513
514 //console.log(`-- Processing key: "${key}" with value:`, value);
515
516 if (key == 'metalness') {
517 metallness = value;
518 //console.log('Metalness:', metallness);
519 }
520 if (key == 'roughness') {
521 roughness = value;
522 //console.log('Roughness:', roughness);
523 }
524 if (key == 'transmission') {
525 transmission = value;
526 //console.log('Transmission:', transmission);
527 }
528 if (key == 'color') {
529 transmission_color = value;
530 //console.log('Color:', color);
531 }
532
533 //console.log(`-- Remapping key "${key}" to "${remapKeys[key]}"`);
534 if (remapKeys[key]) {
535 key = remapKeys[key];
536 }
537
538 let refInput = refNode.getInput(key);
539 if (!refInput)
540 refInput = refNode.addInputFromNodeDef(key);
541 if (refInput) {
542 const input = shaderNode.addInput(key);
543 input.copyContentFrom(refInput);
544 if (input) {
545 // Convert number vector to string
546 if (Array.isArray(value)) {
547 value = value.join(',');
548 }
549 // Convert number to string
550 else if (typeof value === 'number') {
551 value = value.toString();
552 }
553 // Note: This API has side-effects as the
554 // type is set to "string" when the value is set. Thus
555 // we must explicitly set the type here.
556 input.setValueString(value, refInput.getType());
557 }
558 }
559 else {
560 //console.log('>> Could not map input:', key, 'to node definition')
561 }
562 }
563 });
564
565 if (transmission !== null && metallness !== null && roughness !== null && transmission_color !== null)
566 {
567 if (metallness == 0 && roughness == 0)
568 {
569 if (remapKeys['transmission_color']) {
570 let inputName = remapKeys['transmission_color'];
571 let input = shaderNode.addInput(inputName);
572 if (input) {
573 let value = transmission_color.join(',');
574 //console.log(`Add "${inputName}": "${value}"`);
575 input.setValueString(value, 'color3');
576 }
577 }
578 }
579 };
580 }
581 return true;
582 }
let MTLX_NODE_NAME_ATTRIBUTE
getInputRemapping(shadingModel)
Get the remapping keys for a given shading model.
addComment(doc, commentString)
Add a comment to the MaterialX document.

◆ 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 130 of file JsMaterialXPhysicallyBased.js.

131 {
132 if (shadingModel in this.remapMap) {
133 return this.remapMap[shadingModel];
134 }
135 else
136 {
137 console.warn('>> No remap keys for shading model:', shadingModel);
138 }
139 return {};
140 }
remapMap
Remap keys for input values for different shading models.

◆ getInputRemappingMap()

JsPhysicallyBasedMaterialLoader::getInputRemappingMap ( )

Get remmapping map.

Returns
{object} - Remapping map

Definition at line 146 of file JsMaterialXPhysicallyBased.js.

147 {
148 return this.remapMap;
149 }

◆ getJSON()

JsPhysicallyBasedMaterialLoader::getJSON ( )

Get the Physically Based Materials as JSON.

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

Definition at line 86 of file JsMaterialXPhysicallyBased.js.

87 {
88 return this.materials
89 }

◆ getJSONMaterialNames()

JsPhysicallyBasedMaterialLoader::getJSONMaterialNames ( )

Get list of the Physically Based Material names.

Definition at line 94 of file JsMaterialXPhysicallyBased.js.

95 {
96 return this.materialNames
97 }

◆ getMaterialXDocument()

JsPhysicallyBasedMaterialLoader::getMaterialXDocument ( )

Get the MaterialX document.

Definition at line 102 of file JsMaterialXPhysicallyBased.js.

103 {
104 return this.doc;
105 }

◆ 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 328 of file JsMaterialXPhysicallyBased.js.

329 {
330 if (!this.doc) {
331 console.error('No MaterialX document to convert');
332 return '';
333 }
334
335 // Create write options
336 const writeOptions = new this.mx.XmlWriteOptions();
337 writeOptions.writeXIncludeEnable = false;
338 //writeOptions.writeXIncludes = false;
339 writeOptions.elementPredicate = this.skipLibraryElement;
340
341 // Convert the MaterialX document to a string
342 const mtlx = this.mx.writeToXmlString(this.doc, writeOptions);
343 return mtlx;
344 }
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 261 of file JsMaterialXPhysicallyBased.js.

262 {
263 try {
264 this.materials = null
265 this.materialNames = [];
266
267 const response = await fetch(this.url, {
268 method: 'GET',
269 headers: this.headers
270 });
271
272 if (!response.ok) {
273 throw new Error('Network response was not ok ' + response.statusText);
274 }
275
276 this.materials = await response.json();
277 for (let i = 0; i < this.materials.length; i++) {
278 this.materialNames.push(this.materials[i]['name']);
279 }
280 return this.materials;
281 } catch (error) {
282 console.error('There has been a problem with your fetch operation:', error);
283 }
284
285 return null;
286 }

◆ getReferenceList()

JsPhysicallyBasedMaterialLoader::getReferenceList ( )

Return a sorted list reference names mapped reference images.

Returns
{object[]} - List of references.

Definition at line 362 of file JsMaterialXPhysicallyBased.js.

363 {
364 let references = [];
365 if (this.materials) {
366 for (let i = 0; i < this.materials.length; i++) {
367 const mat = this.materials[i];
368 const matName = mat['name'];
369 const refString = mat['reference'];
370 const tags = mat['tags'];
371 const category = mat['category'];
372 if (refString.length > 0)
373 {
374 let referenceItem = { name: matName, reference: refString[0], tags: tags, category: category };
375 //console.log('Add Reference:', referenceItem);
376 references.push(referenceItem);
377 }
378 }
379 // Sort references by name
380 references.sort((a, b) => a.name.localeCompare(b.name));
381 }
382 return references;
383 }

◆ initializeInputRemapping()

JsPhysicallyBasedMaterialLoader::initializeInputRemapping ( )

Initialize the input remapping for different shading models.

Returns
{void}

Definition at line 209 of file JsMaterialXPhysicallyBased.js.

210 {
211 console.log('Initializing input remapping for Physically Based Materials...');
212 this.remapMap = null;
213
214 const remapKeyURL = 'https://raw.githubusercontent.com/kwokcb/materialxMaterials/refs/heads/main/src/materialxMaterials/data/PhysicallyBasedMaterialX/PhysicallyBasedToMtlxMappings.json';
215
216 fetch(remapKeyURL)
217 .then((response) =>
218 {
219 if (!response.ok) {
220 console.warn(`HTTP error! Status: ${response.status}`);
221 return null;
222 }
223 return response.json();
224 })
225 .then((data) => {
226 if (data) {
227 this.remapMap = data;
228 console.log('- Remap keys loaded from repo:', this.remapMap);
229 } else {
230 console.warn('- No remap keys from repo. Using default remap keys.');
231 this.setDefaultRemapKeys();
232 }
233 })
234 .catch((error) => {
235 console.log('- Error loading remap keys:', error);
236 this.setDefaultRemapKeys();
237 console.warn('- Using default remap keys.', this.remapMap);
238 });
239 }
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 245 of file JsMaterialXPhysicallyBased.js.

246 {
247 return new Promise((resolve, reject) => {
248 MaterialX().then((mtlx) => {
249 this.mx = mtlx;
250 resolve();
251 }).catch((error) => {
252 reject(error);
253 });
254 });
255 }

◆ loadStandardLibraries()

JsPhysicallyBasedMaterialLoader::loadStandardLibraries ( )

Load the MaterialX standard libraries.

Returns
{void}

Definition at line 292 of file JsMaterialXPhysicallyBased.js.

293 {
294 if (!this.mx) {
295 // Call the asynchronous function and then perform additional logic
296 this.loadMaterialX().then(() => {
297
298 this.esslgenerator = new this.mx.EsslShaderGenerator.create();
299 this.esslgenContext = new this.mx.GenContext(this.esslgenerator);
300 this.stdlib = this.mx.loadStandardLibraries(this.esslgenContext);
301 let children = this.stdlib.getChildren();
302 for (let i = 0; i < children.length; i++) {
303 let child = children[i];
304 child.setSourceUri('STDLIB_ELEMENT');
305 }
306
307 console.log("MaterialX is loaded");
308 }).catch((error) => {
309 console.error("Error loading MaterialX:", error);
310 });
311 }
312 }

◆ setDefaultRemapKeys()

JsPhysicallyBasedMaterialLoader::setDefaultRemapKeys ( )

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

Returns
{void}

Definition at line 155 of file JsMaterialXPhysicallyBased.js.

156 {
157 const standard_surface_remapKeys = {
158 "color": "base_color",
159 "specularColor": "specular_color",
160 "roughness": "specular_roughness",
161 "metalness": "metalness",
162 "ior": "specular_IOR",
163 "subsurfaceRadius": "subsurface_radius",
164 "transmission": "transmission",
165 "transmission_color": "transmission_color",
166 "transmissionDispersion": "transmission_dispersion",
167 "thinFilmThickness": "thin_film_thickness",
168 "thinFilmIor": "thin_film_IOR"
169 };
170
171 const openpbr_remapKeys = {
172 "color": "base_color",
173 "specularColor": "specular_color",
174 "roughness": "specular_roughness",
175 "metalness": "base_metalness",
176 "ior": "specular_ior",
177 "subsurfaceRadius": "subsurface_radius",
178 "transmission": "transmission_weight",
179 "transmission_color": "transmission_color",
180 "transmissionDispersion": "transmission_dispersion_abbe_number",
181 "thinFilmThickness": "thin_film_thickness",
182 "thinFilmIor": "thin_film_ior"
183 };
184
185 const gltf_remapKeys = {
186 "color": "base_color",
187 "specularColor": "specular_color",
188 "roughness": "roughness",
189 "metalness": "metallic",
190 "ior": "ior",
191 "transmission": "transmission",
192 "transmission_color": "attenuation_color",
193 "thinFilmThickness": "iridescence_thickness",
194 "thinFilmIor": "iridescence_ior"
195 };
196
197 this.remapMap = {
198 'standard_surface': standard_surface_remapKeys,
199 'gltf_pbr': gltf_remapKeys,
200 'open_pbr_surface': openpbr_remapKeys
201 };
202 }

◆ 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 319 of file JsMaterialXPhysicallyBased.js.

320 {
321 return !elem.hasSourceUri()
322 }

◆ validateDocument()

JsPhysicallyBasedMaterialLoader::validateDocument ( )

Validate the MaterialX document.

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

Definition at line 111 of file JsMaterialXPhysicallyBased.js.

112 {
113 if (this.doc) {
114 let errors = {}
115 let errorString = ''
116 var valid = this.doc.validate(errors);
117 if (!valid) {
118 errorString = errors.message;
119 }
120 return [valid, errorString]
121 }
122 return [false, 'No MaterialX document'];
123 }

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: