1 # SPDX-License-Identifier: Apache-2.0
2 # Copyright 2018-2021 The glTF-Blender-IO authors.
5 'name': 'glTF 2.0 format',
6 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
9 'location': 'File > Import-Export',
10 'description': 'Import-Export as glTF 2.0',
12 'doc_url': "{BLENDER_MANUAL_URL}/addons/import_export/scene_gltf2.html",
13 'tracker_url': "https://github.com/KhronosGroup/glTF-Blender-IO/issues/",
14 'support': 'OFFICIAL',
15 'category': 'Import-Export',
18 def get_version_string():
19 return str(bl_info
['version'][0]) + '.' + str(bl_info
['version'][1]) + '.' + str(bl_info
['version'][2])
22 # Script reloading (if the user calls 'Reload Scripts' from Blender)
25 def reload_package(module_dict_main
):
27 from pathlib
import Path
29 def reload_package_recursive(current_dir
, module_dict
):
30 for path
in current_dir
.iterdir():
31 if "__init__" in str(path
) or path
.stem
not in module_dict
:
34 if path
.is_file() and path
.suffix
== ".py":
35 importlib
.reload(module_dict
[path
.stem
])
37 reload_package_recursive(path
, module_dict
[path
.stem
].__dict
__)
39 reload_package_recursive(Path(__file__
).parent
, module_dict_main
)
43 reload_package(locals())
46 from bpy
.props
import (StringProperty
,
51 from bpy
.types
import Operator
52 from bpy_extras
.io_utils
import ImportHelper
, ExportHelper
56 # Functions / Classes.
59 exporter_extension_panel_unregister_functors
= []
60 importer_extension_panel_unregister_functors
= []
63 def ensure_filepath_matches_export_format(filepath
, export_format
):
65 filename
= os
.path
.basename(filepath
)
69 stem
, ext
= os
.path
.splitext(filename
)
70 if stem
.startswith('.') and not ext
:
73 desired_ext
= '.glb' if export_format
== 'GLB' else '.gltf'
74 ext_lower
= ext
.lower()
75 if ext_lower
not in ['.glb', '.gltf']:
76 return filepath
+ desired_ext
77 elif ext_lower
!= desired_ext
:
78 filepath
= filepath
[:-len(ext
)] # strip off ext
79 return filepath
+ desired_ext
84 def on_export_format_changed(self
, context
):
85 # Update the filename in the file browser when the format (.glb/.gltf)
87 sfile
= context
.space_data
88 if not isinstance(sfile
, bpy
.types
.SpaceFileBrowser
):
90 if not sfile
.active_operator
:
92 if sfile
.active_operator
.bl_idname
!= "EXPORT_SCENE_OT_gltf":
95 sfile
.params
.filename
= ensure_filepath_matches_export_format(
96 sfile
.params
.filename
,
101 class ExportGLTF2_Base
:
102 # TODO: refactor to avoid boilerplate
105 from io_scene_gltf2
.io
.com
import gltf2_io_draco_compression_extension
106 self
.is_draco_available
= gltf2_io_draco_compression_extension
.dll_exists()
108 bl_options
= {'PRESET'}
110 export_format
: EnumProperty(
112 items
=(('GLB', 'glTF Binary (.glb)',
113 'Exports a single file, with all data packed in binary form. '
114 'Most efficient and portable, but more difficult to edit later'),
115 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
116 'Exports multiple files, with separate JSON, binary and texture data. '
117 'Easiest to edit later'),
118 ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
119 'Exports a single file, with all data packed in JSON. '
120 'Less efficient than binary, but easier to edit later')),
122 'Output format and embedding options. Binary is most efficient, '
123 'but JSON (embedded or separate) may be easier to edit later'
126 update
=on_export_format_changed
,
129 ui_tab
: EnumProperty(
130 items
=(('GENERAL', "General", "General settings"),
131 ('MESHES', "Meshes", "Mesh settings"),
132 ('OBJECTS', "Objects", "Object settings"),
133 ('ANIMATION', "Animation", "Animation settings")),
135 description
="Export setting categories",
138 export_copyright
: StringProperty(
140 description
='Legal rights and conditions for the model',
144 export_image_format
: EnumProperty(
146 items
=(('AUTO', 'Automatic',
147 'Save PNGs as PNGs and JPEGs as JPEGs. '
148 'If neither one, use PNG'),
149 ('JPEG', 'JPEG Format (.jpg)',
150 'Save images as JPEGs. (Images that need alpha are saved as PNGs though.) '
151 'Be aware of a possible loss in quality'),
153 'Don\'t export images'),
156 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
157 'applications due to the smaller file size. Alternatively they can be omitted if they are not needed'
162 export_texture_dir
: StringProperty(
164 description
='Folder to place texture files in. Relative to the .gltf file',
168 export_keep_originals
: BoolProperty(
169 name
='Keep original',
170 description
=('Keep original textures files if possible. '
171 'WARNING: if you use more than one texture, '
172 'where pbr standard requires only one, only one texture will be used. '
173 'This can lead to unexpected results'
178 export_texcoords
: BoolProperty(
180 description
='Export UVs (texture coordinates) with meshes',
184 export_normals
: BoolProperty(
186 description
='Export vertex normals with meshes',
190 export_draco_mesh_compression_enable
: BoolProperty(
191 name
='Draco mesh compression',
192 description
='Compress mesh using Draco',
196 export_draco_mesh_compression_level
: IntProperty(
197 name
='Compression level',
198 description
='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
204 export_draco_position_quantization
: IntProperty(
205 name
='Position quantization bits',
206 description
='Quantization bits for position values (0 = no quantization)',
212 export_draco_normal_quantization
: IntProperty(
213 name
='Normal quantization bits',
214 description
='Quantization bits for normal values (0 = no quantization)',
220 export_draco_texcoord_quantization
: IntProperty(
221 name
='Texcoord quantization bits',
222 description
='Quantization bits for texture coordinate values (0 = no quantization)',
228 export_draco_color_quantization
: IntProperty(
229 name
='Color quantization bits',
230 description
='Quantization bits for color values (0 = no quantization)',
236 export_draco_generic_quantization
: IntProperty(
237 name
='Generic quantization bits',
238 description
='Quantization bits for generic coordinate values like weights or joints (0 = no quantization)',
244 export_tangents
: BoolProperty(
246 description
='Export vertex tangents with meshes',
250 export_materials
: EnumProperty(
252 items
=(('EXPORT', 'Export',
253 'Export all materials used by included objects'),
254 ('PLACEHOLDER', 'Placeholder',
255 'Do not export materials, but write multiple primitive groups per mesh, keeping material slot information'),
256 ('NONE', 'No export',
257 'Do not export materials, and combine mesh primitive groups, losing material slot information')),
258 description
='Export materials ',
262 export_colors
: BoolProperty(
263 name
='Vertex Colors',
264 description
='Export vertex colors with meshes',
268 use_mesh_edges
: BoolProperty(
271 'Export loose edges as lines, using the material from the first material slot'
276 use_mesh_vertices
: BoolProperty(
279 'Export loose points as glTF points, using the material from the first material slot'
284 export_cameras
: BoolProperty(
286 description
='Export cameras',
290 use_selection
: BoolProperty(
291 name
='Selected Objects',
292 description
='Export selected objects only',
296 use_visible
: BoolProperty(
297 name
='Visible Objects',
298 description
='Export visible objects only',
302 use_renderable
: BoolProperty(
303 name
='Renderable Objects',
304 description
='Export renderable objects only',
308 use_active_collection
: BoolProperty(
309 name
='Active Collection',
310 description
='Export objects in the active collection only',
314 use_active_scene
: BoolProperty(
316 description
='Export active scene only',
320 export_extras
: BoolProperty(
321 name
='Custom Properties',
322 description
='Export custom properties as glTF extras',
326 export_yup
: BoolProperty(
328 description
='Export using glTF convention, +Y up',
332 export_apply
: BoolProperty(
333 name
='Apply Modifiers',
334 description
='Apply modifiers (excluding Armatures) to mesh objects -'
335 'WARNING: prevents exporting shape keys',
339 export_animations
: BoolProperty(
341 description
='Exports active actions and NLA tracks as glTF animations',
345 export_frame_range
: BoolProperty(
346 name
='Limit to Playback Range',
347 description
='Clips animations to selected playback range',
351 export_frame_step
: IntProperty(
352 name
='Sampling Rate',
353 description
='How often to evaluate animated values (in frames)',
359 export_force_sampling
: BoolProperty(
360 name
='Always Sample Animations',
361 description
='Apply sampling to all animations',
365 export_nla_strips
: BoolProperty(
366 name
='Group by NLA Track',
368 "When on, multiple actions become part of the same glTF animation if "
369 "they're pushed onto NLA tracks with the same name. "
370 "When off, all the currently assigned actions become one glTF animation"
375 export_nla_strips_merged_animation_name
: StringProperty(
376 name
='Merged Animation Name',
378 "Name of single glTF animation to be exported"
383 export_def_bones
: BoolProperty(
384 name
='Export Deformation Bones Only',
385 description
='Export Deformation bones only',
389 optimize_animation_size
: BoolProperty(
390 name
='Optimize Animation Size',
392 "Reduce exported file-size by removing duplicate keyframes"
393 "(can cause problems with stepped animation)"
398 export_current_frame
: BoolProperty(
399 name
='Use Current Frame',
400 description
='Export the scene in the current animation frame',
404 export_skins
: BoolProperty(
406 description
='Export skinning (armature) data',
410 export_all_influences
: BoolProperty(
411 name
='Include All Bone Influences',
412 description
='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
416 export_morph
: BoolProperty(
418 description
='Export shape keys (morph targets)',
422 export_morph_normal
: BoolProperty(
423 name
='Shape Key Normals',
424 description
='Export vertex normals with shape keys (morph targets)',
428 export_morph_tangent
: BoolProperty(
429 name
='Shape Key Tangents',
430 description
='Export vertex tangents with shape keys (morph targets)',
434 export_lights
: BoolProperty(
435 name
='Punctual Lights',
436 description
='Export directional, point, and spot lights. '
437 'Uses "KHR_lights_punctual" glTF extension',
441 export_displacement
: BoolProperty(
442 name
='Displacement Textures (EXPERIMENTAL)',
443 description
='EXPERIMENTAL: Export displacement textures. '
444 'Uses incomplete "KHR_materials_displacement" glTF extension',
448 will_save_settings
: BoolProperty(
449 name
='Remember Export Settings',
450 description
='Store glTF export settings in the Blender project',
453 # Custom scene property for saving settings
454 scene_key
= "glTF2ExportSettings"
458 def check(self
, _context
):
459 # Ensure file extension matches format
460 old_filepath
= self
.filepath
461 self
.filepath
= ensure_filepath_matches_export_format(
465 return self
.filepath
!= old_filepath
467 def invoke(self
, context
, event
):
468 settings
= context
.scene
.get(self
.scene_key
)
469 self
.will_save_settings
= False
472 for (k
, v
) in settings
.items():
474 self
.will_save_settings
= True
476 except (AttributeError, TypeError):
477 self
.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
478 del context
.scene
[self
.scene_key
]
481 preferences
= bpy
.context
.preferences
482 for addon_name
in preferences
.addons
.keys():
484 if hasattr(sys
.modules
[addon_name
], 'glTF2ExportUserExtension') or hasattr(sys
.modules
[addon_name
], 'glTF2ExportUserExtensions'):
485 exporter_extension_panel_unregister_functors
.append(sys
.modules
[addon_name
].register_panel())
489 self
.has_active_exporter_extensions
= len(exporter_extension_panel_unregister_functors
) > 0
490 return ExportHelper
.invoke(self
, context
, event
)
492 def save_settings(self
, context
):
493 # find all props to save
495 # options that don't start with 'export_'
499 'use_active_collection',
504 all_props
= self
.properties
506 x
: getattr(self
, x
) for x
in dir(all_props
)
507 if (x
.startswith("export_") or x
in exceptional
) and all_props
.get(x
) is not None
509 context
.scene
[self
.scene_key
] = export_props
511 def execute(self
, context
):
514 from .blender
.exp
import gltf2_blender_export
516 if self
.will_save_settings
:
517 self
.save_settings(context
)
519 self
.check(context
) # ensure filepath has the right extension
521 # All custom export settings are stored in this container.
524 export_settings
['timestamp'] = datetime
.datetime
.now()
526 export_settings
['gltf_filepath'] = self
.filepath
527 export_settings
['gltf_filedirectory'] = os
.path
.dirname(export_settings
['gltf_filepath']) + '/'
528 export_settings
['gltf_texturedirectory'] = os
.path
.join(
529 export_settings
['gltf_filedirectory'],
530 self
.export_texture_dir
,
532 export_settings
['gltf_keep_original_textures'] = self
.export_keep_originals
534 export_settings
['gltf_format'] = self
.export_format
535 export_settings
['gltf_image_format'] = self
.export_image_format
536 export_settings
['gltf_copyright'] = self
.export_copyright
537 export_settings
['gltf_texcoords'] = self
.export_texcoords
538 export_settings
['gltf_normals'] = self
.export_normals
539 export_settings
['gltf_tangents'] = self
.export_tangents
and self
.export_normals
540 export_settings
['gltf_loose_edges'] = self
.use_mesh_edges
541 export_settings
['gltf_loose_points'] = self
.use_mesh_vertices
543 if self
.is_draco_available
:
544 export_settings
['gltf_draco_mesh_compression'] = self
.export_draco_mesh_compression_enable
545 export_settings
['gltf_draco_mesh_compression_level'] = self
.export_draco_mesh_compression_level
546 export_settings
['gltf_draco_position_quantization'] = self
.export_draco_position_quantization
547 export_settings
['gltf_draco_normal_quantization'] = self
.export_draco_normal_quantization
548 export_settings
['gltf_draco_texcoord_quantization'] = self
.export_draco_texcoord_quantization
549 export_settings
['gltf_draco_color_quantization'] = self
.export_draco_color_quantization
550 export_settings
['gltf_draco_generic_quantization'] = self
.export_draco_generic_quantization
552 export_settings
['gltf_draco_mesh_compression'] = False
554 export_settings
['gltf_materials'] = self
.export_materials
555 export_settings
['gltf_colors'] = self
.export_colors
556 export_settings
['gltf_cameras'] = self
.export_cameras
559 export_settings
['gltf_visible'] = self
.use_visible
560 export_settings
['gltf_renderable'] = self
.use_renderable
561 export_settings
['gltf_active_collection'] = self
.use_active_collection
562 export_settings
['gltf_active_scene'] = self
.use_active_scene
564 export_settings
['gltf_selected'] = self
.use_selection
565 export_settings
['gltf_layers'] = True # self.export_layers
566 export_settings
['gltf_extras'] = self
.export_extras
567 export_settings
['gltf_yup'] = self
.export_yup
568 export_settings
['gltf_apply'] = self
.export_apply
569 export_settings
['gltf_current_frame'] = self
.export_current_frame
570 export_settings
['gltf_animations'] = self
.export_animations
571 export_settings
['gltf_def_bones'] = self
.export_def_bones
572 if self
.export_animations
:
573 export_settings
['gltf_frame_range'] = self
.export_frame_range
574 export_settings
['gltf_force_sampling'] = self
.export_force_sampling
575 if not self
.export_force_sampling
:
576 export_settings
['gltf_def_bones'] = False
577 export_settings
['gltf_nla_strips'] = self
.export_nla_strips
578 export_settings
['gltf_nla_strips_merged_animation_name'] = self
.export_nla_strips_merged_animation_name
579 export_settings
['gltf_optimize_animation'] = self
.optimize_animation_size
581 export_settings
['gltf_frame_range'] = False
582 export_settings
['gltf_move_keyframes'] = False
583 export_settings
['gltf_force_sampling'] = False
584 export_settings
['gltf_optimize_animation'] = False
585 export_settings
['gltf_skins'] = self
.export_skins
586 if self
.export_skins
:
587 export_settings
['gltf_all_vertex_influences'] = self
.export_all_influences
589 export_settings
['gltf_all_vertex_influences'] = False
590 export_settings
['gltf_def_bones'] = False
591 export_settings
['gltf_frame_step'] = self
.export_frame_step
592 export_settings
['gltf_morph'] = self
.export_morph
593 if self
.export_morph
:
594 export_settings
['gltf_morph_normal'] = self
.export_morph_normal
596 export_settings
['gltf_morph_normal'] = False
597 if self
.export_morph
and self
.export_morph_normal
:
598 export_settings
['gltf_morph_tangent'] = self
.export_morph_tangent
600 export_settings
['gltf_morph_tangent'] = False
602 export_settings
['gltf_lights'] = self
.export_lights
603 export_settings
['gltf_displacement'] = self
.export_displacement
605 export_settings
['gltf_binary'] = bytearray()
606 export_settings
['gltf_binaryfilename'] = (
607 os
.path
.splitext(os
.path
.basename(self
.filepath
))[0] + '.bin'
611 pre_export_callbacks
= []
612 post_export_callbacks
= []
615 preferences
= bpy
.context
.preferences
616 for addon_name
in preferences
.addons
.keys():
618 module
= sys
.modules
[addon_name
]
621 if hasattr(module
, 'glTF2ExportUserExtension'):
622 extension_ctor
= module
.glTF2ExportUserExtension
623 user_extensions
.append(extension_ctor())
624 if hasattr(module
, 'glTF2ExportUserExtensions'):
625 extension_ctors
= module
.glTF2ExportUserExtensions
626 for extension_ctor
in extension_ctors
:
627 user_extensions
.append(extension_ctor())
628 if hasattr(module
, 'glTF2_pre_export_callback'):
629 pre_export_callbacks
.append(module
.glTF2_pre_export_callback
)
630 if hasattr(module
, 'glTF2_post_export_callback'):
631 post_export_callbacks
.append(module
.glTF2_post_export_callback
)
632 export_settings
['gltf_user_extensions'] = user_extensions
633 export_settings
['pre_export_callbacks'] = pre_export_callbacks
634 export_settings
['post_export_callbacks'] = post_export_callbacks
636 return gltf2_blender_export
.save(context
, export_settings
)
638 def draw(self
, context
):
639 pass # Is needed to get panels available
642 class GLTF_PT_export_main(bpy
.types
.Panel
):
643 bl_space_type
= 'FILE_BROWSER'
644 bl_region_type
= 'TOOL_PROPS'
646 bl_parent_id
= "FILE_PT_operator"
647 bl_options
= {'HIDE_HEADER'}
650 def poll(cls
, context
):
651 sfile
= context
.space_data
652 operator
= sfile
.active_operator
654 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
656 def draw(self
, context
):
658 layout
.use_property_split
= True
659 layout
.use_property_decorate
= False # No animation.
661 sfile
= context
.space_data
662 operator
= sfile
.active_operator
664 layout
.prop(operator
, 'export_format')
665 if operator
.export_format
== 'GLTF_SEPARATE':
666 layout
.prop(operator
, 'export_keep_originals')
667 if operator
.export_keep_originals
is False:
668 layout
.prop(operator
, 'export_texture_dir', icon
='FILE_FOLDER')
670 layout
.prop(operator
, 'export_copyright')
671 layout
.prop(operator
, 'will_save_settings')
674 class GLTF_PT_export_include(bpy
.types
.Panel
):
675 bl_space_type
= 'FILE_BROWSER'
676 bl_region_type
= 'TOOL_PROPS'
678 bl_parent_id
= "FILE_PT_operator"
679 bl_options
= {'DEFAULT_CLOSED'}
682 def poll(cls
, context
):
683 sfile
= context
.space_data
684 operator
= sfile
.active_operator
686 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
688 def draw(self
, context
):
690 layout
.use_property_split
= True
691 layout
.use_property_decorate
= False # No animation.
693 sfile
= context
.space_data
694 operator
= sfile
.active_operator
696 col
= layout
.column(heading
= "Limit to", align
= True)
697 col
.prop(operator
, 'use_selection')
698 col
.prop(operator
, 'use_visible')
699 col
.prop(operator
, 'use_renderable')
700 col
.prop(operator
, 'use_active_collection')
701 col
.prop(operator
, 'use_active_scene')
703 col
= layout
.column(heading
= "Data", align
= True)
704 col
.prop(operator
, 'export_extras')
705 col
.prop(operator
, 'export_cameras')
706 col
.prop(operator
, 'export_lights')
709 class GLTF_PT_export_transform(bpy
.types
.Panel
):
710 bl_space_type
= 'FILE_BROWSER'
711 bl_region_type
= 'TOOL_PROPS'
712 bl_label
= "Transform"
713 bl_parent_id
= "FILE_PT_operator"
714 bl_options
= {'DEFAULT_CLOSED'}
717 def poll(cls
, context
):
718 sfile
= context
.space_data
719 operator
= sfile
.active_operator
721 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
723 def draw(self
, context
):
725 layout
.use_property_split
= True
726 layout
.use_property_decorate
= False # No animation.
728 sfile
= context
.space_data
729 operator
= sfile
.active_operator
731 layout
.prop(operator
, 'export_yup')
734 class GLTF_PT_export_geometry(bpy
.types
.Panel
):
735 bl_space_type
= 'FILE_BROWSER'
736 bl_region_type
= 'TOOL_PROPS'
737 bl_label
= "Geometry"
738 bl_parent_id
= "FILE_PT_operator"
739 bl_options
= {'DEFAULT_CLOSED'}
742 def poll(cls
, context
):
743 sfile
= context
.space_data
744 operator
= sfile
.active_operator
746 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
748 def draw(self
, context
):
750 layout
.use_property_split
= True
751 layout
.use_property_decorate
= False # No animation.
753 sfile
= context
.space_data
754 operator
= sfile
.active_operator
756 layout
.prop(operator
, 'export_apply')
757 layout
.prop(operator
, 'export_texcoords')
758 layout
.prop(operator
, 'export_normals')
759 col
= layout
.column()
760 col
.active
= operator
.export_normals
761 col
.prop(operator
, 'export_tangents')
762 layout
.prop(operator
, 'export_colors')
764 col
= layout
.column()
765 col
.prop(operator
, 'use_mesh_edges')
766 col
.prop(operator
, 'use_mesh_vertices')
768 layout
.prop(operator
, 'export_materials')
769 col
= layout
.column()
770 col
.active
= operator
.export_materials
== "EXPORT"
771 col
.prop(operator
, 'export_image_format')
774 class GLTF_PT_export_geometry_compression(bpy
.types
.Panel
):
775 bl_space_type
= 'FILE_BROWSER'
776 bl_region_type
= 'TOOL_PROPS'
777 bl_label
= "Compression"
778 bl_parent_id
= "GLTF_PT_export_geometry"
779 bl_options
= {'DEFAULT_CLOSED'}
782 from io_scene_gltf2
.io
.com
import gltf2_io_draco_compression_extension
783 self
.is_draco_available
= gltf2_io_draco_compression_extension
.dll_exists(quiet
=True)
786 def poll(cls
, context
):
787 sfile
= context
.space_data
788 operator
= sfile
.active_operator
789 if operator
.is_draco_available
:
790 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
792 def draw_header(self
, context
):
793 sfile
= context
.space_data
794 operator
= sfile
.active_operator
795 self
.layout
.prop(operator
, "export_draco_mesh_compression_enable", text
="")
797 def draw(self
, context
):
799 layout
.use_property_split
= True
800 layout
.use_property_decorate
= False # No animation.
802 sfile
= context
.space_data
803 operator
= sfile
.active_operator
805 layout
.active
= operator
.export_draco_mesh_compression_enable
806 layout
.prop(operator
, 'export_draco_mesh_compression_level')
808 col
= layout
.column(align
=True)
809 col
.prop(operator
, 'export_draco_position_quantization', text
="Quantize Position")
810 col
.prop(operator
, 'export_draco_normal_quantization', text
="Normal")
811 col
.prop(operator
, 'export_draco_texcoord_quantization', text
="Tex Coord")
812 col
.prop(operator
, 'export_draco_color_quantization', text
="Color")
813 col
.prop(operator
, 'export_draco_generic_quantization', text
="Generic")
816 class GLTF_PT_export_animation(bpy
.types
.Panel
):
817 bl_space_type
= 'FILE_BROWSER'
818 bl_region_type
= 'TOOL_PROPS'
819 bl_label
= "Animation"
820 bl_parent_id
= "FILE_PT_operator"
821 bl_options
= {'DEFAULT_CLOSED'}
824 def poll(cls
, context
):
825 sfile
= context
.space_data
826 operator
= sfile
.active_operator
828 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
830 def draw(self
, context
):
832 layout
.use_property_split
= True
833 layout
.use_property_decorate
= False # No animation.
835 sfile
= context
.space_data
836 operator
= sfile
.active_operator
838 layout
.prop(operator
, 'export_current_frame')
841 class GLTF_PT_export_animation_export(bpy
.types
.Panel
):
842 bl_space_type
= 'FILE_BROWSER'
843 bl_region_type
= 'TOOL_PROPS'
844 bl_label
= "Animation"
845 bl_parent_id
= "GLTF_PT_export_animation"
846 bl_options
= {'DEFAULT_CLOSED'}
849 def poll(cls
, context
):
850 sfile
= context
.space_data
851 operator
= sfile
.active_operator
853 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
855 def draw_header(self
, context
):
856 sfile
= context
.space_data
857 operator
= sfile
.active_operator
858 self
.layout
.prop(operator
, "export_animations", text
="")
860 def draw(self
, context
):
862 layout
.use_property_split
= True
863 layout
.use_property_decorate
= False # No animation.
865 sfile
= context
.space_data
866 operator
= sfile
.active_operator
868 layout
.active
= operator
.export_animations
870 layout
.prop(operator
, 'export_frame_range')
871 layout
.prop(operator
, 'export_frame_step')
872 layout
.prop(operator
, 'export_force_sampling')
873 layout
.prop(operator
, 'export_nla_strips')
874 if operator
.export_nla_strips
is False:
875 layout
.prop(operator
, 'export_nla_strips_merged_animation_name')
876 layout
.prop(operator
, 'optimize_animation_size')
879 class GLTF_PT_export_animation_shapekeys(bpy
.types
.Panel
):
880 bl_space_type
= 'FILE_BROWSER'
881 bl_region_type
= 'TOOL_PROPS'
882 bl_label
= "Shape Keys"
883 bl_parent_id
= "GLTF_PT_export_animation"
884 bl_options
= {'DEFAULT_CLOSED'}
887 def poll(cls
, context
):
888 sfile
= context
.space_data
889 operator
= sfile
.active_operator
891 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
893 def draw_header(self
, context
):
894 sfile
= context
.space_data
895 operator
= sfile
.active_operator
896 self
.layout
.prop(operator
, "export_morph", text
="")
898 def draw(self
, context
):
900 layout
.use_property_split
= True
901 layout
.use_property_decorate
= False # No animation.
903 sfile
= context
.space_data
904 operator
= sfile
.active_operator
906 layout
.active
= operator
.export_morph
908 layout
.prop(operator
, 'export_morph_normal')
909 col
= layout
.column()
910 col
.active
= operator
.export_morph_normal
911 col
.prop(operator
, 'export_morph_tangent')
914 class GLTF_PT_export_animation_skinning(bpy
.types
.Panel
):
915 bl_space_type
= 'FILE_BROWSER'
916 bl_region_type
= 'TOOL_PROPS'
917 bl_label
= "Skinning"
918 bl_parent_id
= "GLTF_PT_export_animation"
919 bl_options
= {'DEFAULT_CLOSED'}
922 def poll(cls
, context
):
923 sfile
= context
.space_data
924 operator
= sfile
.active_operator
926 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
928 def draw_header(self
, context
):
929 sfile
= context
.space_data
930 operator
= sfile
.active_operator
931 self
.layout
.prop(operator
, "export_skins", text
="")
933 def draw(self
, context
):
935 layout
.use_property_split
= True
936 layout
.use_property_decorate
= False # No animation.
938 sfile
= context
.space_data
939 operator
= sfile
.active_operator
941 layout
.active
= operator
.export_skins
942 layout
.prop(operator
, 'export_all_influences')
945 row
.active
= operator
.export_force_sampling
946 row
.prop(operator
, 'export_def_bones')
947 if operator
.export_force_sampling
is False and operator
.export_def_bones
is True:
948 layout
.label(text
="Export only deformation bones is not possible when not sampling animation")
950 class GLTF_PT_export_user_extensions(bpy
.types
.Panel
):
951 bl_space_type
= 'FILE_BROWSER'
952 bl_region_type
= 'TOOL_PROPS'
953 bl_label
= "Exporter Extensions"
954 bl_parent_id
= "FILE_PT_operator"
955 bl_options
= {'DEFAULT_CLOSED'}
958 def poll(cls
, context
):
959 sfile
= context
.space_data
960 operator
= sfile
.active_operator
962 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf" and operator
.has_active_exporter_extensions
964 def draw(self
, context
):
966 layout
.use_property_split
= True
967 layout
.use_property_decorate
= False # No animation.
969 class GLTF_PT_import_user_extensions(bpy
.types
.Panel
):
970 bl_space_type
= 'FILE_BROWSER'
971 bl_region_type
= 'TOOL_PROPS'
972 bl_label
= "Importer Extensions"
973 bl_parent_id
= "FILE_PT_operator"
974 bl_options
= {'DEFAULT_CLOSED'}
977 def poll(cls
, context
):
978 sfile
= context
.space_data
979 operator
= sfile
.active_operator
980 return operator
.bl_idname
== "IMPORT_SCENE_OT_gltf" and operator
.has_active_importer_extensions
982 def draw(self
, context
):
984 layout
.use_property_split
= True
985 layout
.use_property_decorate
= False # No animation.
987 class ExportGLTF2(bpy
.types
.Operator
, ExportGLTF2_Base
, ExportHelper
):
988 """Export scene as glTF 2.0 file"""
989 bl_idname
= 'export_scene.gltf'
990 bl_label
= 'Export glTF 2.0'
994 filter_glob
: StringProperty(default
='*.glb;*.gltf', options
={'HIDDEN'})
997 def menu_func_export(self
, context
):
998 self
.layout
.operator(ExportGLTF2
.bl_idname
, text
='glTF 2.0 (.glb/.gltf)')
1001 class ImportGLTF2(Operator
, ImportHelper
):
1002 """Load a glTF 2.0 file"""
1003 bl_idname
= 'import_scene.gltf'
1004 bl_label
= 'Import glTF 2.0'
1005 bl_options
= {'REGISTER', 'UNDO'}
1007 filter_glob
: StringProperty(default
="*.glb;*.gltf", options
={'HIDDEN'})
1009 files
: CollectionProperty(
1011 type=bpy
.types
.OperatorFileListElement
,
1014 loglevel
: IntProperty(
1016 description
="Log Level")
1018 import_pack_images
: BoolProperty(
1020 description
='Pack all images into .blend file',
1024 merge_vertices
: BoolProperty(
1025 name
='Merge Vertices',
1027 'The glTF format requires discontinuous normals, UVs, and '
1028 'other vertex attributes to be stored as separate vertices, '
1029 'as required for rendering on typical graphics hardware. '
1030 'This option attempts to combine co-located vertices where possible. '
1031 'Currently cannot combine verts with different normals'
1036 import_shading
: EnumProperty(
1038 items
=(("NORMALS", "Use Normal Data", ""),
1039 ("FLAT", "Flat Shading", ""),
1040 ("SMOOTH", "Smooth Shading", "")),
1041 description
="How normals are computed during import",
1044 bone_heuristic
: EnumProperty(
1047 ("BLENDER", "Blender (best for re-importing)",
1048 "Good for re-importing glTFs exported from Blender. "
1049 "Bone tips are placed on their local +Y axis (in glTF space)"),
1050 ("TEMPERANCE", "Temperance (average)",
1051 "Decent all-around strategy. "
1052 "A bone with one child has its tip placed on the local axis "
1053 "closest to its child"),
1054 ("FORTUNE", "Fortune (may look better, less accurate)",
1055 "Might look better than Temperance, but also might have errors. "
1056 "A bone with one child has its tip placed at its child's root. "
1057 "Non-uniform scalings may get messed up though, so beware"),
1059 description
="Heuristic for placing bones. Tries to make bones pretty",
1060 default
="TEMPERANCE",
1063 guess_original_bind_pose
: BoolProperty(
1064 name
='Guess Original Bind Pose',
1066 'Try to guess the original bind pose for skinned meshes from '
1067 'the inverse bind matrices. '
1068 'When off, use default/rest pose as bind pose'
1073 def draw(self
, context
):
1074 layout
= self
.layout
1076 layout
.use_property_split
= True
1077 layout
.use_property_decorate
= False # No animation.
1079 layout
.prop(self
, 'import_pack_images')
1080 layout
.prop(self
, 'merge_vertices')
1081 layout
.prop(self
, 'import_shading')
1082 layout
.prop(self
, 'guess_original_bind_pose')
1083 layout
.prop(self
, 'bone_heuristic')
1085 def invoke(self
, context
, event
):
1087 preferences
= bpy
.context
.preferences
1088 for addon_name
in preferences
.addons
.keys():
1090 if hasattr(sys
.modules
[addon_name
], 'glTF2ImportUserExtension') or hasattr(sys
.modules
[addon_name
], 'glTF2ImportUserExtensions'):
1091 importer_extension_panel_unregister_functors
.append(sys
.modules
[addon_name
].register_panel())
1095 self
.has_active_importer_extensions
= len(importer_extension_panel_unregister_functors
) > 0
1096 return ImportHelper
.invoke(self
, context
, event
)
1098 def execute(self
, context
):
1099 return self
.import_gltf2(context
)
1101 def import_gltf2(self
, context
):
1104 self
.set_debug_log()
1105 import_settings
= self
.as_keywords()
1107 user_extensions
= []
1110 preferences
= bpy
.context
.preferences
1111 for addon_name
in preferences
.addons
.keys():
1113 module
= sys
.modules
[addon_name
]
1116 if hasattr(module
, 'glTF2ImportUserExtension'):
1117 extension_ctor
= module
.glTF2ImportUserExtension
1118 user_extensions
.append(extension_ctor())
1119 import_settings
['import_user_extensions'] = user_extensions
1122 # Multiple file import
1124 dirname
= os
.path
.dirname(self
.filepath
)
1125 for file in self
.files
:
1126 path
= os
.path
.join(dirname
, file.name
)
1127 if self
.unit_import(path
, import_settings
) == {'FINISHED'}:
1131 # Single file import
1132 return self
.unit_import(self
.filepath
, import_settings
)
1134 def unit_import(self
, filename
, import_settings
):
1136 from .io
.imp
.gltf2_io_gltf
import glTFImporter
, ImportError
1137 from .blender
.imp
.gltf2_blender_gltf
import BlenderGlTF
1140 gltf_importer
= glTFImporter(filename
, import_settings
)
1141 gltf_importer
.read()
1142 gltf_importer
.checks()
1144 print("Data are loaded, start creating Blender stuff")
1146 start_time
= time
.time()
1147 BlenderGlTF
.create(gltf_importer
)
1148 elapsed_s
= "{:.2f}s".format(time
.time() - start_time
)
1149 print("glTF import finished in " + elapsed_s
)
1151 gltf_importer
.log
.removeHandler(gltf_importer
.log_handler
)
1155 except ImportError as e
:
1156 self
.report({'ERROR'}, e
.args
[0])
1157 return {'CANCELLED'}
1159 def set_debug_log(self
):
1161 if bpy
.app
.debug_value
== 0:
1162 self
.loglevel
= logging
.CRITICAL
1163 elif bpy
.app
.debug_value
== 1:
1164 self
.loglevel
= logging
.ERROR
1165 elif bpy
.app
.debug_value
== 2:
1166 self
.loglevel
= logging
.WARNING
1167 elif bpy
.app
.debug_value
== 3:
1168 self
.loglevel
= logging
.INFO
1170 self
.loglevel
= logging
.NOTSET
1173 class GLTF_AddonPreferences(bpy
.types
.AddonPreferences
):
1174 bl_idname
= __package__
1176 settings_node_ui
: bpy
.props
.BoolProperty(
1178 description
="Displays glTF Settings node in Shader Editor (Menu Add > Output)"
1182 def draw(self
, context
):
1183 layout
= self
.layout
1185 row
.prop(self
, "settings_node_ui", text
="Shader Editor Add-ons")
1187 def menu_func_import(self
, context
):
1188 self
.layout
.operator(ImportGLTF2
.bl_idname
, text
='glTF 2.0 (.glb/.gltf)')
1193 GLTF_PT_export_main
,
1194 GLTF_PT_export_include
,
1195 GLTF_PT_export_transform
,
1196 GLTF_PT_export_geometry
,
1197 GLTF_PT_export_geometry_compression
,
1198 GLTF_PT_export_animation
,
1199 GLTF_PT_export_animation_export
,
1200 GLTF_PT_export_animation_shapekeys
,
1201 GLTF_PT_export_animation_skinning
,
1202 GLTF_PT_export_user_extensions
,
1204 GLTF_PT_import_user_extensions
,
1205 GLTF_AddonPreferences
1210 import io_scene_gltf2
.blender
.com
.gltf2_blender_ui
as blender_ui
1212 bpy
.utils
.register_class(c
)
1213 # bpy.utils.register_module(__name__)
1215 blender_ui
.register()
1217 # add to the export / import menu
1218 bpy
.types
.TOPBAR_MT_file_export
.append(menu_func_export
)
1219 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
1223 import io_scene_gltf2
.blender
.com
.gltf2_blender_ui
as blender_ui
1225 bpy
.utils
.unregister_class(c
)
1226 for f
in exporter_extension_panel_unregister_functors
:
1228 exporter_extension_panel_unregister_functors
.clear()
1230 for f
in importer_extension_panel_unregister_functors
:
1232 importer_extension_panel_unregister_functors
.clear()
1234 blender_ui
.unregister()
1236 # bpy.utils.unregister_module(__name__)
1238 # remove from the export / import menu
1239 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_func_export
)
1240 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)