Fix #100973: Node Wrangler: previewing node if hierarchy not active
[blender-addons.git] / io_scene_gltf2 / __init__.py
blobd3c948a24a7bba571a4d4fa2c4d99fc5b130f8e1
1 # SPDX-FileCopyrightText: 2018-2021 The glTF-Blender-IO authors
3 # SPDX-License-Identifier: Apache-2.0
5 bl_info = {
6 'name': 'glTF 2.0 format',
7 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
8 "version": (4, 1, 38),
9 'blender': (4, 1, 0),
10 'location': 'File > Import-Export',
11 'description': 'Import-Export as glTF 2.0',
12 'warning': '',
13 'doc_url': "{BLENDER_MANUAL_URL}/addons/import_export/scene_gltf2.html",
14 'tracker_url': "https://github.com/KhronosGroup/glTF-Blender-IO/issues/",
15 'support': 'OFFICIAL',
16 'category': 'Import-Export',
19 def get_version_string():
20 return str(bl_info['version'][0]) + '.' + str(bl_info['version'][1]) + '.' + str(bl_info['version'][2])
23 # Script reloading (if the user calls 'Reload Scripts' from Blender)
26 def reload_package(module_dict_main):
27 import importlib
28 from pathlib import Path
30 def reload_package_recursive(current_dir, module_dict):
31 for path in current_dir.iterdir():
32 if "__init__" in str(path) or path.stem not in module_dict:
33 continue
35 if path.is_file() and path.suffix == ".py":
36 importlib.reload(module_dict[path.stem])
37 elif path.is_dir():
38 reload_package_recursive(path, module_dict[path.stem].__dict__)
40 reload_package_recursive(Path(__file__).parent, module_dict_main)
43 if "bpy" in locals():
44 reload_package(locals())
46 import bpy
47 from bpy.props import (StringProperty,
48 BoolProperty,
49 EnumProperty,
50 IntProperty,
51 FloatProperty,
52 CollectionProperty)
53 from bpy.types import Operator
54 from bpy_extras.io_utils import ImportHelper, ExportHelper
58 # Functions / Classes.
61 exporter_extension_panel_unregister_functors = []
62 importer_extension_panel_unregister_functors = []
65 def ensure_filepath_matches_export_format(filepath, export_format):
66 import os
67 filename = os.path.basename(filepath)
68 if not filename:
69 return filepath
71 stem, ext = os.path.splitext(filename)
72 if stem.startswith('.') and not ext:
73 stem, ext = '', stem
75 desired_ext = '.glb' if export_format == 'GLB' else '.gltf'
76 ext_lower = ext.lower()
77 if ext_lower not in ['.glb', '.gltf']:
78 return filepath + desired_ext
79 elif ext_lower != desired_ext:
80 filepath = filepath[:-len(ext)] # strip off ext
81 return filepath + desired_ext
82 else:
83 return filepath
86 def on_export_format_changed(self, context):
87 # Update the filename in the file browser when the format (.glb/.gltf)
88 # changes
89 sfile = context.space_data
90 if not isinstance(sfile, bpy.types.SpaceFileBrowser):
91 return
92 if not sfile.active_operator:
93 return
94 if sfile.active_operator.bl_idname != "EXPORT_SCENE_OT_gltf":
95 return
97 sfile.params.filename = ensure_filepath_matches_export_format(
98 sfile.params.filename,
99 self.export_format,
102 # Also change the filter
103 sfile.params.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf'
104 # Force update of file list, because update the filter does not update the real file list
105 bpy.ops.file.refresh()
107 def on_export_action_filter_changed(self, context):
108 if self.export_action_filter is True:
109 bpy.types.Scene.gltf_action_filter = bpy.props.CollectionProperty(type=GLTF2_filter_action)
110 bpy.types.Scene.gltf_action_filter_active = bpy.props.IntProperty()
112 for action in bpy.data.actions:
113 if id(action) not in [id(item.action) for item in bpy.data.scenes[0].gltf_action_filter]:
114 item = bpy.data.scenes[0].gltf_action_filter.add()
115 item.keep = True
116 item.action = action
118 else:
119 bpy.data.scenes[0].gltf_action_filter.clear()
120 del bpy.types.Scene.gltf_action_filter
121 del bpy.types.Scene.gltf_action_filter_active
126 class ConvertGLTF2_Base:
127 """Base class containing options that should be exposed during both import and export."""
129 export_import_convert_lighting_mode: EnumProperty(
130 name='Lighting Mode',
131 items=(
132 ('SPEC', 'Standard', 'Physically-based glTF lighting units (cd, lx, nt)'),
133 ('COMPAT', 'Unitless', 'Non-physical, unitless lighting. Useful when exposure controls are not available'),
134 ('RAW', 'Raw (Deprecated)', 'Blender lighting strengths with no conversion'),
136 description='Optional backwards compatibility for non-standard render engines. Applies to lights',# TODO: and emissive materials',
137 default='SPEC'
140 class ExportGLTF2_Base(ConvertGLTF2_Base):
141 # TODO: refactor to avoid boilerplate
143 def __init__(self):
144 from .io.com import gltf2_io_draco_compression_extension
145 self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists()
147 bl_options = {'PRESET'}
149 # Don't use export_ prefix here, I don't want it to be saved with other export settings
150 gltf_export_id: StringProperty(
151 name='Identifier',
152 description=(
153 'Identifier of caller (in case of add-on calling this exporter). '
154 'Can be useful in case of Extension added by other add-ons'
156 default=''
159 # gltfpack properties
160 export_use_gltfpack: BoolProperty(
161 name='Use Gltfpack',
162 description='Use gltfpack to simplify the mesh and/or compress its textures',
163 default=False,
166 export_gltfpack_tc: BoolProperty(
167 name='KTX2 Compression',
168 description='Convert all textures to KTX2 with BasisU supercompression',
169 default=True,
172 export_gltfpack_tq: IntProperty(
173 name='Texture Encoding Quality',
174 description='Texture encoding quality',
175 default=8,
176 min=1,
177 max=10,
180 export_gltfpack_si: FloatProperty(
181 name='Mesh Simplification Ratio',
182 description='Simplify meshes targeting triangle count ratio',
183 default=1.0,
184 min=0.0,
185 max=1.0,
188 export_gltfpack_sa: BoolProperty(
189 name='Aggressive Mesh Simplification',
190 description='Aggressively simplify to the target ratio disregarding quality',
191 default=False,
194 export_gltfpack_slb: BoolProperty(
195 name='Lock Mesh Border Vertices',
196 description='Lock border vertices during simplification to avoid gaps on connected meshes',
197 default=False,
200 export_gltfpack_vp: IntProperty(
201 name='Position Quantization',
202 description='Use N-bit quantization for positions',
203 default=14,
204 min=1,
205 max=16,
208 export_gltfpack_vt: IntProperty(
209 name='Texture Coordinate Quantization',
210 description='Use N-bit quantization for texture coordinates',
211 default=12,
212 min=1,
213 max=16,
216 export_gltfpack_vn: IntProperty(
217 name='Normal/Tangent Quantization',
218 description='Use N-bit quantization for normals and tangents',
219 default=8,
220 min=1,
221 max=16,
224 export_gltfpack_vc: IntProperty(
225 name='Vertex Color Quantization',
226 description='Use N-bit quantization for colors',
227 default=8,
228 min=1,
229 max=16,
232 export_gltfpack_vpi: EnumProperty(
233 name='Vertex Position Attributes',
234 description='Type to use for vertex position attributes',
235 items=(('Integer', 'Integer', 'Use integer attributes for positions'),
236 ('Normalized', 'Normalized', 'Use normalized attributes for positions'),
237 ('Floating-point', 'Floating-point', 'Use floating-point attributes for positions')),
238 default='Integer',
241 export_gltfpack_noq: BoolProperty(
242 name='Disable Quantization',
243 description='Disable quantization; produces much larger glTF files with no extensions',
244 default=True,
247 # TODO: some stuff in Textures
249 # TODO: Animations
251 # TODO: Scene
253 # TODO: some stuff in Miscellaneous
255 export_format: EnumProperty(
256 name='Format',
257 items=(('GLB', 'glTF Binary (.glb)',
258 'Exports a single file, with all data packed in binary form. '
259 'Most efficient and portable, but more difficult to edit later'),
260 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
261 'Exports multiple files, with separate JSON, binary and texture data. '
262 'Easiest to edit later')),
263 description=(
264 'Output format. Binary is most efficient, '
265 'but JSON may be easier to edit later'
267 default='GLB', #Warning => If you change the default, need to change the default filter too
268 update=on_export_format_changed,
271 ui_tab: EnumProperty(
272 items=(('GENERAL', "General", "General settings"),
273 ('MESHES', "Meshes", "Mesh settings"),
274 ('OBJECTS', "Objects", "Object settings"),
275 ('ANIMATION', "Animation", "Animation settings")),
276 name="ui_tab",
277 description="Export setting categories",
280 export_copyright: StringProperty(
281 name='Copyright',
282 description='Legal rights and conditions for the model',
283 default=''
286 export_image_format: EnumProperty(
287 name='Images',
288 items=(('AUTO', 'Automatic',
289 'Save PNGs as PNGs, JPEGs as JPEGs, WebPs as WebPs. '
290 'For other formats, use PNG'),
291 ('JPEG', 'JPEG Format (.jpg)',
292 'Save images as JPEGs. (Images that need alpha are saved as PNGs though.) '
293 'Be aware of a possible loss in quality'),
294 ('WEBP', 'WebP Format',
295 'Save images as WebPs as main image (no fallback)'),
296 ('NONE', 'None',
297 'Don\'t export images'),
299 description=(
300 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
301 'applications due to the smaller file size. Alternatively they can be omitted if they are not needed'
303 default='AUTO'
306 export_image_add_webp: BoolProperty(
307 name='Create WebP',
308 description=(
309 "Creates WebP textures for every texture. "
310 "For already WebP textures, nothing happens"
312 default=False
315 export_image_webp_fallback: BoolProperty(
316 name='WebP fallback',
317 description=(
318 "For all WebP textures, create a PNG fallback texture"
320 default=False
323 export_texture_dir: StringProperty(
324 name='Textures',
325 description='Folder to place texture files in. Relative to the .gltf file',
326 default='',
329 # Keep for back compatibility
330 export_jpeg_quality: IntProperty(
331 name='JPEG quality',
332 description='Quality of JPEG export',
333 default=75,
334 min=0,
335 max=100
338 # Keep for back compatibility
339 export_image_quality: IntProperty(
340 name='Image quality',
341 description='Quality of image export',
342 default=75,
343 min=0,
344 max=100
347 export_keep_originals: BoolProperty(
348 name='Keep original',
349 description=('Keep original textures files if possible. '
350 'WARNING: if you use more than one texture, '
351 'where pbr standard requires only one, only one texture will be used. '
352 'This can lead to unexpected results'
354 default=False,
357 export_texcoords: BoolProperty(
358 name='UVs',
359 description='Export UVs (texture coordinates) with meshes',
360 default=True
363 export_normals: BoolProperty(
364 name='Normals',
365 description='Export vertex normals with meshes',
366 default=True
369 export_gn_mesh: BoolProperty(
370 name='Geometry Nodes Instances (Experimental)',
371 description='Export Geometry nodes instance meshes',
372 default=False
375 export_draco_mesh_compression_enable: BoolProperty(
376 name='Draco mesh compression',
377 description='Compress mesh using Draco',
378 default=False
381 export_draco_mesh_compression_level: IntProperty(
382 name='Compression level',
383 description='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
384 default=6,
385 min=0,
386 max=10
389 export_draco_position_quantization: IntProperty(
390 name='Position quantization bits',
391 description='Quantization bits for position values (0 = no quantization)',
392 default=14,
393 min=0,
394 max=30
397 export_draco_normal_quantization: IntProperty(
398 name='Normal quantization bits',
399 description='Quantization bits for normal values (0 = no quantization)',
400 default=10,
401 min=0,
402 max=30
405 export_draco_texcoord_quantization: IntProperty(
406 name='Texcoord quantization bits',
407 description='Quantization bits for texture coordinate values (0 = no quantization)',
408 default=12,
409 min=0,
410 max=30
413 export_draco_color_quantization: IntProperty(
414 name='Color quantization bits',
415 description='Quantization bits for color values (0 = no quantization)',
416 default=10,
417 min=0,
418 max=30
421 export_draco_generic_quantization: IntProperty(
422 name='Generic quantization bits',
423 description='Quantization bits for generic values like weights or joints (0 = no quantization)',
424 default=12,
425 min=0,
426 max=30
429 export_tangents: BoolProperty(
430 name='Tangents',
431 description='Export vertex tangents with meshes',
432 default=False
435 export_materials: EnumProperty(
436 name='Materials',
437 items=(('EXPORT', 'Export',
438 'Export all materials used by included objects'),
439 ('PLACEHOLDER', 'Placeholder',
440 'Do not export materials, but write multiple primitive groups per mesh, keeping material slot information'),
441 ('NONE', 'No export',
442 'Do not export materials, and combine mesh primitive groups, losing material slot information')),
443 description='Export materials',
444 default='EXPORT'
447 export_unused_images: BoolProperty(
448 name='Unused images',
449 description='Export images not assigned to any material',
450 default=False)
452 export_unused_textures: BoolProperty(
453 name='Prepare Unused textures',
454 description=(
455 'Export image texture nodes not assigned to any material. '
456 'This feature is not standard and needs an external extension to be included in the glTF file'
458 default=False)
460 export_colors: BoolProperty(
461 name='Dummy',
462 description='Keep for compatibility only',
463 default=True
466 export_attributes: BoolProperty(
467 name='Attributes',
468 description='Export Attributes (when starting with underscore)',
469 default=False
472 use_mesh_edges: BoolProperty(
473 name='Loose Edges',
474 description=(
475 'Export loose edges as lines, using the material from the first material slot'
477 default=False,
480 use_mesh_vertices: BoolProperty(
481 name='Loose Points',
482 description=(
483 'Export loose points as glTF points, using the material from the first material slot'
485 default=False,
488 export_cameras: BoolProperty(
489 name='Cameras',
490 description='Export cameras',
491 default=False
494 use_selection: BoolProperty(
495 name='Selected Objects',
496 description='Export selected objects only',
497 default=False
500 use_visible: BoolProperty(
501 name='Visible Objects',
502 description='Export visible objects only',
503 default=False
506 use_renderable: BoolProperty(
507 name='Renderable Objects',
508 description='Export renderable objects only',
509 default=False
512 use_active_collection_with_nested: BoolProperty(
513 name='Include Nested Collections',
514 description='Include active collection and nested collections',
515 default=True
518 use_active_collection: BoolProperty(
519 name='Active Collection',
520 description='Export objects in the active collection only',
521 default=False
524 use_active_scene: BoolProperty(
525 name='Active Scene',
526 description='Export active scene only',
527 default=False
530 export_extras: BoolProperty(
531 name='Custom Properties',
532 description='Export custom properties as glTF extras',
533 default=False
536 export_yup: BoolProperty(
537 name='+Y Up',
538 description='Export using glTF convention, +Y up',
539 default=True
542 export_apply: BoolProperty(
543 name='Apply Modifiers',
544 description='Apply modifiers (excluding Armatures) to mesh objects -'
545 'WARNING: prevents exporting shape keys',
546 default=False
549 export_shared_accessors: BoolProperty(
550 name='Shared Accessors',
551 description='Export Primitives using shared accessors for attributes',
552 default=False
555 export_animations: BoolProperty(
556 name='Animations',
557 description='Exports active actions and NLA tracks as glTF animations',
558 default=True
561 export_frame_range: BoolProperty(
562 name='Limit to Playback Range',
563 description='Clips animations to selected playback range',
564 default=False
567 export_frame_step: IntProperty(
568 name='Sampling Rate',
569 description='How often to evaluate animated values (in frames)',
570 default=1,
571 min=1,
572 max=120
575 export_force_sampling: BoolProperty(
576 name='Always Sample Animations',
577 description='Apply sampling to all animations',
578 default=True
581 export_animation_mode: EnumProperty(
582 name='Animation mode',
583 items=(('ACTIONS', 'Actions',
584 'Export actions (actives and on NLA tracks) as separate animations'),
585 ('ACTIVE_ACTIONS', 'Active actions merged',
586 'All the currently assigned actions become one glTF animation'),
587 ('NLA_TRACKS', 'NLA Tracks',
588 'Export individual NLA Tracks as separate animation'),
589 ('SCENE', 'Scene',
590 'Export baked scene as a single animation')
592 description='Export Animation mode',
593 default='ACTIONS'
596 export_nla_strips_merged_animation_name: StringProperty(
597 name='Merged Animation Name',
598 description=(
599 "Name of single glTF animation to be exported"
601 default='Animation'
604 export_def_bones: BoolProperty(
605 name='Export Deformation Bones Only',
606 description='Export Deformation bones only',
607 default=False
610 export_hierarchy_flatten_bones: BoolProperty(
611 name='Flatten Bone Hierarchy',
612 description='Flatten Bone Hierarchy. Useful in case of non decomposable transformation matrix',
613 default=False
616 export_hierarchy_flatten_objs: BoolProperty(
617 name='Flatten Object Hierarchy',
618 description='Flatten Object Hierarchy. Useful in case of non decomposable transformation matrix',
619 default=False
622 export_armature_object_remove: BoolProperty(
623 name='Remove Armature Object',
624 description=(
625 'Remove Armature object if possible. '
626 'If Armature has multiple root bones, object will not be removed'
628 default=False
631 export_optimize_animation_size: BoolProperty(
632 name='Optimize Animation Size',
633 description=(
634 "Reduce exported file size by removing duplicate keyframes"
636 default=True
639 export_optimize_animation_keep_anim_armature: BoolProperty(
640 name='Force keeping channels for bones',
641 description=(
642 "If all keyframes are identical in a rig, "
643 "force keeping the minimal animation. "
644 "When off, all possible channels for "
645 "the bones will be exported, even if empty "
646 "(minimal animation, 2 keyframes)"
648 default=True
651 export_optimize_animation_keep_anim_object: BoolProperty(
652 name='Force keeping channel for objects',
653 description=(
654 "If all keyframes are identical for object transformations, "
655 "force keeping the minimal animation"
657 default=False
660 export_negative_frame: EnumProperty(
661 name='Negative Frames',
662 items=(('SLIDE', 'Slide',
663 'Slide animation to start at frame 0'),
664 ('CROP', 'Crop',
665 'Keep only frames above frame 0'),
667 description='Negative Frames are slid or cropped',
668 default='SLIDE'
671 export_anim_slide_to_zero: BoolProperty(
672 name='Set all glTF Animation starting at 0',
673 description=(
674 "Set all glTF animation starting at 0.0s. "
675 "Can be useful for looping animations"
677 default=False
680 export_bake_animation: BoolProperty(
681 name='Bake All Objects Animations',
682 description=(
683 "Force exporting animation on every object. "
684 "Can be useful when using constraints or driver. "
685 "Also useful when exporting only selection"
687 default=False
690 export_anim_single_armature: BoolProperty(
691 name='Export all Armature Actions',
692 description=(
693 "Export all actions, bound to a single armature. "
694 "WARNING: Option does not support exports including multiple armatures"
696 default=True
699 export_reset_pose_bones: BoolProperty(
700 name='Reset pose bones between actions',
701 description=(
702 "Reset pose bones between each action exported. "
703 "This is needed when some bones are not keyed on some animations"
705 default=True
708 export_current_frame: BoolProperty(
709 name='Use Current Frame as Object Rest Transformations',
710 description=(
711 'Export the scene in the current animation frame. '
712 'When off, frame 0 is used as rest transformations for objects'
714 default=False
717 export_rest_position_armature: BoolProperty(
718 name='Use Rest Position Armature',
719 description=(
720 "Export armatures using rest position as joints' rest pose. "
721 "When off, current frame pose is used as rest pose"
723 default=True
726 export_anim_scene_split_object: BoolProperty(
727 name='Split Animation by Object',
728 description=(
729 "Export Scene as seen in Viewport, "
730 "But split animation by Object"
732 default=True
735 export_skins: BoolProperty(
736 name='Skinning',
737 description='Export skinning (armature) data',
738 default=True
741 export_influence_nb: IntProperty(
742 name='Bone Influences',
743 description='Choose how many Bone influences to export',
744 default=4,
745 min=1
748 export_all_influences: BoolProperty(
749 name='Include All Bone Influences',
750 description='Allow export of all joint vertex influences. Models may appear incorrectly in many viewers',
751 default=False
754 export_morph: BoolProperty(
755 name='Shape Keys',
756 description='Export shape keys (morph targets)',
757 default=True
760 export_morph_normal: BoolProperty(
761 name='Shape Key Normals',
762 description='Export vertex normals with shape keys (morph targets)',
763 default=True
766 export_morph_tangent: BoolProperty(
767 name='Shape Key Tangents',
768 description='Export vertex tangents with shape keys (morph targets)',
769 default=False
772 export_morph_animation: BoolProperty(
773 name='Shape Key Animations',
774 description='Export shape keys animations (morph targets)',
775 default=True
778 export_morph_reset_sk_data: BoolProperty(
779 name='Reset shape keys between actions',
780 description=(
781 "Reset shape keys between each action exported. "
782 "This is needed when some SK channels are not keyed on some animations"
784 default=True
787 export_lights: BoolProperty(
788 name='Punctual Lights',
789 description='Export directional, point, and spot lights. '
790 'Uses "KHR_lights_punctual" glTF extension',
791 default=False
794 export_try_sparse_sk: BoolProperty(
795 name='Use Sparse Accessor if better',
796 description='Try using Sparse Accessor if it saves space',
797 default=True
800 export_try_omit_sparse_sk: BoolProperty(
801 name='Omitting Sparse Accessor if data is empty',
802 description='Omitting Sparse Accessor if data is empty',
803 default=False
806 export_gpu_instances: BoolProperty(
807 name='GPU Instances',
808 description='Export using EXT_mesh_gpu_instancing. '
809 'Limited to children of a given Empty. '
810 'Multiple materials might be omitted',
811 default=False
814 export_action_filter: BoolProperty(
815 name='Filter Actions',
816 description='Filter Actions to be exported',
817 default=False,
818 update=on_export_action_filter_changed,
821 # This parameter is only here for backward compatibility, as this option is removed in 3.6
822 # This option does nothing, and is not displayed in UI
823 # What you are looking for is probably "export_animation_mode"
824 export_nla_strips: BoolProperty(
825 name='Group by NLA Track',
826 description=(
827 "When on, multiple actions become part of the same glTF animation if "
828 "they're pushed onto NLA tracks with the same name. "
829 "When off, all the currently assigned actions become one glTF animation"
831 default=True
834 # Keep for back compatibility, but no more used
835 export_original_specular: BoolProperty(
836 name='Export original PBR Specular',
837 description=(
838 'Export original glTF PBR Specular, instead of Blender Principled Shader Specular'
840 default=False,
843 will_save_settings: BoolProperty(
844 name='Remember Export Settings',
845 description='Store glTF export settings in the Blender project',
846 default=False)
848 export_hierarchy_full_collections: BoolProperty(
849 name='Full Collection Hierarchy',
850 description='Export full hierarchy, including intermediate collections',
851 default=False
854 # Custom scene property for saving settings
855 scene_key = "glTF2ExportSettings"
859 def check(self, _context):
860 # Ensure file extension matches format
861 old_filepath = self.filepath
862 self.filepath = ensure_filepath_matches_export_format(
863 self.filepath,
864 self.export_format,
866 return self.filepath != old_filepath
868 def invoke(self, context, event):
869 settings = context.scene.get(self.scene_key)
870 self.will_save_settings = False
871 if settings:
872 try:
873 for (k, v) in settings.items():
874 setattr(self, k, v)
875 self.will_save_settings = True
877 # Update filter if user saved settings
878 if hasattr(self, 'export_format'):
879 self.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf'
881 except (AttributeError, TypeError):
882 self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
883 del context.scene[self.scene_key]
885 import sys
886 preferences = bpy.context.preferences
887 for addon_name in preferences.addons.keys():
888 try:
889 if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ExportUserExtensions'):
890 exporter_extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
891 except Exception:
892 pass
894 self.has_active_exporter_extensions = len(exporter_extension_panel_unregister_functors) > 0
895 return ExportHelper.invoke(self, context, event)
897 def save_settings(self, context):
898 # find all props to save
899 exceptional = [
900 # options that don't start with 'export_'
901 'use_selection',
902 'use_visible',
903 'use_renderable',
904 'use_active_collection_with_nested',
905 'use_active_collection',
906 'use_mesh_edges',
907 'use_mesh_vertices',
908 'use_active_scene',
910 all_props = self.properties
911 export_props = {
912 x: getattr(self, x) for x in dir(all_props)
913 if (x.startswith("export_") or x in exceptional) and all_props.get(x) is not None
915 context.scene[self.scene_key] = export_props
917 def execute(self, context):
918 import os
919 import datetime
920 from .blender.exp import gltf2_blender_export
921 from .io.com.gltf2_io_path import path_to_uri
923 if self.will_save_settings:
924 self.save_settings(context)
926 self.check(context) # ensure filepath has the right extension
928 # All custom export settings are stored in this container.
929 export_settings = {}
931 export_settings['exported_images'] = {}
932 export_settings['exported_texture_nodes'] = []
933 export_settings['additional_texture_export'] = []
934 export_settings['additional_texture_export_current_idx'] = 0
936 export_settings['timestamp'] = datetime.datetime.now()
937 export_settings['gltf_export_id'] = self.gltf_export_id
938 export_settings['gltf_filepath'] = self.filepath
939 export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
940 export_settings['gltf_texturedirectory'] = os.path.join(
941 export_settings['gltf_filedirectory'],
942 self.export_texture_dir,
944 export_settings['gltf_keep_original_textures'] = self.export_keep_originals
946 export_settings['gltf_format'] = self.export_format
947 export_settings['gltf_image_format'] = self.export_image_format
948 export_settings['gltf_add_webp'] = self.export_image_add_webp
949 export_settings['gltf_webp_fallback'] = self.export_image_webp_fallback
950 export_settings['gltf_image_quality'] = self.export_image_quality
951 export_settings['gltf_copyright'] = self.export_copyright
952 export_settings['gltf_texcoords'] = self.export_texcoords
953 export_settings['gltf_normals'] = self.export_normals
954 export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
955 export_settings['gltf_loose_edges'] = self.use_mesh_edges
956 export_settings['gltf_loose_points'] = self.use_mesh_vertices
958 if self.is_draco_available:
959 export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
960 export_settings['gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level
961 export_settings['gltf_draco_position_quantization'] = self.export_draco_position_quantization
962 export_settings['gltf_draco_normal_quantization'] = self.export_draco_normal_quantization
963 export_settings['gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization
964 export_settings['gltf_draco_color_quantization'] = self.export_draco_color_quantization
965 export_settings['gltf_draco_generic_quantization'] = self.export_draco_generic_quantization
966 else:
967 export_settings['gltf_draco_mesh_compression'] = False
969 export_settings['gltf_gn_mesh'] = self.export_gn_mesh
971 export_settings['gltf_materials'] = self.export_materials
972 export_settings['gltf_attributes'] = self.export_attributes
973 export_settings['gltf_cameras'] = self.export_cameras
975 export_settings['gltf_unused_textures'] = self.export_unused_textures
976 export_settings['gltf_unused_images'] = self.export_unused_images
978 export_settings['gltf_visible'] = self.use_visible
979 export_settings['gltf_renderable'] = self.use_renderable
981 export_settings['gltf_active_collection'] = self.use_active_collection
982 if self.use_active_collection:
983 export_settings['gltf_active_collection_with_nested'] = self.use_active_collection_with_nested
984 else:
985 export_settings['gltf_active_collection_with_nested'] = False
986 export_settings['gltf_active_scene'] = self.use_active_scene
988 export_settings['gltf_selected'] = self.use_selection
989 export_settings['gltf_layers'] = True # self.export_layers
990 export_settings['gltf_extras'] = self.export_extras
991 export_settings['gltf_yup'] = self.export_yup
992 export_settings['gltf_apply'] = self.export_apply
993 export_settings['gltf_shared_accessors'] = self.export_shared_accessors
994 export_settings['gltf_current_frame'] = self.export_current_frame
995 export_settings['gltf_animations'] = self.export_animations
996 export_settings['gltf_def_bones'] = self.export_def_bones
997 export_settings['gltf_flatten_bones_hierarchy'] = self.export_hierarchy_flatten_bones
998 export_settings['gltf_flatten_obj_hierarchy'] = self.export_hierarchy_flatten_objs
999 export_settings['gltf_armature_object_remove'] = self.export_armature_object_remove
1000 if self.export_animations:
1001 export_settings['gltf_frame_range'] = self.export_frame_range
1002 export_settings['gltf_force_sampling'] = self.export_force_sampling
1003 if not self.export_force_sampling:
1004 export_settings['gltf_def_bones'] = False
1005 export_settings['gltf_bake_animation'] = False
1006 export_settings['gltf_animation_mode'] = self.export_animation_mode
1007 if export_settings['gltf_animation_mode'] == "NLA_TRACKS":
1008 export_settings['gltf_force_sampling'] = True
1009 if export_settings['gltf_animation_mode'] == "SCENE":
1010 export_settings['gltf_anim_scene_split_object'] = self.export_anim_scene_split_object
1011 else:
1012 export_settings['gltf_anim_scene_split_object'] = False
1014 export_settings['gltf_nla_strips_merged_animation_name'] = self.export_nla_strips_merged_animation_name
1015 export_settings['gltf_optimize_animation'] = self.export_optimize_animation_size
1016 export_settings['gltf_optimize_animation_keep_armature'] = self.export_optimize_animation_keep_anim_armature
1017 export_settings['gltf_optimize_animation_keep_object'] = self.export_optimize_animation_keep_anim_object
1018 export_settings['gltf_export_anim_single_armature'] = self.export_anim_single_armature
1019 export_settings['gltf_export_reset_pose_bones'] = self.export_reset_pose_bones
1020 export_settings['gltf_export_reset_sk_data'] = self.export_morph_reset_sk_data
1021 export_settings['gltf_bake_animation'] = self.export_bake_animation
1022 export_settings['gltf_negative_frames'] = self.export_negative_frame
1023 export_settings['gltf_anim_slide_to_zero'] = self.export_anim_slide_to_zero
1024 else:
1025 export_settings['gltf_frame_range'] = False
1026 export_settings['gltf_force_sampling'] = False
1027 export_settings['gltf_bake_animation'] = False
1028 export_settings['gltf_optimize_animation'] = False
1029 export_settings['gltf_optimize_animation_keep_armature'] = False
1030 export_settings['gltf_optimize_animation_keep_object'] = False
1031 export_settings['gltf_export_anim_single_armature'] = False
1032 export_settings['gltf_export_reset_pose_bones'] = False
1033 export_settings['gltf_export_reset_sk_data'] = False
1034 export_settings['gltf_skins'] = self.export_skins
1035 if self.export_skins:
1036 export_settings['gltf_all_vertex_influences'] = self.export_all_influences
1037 export_settings['gltf_vertex_influences_nb'] = self.export_influence_nb
1038 else:
1039 export_settings['gltf_all_vertex_influences'] = False
1040 export_settings['gltf_def_bones'] = False
1041 export_settings['gltf_rest_position_armature'] = self.export_rest_position_armature
1042 export_settings['gltf_frame_step'] = self.export_frame_step
1044 export_settings['gltf_morph'] = self.export_morph
1045 if self.export_morph:
1046 export_settings['gltf_morph_normal'] = self.export_morph_normal
1047 export_settings['gltf_morph_tangent'] = self.export_morph_tangent
1048 export_settings['gltf_morph_anim'] = self.export_morph_animation
1049 else:
1050 export_settings['gltf_morph_normal'] = False
1051 export_settings['gltf_morph_tangent'] = False
1052 export_settings['gltf_morph_anim'] = False
1054 export_settings['gltf_lights'] = self.export_lights
1055 export_settings['gltf_lighting_mode'] = self.export_import_convert_lighting_mode
1056 export_settings['gltf_gpu_instances'] = self.export_gpu_instances
1058 export_settings['gltf_try_sparse_sk'] = self.export_try_sparse_sk
1059 export_settings['gltf_try_omit_sparse_sk'] = self.export_try_omit_sparse_sk
1060 if not self.export_try_sparse_sk:
1061 export_settings['gltf_try_omit_sparse_sk'] = False
1063 export_settings['gltf_hierarchy_full_collections'] = self.export_hierarchy_full_collections
1065 # gltfpack stuff
1066 export_settings['gltf_use_gltfpack'] = self.export_use_gltfpack
1067 if self.export_use_gltfpack:
1068 export_settings['gltf_gltfpack_tc'] = self.export_gltfpack_tc
1069 export_settings['gltf_gltfpack_tq'] = self.export_gltfpack_tq
1071 export_settings['gltf_gltfpack_si'] = self.export_gltfpack_si
1072 export_settings['gltf_gltfpack_sa'] = self.export_gltfpack_sa
1073 export_settings['gltf_gltfpack_slb'] = self.export_gltfpack_slb
1075 export_settings['gltf_gltfpack_vp'] = self.export_gltfpack_vp
1076 export_settings['gltf_gltfpack_vt'] = self.export_gltfpack_vt
1077 export_settings['gltf_gltfpack_vn'] = self.export_gltfpack_vn
1078 export_settings['gltf_gltfpack_vc'] = self.export_gltfpack_vc
1080 export_settings['gltf_gltfpack_vpi'] = self.export_gltfpack_vpi
1082 export_settings['gltf_gltfpack_noq'] = self.export_gltfpack_noq
1084 export_settings['gltf_binary'] = bytearray()
1085 export_settings['gltf_binaryfilename'] = (
1086 path_to_uri(os.path.splitext(os.path.basename(self.filepath))[0] + '.bin')
1089 user_extensions = []
1090 pre_export_callbacks = []
1091 post_export_callbacks = []
1093 import sys
1094 preferences = bpy.context.preferences
1095 for addon_name in preferences.addons.keys():
1096 try:
1097 module = sys.modules[addon_name]
1098 except Exception:
1099 continue
1100 if hasattr(module, 'glTF2ExportUserExtension'):
1101 extension_ctor = module.glTF2ExportUserExtension
1102 user_extensions.append(extension_ctor())
1103 if hasattr(module, 'glTF2ExportUserExtensions'):
1104 extension_ctors = module.glTF2ExportUserExtensions
1105 for extension_ctor in extension_ctors:
1106 user_extensions.append(extension_ctor())
1107 if hasattr(module, 'glTF2_pre_export_callback'):
1108 pre_export_callbacks.append(module.glTF2_pre_export_callback)
1109 if hasattr(module, 'glTF2_post_export_callback'):
1110 post_export_callbacks.append(module.glTF2_post_export_callback)
1111 export_settings['gltf_user_extensions'] = user_extensions
1112 export_settings['pre_export_callbacks'] = pre_export_callbacks
1113 export_settings['post_export_callbacks'] = post_export_callbacks
1115 return gltf2_blender_export.save(context, export_settings)
1117 def draw(self, context):
1118 pass # Is needed to get panels available
1121 class GLTF_PT_export_main(bpy.types.Panel):
1122 bl_space_type = 'FILE_BROWSER'
1123 bl_region_type = 'TOOL_PROPS'
1124 bl_label = ""
1125 bl_parent_id = "FILE_PT_operator"
1126 bl_options = {'HIDE_HEADER'}
1128 @classmethod
1129 def poll(cls, context):
1130 sfile = context.space_data
1131 operator = sfile.active_operator
1133 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1135 def draw(self, context):
1136 layout = self.layout
1137 layout.use_property_split = True
1138 layout.use_property_decorate = False # No animation.
1140 sfile = context.space_data
1141 operator = sfile.active_operator
1143 layout.prop(operator, 'export_format')
1144 if operator.export_format == 'GLTF_SEPARATE':
1145 layout.prop(operator, 'export_keep_originals')
1146 if operator.export_keep_originals is False:
1147 layout.prop(operator, 'export_texture_dir', icon='FILE_FOLDER')
1149 layout.prop(operator, 'export_copyright')
1150 layout.prop(operator, 'will_save_settings')
1153 class GLTF_PT_export_gltfpack(bpy.types.Panel):
1154 bl_space_type = 'FILE_BROWSER'
1155 bl_region_type = 'TOOL_PROPS'
1156 bl_label = "gltfpack"
1157 bl_parent_id = "FILE_PT_operator"
1158 bl_options = {'DEFAULT_CLOSED'}
1160 @classmethod
1161 def poll(cls, context):
1162 gltfpack_path = context.preferences.addons['io_scene_gltf2'].preferences.gltfpack_path_ui.strip()
1163 if (gltfpack_path == ''): # gltfpack not setup in plugin preferences -> dont show any gltfpack relevant options in export dialog
1164 return False;
1166 sfile = context.space_data
1167 operator = sfile.active_operator
1169 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1171 def draw(self, context):
1173 layout = self.layout
1174 layout.use_property_split = True
1175 layout.use_property_decorate = False # No animation.
1177 sfile = context.space_data
1178 operator = sfile.active_operator
1180 col = layout.column(heading = "gltfpack", align = True)
1181 col.prop(operator, 'export_use_gltfpack')
1183 col = layout.column(heading = "Textures", align = True)
1184 col.prop(operator, 'export_gltfpack_tc')
1185 col.prop(operator, 'export_gltfpack_tq')
1186 col = layout.column(heading = "Simplification", align = True)
1187 col.prop(operator, 'export_gltfpack_si')
1188 col.prop(operator, 'export_gltfpack_sa')
1189 col.prop(operator, 'export_gltfpack_slb')
1190 col = layout.column(heading = "Vertices", align = True)
1191 col.prop(operator, 'export_gltfpack_vp')
1192 col.prop(operator, 'export_gltfpack_vt')
1193 col.prop(operator, 'export_gltfpack_vn')
1194 col.prop(operator, 'export_gltfpack_vc')
1195 col = layout.column(heading = "Vertex positions", align = True)
1196 col.prop(operator, 'export_gltfpack_vpi')
1197 #col = layout.column(heading = "Animations", align = True)
1198 #col = layout.column(heading = "Scene", align = True)
1199 col = layout.column(heading = "Miscellaneous", align = True)
1200 col.prop(operator, 'export_gltfpack_noq')
1203 class GLTF_PT_export_include(bpy.types.Panel):
1204 bl_space_type = 'FILE_BROWSER'
1205 bl_region_type = 'TOOL_PROPS'
1206 bl_label = "Include"
1207 bl_parent_id = "FILE_PT_operator"
1208 bl_options = {'DEFAULT_CLOSED'}
1210 @classmethod
1211 def poll(cls, context):
1212 sfile = context.space_data
1213 operator = sfile.active_operator
1215 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1217 def draw(self, context):
1218 layout = self.layout
1219 layout.use_property_split = True
1220 layout.use_property_decorate = False # No animation.
1222 sfile = context.space_data
1223 operator = sfile.active_operator
1225 col = layout.column(heading = "Limit to", align = True)
1226 col.prop(operator, 'use_selection')
1227 col.prop(operator, 'use_visible')
1228 col.prop(operator, 'use_renderable')
1229 col.prop(operator, 'use_active_collection')
1230 if operator.use_active_collection:
1231 col.prop(operator, 'use_active_collection_with_nested')
1232 col.prop(operator, 'use_active_scene')
1234 col = layout.column(heading = "Data", align = True)
1235 col.prop(operator, 'export_extras')
1236 col.prop(operator, 'export_cameras')
1237 col.prop(operator, 'export_lights')
1240 class GLTF_PT_export_transform(bpy.types.Panel):
1241 bl_space_type = 'FILE_BROWSER'
1242 bl_region_type = 'TOOL_PROPS'
1243 bl_label = "Transform"
1244 bl_parent_id = "FILE_PT_operator"
1245 bl_options = {'DEFAULT_CLOSED'}
1247 @classmethod
1248 def poll(cls, context):
1249 sfile = context.space_data
1250 operator = sfile.active_operator
1252 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1254 def draw(self, context):
1255 layout = self.layout
1256 layout.use_property_split = True
1257 layout.use_property_decorate = False # No animation.
1259 sfile = context.space_data
1260 operator = sfile.active_operator
1262 layout.prop(operator, 'export_yup')
1265 class GLTF_PT_export_data(bpy.types.Panel):
1266 bl_space_type = 'FILE_BROWSER'
1267 bl_region_type = 'TOOL_PROPS'
1268 bl_label = "Data"
1269 bl_parent_id = "FILE_PT_operator"
1270 bl_options = {'DEFAULT_CLOSED'}
1272 @classmethod
1273 def poll(cls, context):
1274 sfile = context.space_data
1275 operator = sfile.active_operator
1277 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1279 def draw(self, context):
1280 pass
1282 class GLTF_PT_export_data_scene(bpy.types.Panel):
1283 bl_space_type = 'FILE_BROWSER'
1284 bl_region_type = 'TOOL_PROPS'
1285 bl_label = "Scene Graph"
1286 bl_parent_id = "GLTF_PT_export_data"
1287 bl_options = {'DEFAULT_CLOSED'}
1289 @classmethod
1290 def poll(cls, context):
1291 sfile = context.space_data
1292 operator = sfile.active_operator
1293 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1295 def draw(self, context):
1296 layout = self.layout
1297 layout.use_property_split = True
1298 layout.use_property_decorate = False # No animation.
1300 sfile = context.space_data
1301 operator = sfile.active_operator
1302 layout.prop(operator, 'export_gn_mesh')
1303 layout.prop(operator, 'export_gpu_instances')
1304 layout.prop(operator, 'export_hierarchy_flatten_objs')
1305 layout.prop(operator, 'export_hierarchy_full_collections')
1307 class GLTF_PT_export_data_mesh(bpy.types.Panel):
1308 bl_space_type = 'FILE_BROWSER'
1309 bl_region_type = 'TOOL_PROPS'
1310 bl_label = "Mesh"
1311 bl_parent_id = "GLTF_PT_export_data"
1312 bl_options = {'DEFAULT_CLOSED'}
1314 @classmethod
1315 def poll(cls, context):
1316 sfile = context.space_data
1317 operator = sfile.active_operator
1318 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1320 def draw(self, context):
1321 layout = self.layout
1322 layout.use_property_split = True
1323 layout.use_property_decorate = False # No animation.
1325 sfile = context.space_data
1326 operator = sfile.active_operator
1328 layout.prop(operator, 'export_apply')
1329 layout.prop(operator, 'export_texcoords')
1330 layout.prop(operator, 'export_normals')
1331 col = layout.column()
1332 col.active = operator.export_normals
1333 col.prop(operator, 'export_tangents')
1334 layout.prop(operator, 'export_attributes')
1336 col = layout.column()
1337 col.prop(operator, 'use_mesh_edges')
1338 col.prop(operator, 'use_mesh_vertices')
1340 col = layout.column()
1341 col.prop(operator, 'export_shared_accessors')
1344 class GLTF_PT_export_data_material(bpy.types.Panel):
1345 bl_space_type = 'FILE_BROWSER'
1346 bl_region_type = 'TOOL_PROPS'
1347 bl_label = "Material"
1348 bl_parent_id = "GLTF_PT_export_data"
1349 bl_options = {'DEFAULT_CLOSED'}
1351 @classmethod
1352 def poll(cls, context):
1353 sfile = context.space_data
1354 operator = sfile.active_operator
1355 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1357 def draw(self, context):
1358 layout = self.layout
1359 layout.use_property_split = True
1360 layout.use_property_decorate = False # No animation.
1362 sfile = context.space_data
1363 operator = sfile.active_operator
1365 layout.prop(operator, 'export_materials')
1366 col = layout.column()
1367 col.active = operator.export_materials == "EXPORT"
1368 col.prop(operator, 'export_image_format')
1369 if operator.export_image_format in ["AUTO", "JPEG", "WEBP"]:
1370 col.prop(operator, 'export_image_quality')
1371 col = layout.column()
1372 col.active = operator.export_image_format != "WEBP"
1373 col.prop(operator, "export_image_add_webp")
1374 col = layout.column()
1375 col.active = operator.export_image_format != "WEBP"
1376 col.prop(operator, "export_image_webp_fallback")
1378 class GLTF_PT_export_unsed_tex_image(bpy.types.Panel):
1379 bl_space_type = 'FILE_BROWSER'
1380 bl_region_type = 'TOOL_PROPS'
1381 bl_label = "Unused Textures & Images"
1382 bl_parent_id = "GLTF_PT_export_data_material"
1383 bl_options = {'DEFAULT_CLOSED'}
1385 @classmethod
1386 def poll(cls, context):
1387 sfile = context.space_data
1388 operator = sfile.active_operator
1390 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1392 def draw(self, context):
1393 layout = self.layout
1394 layout.use_property_split = True
1395 layout.use_property_decorate = False # No animation.
1397 sfile = context.space_data
1398 operator = sfile.active_operator
1400 row = layout.row()
1401 row.prop(operator, 'export_unused_images')
1402 row = layout.row()
1403 row.prop(operator, 'export_unused_textures')
1406 class GLTF_PT_export_data_lighting(bpy.types.Panel):
1407 bl_space_type = 'FILE_BROWSER'
1408 bl_region_type = 'TOOL_PROPS'
1409 bl_label = "Lighting"
1410 bl_parent_id = "GLTF_PT_export_data"
1411 bl_options = {'DEFAULT_CLOSED'}
1413 @classmethod
1414 def poll(cls, context):
1415 sfile = context.space_data
1416 operator = sfile.active_operator
1417 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1419 def draw(self, context):
1420 layout = self.layout
1421 layout.use_property_split = True
1422 layout.use_property_decorate = False # No animation.
1424 sfile = context.space_data
1425 operator = sfile.active_operator
1427 layout.prop(operator, 'export_import_convert_lighting_mode')
1429 class GLTF_PT_export_data_shapekeys(bpy.types.Panel):
1430 bl_space_type = 'FILE_BROWSER'
1431 bl_region_type = 'TOOL_PROPS'
1432 bl_label = "Shape Keys"
1433 bl_parent_id = "GLTF_PT_export_data"
1434 bl_options = {'DEFAULT_CLOSED'}
1436 @classmethod
1437 def poll(cls, context):
1438 sfile = context.space_data
1439 operator = sfile.active_operator
1441 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1443 def draw_header(self, context):
1444 sfile = context.space_data
1445 operator = sfile.active_operator
1446 self.layout.prop(operator, "export_morph", text="")
1448 def draw(self, context):
1449 layout = self.layout
1450 layout.use_property_split = True
1451 layout.use_property_decorate = False # No animation.
1453 sfile = context.space_data
1454 operator = sfile.active_operator
1456 layout.active = operator.export_morph
1458 layout.prop(operator, 'export_morph_normal')
1459 col = layout.column()
1460 col.active = operator.export_morph_normal
1461 col.prop(operator, 'export_morph_tangent')
1464 class GLTF_PT_export_data_sk_optimize(bpy.types.Panel):
1465 bl_space_type = 'FILE_BROWSER'
1466 bl_region_type = 'TOOL_PROPS'
1467 bl_label = "Optimize Shape Keys"
1468 bl_parent_id = "GLTF_PT_export_data_shapekeys"
1469 bl_options = {'DEFAULT_CLOSED'}
1471 @classmethod
1472 def poll(cls, context):
1473 sfile = context.space_data
1474 operator = sfile.active_operator
1476 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1478 def draw(self, context):
1479 layout = self.layout
1480 layout.use_property_split = True
1481 layout.use_property_decorate = False # No animation.
1483 sfile = context.space_data
1484 operator = sfile.active_operator
1486 row = layout.row()
1487 row.prop(operator, 'export_try_sparse_sk')
1489 row = layout.row()
1490 row.active = operator.export_try_sparse_sk
1491 row.prop(operator, 'export_try_omit_sparse_sk')
1494 class GLTF_PT_export_data_skinning(bpy.types.Panel):
1495 bl_space_type = 'FILE_BROWSER'
1496 bl_region_type = 'TOOL_PROPS'
1497 bl_label = "Skinning"
1498 bl_parent_id = "GLTF_PT_export_data"
1499 bl_options = {'DEFAULT_CLOSED'}
1501 @classmethod
1502 def poll(cls, context):
1503 sfile = context.space_data
1504 operator = sfile.active_operator
1506 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1508 def draw_header(self, context):
1509 sfile = context.space_data
1510 operator = sfile.active_operator
1511 self.layout.prop(operator, "export_skins", text="")
1513 def draw(self, context):
1514 layout = self.layout
1515 layout.use_property_split = True
1516 layout.use_property_decorate = False # No animation.
1518 sfile = context.space_data
1519 operator = sfile.active_operator
1521 layout.active = operator.export_skins
1523 row = layout.row()
1524 row.prop(operator, 'export_influence_nb')
1525 row.active = not operator.export_all_influences
1526 layout.prop(operator, 'export_all_influences')
1529 class GLTF_PT_export_data_armature(bpy.types.Panel):
1530 bl_space_type = 'FILE_BROWSER'
1531 bl_region_type = 'TOOL_PROPS'
1532 bl_label = "Armature"
1533 bl_parent_id = "GLTF_PT_export_data"
1534 bl_options = {'DEFAULT_CLOSED'}
1536 @classmethod
1537 def poll(cls, context):
1538 sfile = context.space_data
1539 operator = sfile.active_operator
1541 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1543 def draw(self, context):
1544 layout = self.layout
1545 layout.use_property_split = True
1546 layout.use_property_decorate = False # No animation.
1548 sfile = context.space_data
1549 operator = sfile.active_operator
1551 layout.active = operator.export_skins
1553 layout.prop(operator, 'export_rest_position_armature')
1555 row = layout.row()
1556 row.active = operator.export_force_sampling
1557 row.prop(operator, 'export_def_bones')
1558 if operator.export_force_sampling is False and operator.export_def_bones is True:
1559 layout.label(text="Export only deformation bones is not possible when not sampling animation")
1560 row = layout.row()
1561 row.prop(operator, 'export_armature_object_remove')
1562 row = layout.row()
1563 row.prop(operator, 'export_hierarchy_flatten_bones')
1565 class GLTF_PT_export_data_compression(bpy.types.Panel):
1566 bl_space_type = 'FILE_BROWSER'
1567 bl_region_type = 'TOOL_PROPS'
1568 bl_label = "Compression"
1569 bl_parent_id = "GLTF_PT_export_data"
1570 bl_options = {'DEFAULT_CLOSED'}
1572 def __init__(self):
1573 from .io.com import gltf2_io_draco_compression_extension
1574 self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists(quiet=True)
1576 @classmethod
1577 def poll(cls, context):
1578 sfile = context.space_data
1579 operator = sfile.active_operator
1580 if operator.is_draco_available:
1581 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1583 def draw_header(self, context):
1584 sfile = context.space_data
1585 operator = sfile.active_operator
1586 self.layout.prop(operator, "export_draco_mesh_compression_enable", text="")
1588 def draw(self, context):
1589 layout = self.layout
1590 layout.use_property_split = True
1591 layout.use_property_decorate = False # No animation.
1593 sfile = context.space_data
1594 operator = sfile.active_operator
1596 layout.active = operator.export_draco_mesh_compression_enable
1597 layout.prop(operator, 'export_draco_mesh_compression_level')
1599 col = layout.column(align=True)
1600 col.prop(operator, 'export_draco_position_quantization', text="Quantize Position")
1601 col.prop(operator, 'export_draco_normal_quantization', text="Normal")
1602 col.prop(operator, 'export_draco_texcoord_quantization', text="Tex Coord")
1603 col.prop(operator, 'export_draco_color_quantization', text="Color")
1604 col.prop(operator, 'export_draco_generic_quantization', text="Generic")
1607 class GLTF_PT_export_animation(bpy.types.Panel):
1608 bl_space_type = 'FILE_BROWSER'
1609 bl_region_type = 'TOOL_PROPS'
1610 bl_label = "Animation"
1611 bl_parent_id = "FILE_PT_operator"
1612 bl_options = {'DEFAULT_CLOSED'}
1614 @classmethod
1615 def poll(cls, context):
1616 sfile = context.space_data
1617 operator = sfile.active_operator
1619 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1621 def draw_header(self, context):
1622 sfile = context.space_data
1623 operator = sfile.active_operator
1624 self.layout.prop(operator, "export_animations", text="")
1626 def draw(self, context):
1627 layout = self.layout
1628 layout.use_property_split = True
1629 layout.use_property_decorate = False # No animation.
1631 sfile = context.space_data
1632 operator = sfile.active_operator
1634 layout.active = operator.export_animations
1636 layout.prop(operator, 'export_animation_mode')
1637 if operator.export_animation_mode == "ACTIVE_ACTIONS":
1638 layout.prop(operator, 'export_nla_strips_merged_animation_name')
1640 row = layout.row()
1641 row.active = operator.export_force_sampling and operator.export_animation_mode in ['ACTIONS', 'ACTIVE_ACTIONS']
1642 row.prop(operator, 'export_bake_animation')
1643 if operator.export_animation_mode == "SCENE":
1644 layout.prop(operator, 'export_anim_scene_split_object')
1646 class GLTF_PT_export_animation_notes(bpy.types.Panel):
1647 bl_space_type = 'FILE_BROWSER'
1648 bl_region_type = 'TOOL_PROPS'
1649 bl_label = "Notes"
1650 bl_parent_id = "GLTF_PT_export_animation"
1651 bl_options = {'DEFAULT_CLOSED'}
1653 @classmethod
1654 def poll(cls, context):
1655 sfile = context.space_data
1656 operator = sfile.active_operator
1658 return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and \
1659 operator.export_animation_mode in ["NLA_TRACKS", "SCENE"]
1661 def draw(self, context):
1662 operator = context.space_data.active_operator
1663 layout = self.layout
1664 if operator.export_animation_mode == "SCENE":
1665 layout.label(text="Scene mode uses full bake mode:")
1666 layout.label(text="- sampling is active")
1667 layout.label(text="- baking all objects is active")
1668 layout.label(text="- Using scene frame range")
1669 elif operator.export_animation_mode == "NLA_TRACKS":
1670 layout.label(text="Track mode uses full bake mode:")
1671 layout.label(text="- sampling is active")
1672 layout.label(text="- baking all objects is active")
1674 class GLTF_PT_export_animation_ranges(bpy.types.Panel):
1675 bl_space_type = 'FILE_BROWSER'
1676 bl_region_type = 'TOOL_PROPS'
1677 bl_label = "Rest & Ranges"
1678 bl_parent_id = "GLTF_PT_export_animation"
1679 bl_options = {'DEFAULT_CLOSED'}
1681 @classmethod
1682 def poll(cls, context):
1683 sfile = context.space_data
1684 operator = sfile.active_operator
1686 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1688 def draw(self, context):
1689 layout = self.layout
1690 layout.use_property_split = True
1691 layout.use_property_decorate = False # No animation.
1693 sfile = context.space_data
1694 operator = sfile.active_operator
1696 layout.active = operator.export_animations
1698 layout.prop(operator, 'export_current_frame')
1699 row = layout.row()
1700 row.active = operator.export_animation_mode in ['ACTIONS', 'ACTIVE_ACTIONS', 'NLA_TRACKS']
1701 row.prop(operator, 'export_frame_range')
1702 layout.prop(operator, 'export_anim_slide_to_zero')
1703 row = layout.row()
1704 row.active = operator.export_animation_mode in ['ACTIONS', 'ACTIVE_ACTIONS', 'NLA_TRACKS']
1705 layout.prop(operator, 'export_negative_frame')
1707 class GLTF_PT_export_animation_armature(bpy.types.Panel):
1708 bl_space_type = 'FILE_BROWSER'
1709 bl_region_type = 'TOOL_PROPS'
1710 bl_label = "Armature"
1711 bl_parent_id = "GLTF_PT_export_animation"
1712 bl_options = {'DEFAULT_CLOSED'}
1714 @classmethod
1715 def poll(cls, context):
1716 sfile = context.space_data
1717 operator = sfile.active_operator
1719 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1721 def draw(self, context):
1722 layout = self.layout
1723 layout.use_property_split = True
1724 layout.use_property_decorate = False # No animation.
1726 sfile = context.space_data
1727 operator = sfile.active_operator
1729 layout.active = operator.export_animations
1731 layout.prop(operator, 'export_anim_single_armature')
1732 layout.prop(operator, 'export_reset_pose_bones')
1734 class GLTF_PT_export_animation_shapekeys(bpy.types.Panel):
1735 bl_space_type = 'FILE_BROWSER'
1736 bl_region_type = 'TOOL_PROPS'
1737 bl_label = "Shape Keys Animation"
1738 bl_parent_id = "GLTF_PT_export_animation"
1739 bl_options = {'DEFAULT_CLOSED'}
1741 @classmethod
1742 def poll(cls, context):
1743 sfile = context.space_data
1744 operator = sfile.active_operator
1746 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1748 def draw_header(self, context):
1749 sfile = context.space_data
1750 operator = sfile.active_operator
1751 self.layout.active = operator.export_animations and operator.export_morph
1752 self.layout.prop(operator, "export_morph_animation", text="")
1754 def draw(self, context):
1755 layout = self.layout
1756 layout.use_property_split = True
1757 layout.use_property_decorate = False # No animation.
1759 sfile = context.space_data
1760 operator = sfile.active_operator
1762 layout.active = operator.export_animations
1764 layout.prop(operator, 'export_morph_reset_sk_data')
1767 class GLTF_PT_export_animation_sampling(bpy.types.Panel):
1768 bl_space_type = 'FILE_BROWSER'
1769 bl_region_type = 'TOOL_PROPS'
1770 bl_label = "Sampling Animations"
1771 bl_parent_id = "GLTF_PT_export_animation"
1772 bl_options = {'DEFAULT_CLOSED'}
1774 @classmethod
1775 def poll(cls, context):
1776 sfile = context.space_data
1777 operator = sfile.active_operator
1779 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1781 def draw_header(self, context):
1782 sfile = context.space_data
1783 operator = sfile.active_operator
1784 self.layout.active = operator.export_animations and operator.export_animation_mode in ['ACTIONS', 'ACTIVE_ACTIONS']
1785 self.layout.prop(operator, "export_force_sampling", text="")
1787 def draw(self, context):
1788 layout = self.layout
1789 layout.use_property_split = True
1790 layout.use_property_decorate = False # No animation.
1792 sfile = context.space_data
1793 operator = sfile.active_operator
1795 layout.active = operator.export_animations
1797 layout.prop(operator, 'export_frame_step')
1800 class GLTF_PT_export_animation_optimize(bpy.types.Panel):
1801 bl_space_type = 'FILE_BROWSER'
1802 bl_region_type = 'TOOL_PROPS'
1803 bl_label = "Optimize Animations"
1804 bl_parent_id = "GLTF_PT_export_animation"
1805 bl_options = {'DEFAULT_CLOSED'}
1807 @classmethod
1808 def poll(cls, context):
1809 sfile = context.space_data
1810 operator = sfile.active_operator
1812 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1814 def draw(self, context):
1815 layout = self.layout
1816 layout.use_property_split = True
1817 layout.use_property_decorate = False # No animation.
1819 sfile = context.space_data
1820 operator = sfile.active_operator
1822 layout.active = operator.export_animations
1824 layout.prop(operator, 'export_optimize_animation_size')
1826 row = layout.row()
1827 row.prop(operator, 'export_optimize_animation_keep_anim_armature')
1829 row = layout.row()
1830 row.prop(operator, 'export_optimize_animation_keep_anim_object')
1833 class GLTF_PT_export_user_extensions(bpy.types.Panel):
1834 bl_space_type = 'FILE_BROWSER'
1835 bl_region_type = 'TOOL_PROPS'
1836 bl_label = "Exporter Extensions"
1837 bl_parent_id = "FILE_PT_operator"
1838 bl_options = {'DEFAULT_CLOSED'}
1840 @classmethod
1841 def poll(cls, context):
1842 sfile = context.space_data
1843 operator = sfile.active_operator
1845 return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_exporter_extensions
1847 def draw(self, context):
1848 layout = self.layout
1849 layout.use_property_split = True
1850 layout.use_property_decorate = False # No animation.
1852 class GLTF_PT_import_user_extensions(bpy.types.Panel):
1853 bl_space_type = 'FILE_BROWSER'
1854 bl_region_type = 'TOOL_PROPS'
1855 bl_label = "Importer Extensions"
1856 bl_parent_id = "FILE_PT_operator"
1857 bl_options = {'DEFAULT_CLOSED'}
1859 @classmethod
1860 def poll(cls, context):
1861 sfile = context.space_data
1862 operator = sfile.active_operator
1863 return operator.bl_idname == "IMPORT_SCENE_OT_gltf" and operator.has_active_importer_extensions
1865 def draw(self, context):
1866 layout = self.layout
1867 layout.use_property_split = True
1868 layout.use_property_decorate = False # No animation.
1870 class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
1871 """Export scene as glTF 2.0 file"""
1872 bl_idname = 'export_scene.gltf'
1873 bl_label = 'Export glTF 2.0'
1875 filename_ext = ''
1877 filter_glob: StringProperty(default='*.glb', options={'HIDDEN'})
1880 def menu_func_export(self, context):
1881 self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
1884 class ImportGLTF2(Operator, ConvertGLTF2_Base, ImportHelper):
1885 """Load a glTF 2.0 file"""
1886 bl_idname = 'import_scene.gltf'
1887 bl_label = 'Import glTF 2.0'
1888 bl_options = {'REGISTER', 'UNDO'}
1890 filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
1892 files: CollectionProperty(
1893 name="File Path",
1894 type=bpy.types.OperatorFileListElement,
1897 loglevel: IntProperty(
1898 name='Log Level',
1899 description="Log Level")
1901 import_pack_images: BoolProperty(
1902 name='Pack Images',
1903 description='Pack all images into .blend file',
1904 default=True
1907 merge_vertices: BoolProperty(
1908 name='Merge Vertices',
1909 description=(
1910 'The glTF format requires discontinuous normals, UVs, and '
1911 'other vertex attributes to be stored as separate vertices, '
1912 'as required for rendering on typical graphics hardware. '
1913 'This option attempts to combine co-located vertices where possible. '
1914 'Currently cannot combine verts with different normals'
1916 default=False,
1919 import_shading: EnumProperty(
1920 name="Shading",
1921 items=(("NORMALS", "Use Normal Data", ""),
1922 ("FLAT", "Flat Shading", ""),
1923 ("SMOOTH", "Smooth Shading", "")),
1924 description="How normals are computed during import",
1925 default="NORMALS")
1927 bone_heuristic: EnumProperty(
1928 name="Bone Dir",
1929 items=(
1930 ("BLENDER", "Blender (best for import/export round trip)",
1931 "Good for re-importing glTFs exported from Blender, "
1932 "and re-exporting glTFs to glTFs after Blender editing. "
1933 "Bone tips are placed on their local +Y axis (in glTF space)"),
1934 ("TEMPERANCE", "Temperance (average)",
1935 "Decent all-around strategy. "
1936 "A bone with one child has its tip placed on the local axis "
1937 "closest to its child"),
1938 ("FORTUNE", "Fortune (may look better, less accurate)",
1939 "Might look better than Temperance, but also might have errors. "
1940 "A bone with one child has its tip placed at its child's root. "
1941 "Non-uniform scalings may get messed up though, so beware"),
1943 description="Heuristic for placing bones. Tries to make bones pretty",
1944 default="BLENDER",
1947 guess_original_bind_pose: BoolProperty(
1948 name='Guess Original Bind Pose',
1949 description=(
1950 'Try to guess the original bind pose for skinned meshes from '
1951 'the inverse bind matrices. '
1952 'When off, use default/rest pose as bind pose'
1954 default=True,
1957 import_webp_texture: BoolProperty(
1958 name='Import WebP textures',
1959 description=(
1960 "If a texture exists in WebP format, "
1961 "loads the WebP texture instead of the fallback PNG/JPEG one"
1963 default=False,
1966 def draw(self, context):
1967 layout = self.layout
1969 layout.use_property_split = True
1970 layout.use_property_decorate = False # No animation.
1972 layout.prop(self, 'import_pack_images')
1973 layout.prop(self, 'merge_vertices')
1974 layout.prop(self, 'import_shading')
1975 layout.prop(self, 'guess_original_bind_pose')
1976 layout.prop(self, 'bone_heuristic')
1977 layout.prop(self, 'export_import_convert_lighting_mode')
1978 layout.prop(self, 'import_webp_texture')
1980 def invoke(self, context, event):
1981 import sys
1982 preferences = bpy.context.preferences
1983 for addon_name in preferences.addons.keys():
1984 try:
1985 if hasattr(sys.modules[addon_name], 'glTF2ImportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ImportUserExtensions'):
1986 importer_extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
1987 except Exception:
1988 pass
1990 self.has_active_importer_extensions = len(importer_extension_panel_unregister_functors) > 0
1991 return ImportHelper.invoke(self, context, event)
1993 def execute(self, context):
1994 return self.import_gltf2(context)
1996 def import_gltf2(self, context):
1997 import os
1999 self.set_debug_log()
2000 import_settings = self.as_keywords()
2002 user_extensions = []
2004 import sys
2005 preferences = bpy.context.preferences
2006 for addon_name in preferences.addons.keys():
2007 try:
2008 module = sys.modules[addon_name]
2009 except Exception:
2010 continue
2011 if hasattr(module, 'glTF2ImportUserExtension'):
2012 extension_ctor = module.glTF2ImportUserExtension
2013 user_extensions.append(extension_ctor())
2014 import_settings['import_user_extensions'] = user_extensions
2016 if self.files:
2017 # Multiple file import
2018 ret = {'CANCELLED'}
2019 dirname = os.path.dirname(self.filepath)
2020 for file in self.files:
2021 path = os.path.join(dirname, file.name)
2022 if self.unit_import(path, import_settings) == {'FINISHED'}:
2023 ret = {'FINISHED'}
2024 return ret
2025 else:
2026 # Single file import
2027 return self.unit_import(self.filepath, import_settings)
2029 def unit_import(self, filename, import_settings):
2030 import time
2031 from .io.imp.gltf2_io_gltf import glTFImporter, ImportError
2032 from .blender.imp.gltf2_blender_gltf import BlenderGlTF
2034 try:
2035 gltf_importer = glTFImporter(filename, import_settings)
2036 gltf_importer.read()
2037 gltf_importer.checks()
2039 print("Data are loaded, start creating Blender stuff")
2041 start_time = time.time()
2042 BlenderGlTF.create(gltf_importer)
2043 elapsed_s = "{:.2f}s".format(time.time() - start_time)
2044 print("glTF import finished in " + elapsed_s)
2046 gltf_importer.log.removeHandler(gltf_importer.log_handler)
2048 return {'FINISHED'}
2050 except ImportError as e:
2051 self.report({'ERROR'}, e.args[0])
2052 return {'CANCELLED'}
2054 def set_debug_log(self):
2055 import logging
2056 if bpy.app.debug_value == 0:
2057 self.loglevel = logging.CRITICAL
2058 elif bpy.app.debug_value == 1:
2059 self.loglevel = logging.ERROR
2060 elif bpy.app.debug_value == 2:
2061 self.loglevel = logging.WARNING
2062 elif bpy.app.debug_value == 3:
2063 self.loglevel = logging.INFO
2064 else:
2065 self.loglevel = logging.NOTSET
2068 class GLTF2_filter_action(bpy.types.PropertyGroup):
2069 keep : bpy.props.BoolProperty(name="Keep Animation")
2070 action: bpy.props.PointerProperty(type=bpy.types.Action)
2072 def gltf_variant_ui_update(self, context):
2073 from .blender.com.gltf2_blender_ui import variant_register, variant_unregister
2074 if self.KHR_materials_variants_ui is True:
2075 # register all needed types
2076 variant_register()
2077 else:
2078 variant_unregister()
2080 def gltf_animation_ui_update(self, context):
2081 from .blender.com.gltf2_blender_ui import anim_ui_register, anim_ui_unregister
2082 if self.animation_ui is True:
2083 # register all needed types
2084 anim_ui_register()
2085 else:
2086 anim_ui_unregister()
2088 class GLTF_AddonPreferences(bpy.types.AddonPreferences):
2089 bl_idname = __package__
2091 settings_node_ui : bpy.props.BoolProperty(
2092 default= False,
2093 description="Displays glTF Material Output node in Shader Editor (Menu Add > Output)"
2096 KHR_materials_variants_ui : bpy.props.BoolProperty(
2097 default= False,
2098 description="Displays glTF UI to manage material variants",
2099 update=gltf_variant_ui_update
2102 animation_ui: bpy.props.BoolProperty(
2103 default=False,
2104 description="Display glTF UI to manage animations",
2105 update=gltf_animation_ui_update
2108 gltfpack_path_ui: bpy.props.StringProperty(
2109 default="",
2110 name="glTFpack file path",
2111 description="Path to gltfpack binary",
2112 subtype='FILE_PATH'
2115 def draw(self, context):
2116 layout = self.layout
2117 row = layout.row()
2118 row.prop(self, "settings_node_ui", text="Shader Editor Add-ons")
2119 row.prop(self, "KHR_materials_variants_ui", text="Material Variants")
2120 row.prop(self, "animation_ui", text="Animation UI")
2121 row = layout.row()
2122 row.prop(self, "gltfpack_path_ui", text="Path to gltfpack")
2124 def menu_func_import(self, context):
2125 self.layout.operator(ImportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
2128 classes = (
2129 ExportGLTF2,
2130 GLTF_PT_export_main,
2131 GLTF_PT_export_include,
2132 GLTF_PT_export_transform,
2133 GLTF_PT_export_data,
2134 GLTF_PT_export_data_scene,
2135 GLTF_PT_export_data_mesh,
2136 GLTF_PT_export_data_material,
2137 GLTF_PT_export_unsed_tex_image,
2138 GLTF_PT_export_data_shapekeys,
2139 GLTF_PT_export_data_sk_optimize,
2140 GLTF_PT_export_data_armature,
2141 GLTF_PT_export_data_skinning,
2142 GLTF_PT_export_data_lighting,
2143 GLTF_PT_export_data_compression,
2144 GLTF_PT_export_animation,
2145 GLTF_PT_export_animation_notes,
2146 GLTF_PT_export_animation_ranges,
2147 GLTF_PT_export_animation_armature,
2148 GLTF_PT_export_animation_shapekeys,
2149 GLTF_PT_export_animation_sampling,
2150 GLTF_PT_export_animation_optimize,
2151 GLTF_PT_export_gltfpack,
2152 GLTF_PT_export_user_extensions,
2153 ImportGLTF2,
2154 GLTF_PT_import_user_extensions,
2155 GLTF2_filter_action,
2156 GLTF_AddonPreferences
2160 def register():
2161 from .blender.com import gltf2_blender_ui as blender_ui
2163 for c in classes:
2164 bpy.utils.register_class(c)
2165 # bpy.utils.register_module(__name__)
2167 blender_ui.register()
2168 if bpy.context.preferences.addons['io_scene_gltf2'].preferences.KHR_materials_variants_ui is True:
2169 blender_ui.variant_register()
2170 if bpy.context.preferences.addons['io_scene_gltf2'].preferences.animation_ui is True:
2171 blender_ui.anim_ui_register()
2173 # add to the export / import menu
2174 bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
2175 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
2178 def unregister():
2179 from .blender.com import gltf2_blender_ui as blender_ui
2180 blender_ui.unregister()
2181 if bpy.context.preferences.addons['io_scene_gltf2'].preferences.KHR_materials_variants_ui is True:
2182 blender_ui.variant_unregister()
2184 for c in classes:
2185 bpy.utils.unregister_class(c)
2186 for f in exporter_extension_panel_unregister_functors:
2188 exporter_extension_panel_unregister_functors.clear()
2190 for f in importer_extension_panel_unregister_functors:
2192 importer_extension_panel_unregister_functors.clear()
2194 # bpy.utils.unregister_module(__name__)
2196 # remove from the export / import menu
2197 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
2198 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)