MaterialXMaterials 1.39.5
Utilities for retrieving materials from remote servers
Loading...
Searching...
No Matches
materialxMaterials.physicallyBasedMaterialXCmd Namespace Reference

Command to convert Physically Based Materials to MaterialX Command Line Utility. More...

Functions

 physicallBasedMaterialXCmd ()
 Command to parse PhysicallyBased materials and create MaterialX materials.

Detailed Description

Command to convert Physically Based Materials to MaterialX Command Line Utility.

This script converts Physically Based Materials to MaterialX using the MaterialX Python API.

The script can be run from the command line with the following options:

–shadingModel: Shading models to use for conversion. If not specified then all will be used.

Options: standard_surface, gltf_pbr, open_pbr_surface

–outputDir: Output directory for MaterialX files

–writeJSON: Write materials JSON file. Default is True

–separateFiles: Convert individual MaterialX files per material. Default is false

Example usage:

Function Documentation

◆ physicallBasedMaterialXCmd()

materialxMaterials.physicallyBasedMaterialXCmd.physicallBasedMaterialXCmd ( )

Command to parse PhysicallyBased materials and create MaterialX materials.

Definition at line 26 of file physicallyBasedMaterialXCmd.py.

26def physicallBasedMaterialXCmd():
27 '''
28 Command to parse PhysicallyBased materials and create MaterialX materials
29 '''
30 logger = logging.getLogger('PB_CMD')
31 logging.basicConfig(level=logging.INFO)
32
33 parser = argparse.ArgumentParser(description='Convert Physically Based Materials to MaterialX')
34 parser.add_argument('-m', '--shadingModel', type=str, default='', help='Shading models to use for conversion. '
35 ' If not specified then all will be used. '
36 ' Options: standard_surface, gltf_pbr, open_pbr_surface')
37 parser.add_argument('-o', '--outputDir', type=str, default='',
38 help='Output directory for MaterialX files. Default location is PhysicallyBasedMaterialX')
39 parser.add_argument('-j', '--writeJSON', type=bool, default=True,
40 help='Write materials JSON file. Default is True')
41 parser.add_argument('-s', '--separateFiles', type=bool, default=False,
42 help='Convert individual MaterialX files per material. Default is false')
43 parser.add_argument('-l', '--loadFromFile', type=str, default='', help='Load materials a specified file')
44 parser.add_argument('-wr', '--writeRemapping', type=bool, default=False, help='Write remapping from PhysicallyBased to MaterialX. Default is False')
45 parser.add_argument('-rr', '--readRemapping', type=str, default='', help='Read remapping from PhysicallyBased to MaterialX. Default is empty')
46 parser.add_argument('-nd', '--createNodeDef', type=bool, default=False, help='Create NodeDef for Physically Based Material inputs. Default is False')
47
48 # V2_TODO : Expose this argument when all materials support all colorspaces.
49 support_colorspaces = False
50 if support_colorspaces:
51 parser.add_argument('-cs', '--colorspace', type=str, default='', help='Write colors using this color space. Default is to use srgb-linear = lin_rec709. Options incllude: srgb-linear, acescg')
52
53 opts = parser.parse_args()
54
55 outputDir = 'PhysicallyBasedMaterialX'
56 if opts.outputDir:
57 if not os.path.exists(opts.outputDir):
58 logger.info(f'Error: Output directory does not exist: {opts.outputDir}')
59 # Create the output directory
60 try:
61 os.makedirs(opts.outputDir)
62 logger.info(f'> Created output directory: {opts.outputDir}')
63 outputDir = opts.outputDir
64 except Exception as e:
65 logger.info(f'> Error: Could not create output directory: {opts.outputDir}')
66 sys.exit(1)
67 else:
68 outputDir = opts.outputDir
69
70 shadingModels = []
71 if opts.shadingModel:
72 shadingModels = opts.shadingModel.split(',')
73 shadingModePrefixMap = { 'standard_surface': 'SS', 'gltf_pbr': 'GLTF', 'open_pbr_surface': 'OPBR' }
74 shadingModelPrefixes = []
75 if len(shadingModels) == 0:
76 shadingModels = ['standard_surface', 'gltf_pbr', 'open_pbr_surface']
77 shadingModelPrefixes = ['SS', 'GLTF', 'OPBR']
78 else:
79 for shadingModel in shadingModels:
80 shadingModelPrefixes.append(shadingModePrefixMap[shadingModel])
81
82 writeJSON = opts.writeJSON
83 separateFiles = opts.separateFiles
84
85 material_file = opts.loadFromFile
86 if material_file:
87 if not os.path.exists(opts.loadFromFile):
88 logger.info(f'> Error: File does not exist: {material_file}')
89 sys.exit(1)
90 logger.info(f'> Load materials from file: {material_file}')
91
92 # Create loader and get PhysicallyBasedMaterials
93 # Uses default remapping.
94 loader = pbmx.PhysicallyBasedMaterialLoader(mx, None, material_file)
95 if support_colorspaces and opts.colorspace:
96 loader.set_desired_color_space(opts.colorspace)
97
98 readRemapping = opts.readRemapping
99 if readRemapping:
100 if not os.path.exists(readRemapping):
101 logger.info(f'> Error: Remapping file does not exist: {readRemapping}')
102 logger.info(f'> Read remapping file: {readRemapping}')
103 loader.readRemappingFile(readRemapping)
104 else:
105 writeRemapping = opts.writeRemapping
106 if writeRemapping:
107 outputFile = os.path.join(outputDir, 'PhysicallyBasedToMtlxMappings.json')
108 logger.info(f'> Write remapping file: {outputFile}')
109 loader.writeRemappingFile(outputFile)
110
111 jsonMat = loader.getJSON()
112 if jsonMat:
113
114 # Create folder for MaterialX call PhysicallyBasedMaterialX
115 os.makedirs(outputDir, exist_ok=True)
116
117 create_nodedef = opts.createNodeDef
118 if create_nodedef:
119
120 # Write PhysicallyBased BSDF definition
121 #
122 logger.info('> Write definition for PhysicallyBased materials')
123 definitions_doc = loader.get_physlib()
124 if definitions_doc:
125 nodedef_file_name = os.path.join(outputDir, 'physbased_pbr.mtlx')
126 mx.writeToXmlFile(definitions_doc, nodedef_file_name)
127 logger.info(f'> Write definition file: {nodedef_file_name}')
128
129 # Get PhysicallyBased materials using the definition
130 #
131 doc_mat = loader.get_physlib_materials()
132 if doc_mat:
133 status, error = doc_mat.validate()
134 if not status:
135 logger.error('> Error validating definition materials document:')
136 logger.error(error)
137 else:
138 logger.info('> Definition materials document passed validation.')
139
140 nodedef_mat_file_name = os.path.join(outputDir, 'physbased_pbr_materials.mtlx')
141 mx.writeToXmlFile(doc_mat, mx.FilePath(nodedef_mat_file_name))
142 logger.info(f'> Write materials file: {nodedef_mat_file_name}')
143
144 # Write out translator definitions
145 #
146 translators_doc = loader.get_translators()
147 translators = translators_doc.getNodeDefs()
148 print(f'Found translator definitions: {len(translators)}')
149
150 if translators_doc and translators:
151 output_file_name = 'physbased_pbr_translators.mtlx'
152 output_path = os.path.join(outputDir, output_file_name)
153 logger.info('> Write translator file:' + output_path)
154 mx.writeToXmlFile(translators_doc, mx.FilePath(output_path))
155 logger.info(f'> Write translator file: {output_path}')
156
157 # Get doc with all required definitions: stdlib, PhysicallyBased definition, and translator definitions
158 stdlib = loader.get_definitions()
159
160 # Export single file with all translated materials
161 if not separateFiles:
162 translated_doc = loader.get_physlib_materials()
163
164 # Copy over materials + reference libraries
165 #translated_doc.copyContentFrom(doc_mat)
166 #translated_doc.setDataLibrary(doc_mat.getDataLibrary())
167
168 for shadingModel, prefix in zip(shadingModels, shadingModelPrefixes):
169
170 for node in translated_doc.getNodes():
171 if node.getCategory() == loader.get_physlib_category():
172 trans_result = loader.translate_node(translated_doc, loader.get_physlib_category(), shadingModel, node)
173
174 logger.info(f'> Generate MaterialX using nodedefs for shading model: {shadingModel}')
175 fileName = os.path.join(outputDir, f'PhysicallyBasedMaterialX_translated_{prefix}.mtlx')
176 loader.writeMaterialXToFile(fileName, translated_doc)
177 logger.info(f'> Write: {fileName}')
178
179 # Export separate files per translated material
180 else:
181 matDir = os.path.join(outputDir, 'Sep')
182 os.makedirs(matDir, exist_ok=True)
183 for shadingModel, prefix in zip(shadingModels, shadingModelPrefixes):
184 converted = []
185 for mat in loader.getJSONMaterialNames():
186 materialFilter = [mat]
187
188 # Create doc with single material
189 matdoc = loader.create_definition_materials(None, materialFilter)
190 if matdoc is not None:
191
192 # Translate the material
193 mat_name = mx.createValidName(mat)
194 node = matdoc.getNode(mat_name)
195 if node:
196 trans_result = loader.translate_node(matdoc, loader.get_physlib_category(), shadingModel, node)
197 if not trans_result:
198 logger.warning(f'Failed to translate node: {mat_name} for shading model: {shadingModel}')
199 else:
200 converted.append(trans_result['targetNode'].getName())
201 valid, errors = loader.validateMaterialXDocument(matdoc)
202 if valid:
203 #logger.info(f'> Generate material {mat_name} for shading model: {shadingModel}')
204 fileName = os.path.join(matDir, f'PB_{prefix}_{mat}.mtlx')
205 loader.writeMaterialXToFile(fileName, matdoc)
206 logger.info(f'> Write: {fileName}')
207
208 logger.info(f'> Converted {len(converted)} materials for shading model: {shadingModel}')
209
210 if writeJSON:
211 logger.info(f'> Write PB material file: {outputDir}/PhysicallyBasedMaterial.json')
212 loader.writeJSONToFile(os.path.join(outputDir, 'PhysicallyBasedMaterial.json'))
213
214 if create_nodedef:
215 return
216
217 # Direct translation from JSON to MaterialX path. Skip if using PhysicallyBased nodedefs
218 if not separateFiles:
219 for shadingModel, prefix in zip(shadingModels, shadingModelPrefixes):
220 logger.info(f'> Generate MaterialX for shading model: {shadingModel}')
221 matdoc = loader.convertToMaterialX([], shadingModel, {}, prefix)
222 valid, errors = loader.validateMaterialXDocument(matdoc)
223 if not valid:
224 logger.error(f'> Error validating MaterialX document for shading model: {shadingModel}')
225 logger.error(errors)
226
227 if support_colorspaces and opts.colorspace:
228 prefix = prefix + '_' + opts.colorspace
229 fileName = os.path.join(outputDir, f'PhysicallyBasedMaterialX_{prefix}.mtlx')
230 loader.writeMaterialXToFile(fileName)
231 logger.info(f'> Write: {fileName}')
232
233 else:
234 for shadingModel, prefix in zip(shadingModels, shadingModelPrefixes):
235 logger.info(f'> Generate MaterialX for shading model: {shadingModel}')
236 for mat in loader.getJSONMaterialNames():
237 materialFilter = [mat]
238 matdoc = loader.convertToMaterialX(materialFilter, shadingModel, {}, prefix)
239 if matdoc is not None:
240 valid, errors = loader.validateMaterialXDocument(matdoc)
241 if not valid:
242 logger.error(f'> Error validating MaterialX document for material: {mat} shading model: {shadingModel}')
243 logger.error(errors)
244
245 if support_colorspaces and opts.colorspace:
246 prefix = prefix + '_' + opts.colorspace
247 fileName = os.path.join(outputDir, f'PB_{prefix}_{mat}.mtlx')
248 loader.writeMaterialXToFile(fileName)
249 logger.info(f'> Write: {fileName}')
250
251 else:
252 logger.info('Could not retrieve PhysicallyBased Materials')
253