QuiltiX Plugins 0.0.1
Custom Plugins for QuiltiX
Loading...
Searching...
No Matches
plugin.QuiltiX_glTF_serializer Class Reference

glTF serializer for MaterialX More...

Public Member Functions

None __init__ (self, editor, root)
 Initialize the plugin.
 
 custom_on_view_menu_about_to_show (self)
 Custom about to show event for the view menu.
 
None on_gltf_viewer_toggled (self, checked)
 Toggle the glTF viewer dock widget.
 
None setup_gltf_viewer_doc (self)
 Set up the glTF viewer dock widget.
 
None show_text_box (self, text, title="")
 Core utilities.
 
None import_gltf_triggered (self)
 Import a glTF file into the current graph.
 
dict setup_default_export_options (self, path, bakeFileName, bakeResolution=1024, embed_geometry=False)
 Set up the default export options for gltf output.
 
 create_baked_path (self, path)
 Create a baked path name from an original path.
 
None export_gltf_triggered (self, writeToTemp=False)
 Export the current graph to a glTF file in binary format (glb)
 
str convert_graph_to_gltf (self, options)
 Convert the current graph to a glTF document string.
 
 show_gltf_text_triggered (self)
 Show the current graph as glTF text popup.
 

Public Attributes

 editor = editor
 
 root = root
 
 import_gltf_triggered
 
 show_gltf_text_triggered
 
 bake_textures_option = QAction("Always Bake Textures", editor)
 
 act_gltf_viewer = QAction("glTF Viewer", editor)
 Add viewer toggle.
 
 on_gltf_viewer_toggled
 
 custom_on_view_menu_about_to_show
 
 web_dock_widget = glTFWidget(self.editor)
 

Detailed Description

glTF serializer for MaterialX

Definition at line 211 of file materialxgltf/plugin.py.

Constructor & Destructor Documentation

◆ __init__()

None plugin.QuiltiX_glTF_serializer.__init__ ( self,
editor,
root )

Initialize the plugin.

Adds in:

  • Menu items for loading and saving glTF files
  • Menu items for setting options for glTF export
  • Menu item for showing the current graph as glTF text
Parameters
editorThe QuiltiX editor
rootThe root path of QuitiX

Definition at line 216 of file materialxgltf/plugin.py.

216 def __init__(self, editor, root) -> None:
217 '''
218 Initialize the plugin. Adds in:
219 - Menu items for loading and saving glTF files
220 - Menu items for setting options for glTF export
221 - Menu item for showing the current graph as glTF text
222
223 @param editor: The QuiltiX editor
224 @param root: The root path of QuitiX
225 '''
226 self.editor = editor
227 self.root = root
228
229 # glTF menu items
230 # ----------------------------------------
231 # Update 'File' menu
232
233 editor.file_menu.addSeparator()
234 gltfMenu1 = self.editor.file_menu.addMenu("glTF")
235
236 # Load menu item
237 import_gltf_item = QAction("Load glTF...", editor)
238 import_gltf_item.triggered.connect(self.import_gltf_triggered)
239 gltfMenu1.addAction(import_gltf_item)
240
241 # Save menu item
242 export_gltf_item = QAction("Save glTF...", editor)
243 export_gltf_item.triggered.connect(lambda: self.export_gltf_triggered(False))
244 gltfMenu1.addAction(export_gltf_item)
245
246 # Export to Viewer menu item
247 export_view_gltf_item = QAction("Export to Viewer...", editor)
248 export_view_gltf_item.triggered.connect(lambda: self.export_gltf_triggered(True))
249 gltfMenu1.addAction(export_view_gltf_item)
250
251 # Show glTF text. Does most of export, except does not write to file
252 show_gltf_text = QAction("Show glTF as text...", editor)
253 show_gltf_text.triggered.connect(self.show_gltf_text_triggered)
254 gltfMenu1.addAction(show_gltf_text)
255
256 # Update 'Options' menu
257
258 editor.options_menu.addSeparator()
259 gltfMenu2 = editor.options_menu.addMenu("glTF Options")
260
261 self.bake_textures_option = QAction("Always Bake Textures", editor)
262 self.bake_textures_option.setCheckable(True)
263 self.bake_textures_option.setChecked(False)
264 gltfMenu2.addAction(self.bake_textures_option)
265
266 #version = 'materialxgltf version: ' + materialxgltf.__version__
267 #version_action = QAction(version, self.editor)
268 #version_action.setEnabled(False)
269 #gltfMenu.addAction(version_action)
270
271 # Add glTF Viewer
272 self.setup_gltf_viewer_doc()
273
274 # Update 'View' menu
275
277 self.act_gltf_viewer = QAction("glTF Viewer", editor)
278 self.act_gltf_viewer.setCheckable(True)
279 self.act_gltf_viewer.toggled.connect(self.on_gltf_viewer_toggled)
280 editor.view_menu.addSeparator()
281 editor.view_menu.addAction(self.act_gltf_viewer)
282
283 # Override about to show event to update the gltf viewer toggle
284 editor.view_menu.aboutToShow.connect(self.custom_on_view_menu_about_to_show)
285

Member Function Documentation

◆ convert_graph_to_gltf()

str plugin.QuiltiX_glTF_serializer.convert_graph_to_gltf ( self,
options )

Convert the current graph to a glTF document string.

Will perform:

  • Shader translation if needed (not that only standard surface is supported)
  • Baking if needed. Note that this writes local files.
  • Uses the materialgltf package to perform conversion
Parameters
options(dict): Dictionary of options for the conversion
Returns
The glTF string.

Definition at line 504 of file materialxgltf/plugin.py.

504 def convert_graph_to_gltf(self, options) -> str:
505 '''
506 Convert the current graph to a glTF document string.
507 Will perform:
508 - Shader translation if needed (not that only standard surface is supported)
509 - Baking if needed. Note that this writes local files.
510 - Uses the materialgltf package to perform conversion
511
512 @param options (dict): Dictionary of options for the conversion
513 @return The glTF string.
514 '''
515 # Disable auto nodegraph creation during
516 ng_abstraction = self.editor.act_ng_abstraction.isChecked()
517 self.editor.act_ng_abstraction.setChecked(False)
518
519 doc = self.editor.qx_node_graph.get_current_mx_graph_doc()
520
521 self.editor.act_ng_abstraction.setChecked(ng_abstraction)
522
523 mtlx2glTFWriter = core.MTLX2GLTFWriter()
524 mtlx2glTFWriter.setOptions(options)
525
526 # Need to load in definition libraries to get translation graphs
527 stdlib = mx.createDocument()
528 searchPath = mx.getDefaultDataSearchPath()
529 libraryFolders = []
530 libraryFolders.extend(mx.getDefaultDataLibraryFolders())
531 mx.loadLibraries(libraryFolders, searchPath, stdlib)
532 doc.importLibrary(stdlib)
533
534 # Perform shader translation if needed
535 translatedCount = 0
536 if options['translateShaders']:
537 translatedCount = mtlx2glTFWriter.translateShaders(doc)
538 logger.debug('- Translated shaders: ' + str(translatedCount))
539
540 forceBake = False
541 if self.bake_textures_option.isChecked():
542 logger.debug('--- Forcing baking of textures')
543 forceBake = True
544
545 # Perform baking if needed
546 if forceBake or (translatedCount > 0 and options['bakeTextures']):
547 bakedFileName = options['bakeFileName']
548 bakeResolution = 1024
549 if options['bakeResolution']:
550 bakeResolution = options['bakeResolution']
551 logger.debug(f'- START baking to {bakedFileName}. Resolution: {bakeResolution} ...')
552 mtlx2glTFWriter.bakeTextures(doc, False, bakeResolution, bakeResolution, True,
553 False, False, bakedFileName)
554 if os.path.exists(bakedFileName):
555 logger.debug(' - Baked textures to: ' + bakedFileName)
556 doc, libFiles = core.Util.createMaterialXDoc()
557 mx.readFromXmlFile(doc, bakedFileName, options['searchPath'])
558 remappedUris = core.Util.makeFilePathsRelative(doc, bakedFileName)
559 for uri in remappedUris:
560 logger.debug(' - Remapped URI: ' + uri[0] + ' to ' + uri[1])
561 core.Util.writeMaterialXDoc(doc, bakedFileName)
562 logger.debug('- ... END baking.')
563
564 gltfString = mtlx2glTFWriter.convert(doc)
565 return gltfString
566

◆ create_baked_path()

plugin.QuiltiX_glTF_serializer.create_baked_path ( self,
path )

Create a baked path name from an original path.

Parameters
path(str): The original path
Returns
: The baked path

Definition at line 426 of file materialxgltf/plugin.py.

426 def create_baked_path(self, path):
427 '''
428 Create a baked path name from an original path
429 @param path (str): The original path
430 @return: The baked path
431 '''
432 # If is a directory, add a file name
433 if os.path.isdir(path):
434 path = os.path.join(path, 'temp_baked.mtlx')
435 else:
436 path = path.replace('.mtlx', '_baked.mtlx')
437 return path
438

◆ custom_on_view_menu_about_to_show()

plugin.QuiltiX_glTF_serializer.custom_on_view_menu_about_to_show ( self)

Custom about to show event for the view menu.

Updates the glTF viewer toggle.

Definition at line 286 of file materialxgltf/plugin.py.

286 def custom_on_view_menu_about_to_show(self):
287 '''
288 Custom about to show event for the view menu. Updates the glTF viewer toggle.
289 '''
290 self.editor.on_view_menu_showing()
291 self.act_gltf_viewer.setChecked(self.web_dock_widget.isVisible())
292

◆ export_gltf_triggered()

None plugin.QuiltiX_glTF_serializer.export_gltf_triggered ( self,
writeToTemp = False )

Export the current graph to a glTF file in binary format (glb)

  • Will perform shader translation if needed to glTF
  • Will perform baking if needed
  • Will package to a binary file
    Parameters
    writeToTemp(bool): Whether to write to a temporary file
    Returns
    : None

Definition at line 439 of file materialxgltf/plugin.py.

439 def export_gltf_triggered(self, writeToTemp=False) -> None:
440 '''
441 Export the current graph to a glTF file in binary format (glb)
442 - Will perform shader translation if needed to glTF
443 - Will perform baking if needed
444 - Will package to a binary file
445 @param writeToTemp (bool): Whether to write to a temporary file
446 @return: None
447 '''
448 if writeToTemp:
449 start_path = os.environ["TEMP"]
450 if not start_path:
451 start_path = os.path.join(ROOT, "resources", "materials")
452 path = os.path.join(start_path, "_tmp_quiltix.gltf")
453 else:
454 start_path = self.editor.mx_selection_path
455 if not start_path:
456 start_path = self.editor.geometry_selection_path
457
458 if not start_path:
459 start_path = os.path.join(ROOT, "resources", "materials")
460
461 path = self.editor.request_filepath(
462 title="Save glTF file", start_path=start_path, file_filter="glTF files (*.gltf)", mode="save",
463 )
464
465 # Set up export options
466 bakeFileName = self.create_baked_path(start_path)
467 options = self.setup_default_export_options(path, bakeFileName, bakeResolution=1024, embed_geometry=True)
468 gltf_string = self.convert_graph_to_gltf(options)
469
470 if gltf_string == '{}':
471 return
472
473 #self.editor.set_current_filepath("")
474
475 # To be able to view the exported file in the glTF viewer, we need to package to a binary file
476 options['packageBinary'] = True
477 try:
478 with open(path, "w") as f:
479 f.write(gltf_string)
480 logger.info(f"Wrote .gltf file to {path}")
481
482 # Package binary file
483 binaryFileName = str(path)
484 binaryFileName = binaryFileName.replace('.gltf', '.glb')
485 logger.debug('- Packaging GLB file...')
486 mtlx2glTFWriter = core.MTLX2GLTFWriter()
487 mtlx2glTFWriter.setOptions(options)
488 saved, images, buffers = mtlx2glTFWriter.packageGLTF(path, binaryFileName)
489 logger.info('- Save GLB file:' + binaryFileName + '. Status:' + str(saved))
490 for image in images:
491 logger.debug(' - Embedded image: ' + image)
492 for buffer in buffers:
493 logger.debug(' - Embedded buffer: ' + buffer)
494 logger.debug('- Packaging GLB file... finished.')
495
496 # Load the glb file into the glTF viewer
497 logger.debug(f'Loading GLB file into glTF viewer: {binaryFileName}')
498 if self.web_dock_widget.page:
499 self.web_dock_widget.page.load_glb(binaryFileName)
500
501 except Exception as e:
502 logger.error(e)
503

◆ import_gltf_triggered()

None plugin.QuiltiX_glTF_serializer.import_gltf_triggered ( self)

Import a glTF file into the current graph.

Definition at line 327 of file materialxgltf/plugin.py.

327 def import_gltf_triggered(self) -> None:
328 '''
329 Import a glTF file into the current graph.
330 '''
331 start_path = self.editor.mx_selection_path
332 if not start_path:
333 start_path = self.editor.geometry_selection_path
334
335 if not start_path:
336 start_path = os.path.join(ROOT, "resources", "materials")
337
338 path = self.editor.request_filepath(
339 title="Load glTF file", start_path=start_path, file_filter="glTF files (*.gltf)", mode="open",
340 )
341
342 if not os.path.exists(path):
343 logger.error('Cannot find input file: ' + path)
344 return
345
346 # Setup defaults for glTF import and create the MaterialX document
347 # - Do not create assignments
348 # - Do not add all inputs
349 # - Add extract nodes. Only required for pre 1.39 MaterialX
350 options = core.GLTF2MtlxOptions()
351 options['createAssignments'] = False
352 options['addAllInputs'] = False
353 options['addExtractNodes'] = True
354 gltf2MtlxReader = core.GLTF2MtlxReader()
355 gltf2MtlxReader.setOptions(options)
356 doc = gltf2MtlxReader.convert(path)
357
358 success = True
359 if not doc:
360 success = False
361 logger.error('Error converting glTF file to MaterialX file')
362 else:
363 success , err = doc.validate()
364 if not success:
365 logger.error(err)
366 else:
367 # Extract out the appropriate data from the original MaterialX document
368 docString = core.Util.writeMaterialXDocString(doc)
369 doc = mx.createDocument()
370 mx.readFromXmlString(doc, docString)
371
372 # Auto ng creation can cause issues for nodes with multiple outputs. Turn off on import
373 ng_abstraction = self.editor.act_ng_abstraction.isChecked()
374 self.editor.act_ng_abstraction.setChecked(False)
375
376 self.editor.mx_selection_path = path
377 self.editor.qx_node_graph.load_graph_from_mx_doc(doc)
378 # Blank out as there is no MaterialX file this was read from
379 self.editor.qx_node_graph.mx_file_loaded.emit("")
380
381 self.editor.act_ng_abstraction.setChecked(ng_abstraction)
382

◆ on_gltf_viewer_toggled()

None plugin.QuiltiX_glTF_serializer.on_gltf_viewer_toggled ( self,
checked )

Toggle the glTF viewer dock widget.

Definition at line 293 of file materialxgltf/plugin.py.

293 def on_gltf_viewer_toggled(self, checked) -> None:
294 '''
295 Toggle the glTF viewer dock widget.
296 '''
297 self.web_dock_widget.setVisible(checked)
298

◆ setup_default_export_options()

dict plugin.QuiltiX_glTF_serializer.setup_default_export_options ( self,
path,
bakeFileName,
bakeResolution = 1024,
embed_geometry = False )

Set up the default export options for gltf output.

Parameters
path(str): path to the gltf file
bakeFileName(str): path to the baked file
bakeResolution(int): resolution of the baked textures. Default is 1024.
embed_geometry(bool): whether to embed the geometry in the gltf file. Default is False.
Returns
options (dict): Dictionary of options for the conversion

Definition at line 383 of file materialxgltf/plugin.py.

383 def setup_default_export_options(self, path, bakeFileName, bakeResolution=1024, embed_geometry=False) -> dict:
384 '''
385 Set up the default export options for gltf output.
386 @param path (str): path to the gltf file
387 @param bakeFileName (str): path to the baked file
388 @param bakeResolution (int): resolution of the baked textures. Default is 1024.
389 @param embed_geometry (bool): whether to embed the geometry in the gltf file. Default is False.
390 @return options (dict): Dictionary of options for the conversion
391 '''
392 options = core.MTLX2GLTFOptions()
393
394 options['debugOutput'] = False
395 options['bakeFileName'] = bakeFileName
396 # Clamp to a minimum power-of-2 resolution
397 bakeResolution = max(bakeResolution, 16)
398 options['bakeResolution'] = bakeResolution
399
400 # TODO: Expose these options to the user
401 if embed_geometry:
402 # By default uses the "MaterialX" shader ball provided as part of
403 # the materialxgltf package for binary export.
404 gltfGeometryFile = pkg_resources.resource_filename('materialxgltf', 'data/shaderBall.gltf')
405 msg = '> Load default geometry: %s' % mx.FilePath(gltfGeometryFile).getBaseName()
406 logger.info(msg)
407 options['geometryFile'] = gltfGeometryFile
408 options['primsPerMaterial'] = True
409 options['writeDefaultInputs'] = False
410 options['translateShaders'] = True
411 options['bakeTextures'] = True
412 # Always should be set
413 options['addExtractNodes'] = True
414
415 searchPath = mx.getDefaultDataSearchPath()
416 if not mx.FilePath(path).isAbsolute():
417 path = os.path.abspath(path)
418 searchPath.append(mx.FilePath(path).getParentPath())
419 searchPath.append(mx.FilePath.getCurrentPath())
420 if embed_geometry:
421 searchPath.append(mx.FilePath(gltfGeometryFile).getParentPath())
422 options['searchPath'] = searchPath
423
424 return options
425

◆ setup_gltf_viewer_doc()

None plugin.QuiltiX_glTF_serializer.setup_gltf_viewer_doc ( self)

Set up the glTF viewer dock widget.

Definition at line 299 of file materialxgltf/plugin.py.

299 def setup_gltf_viewer_doc(self) -> None:
300 '''
301 Set up the glTF viewer dock widget.
302 '''
303 self.web_dock_widget = glTFWidget(self.editor)
304 self.editor.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.web_dock_widget)
305

◆ show_gltf_text_triggered()

plugin.QuiltiX_glTF_serializer.show_gltf_text_triggered ( self)

Show the current graph as glTF text popup.

Definition at line 567 of file materialxgltf/plugin.py.

567 def show_gltf_text_triggered(self):
568 '''
569 Show the current graph as glTF text popup.
570 '''
571 path = self.editor.mx_selection_path
572 if not path:
573 path = self.editor.geometry_selection_path
574 if not path:
575 path = os.path.join(ROOT, "resources", "materials")
576
577 # Setup export options
578 bakeFileName = self.create_baked_path(path)
579 options = self.setup_default_export_options(path, bakeFileName, bakeResolution=64, embed_geometry=False)
580
581 logger.debug('Show glTF text triggered. Path:' + path + '. bakeFileName: ' + bakeFileName)
582
583 # Convert and display the text
584 text = self.convert_graph_to_gltf(options)
585 self.show_text_box(text, 'glTF Representation')
586
587@qx_plugin.hookimpl

◆ show_text_box()

None plugin.QuiltiX_glTF_serializer.show_text_box ( self,
text,
title = "" )

Core utilities.

Show a text box with the given text.

Parameters
textThe text to show
titleThe title of the text box. Default is empty string.

Definition at line 307 of file materialxgltf/plugin.py.

307 def show_text_box(self, text, title="") -> None:
308 '''
309 Show a text box with the given text.
310 @param text: The text to show
311 @param title: The title of the text box. Default is empty string.
312 '''
313 te_text = QTextEdit()
314
315 if have_highliting:
316 jsonHighlighter = GLTFHighlighter()
317 highlighted_html = jsonHighlighter.highlight(text)
318 te_text.setHtml(highlighted_html)
319 else:
320 te_text.setText(text)
321 te_text.setReadOnly(True)
322 te_text.setParent(self.editor, QtCore.Qt.Window)
323 te_text.setWindowTitle(title)
324 te_text.resize(1000, 800)
325 te_text.show()
326

Member Data Documentation

◆ act_gltf_viewer

plugin.QuiltiX_glTF_serializer.act_gltf_viewer = QAction("glTF Viewer", editor)

Add viewer toggle.

Definition at line 277 of file materialxgltf/plugin.py.

◆ bake_textures_option

plugin.QuiltiX_glTF_serializer.bake_textures_option = QAction("Always Bake Textures", editor)

Definition at line 261 of file materialxgltf/plugin.py.

◆ custom_on_view_menu_about_to_show

plugin.QuiltiX_glTF_serializer.custom_on_view_menu_about_to_show

Definition at line 284 of file materialxgltf/plugin.py.

◆ editor

plugin.QuiltiX_glTF_serializer.editor = editor

Definition at line 226 of file materialxgltf/plugin.py.

◆ import_gltf_triggered

plugin.QuiltiX_glTF_serializer.import_gltf_triggered

Definition at line 238 of file materialxgltf/plugin.py.

◆ on_gltf_viewer_toggled

plugin.QuiltiX_glTF_serializer.on_gltf_viewer_toggled

Definition at line 279 of file materialxgltf/plugin.py.

◆ root

plugin.QuiltiX_glTF_serializer.root = root

Definition at line 227 of file materialxgltf/plugin.py.

◆ show_gltf_text_triggered

plugin.QuiltiX_glTF_serializer.show_gltf_text_triggered

Definition at line 253 of file materialxgltf/plugin.py.

◆ web_dock_widget

plugin.QuiltiX_glTF_serializer.web_dock_widget = glTFWidget(self.editor)

Definition at line 303 of file materialxgltf/plugin.py.


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