1 # SPDX-FileCopyrightText: 2018-2021 The glTF-Blender-IO authors
3 # SPDX-License-Identifier: Apache-2.0
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',
10 'location': 'File > Import-Export',
11 'description': 'Import-Export as glTF 2.0',
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
):
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
:
35 if path
.is_file() and path
.suffix
== ".py":
36 importlib
.reload(module_dict
[path
.stem
])
38 reload_package_recursive(path
, module_dict
[path
.stem
].__dict
__)
40 reload_package_recursive(Path(__file__
).parent
, module_dict_main
)
44 reload_package(locals())
47 from bpy
.props
import (StringProperty
,
52 from bpy
.types
import Operator
53 from bpy_extras
.io_utils
import ImportHelper
, ExportHelper
57 # Functions / Classes.
60 exporter_extension_panel_unregister_functors
= []
61 importer_extension_panel_unregister_functors
= []
64 def ensure_filepath_matches_export_format(filepath
, export_format
):
66 filename
= os
.path
.basename(filepath
)
70 stem
, ext
= os
.path
.splitext(filename
)
71 if stem
.startswith('.') and not ext
:
74 desired_ext
= '.glb' if export_format
== 'GLB' else '.gltf'
75 ext_lower
= ext
.lower()
76 if ext_lower
not in ['.glb', '.gltf']:
77 return filepath
+ desired_ext
78 elif ext_lower
!= desired_ext
:
79 filepath
= filepath
[:-len(ext
)] # strip off ext
80 return filepath
+ desired_ext
85 def on_export_format_changed(self
, context
):
86 # Update the filename in the file browser when the format (.glb/.gltf)
88 sfile
= context
.space_data
89 if not isinstance(sfile
, bpy
.types
.SpaceFileBrowser
):
91 if not sfile
.active_operator
:
93 if sfile
.active_operator
.bl_idname
!= "EXPORT_SCENE_OT_gltf":
96 sfile
.params
.filename
= ensure_filepath_matches_export_format(
97 sfile
.params
.filename
,
101 # Also change the filter
102 sfile
.params
.filter_glob
= '*.glb' if self
.export_format
== 'GLB' else '*.gltf'
103 # Force update of file list, because update the filter does not update the real file list
104 bpy
.ops
.file.refresh()
107 class ConvertGLTF2_Base
:
108 """Base class containing options that should be exposed during both import and export."""
110 export_import_convert_lighting_mode
: EnumProperty(
111 name
='Lighting Mode',
113 ('SPEC', 'Standard', 'Physically-based glTF lighting units (cd, lx, nt)'),
114 ('COMPAT', 'Unitless', 'Non-physical, unitless lighting. Useful when exposure controls are not available'),
115 ('RAW', 'Raw (Deprecated)', 'Blender lighting strengths with no conversion'),
117 description
='Optional backwards compatibility for non-standard render engines. Applies to lights',# TODO: and emissive materials',
121 class ExportGLTF2_Base(ConvertGLTF2_Base
):
122 # TODO: refactor to avoid boilerplate
125 from .io
.com
import gltf2_io_draco_compression_extension
126 self
.is_draco_available
= gltf2_io_draco_compression_extension
.dll_exists()
128 bl_options
= {'PRESET'}
130 # Don't use export_ prefix here, I don't want it to be saved with other export settings
131 gltf_export_id
: StringProperty(
134 'Identifier of caller (in case of add-on calling this exporter). '
135 'Can be useful in case of Extension added by other add-ons'
140 export_format
: EnumProperty(
142 items
=(('GLB', 'glTF Binary (.glb)',
143 'Exports a single file, with all data packed in binary form. '
144 'Most efficient and portable, but more difficult to edit later'),
145 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
146 'Exports multiple files, with separate JSON, binary and texture data. '
147 'Easiest to edit later'),
148 ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
149 'Exports a single file, with all data packed in JSON. '
150 'Less efficient than binary, but easier to edit later')),
152 'Output format and embedding options. Binary is most efficient, '
153 'but JSON (embedded or separate) may be easier to edit later'
155 default
='GLB', #Warning => If you change the default, need to change the default filter too
156 update
=on_export_format_changed
,
159 ui_tab
: EnumProperty(
160 items
=(('GENERAL', "General", "General settings"),
161 ('MESHES', "Meshes", "Mesh settings"),
162 ('OBJECTS', "Objects", "Object settings"),
163 ('ANIMATION', "Animation", "Animation settings")),
165 description
="Export setting categories",
168 export_copyright
: StringProperty(
170 description
='Legal rights and conditions for the model',
174 export_image_format
: EnumProperty(
176 items
=(('AUTO', 'Automatic',
177 'Save PNGs as PNGs and JPEGs as JPEGs. '
178 'If neither one, use PNG'),
179 ('JPEG', 'JPEG Format (.jpg)',
180 'Save images as JPEGs. (Images that need alpha are saved as PNGs though.) '
181 'Be aware of a possible loss in quality'),
183 'Don\'t export images'),
186 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
187 'applications due to the smaller file size. Alternatively they can be omitted if they are not needed'
192 export_texture_dir
: StringProperty(
194 description
='Folder to place texture files in. Relative to the .gltf file',
198 export_jpeg_quality
: IntProperty(
200 description
='Quality of JPEG export',
206 export_keep_originals
: BoolProperty(
207 name
='Keep original',
208 description
=('Keep original textures files if possible. '
209 'WARNING: if you use more than one texture, '
210 'where pbr standard requires only one, only one texture will be used. '
211 'This can lead to unexpected results'
216 export_texcoords
: BoolProperty(
218 description
='Export UVs (texture coordinates) with meshes',
222 export_normals
: BoolProperty(
224 description
='Export vertex normals with meshes',
228 export_draco_mesh_compression_enable
: BoolProperty(
229 name
='Draco mesh compression',
230 description
='Compress mesh using Draco',
234 export_draco_mesh_compression_level
: IntProperty(
235 name
='Compression level',
236 description
='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
242 export_draco_position_quantization
: IntProperty(
243 name
='Position quantization bits',
244 description
='Quantization bits for position values (0 = no quantization)',
250 export_draco_normal_quantization
: IntProperty(
251 name
='Normal quantization bits',
252 description
='Quantization bits for normal values (0 = no quantization)',
258 export_draco_texcoord_quantization
: IntProperty(
259 name
='Texcoord quantization bits',
260 description
='Quantization bits for texture coordinate values (0 = no quantization)',
266 export_draco_color_quantization
: IntProperty(
267 name
='Color quantization bits',
268 description
='Quantization bits for color values (0 = no quantization)',
274 export_draco_generic_quantization
: IntProperty(
275 name
='Generic quantization bits',
276 description
='Quantization bits for generic values like weights or joints (0 = no quantization)',
282 export_tangents
: BoolProperty(
284 description
='Export vertex tangents with meshes',
288 export_materials
: EnumProperty(
290 items
=(('EXPORT', 'Export',
291 'Export all materials used by included objects'),
292 ('PLACEHOLDER', 'Placeholder',
293 'Do not export materials, but write multiple primitive groups per mesh, keeping material slot information'),
294 ('NONE', 'No export',
295 'Do not export materials, and combine mesh primitive groups, losing material slot information')),
296 description
='Export materials',
300 export_original_specular
: BoolProperty(
301 name
='Export original PBR Specular',
303 'Export original glTF PBR Specular, instead of Blender Principled Shader Specular'
308 export_colors
: BoolProperty(
309 name
='Vertex Colors',
310 description
='Export vertex colors with meshes',
314 export_attributes
: BoolProperty(
316 description
='Export Attributes (when starting with underscore)',
320 use_mesh_edges
: BoolProperty(
323 'Export loose edges as lines, using the material from the first material slot'
328 use_mesh_vertices
: BoolProperty(
331 'Export loose points as glTF points, using the material from the first material slot'
336 export_cameras
: BoolProperty(
338 description
='Export cameras',
342 use_selection
: BoolProperty(
343 name
='Selected Objects',
344 description
='Export selected objects only',
348 use_visible
: BoolProperty(
349 name
='Visible Objects',
350 description
='Export visible objects only',
354 use_renderable
: BoolProperty(
355 name
='Renderable Objects',
356 description
='Export renderable objects only',
360 use_active_collection_with_nested
: BoolProperty(
361 name
='Include Nested Collections',
362 description
='Include active collection and nested collections',
366 use_active_collection
: BoolProperty(
367 name
='Active Collection',
368 description
='Export objects in the active collection only',
372 use_active_scene
: BoolProperty(
374 description
='Export active scene only',
378 export_extras
: BoolProperty(
379 name
='Custom Properties',
380 description
='Export custom properties as glTF extras',
384 export_yup
: BoolProperty(
386 description
='Export using glTF convention, +Y up',
390 export_apply
: BoolProperty(
391 name
='Apply Modifiers',
392 description
='Apply modifiers (excluding Armatures) to mesh objects -'
393 'WARNING: prevents exporting shape keys',
397 export_animations
: BoolProperty(
399 description
='Exports active actions and NLA tracks as glTF animations',
403 export_frame_range
: BoolProperty(
404 name
='Limit to Playback Range',
405 description
='Clips animations to selected playback range',
409 export_frame_step
: IntProperty(
410 name
='Sampling Rate',
411 description
='How often to evaluate animated values (in frames)',
417 export_force_sampling
: BoolProperty(
418 name
='Always Sample Animations',
419 description
='Apply sampling to all animations',
423 export_animation_mode
: EnumProperty(
424 name
='Animation mode',
425 items
=(('ACTIONS', 'Actions',
426 'Export actions (actives and on NLA tracks) as separate animations'),
427 ('ACTIVE_ACTIONS', 'Active actions merged',
428 'All the currently assigned actions become one glTF animation'),
429 ('NLA_TRACKS', 'NLA Tracks',
430 'Export individual NLA Tracks as separate animation'),
432 'Export baked scene as a single animation')
434 description
='Export Animation mode',
438 export_nla_strips_merged_animation_name
: StringProperty(
439 name
='Merged Animation Name',
441 "Name of single glTF animation to be exported"
446 export_def_bones
: BoolProperty(
447 name
='Export Deformation Bones Only',
448 description
='Export Deformation bones only',
452 export_hierarchy_flatten_bones
: BoolProperty(
453 name
='Flatten Bone Hierarchy',
454 description
='Flatten Bone Hierarchy. Useful in case of non decomposable transformation matrix',
458 export_optimize_animation_size
: BoolProperty(
459 name
='Optimize Animation Size',
461 "Reduce exported file size by removing duplicate keyframes"
466 export_optimize_animation_keep_anim_armature
: BoolProperty(
467 name
='Force keeping channels for bones',
469 "if all keyframes are identical in a rig, "
470 "force keeping the minimal animation. "
471 "When off, all possible channels for "
472 "the bones will be exported, even if empty "
473 "(minimal animation, 2 keyframes)"
478 export_optimize_animation_keep_anim_object
: BoolProperty(
479 name
='Force keeping channel for objects',
481 "If all keyframes are identical for object transformations, "
482 "force keeping the minimal animation"
487 export_negative_frame
: EnumProperty(
488 name
='Negative Frames',
489 items
=(('SLIDE', 'Slide',
490 'Slide animation to start at frame 0'),
492 'Keep only frames above frame 0'),
494 description
='Negative Frames are slid or cropped',
498 export_anim_slide_to_zero
: BoolProperty(
499 name
='Set all glTF Animation starting at 0',
501 "Set all glTF animation starting at 0.0s. "
502 "Can be useful for looping animations"
507 export_bake_animation
: BoolProperty(
508 name
='Bake All Objects Animations',
510 "Force exporting animation on every object. "
511 "Can be useful when using constraints or driver. "
512 "Also useful when exporting only selection"
517 export_anim_single_armature
: BoolProperty(
518 name
='Export all Armature Actions',
520 "Export all actions, bound to a single armature. "
521 "WARNING: Option does not support exports including multiple armatures"
526 export_reset_pose_bones
: BoolProperty(
527 name
='Reset pose bones between actions',
529 "Reset pose bones between each action exported. "
530 "This is needed when some bones are not keyed on some animations"
535 export_current_frame
: BoolProperty(
536 name
='Use Current Frame as Object Rest Transformations',
538 'Export the scene in the current animation frame. '
539 'When off, frame 0 is used as rest transformations for objects'
544 export_rest_position_armature
: BoolProperty(
545 name
='Use Rest Position Armature',
547 "Export armatures using rest position as joints' rest pose. "
548 "When off, current frame pose is used as rest pose"
553 export_anim_scene_split_object
: BoolProperty(
554 name
='Split Animation by Object',
556 "Export Scene as seen in Viewport, "
557 "But split animation by Object"
562 export_skins
: BoolProperty(
564 description
='Export skinning (armature) data',
568 export_all_influences
: BoolProperty(
569 name
='Include All Bone Influences',
570 description
='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
574 export_morph
: BoolProperty(
576 description
='Export shape keys (morph targets)',
580 export_morph_normal
: BoolProperty(
581 name
='Shape Key Normals',
582 description
='Export vertex normals with shape keys (morph targets)',
586 export_morph_tangent
: BoolProperty(
587 name
='Shape Key Tangents',
588 description
='Export vertex tangents with shape keys (morph targets)',
592 export_morph_animation
: BoolProperty(
593 name
='Shape Key Animations',
594 description
='Export shape keys animations (morph targets)',
598 export_morph_reset_sk_data
: BoolProperty(
599 name
='Reset shape keys between actions',
601 "Reset shape keys between each action exported. "
602 "This is needed when some SK channels are not keyed on some animations"
607 export_lights
: BoolProperty(
608 name
='Punctual Lights',
609 description
='Export directional, point, and spot lights. '
610 'Uses "KHR_lights_punctual" glTF extension',
614 # This parameter is only here for backward compatibility, as this option is removed in 3.6
615 # This option does nothing, and is not displayed in UI
616 # What you are looking for is probably "export_animation_mode"
617 export_nla_strips
: BoolProperty(
618 name
='Group by NLA Track',
620 "When on, multiple actions become part of the same glTF animation if "
621 "they're pushed onto NLA tracks with the same name. "
622 "When off, all the currently assigned actions become one glTF animation"
627 will_save_settings
: BoolProperty(
628 name
='Remember Export Settings',
629 description
='Store glTF export settings in the Blender project',
632 # Custom scene property for saving settings
633 scene_key
= "glTF2ExportSettings"
637 def check(self
, _context
):
638 # Ensure file extension matches format
639 old_filepath
= self
.filepath
640 self
.filepath
= ensure_filepath_matches_export_format(
644 return self
.filepath
!= old_filepath
646 def invoke(self
, context
, event
):
647 settings
= context
.scene
.get(self
.scene_key
)
648 self
.will_save_settings
= False
651 for (k
, v
) in settings
.items():
653 self
.will_save_settings
= True
655 # Update filter if user saved settings
656 if hasattr(self
, 'export_format'):
657 self
.filter_glob
= '*.glb' if self
.export_format
== 'GLB' else '*.gltf'
659 except (AttributeError, TypeError):
660 self
.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
661 del context
.scene
[self
.scene_key
]
664 preferences
= bpy
.context
.preferences
665 for addon_name
in preferences
.addons
.keys():
667 if hasattr(sys
.modules
[addon_name
], 'glTF2ExportUserExtension') or hasattr(sys
.modules
[addon_name
], 'glTF2ExportUserExtensions'):
668 exporter_extension_panel_unregister_functors
.append(sys
.modules
[addon_name
].register_panel())
672 self
.has_active_exporter_extensions
= len(exporter_extension_panel_unregister_functors
) > 0
673 return ExportHelper
.invoke(self
, context
, event
)
675 def save_settings(self
, context
):
676 # find all props to save
678 # options that don't start with 'export_'
682 'use_active_collection_with_nested',
683 'use_active_collection',
688 all_props
= self
.properties
690 x
: getattr(self
, x
) for x
in dir(all_props
)
691 if (x
.startswith("export_") or x
in exceptional
) and all_props
.get(x
) is not None
693 context
.scene
[self
.scene_key
] = export_props
695 def execute(self
, context
):
698 from .blender
.exp
import gltf2_blender_export
699 from .io
.com
.gltf2_io_path
import path_to_uri
701 if self
.will_save_settings
:
702 self
.save_settings(context
)
704 self
.check(context
) # ensure filepath has the right extension
706 # All custom export settings are stored in this container.
709 export_settings
['timestamp'] = datetime
.datetime
.now()
710 export_settings
['gltf_export_id'] = self
.gltf_export_id
711 export_settings
['gltf_filepath'] = self
.filepath
712 export_settings
['gltf_filedirectory'] = os
.path
.dirname(export_settings
['gltf_filepath']) + '/'
713 export_settings
['gltf_texturedirectory'] = os
.path
.join(
714 export_settings
['gltf_filedirectory'],
715 self
.export_texture_dir
,
717 export_settings
['gltf_keep_original_textures'] = self
.export_keep_originals
719 export_settings
['gltf_format'] = self
.export_format
720 export_settings
['gltf_image_format'] = self
.export_image_format
721 export_settings
['gltf_jpeg_quality'] = self
.export_jpeg_quality
722 export_settings
['gltf_copyright'] = self
.export_copyright
723 export_settings
['gltf_texcoords'] = self
.export_texcoords
724 export_settings
['gltf_normals'] = self
.export_normals
725 export_settings
['gltf_tangents'] = self
.export_tangents
and self
.export_normals
726 export_settings
['gltf_loose_edges'] = self
.use_mesh_edges
727 export_settings
['gltf_loose_points'] = self
.use_mesh_vertices
729 if self
.is_draco_available
:
730 export_settings
['gltf_draco_mesh_compression'] = self
.export_draco_mesh_compression_enable
731 export_settings
['gltf_draco_mesh_compression_level'] = self
.export_draco_mesh_compression_level
732 export_settings
['gltf_draco_position_quantization'] = self
.export_draco_position_quantization
733 export_settings
['gltf_draco_normal_quantization'] = self
.export_draco_normal_quantization
734 export_settings
['gltf_draco_texcoord_quantization'] = self
.export_draco_texcoord_quantization
735 export_settings
['gltf_draco_color_quantization'] = self
.export_draco_color_quantization
736 export_settings
['gltf_draco_generic_quantization'] = self
.export_draco_generic_quantization
738 export_settings
['gltf_draco_mesh_compression'] = False
740 export_settings
['gltf_materials'] = self
.export_materials
741 export_settings
['gltf_colors'] = self
.export_colors
742 export_settings
['gltf_attributes'] = self
.export_attributes
743 export_settings
['gltf_cameras'] = self
.export_cameras
745 export_settings
['gltf_original_specular'] = self
.export_original_specular
747 export_settings
['gltf_visible'] = self
.use_visible
748 export_settings
['gltf_renderable'] = self
.use_renderable
750 export_settings
['gltf_active_collection'] = self
.use_active_collection
751 if self
.use_active_collection
:
752 export_settings
['gltf_active_collection_with_nested'] = self
.use_active_collection_with_nested
754 export_settings
['gltf_active_collection_with_nested'] = False
755 export_settings
['gltf_active_scene'] = self
.use_active_scene
757 export_settings
['gltf_selected'] = self
.use_selection
758 export_settings
['gltf_layers'] = True # self.export_layers
759 export_settings
['gltf_extras'] = self
.export_extras
760 export_settings
['gltf_yup'] = self
.export_yup
761 export_settings
['gltf_apply'] = self
.export_apply
762 export_settings
['gltf_current_frame'] = self
.export_current_frame
763 export_settings
['gltf_animations'] = self
.export_animations
764 export_settings
['gltf_def_bones'] = self
.export_def_bones
765 export_settings
['gltf_flatten_bones_hierarchy'] = self
.export_hierarchy_flatten_bones
766 if self
.export_animations
:
767 export_settings
['gltf_frame_range'] = self
.export_frame_range
768 export_settings
['gltf_force_sampling'] = self
.export_force_sampling
769 if not self
.export_force_sampling
:
770 export_settings
['gltf_def_bones'] = False
771 export_settings
['gltf_bake_animation'] = False
772 export_settings
['gltf_animation_mode'] = self
.export_animation_mode
773 if export_settings
['gltf_animation_mode'] == "NLA_TRACKS":
774 export_settings
['gltf_force_sampling'] = True
775 if export_settings
['gltf_animation_mode'] == "SCENE":
776 export_settings
['gltf_anim_scene_split_object'] = self
.export_anim_scene_split_object
778 export_settings
['gltf_anim_scene_split_object'] = False
780 export_settings
['gltf_nla_strips_merged_animation_name'] = self
.export_nla_strips_merged_animation_name
781 export_settings
['gltf_optimize_animation'] = self
.export_optimize_animation_size
782 export_settings
['gltf_optimize_animation_keep_armature'] = self
.export_optimize_animation_keep_anim_armature
783 export_settings
['gltf_optimize_animation_keep_object'] = self
.export_optimize_animation_keep_anim_object
784 export_settings
['gltf_export_anim_single_armature'] = self
.export_anim_single_armature
785 export_settings
['gltf_export_reset_pose_bones'] = self
.export_reset_pose_bones
786 export_settings
['gltf_export_reset_sk_data'] = self
.export_morph_reset_sk_data
787 export_settings
['gltf_bake_animation'] = self
.export_bake_animation
788 export_settings
['gltf_negative_frames'] = self
.export_negative_frame
789 export_settings
['gltf_anim_slide_to_zero'] = self
.export_anim_slide_to_zero
791 export_settings
['gltf_frame_range'] = False
792 export_settings
['gltf_force_sampling'] = False
793 export_settings
['gltf_bake_animation'] = False
794 export_settings
['gltf_optimize_animation'] = False
795 export_settings
['gltf_optimize_animation_keep_armature'] = False
796 export_settings
['gltf_optimize_animation_keep_object'] = False
797 export_settings
['gltf_export_anim_single_armature'] = False
798 export_settings
['gltf_export_reset_pose_bones'] = False
799 export_settings
['gltf_export_reset_sk_data'] = False
800 export_settings
['gltf_skins'] = self
.export_skins
801 if self
.export_skins
:
802 export_settings
['gltf_all_vertex_influences'] = self
.export_all_influences
804 export_settings
['gltf_all_vertex_influences'] = False
805 export_settings
['gltf_def_bones'] = False
806 export_settings
['gltf_rest_position_armature'] = self
.export_rest_position_armature
807 export_settings
['gltf_frame_step'] = self
.export_frame_step
809 export_settings
['gltf_morph'] = self
.export_morph
810 if self
.export_morph
:
811 export_settings
['gltf_morph_normal'] = self
.export_morph_normal
812 export_settings
['gltf_morph_tangent'] = self
.export_morph_tangent
813 export_settings
['gltf_morph_anim'] = self
.export_morph_animation
815 export_settings
['gltf_morph_normal'] = False
816 export_settings
['gltf_morph_tangent'] = False
817 export_settings
['gltf_morph_anim'] = False
819 export_settings
['gltf_lights'] = self
.export_lights
820 export_settings
['gltf_lighting_mode'] = self
.export_import_convert_lighting_mode
822 export_settings
['gltf_binary'] = bytearray()
823 export_settings
['gltf_binaryfilename'] = (
824 path_to_uri(os
.path
.splitext(os
.path
.basename(self
.filepath
))[0] + '.bin')
828 pre_export_callbacks
= []
829 post_export_callbacks
= []
832 preferences
= bpy
.context
.preferences
833 for addon_name
in preferences
.addons
.keys():
835 module
= sys
.modules
[addon_name
]
838 if hasattr(module
, 'glTF2ExportUserExtension'):
839 extension_ctor
= module
.glTF2ExportUserExtension
840 user_extensions
.append(extension_ctor())
841 if hasattr(module
, 'glTF2ExportUserExtensions'):
842 extension_ctors
= module
.glTF2ExportUserExtensions
843 for extension_ctor
in extension_ctors
:
844 user_extensions
.append(extension_ctor())
845 if hasattr(module
, 'glTF2_pre_export_callback'):
846 pre_export_callbacks
.append(module
.glTF2_pre_export_callback
)
847 if hasattr(module
, 'glTF2_post_export_callback'):
848 post_export_callbacks
.append(module
.glTF2_post_export_callback
)
849 export_settings
['gltf_user_extensions'] = user_extensions
850 export_settings
['pre_export_callbacks'] = pre_export_callbacks
851 export_settings
['post_export_callbacks'] = post_export_callbacks
853 return gltf2_blender_export
.save(context
, export_settings
)
855 def draw(self
, context
):
856 pass # Is needed to get panels available
859 class GLTF_PT_export_main(bpy
.types
.Panel
):
860 bl_space_type
= 'FILE_BROWSER'
861 bl_region_type
= 'TOOL_PROPS'
863 bl_parent_id
= "FILE_PT_operator"
864 bl_options
= {'HIDE_HEADER'}
867 def poll(cls
, context
):
868 sfile
= context
.space_data
869 operator
= sfile
.active_operator
871 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
873 def draw(self
, context
):
875 layout
.use_property_split
= True
876 layout
.use_property_decorate
= False # No animation.
878 sfile
= context
.space_data
879 operator
= sfile
.active_operator
881 layout
.prop(operator
, 'export_format')
882 if operator
.export_format
== 'GLTF_SEPARATE':
883 layout
.prop(operator
, 'export_keep_originals')
884 if operator
.export_keep_originals
is False:
885 layout
.prop(operator
, 'export_texture_dir', icon
='FILE_FOLDER')
887 layout
.prop(operator
, 'export_copyright')
888 layout
.prop(operator
, 'will_save_settings')
891 class GLTF_PT_export_include(bpy
.types
.Panel
):
892 bl_space_type
= 'FILE_BROWSER'
893 bl_region_type
= 'TOOL_PROPS'
895 bl_parent_id
= "FILE_PT_operator"
896 bl_options
= {'DEFAULT_CLOSED'}
899 def poll(cls
, context
):
900 sfile
= context
.space_data
901 operator
= sfile
.active_operator
903 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
905 def draw(self
, context
):
907 layout
.use_property_split
= True
908 layout
.use_property_decorate
= False # No animation.
910 sfile
= context
.space_data
911 operator
= sfile
.active_operator
913 col
= layout
.column(heading
= "Limit to", align
= True)
914 col
.prop(operator
, 'use_selection')
915 col
.prop(operator
, 'use_visible')
916 col
.prop(operator
, 'use_renderable')
917 col
.prop(operator
, 'use_active_collection')
918 if operator
.use_active_collection
:
919 col
.prop(operator
, 'use_active_collection_with_nested')
920 col
.prop(operator
, 'use_active_scene')
922 col
= layout
.column(heading
= "Data", align
= True)
923 col
.prop(operator
, 'export_extras')
924 col
.prop(operator
, 'export_cameras')
925 col
.prop(operator
, 'export_lights')
928 class GLTF_PT_export_transform(bpy
.types
.Panel
):
929 bl_space_type
= 'FILE_BROWSER'
930 bl_region_type
= 'TOOL_PROPS'
931 bl_label
= "Transform"
932 bl_parent_id
= "FILE_PT_operator"
933 bl_options
= {'DEFAULT_CLOSED'}
936 def poll(cls
, context
):
937 sfile
= context
.space_data
938 operator
= sfile
.active_operator
940 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
942 def draw(self
, context
):
944 layout
.use_property_split
= True
945 layout
.use_property_decorate
= False # No animation.
947 sfile
= context
.space_data
948 operator
= sfile
.active_operator
950 layout
.prop(operator
, 'export_yup')
953 class GLTF_PT_export_data(bpy
.types
.Panel
):
954 bl_space_type
= 'FILE_BROWSER'
955 bl_region_type
= 'TOOL_PROPS'
957 bl_parent_id
= "FILE_PT_operator"
958 bl_options
= {'DEFAULT_CLOSED'}
961 def poll(cls
, context
):
962 sfile
= context
.space_data
963 operator
= sfile
.active_operator
965 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
967 def draw(self
, context
):
970 class GLTF_PT_export_data_mesh(bpy
.types
.Panel
):
971 bl_space_type
= 'FILE_BROWSER'
972 bl_region_type
= 'TOOL_PROPS'
974 bl_parent_id
= "GLTF_PT_export_data"
975 bl_options
= {'DEFAULT_CLOSED'}
978 def poll(cls
, context
):
979 sfile
= context
.space_data
980 operator
= sfile
.active_operator
981 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
983 def draw(self
, context
):
985 layout
.use_property_split
= True
986 layout
.use_property_decorate
= False # No animation.
988 sfile
= context
.space_data
989 operator
= sfile
.active_operator
991 layout
.prop(operator
, 'export_apply')
992 layout
.prop(operator
, 'export_texcoords')
993 layout
.prop(operator
, 'export_normals')
994 col
= layout
.column()
995 col
.active
= operator
.export_normals
996 col
.prop(operator
, 'export_tangents')
997 layout
.prop(operator
, 'export_colors')
998 layout
.prop(operator
, 'export_attributes')
1000 col
= layout
.column()
1001 col
.prop(operator
, 'use_mesh_edges')
1002 col
.prop(operator
, 'use_mesh_vertices')
1005 class GLTF_PT_export_data_material(bpy
.types
.Panel
):
1006 bl_space_type
= 'FILE_BROWSER'
1007 bl_region_type
= 'TOOL_PROPS'
1008 bl_label
= "Material"
1009 bl_parent_id
= "GLTF_PT_export_data"
1010 bl_options
= {'DEFAULT_CLOSED'}
1013 def poll(cls
, context
):
1014 sfile
= context
.space_data
1015 operator
= sfile
.active_operator
1016 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1018 def draw(self
, context
):
1019 layout
= self
.layout
1020 layout
.use_property_split
= True
1021 layout
.use_property_decorate
= False # No animation.
1023 sfile
= context
.space_data
1024 operator
= sfile
.active_operator
1026 layout
.prop(operator
, 'export_materials')
1027 col
= layout
.column()
1028 col
.active
= operator
.export_materials
== "EXPORT"
1029 col
.prop(operator
, 'export_image_format')
1030 if operator
.export_image_format
in ["AUTO", "JPEG"]:
1031 col
.prop(operator
, 'export_jpeg_quality')
1033 class GLTF_PT_export_data_original_pbr(bpy
.types
.Panel
):
1034 bl_space_type
= 'FILE_BROWSER'
1035 bl_region_type
= 'TOOL_PROPS'
1036 bl_label
= "PBR Extensions"
1037 bl_parent_id
= "GLTF_PT_export_data_material"
1038 bl_options
= {'DEFAULT_CLOSED'}
1041 def poll(cls
, context
):
1042 sfile
= context
.space_data
1043 operator
= sfile
.active_operator
1044 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1046 def draw(self
, context
):
1047 layout
= self
.layout
1048 layout
.use_property_split
= True
1049 layout
.use_property_decorate
= False # No animation.
1051 sfile
= context
.space_data
1052 operator
= sfile
.active_operator
1054 layout
.prop(operator
, 'export_original_specular')
1056 class GLTF_PT_export_data_lighting(bpy
.types
.Panel
):
1057 bl_space_type
= 'FILE_BROWSER'
1058 bl_region_type
= 'TOOL_PROPS'
1059 bl_label
= "Lighting"
1060 bl_parent_id
= "GLTF_PT_export_data"
1061 bl_options
= {'DEFAULT_CLOSED'}
1064 def poll(cls
, context
):
1065 sfile
= context
.space_data
1066 operator
= sfile
.active_operator
1067 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1069 def draw(self
, context
):
1070 layout
= self
.layout
1071 layout
.use_property_split
= True
1072 layout
.use_property_decorate
= False # No animation.
1074 sfile
= context
.space_data
1075 operator
= sfile
.active_operator
1077 layout
.prop(operator
, 'export_import_convert_lighting_mode')
1079 class GLTF_PT_export_data_shapekeys(bpy
.types
.Panel
):
1080 bl_space_type
= 'FILE_BROWSER'
1081 bl_region_type
= 'TOOL_PROPS'
1082 bl_label
= "Shape Keys"
1083 bl_parent_id
= "GLTF_PT_export_data"
1084 bl_options
= {'DEFAULT_CLOSED'}
1087 def poll(cls
, context
):
1088 sfile
= context
.space_data
1089 operator
= sfile
.active_operator
1091 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1093 def draw_header(self
, context
):
1094 sfile
= context
.space_data
1095 operator
= sfile
.active_operator
1096 self
.layout
.prop(operator
, "export_morph", text
="")
1098 def draw(self
, context
):
1099 layout
= self
.layout
1100 layout
.use_property_split
= True
1101 layout
.use_property_decorate
= False # No animation.
1103 sfile
= context
.space_data
1104 operator
= sfile
.active_operator
1106 layout
.active
= operator
.export_morph
1108 layout
.prop(operator
, 'export_morph_normal')
1109 col
= layout
.column()
1110 col
.active
= operator
.export_morph_normal
1111 col
.prop(operator
, 'export_morph_tangent')
1114 class GLTF_PT_export_data_skinning(bpy
.types
.Panel
):
1115 bl_space_type
= 'FILE_BROWSER'
1116 bl_region_type
= 'TOOL_PROPS'
1117 bl_label
= "Skinning"
1118 bl_parent_id
= "GLTF_PT_export_data"
1119 bl_options
= {'DEFAULT_CLOSED'}
1122 def poll(cls
, context
):
1123 sfile
= context
.space_data
1124 operator
= sfile
.active_operator
1126 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1128 def draw_header(self
, context
):
1129 sfile
= context
.space_data
1130 operator
= sfile
.active_operator
1131 self
.layout
.prop(operator
, "export_skins", text
="")
1133 def draw(self
, context
):
1134 layout
= self
.layout
1135 layout
.use_property_split
= True
1136 layout
.use_property_decorate
= False # No animation.
1138 sfile
= context
.space_data
1139 operator
= sfile
.active_operator
1141 layout
.active
= operator
.export_skins
1143 layout
.prop(operator
, 'export_all_influences')
1146 class GLTF_PT_export_data_armature(bpy
.types
.Panel
):
1147 bl_space_type
= 'FILE_BROWSER'
1148 bl_region_type
= 'TOOL_PROPS'
1149 bl_label
= "Armature"
1150 bl_parent_id
= "GLTF_PT_export_data"
1151 bl_options
= {'DEFAULT_CLOSED'}
1154 def poll(cls
, context
):
1155 sfile
= context
.space_data
1156 operator
= sfile
.active_operator
1158 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1160 def draw(self
, context
):
1161 layout
= self
.layout
1162 layout
.use_property_split
= True
1163 layout
.use_property_decorate
= False # No animation.
1165 sfile
= context
.space_data
1166 operator
= sfile
.active_operator
1168 layout
.active
= operator
.export_skins
1170 layout
.prop(operator
, 'export_rest_position_armature')
1173 row
.active
= operator
.export_force_sampling
1174 row
.prop(operator
, 'export_def_bones')
1175 if operator
.export_force_sampling
is False and operator
.export_def_bones
is True:
1176 layout
.label(text
="Export only deformation bones is not possible when not sampling animation")
1178 row
.prop(operator
, 'export_hierarchy_flatten_bones')
1180 class GLTF_PT_export_data_compression(bpy
.types
.Panel
):
1181 bl_space_type
= 'FILE_BROWSER'
1182 bl_region_type
= 'TOOL_PROPS'
1183 bl_label
= "Compression"
1184 bl_parent_id
= "GLTF_PT_export_data"
1185 bl_options
= {'DEFAULT_CLOSED'}
1188 from .io
.com
import gltf2_io_draco_compression_extension
1189 self
.is_draco_available
= gltf2_io_draco_compression_extension
.dll_exists(quiet
=True)
1192 def poll(cls
, context
):
1193 sfile
= context
.space_data
1194 operator
= sfile
.active_operator
1195 if operator
.is_draco_available
:
1196 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1198 def draw_header(self
, context
):
1199 sfile
= context
.space_data
1200 operator
= sfile
.active_operator
1201 self
.layout
.prop(operator
, "export_draco_mesh_compression_enable", text
="")
1203 def draw(self
, context
):
1204 layout
= self
.layout
1205 layout
.use_property_split
= True
1206 layout
.use_property_decorate
= False # No animation.
1208 sfile
= context
.space_data
1209 operator
= sfile
.active_operator
1211 layout
.active
= operator
.export_draco_mesh_compression_enable
1212 layout
.prop(operator
, 'export_draco_mesh_compression_level')
1214 col
= layout
.column(align
=True)
1215 col
.prop(operator
, 'export_draco_position_quantization', text
="Quantize Position")
1216 col
.prop(operator
, 'export_draco_normal_quantization', text
="Normal")
1217 col
.prop(operator
, 'export_draco_texcoord_quantization', text
="Tex Coord")
1218 col
.prop(operator
, 'export_draco_color_quantization', text
="Color")
1219 col
.prop(operator
, 'export_draco_generic_quantization', text
="Generic")
1222 class GLTF_PT_export_animation(bpy
.types
.Panel
):
1223 bl_space_type
= 'FILE_BROWSER'
1224 bl_region_type
= 'TOOL_PROPS'
1225 bl_label
= "Animation"
1226 bl_parent_id
= "FILE_PT_operator"
1227 bl_options
= {'DEFAULT_CLOSED'}
1230 def poll(cls
, context
):
1231 sfile
= context
.space_data
1232 operator
= sfile
.active_operator
1234 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1236 def draw_header(self
, context
):
1237 sfile
= context
.space_data
1238 operator
= sfile
.active_operator
1239 self
.layout
.prop(operator
, "export_animations", text
="")
1241 def draw(self
, context
):
1242 layout
= self
.layout
1243 layout
.use_property_split
= True
1244 layout
.use_property_decorate
= False # No animation.
1246 sfile
= context
.space_data
1247 operator
= sfile
.active_operator
1249 layout
.active
= operator
.export_animations
1251 layout
.prop(operator
, 'export_animation_mode')
1252 if operator
.export_animation_mode
== "ACTIVE_ACTIONS":
1253 layout
.prop(operator
, 'export_nla_strips_merged_animation_name')
1256 row
.active
= operator
.export_force_sampling
and operator
.export_animation_mode
in ['ACTIONS', 'ACTIVE_ACTIONS']
1257 row
.prop(operator
, 'export_bake_animation')
1258 if operator
.export_animation_mode
== "SCENE":
1259 layout
.prop(operator
, 'export_anim_scene_split_object')
1261 class GLTF_PT_export_animation_notes(bpy
.types
.Panel
):
1262 bl_space_type
= 'FILE_BROWSER'
1263 bl_region_type
= 'TOOL_PROPS'
1265 bl_parent_id
= "GLTF_PT_export_animation"
1266 bl_options
= {'DEFAULT_CLOSED'}
1269 def poll(cls
, context
):
1270 sfile
= context
.space_data
1271 operator
= sfile
.active_operator
1273 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf" and \
1274 operator
.export_animation_mode
in ["NLA_TRACKS", "SCENE"]
1276 def draw(self
, context
):
1277 operator
= context
.space_data
.active_operator
1278 layout
= self
.layout
1279 if operator
.export_animation_mode
== "SCENE":
1280 layout
.label(text
="Scene mode uses full bake mode:")
1281 layout
.label(text
="- sampling is active")
1282 layout
.label(text
="- baking all objects is active")
1283 layout
.label(text
="- Using scene frame range")
1284 elif operator
.export_animation_mode
== "NLA_TRACKS":
1285 layout
.label(text
="Track mode uses full bake mode:")
1286 layout
.label(text
="- sampling is active")
1287 layout
.label(text
="- baking all objects is active")
1289 class GLTF_PT_export_animation_ranges(bpy
.types
.Panel
):
1290 bl_space_type
= 'FILE_BROWSER'
1291 bl_region_type
= 'TOOL_PROPS'
1292 bl_label
= "Rest & Ranges"
1293 bl_parent_id
= "GLTF_PT_export_animation"
1294 bl_options
= {'DEFAULT_CLOSED'}
1297 def poll(cls
, context
):
1298 sfile
= context
.space_data
1299 operator
= sfile
.active_operator
1301 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1303 def draw(self
, context
):
1304 layout
= self
.layout
1305 layout
.use_property_split
= True
1306 layout
.use_property_decorate
= False # No animation.
1308 sfile
= context
.space_data
1309 operator
= sfile
.active_operator
1311 layout
.active
= operator
.export_animations
1313 layout
.prop(operator
, 'export_current_frame')
1315 row
.active
= operator
.export_animation_mode
in ['ACTIONS', 'ACTIVE_ACTIONS', 'NLA_TRACKS']
1316 row
.prop(operator
, 'export_frame_range')
1317 layout
.prop(operator
, 'export_anim_slide_to_zero')
1319 row
.active
= operator
.export_animation_mode
in ['ACTIONS', 'ACTIVE_ACTIONS', 'NLA_TRACKS']
1320 layout
.prop(operator
, 'export_negative_frame')
1322 class GLTF_PT_export_animation_armature(bpy
.types
.Panel
):
1323 bl_space_type
= 'FILE_BROWSER'
1324 bl_region_type
= 'TOOL_PROPS'
1325 bl_label
= "Armature"
1326 bl_parent_id
= "GLTF_PT_export_animation"
1327 bl_options
= {'DEFAULT_CLOSED'}
1330 def poll(cls
, context
):
1331 sfile
= context
.space_data
1332 operator
= sfile
.active_operator
1334 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1336 def draw(self
, context
):
1337 layout
= self
.layout
1338 layout
.use_property_split
= True
1339 layout
.use_property_decorate
= False # No animation.
1341 sfile
= context
.space_data
1342 operator
= sfile
.active_operator
1344 layout
.active
= operator
.export_animations
1346 layout
.prop(operator
, 'export_anim_single_armature')
1347 layout
.prop(operator
, 'export_reset_pose_bones')
1349 class GLTF_PT_export_animation_shapekeys(bpy
.types
.Panel
):
1350 bl_space_type
= 'FILE_BROWSER'
1351 bl_region_type
= 'TOOL_PROPS'
1352 bl_label
= "Shapekeys Animation"
1353 bl_parent_id
= "GLTF_PT_export_animation"
1354 bl_options
= {'DEFAULT_CLOSED'}
1357 def poll(cls
, context
):
1358 sfile
= context
.space_data
1359 operator
= sfile
.active_operator
1361 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1363 def draw_header(self
, context
):
1364 sfile
= context
.space_data
1365 operator
= sfile
.active_operator
1366 self
.layout
.active
= operator
.export_animations
and operator
.export_morph
1367 self
.layout
.prop(operator
, "export_morph_animation", text
="")
1369 def draw(self
, context
):
1370 layout
= self
.layout
1371 layout
.use_property_split
= True
1372 layout
.use_property_decorate
= False # No animation.
1374 sfile
= context
.space_data
1375 operator
= sfile
.active_operator
1377 layout
.active
= operator
.export_animations
1379 layout
.prop(operator
, 'export_morph_reset_sk_data')
1382 class GLTF_PT_export_animation_sampling(bpy
.types
.Panel
):
1383 bl_space_type
= 'FILE_BROWSER'
1384 bl_region_type
= 'TOOL_PROPS'
1385 bl_label
= "Sampling Animations"
1386 bl_parent_id
= "GLTF_PT_export_animation"
1387 bl_options
= {'DEFAULT_CLOSED'}
1390 def poll(cls
, context
):
1391 sfile
= context
.space_data
1392 operator
= sfile
.active_operator
1394 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1396 def draw_header(self
, context
):
1397 sfile
= context
.space_data
1398 operator
= sfile
.active_operator
1399 self
.layout
.active
= operator
.export_animations
and operator
.export_animation_mode
in ['ACTIONS', 'ACTIVE_ACTIONS']
1400 self
.layout
.prop(operator
, "export_force_sampling", text
="")
1402 def draw(self
, context
):
1403 layout
= self
.layout
1404 layout
.use_property_split
= True
1405 layout
.use_property_decorate
= False # No animation.
1407 sfile
= context
.space_data
1408 operator
= sfile
.active_operator
1410 layout
.active
= operator
.export_animations
1412 layout
.prop(operator
, 'export_frame_step')
1415 class GLTF_PT_export_animation_optimize(bpy
.types
.Panel
):
1416 bl_space_type
= 'FILE_BROWSER'
1417 bl_region_type
= 'TOOL_PROPS'
1418 bl_label
= "Optimize Animations"
1419 bl_parent_id
= "GLTF_PT_export_animation"
1420 bl_options
= {'DEFAULT_CLOSED'}
1423 def poll(cls
, context
):
1424 sfile
= context
.space_data
1425 operator
= sfile
.active_operator
1427 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
1429 def draw(self
, context
):
1430 layout
= self
.layout
1431 layout
.use_property_split
= True
1432 layout
.use_property_decorate
= False # No animation.
1434 sfile
= context
.space_data
1435 operator
= sfile
.active_operator
1437 layout
.active
= operator
.export_animations
1439 layout
.prop(operator
, 'export_optimize_animation_size')
1442 row
.prop(operator
, 'export_optimize_animation_keep_anim_armature')
1445 row
.prop(operator
, 'export_optimize_animation_keep_anim_object')
1448 class GLTF_PT_export_user_extensions(bpy
.types
.Panel
):
1449 bl_space_type
= 'FILE_BROWSER'
1450 bl_region_type
= 'TOOL_PROPS'
1451 bl_label
= "Exporter Extensions"
1452 bl_parent_id
= "FILE_PT_operator"
1453 bl_options
= {'DEFAULT_CLOSED'}
1456 def poll(cls
, context
):
1457 sfile
= context
.space_data
1458 operator
= sfile
.active_operator
1460 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf" and operator
.has_active_exporter_extensions
1462 def draw(self
, context
):
1463 layout
= self
.layout
1464 layout
.use_property_split
= True
1465 layout
.use_property_decorate
= False # No animation.
1467 class GLTF_PT_import_user_extensions(bpy
.types
.Panel
):
1468 bl_space_type
= 'FILE_BROWSER'
1469 bl_region_type
= 'TOOL_PROPS'
1470 bl_label
= "Importer Extensions"
1471 bl_parent_id
= "FILE_PT_operator"
1472 bl_options
= {'DEFAULT_CLOSED'}
1475 def poll(cls
, context
):
1476 sfile
= context
.space_data
1477 operator
= sfile
.active_operator
1478 return operator
.bl_idname
== "IMPORT_SCENE_OT_gltf" and operator
.has_active_importer_extensions
1480 def draw(self
, context
):
1481 layout
= self
.layout
1482 layout
.use_property_split
= True
1483 layout
.use_property_decorate
= False # No animation.
1485 class ExportGLTF2(bpy
.types
.Operator
, ExportGLTF2_Base
, ExportHelper
):
1486 """Export scene as glTF 2.0 file"""
1487 bl_idname
= 'export_scene.gltf'
1488 bl_label
= 'Export glTF 2.0'
1492 filter_glob
: StringProperty(default
='*.glb', options
={'HIDDEN'})
1495 def menu_func_export(self
, context
):
1496 self
.layout
.operator(ExportGLTF2
.bl_idname
, text
='glTF 2.0 (.glb/.gltf)')
1499 class ImportGLTF2(Operator
, ConvertGLTF2_Base
, ImportHelper
):
1500 """Load a glTF 2.0 file"""
1501 bl_idname
= 'import_scene.gltf'
1502 bl_label
= 'Import glTF 2.0'
1503 bl_options
= {'REGISTER', 'UNDO'}
1505 filter_glob
: StringProperty(default
="*.glb;*.gltf", options
={'HIDDEN'})
1507 files
: CollectionProperty(
1509 type=bpy
.types
.OperatorFileListElement
,
1512 loglevel
: IntProperty(
1514 description
="Log Level")
1516 import_pack_images
: BoolProperty(
1518 description
='Pack all images into .blend file',
1522 merge_vertices
: BoolProperty(
1523 name
='Merge Vertices',
1525 'The glTF format requires discontinuous normals, UVs, and '
1526 'other vertex attributes to be stored as separate vertices, '
1527 'as required for rendering on typical graphics hardware. '
1528 'This option attempts to combine co-located vertices where possible. '
1529 'Currently cannot combine verts with different normals'
1534 import_shading
: EnumProperty(
1536 items
=(("NORMALS", "Use Normal Data", ""),
1537 ("FLAT", "Flat Shading", ""),
1538 ("SMOOTH", "Smooth Shading", "")),
1539 description
="How normals are computed during import",
1542 bone_heuristic
: EnumProperty(
1545 ("BLENDER", "Blender (best for re-importing)",
1546 "Good for re-importing glTFs exported from Blender. "
1547 "Bone tips are placed on their local +Y axis (in glTF space)"),
1548 ("TEMPERANCE", "Temperance (average)",
1549 "Decent all-around strategy. "
1550 "A bone with one child has its tip placed on the local axis "
1551 "closest to its child"),
1552 ("FORTUNE", "Fortune (may look better, less accurate)",
1553 "Might look better than Temperance, but also might have errors. "
1554 "A bone with one child has its tip placed at its child's root. "
1555 "Non-uniform scalings may get messed up though, so beware"),
1557 description
="Heuristic for placing bones. Tries to make bones pretty",
1558 default
="TEMPERANCE",
1561 guess_original_bind_pose
: BoolProperty(
1562 name
='Guess Original Bind Pose',
1564 'Try to guess the original bind pose for skinned meshes from '
1565 'the inverse bind matrices. '
1566 'When off, use default/rest pose as bind pose'
1571 def draw(self
, context
):
1572 layout
= self
.layout
1574 layout
.use_property_split
= True
1575 layout
.use_property_decorate
= False # No animation.
1577 layout
.prop(self
, 'import_pack_images')
1578 layout
.prop(self
, 'merge_vertices')
1579 layout
.prop(self
, 'import_shading')
1580 layout
.prop(self
, 'guess_original_bind_pose')
1581 layout
.prop(self
, 'bone_heuristic')
1582 layout
.prop(self
, 'export_import_convert_lighting_mode')
1584 def invoke(self
, context
, event
):
1586 preferences
= bpy
.context
.preferences
1587 for addon_name
in preferences
.addons
.keys():
1589 if hasattr(sys
.modules
[addon_name
], 'glTF2ImportUserExtension') or hasattr(sys
.modules
[addon_name
], 'glTF2ImportUserExtensions'):
1590 importer_extension_panel_unregister_functors
.append(sys
.modules
[addon_name
].register_panel())
1594 self
.has_active_importer_extensions
= len(importer_extension_panel_unregister_functors
) > 0
1595 return ImportHelper
.invoke(self
, context
, event
)
1597 def execute(self
, context
):
1598 return self
.import_gltf2(context
)
1600 def import_gltf2(self
, context
):
1603 self
.set_debug_log()
1604 import_settings
= self
.as_keywords()
1606 user_extensions
= []
1609 preferences
= bpy
.context
.preferences
1610 for addon_name
in preferences
.addons
.keys():
1612 module
= sys
.modules
[addon_name
]
1615 if hasattr(module
, 'glTF2ImportUserExtension'):
1616 extension_ctor
= module
.glTF2ImportUserExtension
1617 user_extensions
.append(extension_ctor())
1618 import_settings
['import_user_extensions'] = user_extensions
1621 # Multiple file import
1623 dirname
= os
.path
.dirname(self
.filepath
)
1624 for file in self
.files
:
1625 path
= os
.path
.join(dirname
, file.name
)
1626 if self
.unit_import(path
, import_settings
) == {'FINISHED'}:
1630 # Single file import
1631 return self
.unit_import(self
.filepath
, import_settings
)
1633 def unit_import(self
, filename
, import_settings
):
1635 from .io
.imp
.gltf2_io_gltf
import glTFImporter
, ImportError
1636 from .blender
.imp
.gltf2_blender_gltf
import BlenderGlTF
1639 gltf_importer
= glTFImporter(filename
, import_settings
)
1640 gltf_importer
.read()
1641 gltf_importer
.checks()
1643 print("Data are loaded, start creating Blender stuff")
1645 start_time
= time
.time()
1646 BlenderGlTF
.create(gltf_importer
)
1647 elapsed_s
= "{:.2f}s".format(time
.time() - start_time
)
1648 print("glTF import finished in " + elapsed_s
)
1650 gltf_importer
.log
.removeHandler(gltf_importer
.log_handler
)
1654 except ImportError as e
:
1655 self
.report({'ERROR'}, e
.args
[0])
1656 return {'CANCELLED'}
1658 def set_debug_log(self
):
1660 if bpy
.app
.debug_value
== 0:
1661 self
.loglevel
= logging
.CRITICAL
1662 elif bpy
.app
.debug_value
== 1:
1663 self
.loglevel
= logging
.ERROR
1664 elif bpy
.app
.debug_value
== 2:
1665 self
.loglevel
= logging
.WARNING
1666 elif bpy
.app
.debug_value
== 3:
1667 self
.loglevel
= logging
.INFO
1669 self
.loglevel
= logging
.NOTSET
1672 def gltf_variant_ui_update(self
, context
):
1673 from .blender
.com
.gltf2_blender_ui
import variant_register
, variant_unregister
1674 if self
.KHR_materials_variants_ui
is True:
1675 # register all needed types
1678 variant_unregister()
1680 def gltf_animation_ui_update(self
, context
):
1681 from .blender
.com
.gltf2_blender_ui
import anim_ui_register
, anim_ui_unregister
1682 if self
.animation_ui
is True:
1683 # register all needed types
1686 anim_ui_unregister()
1688 class GLTF_AddonPreferences(bpy
.types
.AddonPreferences
):
1689 bl_idname
= __package__
1691 settings_node_ui
: bpy
.props
.BoolProperty(
1693 description
="Displays glTF Material Output node in Shader Editor (Menu Add > Output)"
1696 KHR_materials_variants_ui
: bpy
.props
.BoolProperty(
1698 description
="Displays glTF UI to manage material variants",
1699 update
=gltf_variant_ui_update
1702 animation_ui
: bpy
.props
.BoolProperty(
1704 description
="Display glTF UI to manage animations",
1705 update
=gltf_animation_ui_update
1708 def draw(self
, context
):
1709 layout
= self
.layout
1711 row
.prop(self
, "settings_node_ui", text
="Shader Editor Add-ons")
1712 row
.prop(self
, "KHR_materials_variants_ui", text
="Material Variants")
1713 row
.prop(self
, "animation_ui", text
="Animation UI")
1715 def menu_func_import(self
, context
):
1716 self
.layout
.operator(ImportGLTF2
.bl_idname
, text
='glTF 2.0 (.glb/.gltf)')
1721 GLTF_PT_export_main
,
1722 GLTF_PT_export_include
,
1723 GLTF_PT_export_transform
,
1724 GLTF_PT_export_data
,
1725 GLTF_PT_export_data_mesh
,
1726 GLTF_PT_export_data_material
,
1727 GLTF_PT_export_data_original_pbr
,
1728 GLTF_PT_export_data_shapekeys
,
1729 GLTF_PT_export_data_armature
,
1730 GLTF_PT_export_data_skinning
,
1731 GLTF_PT_export_data_lighting
,
1732 GLTF_PT_export_data_compression
,
1733 GLTF_PT_export_animation
,
1734 GLTF_PT_export_animation_notes
,
1735 GLTF_PT_export_animation_ranges
,
1736 GLTF_PT_export_animation_armature
,
1737 GLTF_PT_export_animation_shapekeys
,
1738 GLTF_PT_export_animation_sampling
,
1739 GLTF_PT_export_animation_optimize
,
1740 GLTF_PT_export_user_extensions
,
1742 GLTF_PT_import_user_extensions
,
1743 GLTF_AddonPreferences
1748 from .blender
.com
import gltf2_blender_ui
as blender_ui
1750 bpy
.utils
.register_class(c
)
1751 # bpy.utils.register_module(__name__)
1753 blender_ui
.register()
1754 if bpy
.context
.preferences
.addons
['io_scene_gltf2'].preferences
.KHR_materials_variants_ui
is True:
1755 blender_ui
.variant_register()
1756 if bpy
.context
.preferences
.addons
['io_scene_gltf2'].preferences
.animation_ui
is True:
1757 blender_ui
.anim_ui_register()
1759 # add to the export / import menu
1760 bpy
.types
.TOPBAR_MT_file_export
.append(menu_func_export
)
1761 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
1765 from .blender
.com
import gltf2_blender_ui
as blender_ui
1766 blender_ui
.unregister()
1767 if bpy
.context
.preferences
.addons
['io_scene_gltf2'].preferences
.KHR_materials_variants_ui
is True:
1768 blender_ui
.variant_unregister()
1771 bpy
.utils
.unregister_class(c
)
1772 for f
in exporter_extension_panel_unregister_functors
:
1774 exporter_extension_panel_unregister_functors
.clear()
1776 for f
in importer_extension_panel_unregister_functors
:
1778 importer_extension_panel_unregister_functors
.clear()
1780 # bpy.utils.unregister_module(__name__)
1782 # remove from the export / import menu
1783 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_func_export
)
1784 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)