MaterialXMaterials 0.0.3
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.
 
 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.
 
 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 338 of file JsMaterialXPhysicallyBased.js.

339 {
340 let comment = doc.addChildOfCategory('comment')
341 comment.setDocString(commentString)
342 }

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

355 {}, shaderPreFix = '')
356 {
357 if (!this.mx) {
358 console.error('MaterialX module is not loaded');
359 return false;
360 }
361
362 if (!this.materials) {
363 console.warn('No Physically Based Materials to convert');
364 return false;
365 }
366
367 if (remapKeys.length == 0) {
368 remapKeys = this.getInputRemapping(shaderCategory);
369 }
370
371 // Create a dummy doc with the surface shader with all inputs
372 // as reference
373 let refDoc = this.mx.createDocument();
374 refDoc.importLibrary(this.stdlib);
375 const refNode = refDoc.addNode(shaderCategory, 'refShader', this.mx.SURFACE_SHADER_TYPE_STRING);
376 //refNode.addInputsFromNodeDef() -- This is missing from the JS API.
377 this.doc = this.mx.createDocument();
378
379 // Add document level accreditation
380 let docString = 'Physically Based Materials from https://api.physicallybased.info.\n'
381 docString += ' Content Author: Anton Palmqvist, https://antonpalmqvist.com/ \n'
382 docString += ` Content processsed via REST API and mapped to MaterialX V${this.mx.getVersionString()} \n`
383 docString += ` Target Shading Model: ${shaderCategory} \n`
384 docString += ' Utility Author: Bernard Kwok. kwokcb@gmail.com '
385 this.doc.setDocString(docString);
386
387 // Add properties to the material
388 for (let i = 0; i < this.materials.length; i++) {
389 const mat = this.materials[i];
390 let matName = mat['name'];
391
392 // Filter by material name(s)
393 if (materialNames.length > 0 && !materialNames.includes(matName)) {
394 // Skip material
395 console.log('Skipping material:', matName);
396 continue;
397 }
398
399
400 if (shaderPreFix.length > 0) {
401 matName = shaderPreFix + '_' + matName;
402 }
403
404 const shaderName = this.doc.createValidChildName('SPB_' + matName + '_' + shaderCategory);
405 this.addComment(this.doc, ' Generated shader: ' + matName + ' ');
406 const shaderNode = this.doc.addNode(shaderCategory, shaderName, this.mx.SURFACE_SHADER_TYPE_STRING);
407
408 const category = mat['category'];
409 const group = mat['group'];
410 let uifolder = '';
411 if (category && category.length > 0) {
412 uifolder = category[0];
413 }
414 if (group && group.length > 0) {
415 if (uifolder.length > 0) {
416 uifolder += '/';
417 }
418 uifolder += group[0];
419 }
420 if (uifolder.length > 0) {
421 shaderNode.setAttribute('uifolder', uifolder);
422 }
423
424 let docString = ''
425 if (mat['description'].length > 0) {
426 docString += 'Description: ' + mat['description'];
427 }
428 const refString = mat['reference'];
429 if (refString.length > 0) {
430 if (docString.length > 0) {
431 docString += '. ';
432 }
433 docString += 'Reference: ' + refString[0];
434
435 let referenceItem = { name: matName, reference: refString[0] };
436 console.log('Add Reference:', referenceItem);
437 references.push(referenceItem);
438 }
439 if (docString.length > 0) {
440 shaderNode.setDocString(docString);
441 }
442
443 // Create a new material
444 const materialName = this.doc.createValidChildName('MPB_' + matName + '_' + shaderCategory);
445 this.addComment(this.doc, ' Generated material: ' + matName + ' ');
446 const materialNode = this.doc.addNode(this.mx.SURFACE_MATERIAL_NODE_STRING, materialName, this.mx.MATERIAL_TYPE_STRING);
447 const shaderInput = materialNode.addInput(this.mx.SURFACE_SHADER_TYPE_STRING, this.mx.SURFACE_SHADER_TYPE_STRING);
448 shaderInput.setAttribute(MTLX_NODE_NAME_ATTRIBUTE, shaderNode.getName());
449
450 // Warning this is a bit bespoke for remapping keys
451 // to Autodesk Standard Surface shader inputs
452 const skipKeys = ['name', "density", "category", "description", "sources", "tags", "reference"];
453
454 let metallness = null;
455 let roughness = null;
456 let transmission_color = null;
457 let transmission = null;
458 Object.entries(mat).forEach(([key, value]) => {
459
460 if (!skipKeys.includes(key)) {
461
462 if (key == 'metalness') {
463 metallness = value;
464 //console.log('Metalness:', metallness);
465 }
466 if (key == 'roughness') {
467 roughness = value;
468 //console.log('Roughness:', roughness);
469 }
470 if (key == 'transmission') {
471 transmission = value;
472 //console.log('Transmission:', transmission);
473 }
474 if (key == 'color') {
475 transmission_color = value;
476 //console.log('Color:', color);
477 }
478
479 if (remapKeys[key]) {
480 key = remapKeys[key];
481 }
482
483 let refInput = refNode.getInput(key);
484 if (!refInput)
485 refInput = refNode.addInputFromNodeDef(key);
486 if (refInput) {
487 const input = shaderNode.addInput(key);
488 input.copyContentFrom(refInput);
489 if (input) {
490 // Convert number vector to string
491 if (Array.isArray(value)) {
492 value = value.join(',');
493 }
494 // Convert number to string
495 else if (typeof value === 'number') {
496 value = value.toString();
497 }
498 // Note: This API has side-effects as the
499 // type is set to "string" when the value is set. Thus
500 // we must explicitly set the type here.
501 input.setValueString(value, refInput.getType());
502 }
503 }
504 else {
505 //console.log('>>> Cannot create input:', key)
506 }
507 }
508 });
509
510 if (transmission !== null && metallness !== null && roughness !== null && transmission_color !== null)
511 {
512 if (metallness == 0 && roughness == 0)
513 {
514 if (remapKeys['transmission_color']) {
515 let inputName = remapKeys['transmission_color'];
516 let input = shaderNode.addInput(inputName);
517 if (input) {
518 let value = transmission_color.join(',');
519 //console.log(`Add "${inputName}": "${value}"`);
520 input.setValueString(value, 'color3');
521 }
522 }
523 }
524 };
525 }
526 return true;
527 }
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 return {};
136 }
remapMap
Remap keys for input values for different shading models.

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

316 {
317 if (!this.doc) {
318 console.error('No MaterialX document to convert');
319 return '';
320 }
321
322 // Create write options
323 const writeOptions = new this.mx.XmlWriteOptions();
324 writeOptions.writeXIncludeEnable = false;
325 //writeOptions.writeXIncludes = false;
326 writeOptions.elementPredicate = this.skipLibraryElement;
327
328 // Convert the MaterialX document to a string
329 const mtlx = this.mx.writeToXmlString(this.doc, writeOptions);
330 return mtlx;
331 }
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 248 of file JsMaterialXPhysicallyBased.js.

249 {
250 try {
251 this.materials = null
252 this.materialNames = [];
253
254 const response = await fetch(this.url, {
255 method: 'GET',
256 headers: this.headers
257 });
258
259 if (!response.ok) {
260 throw new Error('Network response was not ok ' + response.statusText);
261 }
262
263 this.materials = await response.json();
264 for (let i = 0; i < this.materials.length; i++) {
265 this.materialNames.push(this.materials[i]['name']);
266 }
267 return this.materials;
268 } catch (error) {
269 console.error('There has been a problem with your fetch operation:', error);
270 }
271
272 return null;
273 }

◆ initializeInputRemapping()

JsPhysicallyBasedMaterialLoader::initializeInputRemapping ( )

Initialize the input remapping for different shading models.

Returns
{void}

Definition at line 196 of file JsMaterialXPhysicallyBased.js.

197 {
198 console.log('Initializing input remapping for Physically Based Materials...');
199 this.remapMap = null;
200
201 const remapKeyURL = 'https://raw.githubusercontent.com/kwokcb/materialxMaterials/refs/heads/main/src/materialxMaterials/data/PhysicallyBasedMaterialX/PhysicallyBasedToMtlxMappings.json';
202
203 fetch(remapKeyURL)
204 .then((response) =>
205 {
206 if (!response.ok) {
207 console.warn(`HTTP error! Status: ${response.status}`);
208 return null;
209 }
210 return response.json();
211 })
212 .then((data) => {
213 if (data) {
214 this.remapMap = data;
215 console.log('- Remap keys loaded from repo:', this.remapMap);
216 } else {
217 console.warn('- No remap keys from repo. Using default remap keys.');
218 this.setDefaultRemapKeys();
219 }
220 })
221 .catch((error) => {
222 console.log('- Error loading remap keys:', error);
223 this.setDefaultRemapKeys();
224 console.warn('- Using default remap keys.', this.remapMap);
225 });
226 }
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 232 of file JsMaterialXPhysicallyBased.js.

233 {
234 return new Promise((resolve, reject) => {
235 MaterialX().then((mtlx) => {
236 this.mx = mtlx;
237 resolve();
238 }).catch((error) => {
239 reject(error);
240 });
241 });
242 }

◆ loadStandardLibraries()

JsPhysicallyBasedMaterialLoader::loadStandardLibraries ( )

Load the MaterialX standard libraries.

Returns
{void}

Definition at line 279 of file JsMaterialXPhysicallyBased.js.

280 {
281 if (!this.mx) {
282 // Call the asynchronous function and then perform additional logic
283 this.loadMaterialX().then(() => {
284
285 this.esslgenerator = new this.mx.EsslShaderGenerator();
286 this.esslgenContext = new this.mx.GenContext(this.esslgenerator);
287 this.stdlib = this.mx.loadStandardLibraries(this.esslgenContext);
288 let children = this.stdlib.getChildren();
289 for (let i = 0; i < children.length; i++) {
290 let child = children[i];
291 child.setSourceUri('STDLIB_ELEMENT');
292 }
293
294 console.log("MaterialX is loaded");
295 }).catch((error) => {
296 console.error("Error loading MaterialX:", error);
297 });
298 }
299 }

◆ setDefaultRemapKeys()

JsPhysicallyBasedMaterialLoader::setDefaultRemapKeys ( )

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

Returns
{void}

Definition at line 142 of file JsMaterialXPhysicallyBased.js.

143 {
144 const standard_surface_remapKeys = {
145 "color": "base_color",
146 "specularColor": "specular_color",
147 "roughness": "specular_roughness",
148 "metalness": "metalness",
149 "ior": "specular_IOR",
150 "subsurfaceRadius": "subsurface_radius",
151 "transmission": "transmission",
152 "transmission_color": "transmission_color",
153 "transmissionDispersion": "transmission_dispersion",
154 "thinFilmThickness": "thin_film_thickness",
155 "thinFilmIor": "thin_film_IOR"
156 };
157
158 const openpbr_remapKeys = {
159 "color": "base_color",
160 "specularColor": "specular_color",
161 "roughness": "specular_roughness",
162 "metalness": "base_metalness",
163 "ior": "specular_ior",
164 "subsurfaceRadius": "subsurface_radius",
165 "transmission": "transmission_weight",
166 "transmission_color": "transmission_color",
167 "transmissionDispersion": "transmission_dispersion_abbe_number",
168 "thinFilmThickness": "thin_film_thickness",
169 "thinFilmIor": "thin_film_ior"
170 };
171
172 const gltf_remapKeys = {
173 "color": "base_color",
174 "specularColor": "specular_color",
175 "roughness": "roughness",
176 "metalness": "metallic",
177 "ior": "ior",
178 "transmission": "transmission",
179 "transmission_color": "attenuation_color",
180 "thinFilmThickness": "iridescence_thickness",
181 "thinFilmIor": "iridescence_ior"
182 };
183
184 this.remapMap = {
185 'standard_surface': standard_surface_remapKeys,
186 'gltf_pbr': gltf_remapKeys,
187 'open_pbr_surface': openpbr_remapKeys
188 };
189 }

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

307 {
308 return !elem.hasSourceUri()
309 }

◆ 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: