1 # Copyright 2018-2021 The glTF-Blender-IO authors.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
16 'name': 'glTF 2.0 format',
17 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
18 "version": (1, 7, 17),
19 'blender': (2, 91, 0),
20 'location': 'File > Import-Export',
21 'description': 'Import-Export as glTF 2.0',
23 'doc_url': "{BLENDER_MANUAL_URL}/addons/import_export/scene_gltf2.html",
24 'tracker_url': "https://github.com/KhronosGroup/glTF-Blender-IO/issues/",
25 'support': 'OFFICIAL',
26 'category': 'Import-Export',
29 def get_version_string():
30 return str(bl_info
['version'][0]) + '.' + str(bl_info
['version'][1]) + '.' + str(bl_info
['version'][2])
33 # Script reloading (if the user calls 'Reload Scripts' from Blender)
36 def reload_package(module_dict_main
):
38 from pathlib
import Path
40 def reload_package_recursive(current_dir
, module_dict
):
41 for path
in current_dir
.iterdir():
42 if "__init__" in str(path
) or path
.stem
not in module_dict
:
45 if path
.is_file() and path
.suffix
== ".py":
46 importlib
.reload(module_dict
[path
.stem
])
48 reload_package_recursive(path
, module_dict
[path
.stem
].__dict
__)
50 reload_package_recursive(Path(__file__
).parent
, module_dict_main
)
54 reload_package(locals())
57 from bpy
.props
import (StringProperty
,
62 from bpy
.types
import Operator
63 from bpy_extras
.io_utils
import ImportHelper
, ExportHelper
67 # Functions / Classes.
70 extension_panel_unregister_functors
= []
73 def ensure_filepath_matches_export_format(filepath
, export_format
):
75 filename
= os
.path
.basename(filepath
)
79 stem
, ext
= os
.path
.splitext(filename
)
80 if stem
.startswith('.') and not ext
:
83 desired_ext
= '.glb' if export_format
== 'GLB' else '.gltf'
84 ext_lower
= ext
.lower()
85 if ext_lower
not in ['.glb', '.gltf']:
86 return filepath
+ desired_ext
87 elif ext_lower
!= desired_ext
:
88 filepath
= filepath
[:-len(ext
)] # strip off ext
89 return filepath
+ desired_ext
94 def on_export_format_changed(self
, context
):
95 # Update the filename in the file browser when the format (.glb/.gltf)
97 sfile
= context
.space_data
98 if not isinstance(sfile
, bpy
.types
.SpaceFileBrowser
):
100 if not sfile
.active_operator
:
102 if sfile
.active_operator
.bl_idname
!= "EXPORT_SCENE_OT_gltf":
105 sfile
.params
.filename
= ensure_filepath_matches_export_format(
106 sfile
.params
.filename
,
111 class ExportGLTF2_Base
:
112 # TODO: refactor to avoid boilerplate
115 from io_scene_gltf2
.io
.com
import gltf2_io_draco_compression_extension
116 self
.is_draco_available
= gltf2_io_draco_compression_extension
.dll_exists()
118 bl_options
= {'PRESET'}
120 export_format
: EnumProperty(
122 items
=(('GLB', 'glTF Binary (.glb)',
123 'Exports a single file, with all data packed in binary form. '
124 'Most efficient and portable, but more difficult to edit later'),
125 ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
126 'Exports a single file, with all data packed in JSON. '
127 'Less efficient than binary, but easier to edit later'),
128 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
129 'Exports multiple files, with separate JSON, binary and texture data. '
130 'Easiest to edit later')),
132 'Output format and embedding options. Binary is most efficient, '
133 'but JSON (embedded or separate) may be easier to edit later'
136 update
=on_export_format_changed
,
139 ui_tab
: EnumProperty(
140 items
=(('GENERAL', "General", "General settings"),
141 ('MESHES', "Meshes", "Mesh settings"),
142 ('OBJECTS', "Objects", "Object settings"),
143 ('ANIMATION', "Animation", "Animation settings")),
145 description
="Export setting categories",
148 export_copyright
: StringProperty(
150 description
='Legal rights and conditions for the model',
154 export_image_format
: EnumProperty(
156 items
=(('AUTO', 'Automatic',
157 'Save PNGs as PNGs and JPEGs as JPEGs. '
158 'If neither one, use PNG'),
159 ('JPEG', 'JPEG Format (.jpg)',
160 'Save images as JPEGs. (Images that need alpha are saved as PNGs though.) '
161 'Be aware of a possible loss in quality'),
164 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
165 'applications due to the smaller file size'
170 export_texture_dir
: StringProperty(
172 description
='Folder to place texture files in. Relative to the .gltf file',
176 export_keep_originals
: BoolProperty(
177 name
='Keep original',
178 description
=('Keep original textures files if possible. '
179 'WARNING: if you use more than one texture, '
180 'where pbr standard requires only one, only one texture will be used. '
181 'This can lead to unexpected results'
186 export_texcoords
: BoolProperty(
188 description
='Export UVs (texture coordinates) with meshes',
192 export_normals
: BoolProperty(
194 description
='Export vertex normals with meshes',
198 export_draco_mesh_compression_enable
: BoolProperty(
199 name
='Draco mesh compression',
200 description
='Compress mesh using Draco',
204 export_draco_mesh_compression_level
: IntProperty(
205 name
='Compression level',
206 description
='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
212 export_draco_position_quantization
: IntProperty(
213 name
='Position quantization bits',
214 description
='Quantization bits for position values (0 = no quantization)',
220 export_draco_normal_quantization
: IntProperty(
221 name
='Normal quantization bits',
222 description
='Quantization bits for normal values (0 = no quantization)',
228 export_draco_texcoord_quantization
: IntProperty(
229 name
='Texcoord quantization bits',
230 description
='Quantization bits for texture coordinate values (0 = no quantization)',
236 export_draco_color_quantization
: IntProperty(
237 name
='Color quantization bits',
238 description
='Quantization bits for color values (0 = no quantization)',
244 export_draco_generic_quantization
: IntProperty(
245 name
='Generic quantization bits',
246 description
='Quantization bits for generic coordinate values like weights or joints (0 = no quantization)',
252 export_tangents
: BoolProperty(
254 description
='Export vertex tangents with meshes',
258 export_materials
: EnumProperty(
260 items
=(('EXPORT', 'Export',
261 'Export all materials used by included objects'),
262 ('PLACEHOLDER', 'Placeholder',
263 'Do not export materials, but write multiple primitive groups per mesh, keeping material slot information'),
264 ('NONE', 'No export',
265 'Do not export materials, and combine mesh primitive groups, losing material slot information')),
266 description
='Export materials ',
270 export_colors
: BoolProperty(
271 name
='Vertex Colors',
272 description
='Export vertex colors with meshes',
276 use_mesh_edges
: BoolProperty(
279 'Export loose edges as lines, using the material from the first material slot'
284 use_mesh_vertices
: BoolProperty(
287 'Export loose points as glTF points, using the material from the first material slot'
292 export_cameras
: BoolProperty(
294 description
='Export cameras',
298 # keep it for compatibility (for now)
299 export_selected
: BoolProperty(
300 name
='Selected Objects',
301 description
='Export selected objects only',
305 use_selection
: BoolProperty(
306 name
='Selected Objects',
307 description
='Export selected objects only',
311 use_visible
: BoolProperty(
312 name
='Visible Objects',
313 description
='Export visible objects only',
317 use_renderable
: BoolProperty(
318 name
='Renderable Objects',
319 description
='Export renderable objects only',
323 use_active_collection
: BoolProperty(
324 name
='Active Collection',
325 description
='Export objects in the active collection only',
329 export_extras
: BoolProperty(
330 name
='Custom Properties',
331 description
='Export custom properties as glTF extras',
335 export_yup
: BoolProperty(
337 description
='Export using glTF convention, +Y up',
341 export_apply
: BoolProperty(
342 name
='Apply Modifiers',
343 description
='Apply modifiers (excluding Armatures) to mesh objects -'
344 'WARNING: prevents exporting shape keys',
348 export_animations
: BoolProperty(
350 description
='Exports active actions and NLA tracks as glTF animations',
354 export_frame_range
: BoolProperty(
355 name
='Limit to Playback Range',
356 description
='Clips animations to selected playback range',
360 export_frame_step
: IntProperty(
361 name
='Sampling Rate',
362 description
='How often to evaluate animated values (in frames)',
368 export_force_sampling
: BoolProperty(
369 name
='Always Sample Animations',
370 description
='Apply sampling to all animations',
374 export_nla_strips
: BoolProperty(
375 name
='Group by NLA Track',
377 "When on, multiple actions become part of the same glTF animation if "
378 "they're pushed onto NLA tracks with the same name. "
379 "When off, all the currently assigned actions become one glTF animation"
384 export_def_bones
: BoolProperty(
385 name
='Export Deformation Bones Only',
386 description
='Export Deformation bones only (and needed bones for hierarchy)',
390 export_current_frame
: BoolProperty(
391 name
='Use Current Frame',
392 description
='Export the scene in the current animation frame',
396 export_skins
: BoolProperty(
398 description
='Export skinning (armature) data',
402 export_all_influences
: BoolProperty(
403 name
='Include All Bone Influences',
404 description
='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
408 export_morph
: BoolProperty(
410 description
='Export shape keys (morph targets)',
414 export_morph_normal
: BoolProperty(
415 name
='Shape Key Normals',
416 description
='Export vertex normals with shape keys (morph targets)',
420 export_morph_tangent
: BoolProperty(
421 name
='Shape Key Tangents',
422 description
='Export vertex tangents with shape keys (morph targets)',
426 export_lights
: BoolProperty(
427 name
='Punctual Lights',
428 description
='Export directional, point, and spot lights. '
429 'Uses "KHR_lights_punctual" glTF extension',
433 export_displacement
: BoolProperty(
434 name
='Displacement Textures (EXPERIMENTAL)',
435 description
='EXPERIMENTAL: Export displacement textures. '
436 'Uses incomplete "KHR_materials_displacement" glTF extension',
440 will_save_settings
: BoolProperty(
441 name
='Remember Export Settings',
442 description
='Store glTF export settings in the Blender project',
445 # Custom scene property for saving settings
446 scene_key
= "glTF2ExportSettings"
450 def check(self
, _context
):
451 # Ensure file extension matches format
452 old_filepath
= self
.filepath
453 self
.filepath
= ensure_filepath_matches_export_format(
457 return self
.filepath
!= old_filepath
459 def invoke(self
, context
, event
):
460 settings
= context
.scene
.get(self
.scene_key
)
461 self
.will_save_settings
= False
464 for (k
, v
) in settings
.items():
465 if k
== "export_selected": # Back compatibility for export_selected --> use_selection
466 setattr(self
, "use_selection", v
)
468 settings
["use_selection"] = v
469 print("export_selected is now renamed use_selection, and will be deleted in a few release")
472 self
.will_save_settings
= True
474 except (AttributeError, TypeError):
475 self
.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
476 del context
.scene
[self
.scene_key
]
479 preferences
= bpy
.context
.preferences
480 for addon_name
in preferences
.addons
.keys():
482 if hasattr(sys
.modules
[addon_name
], 'glTF2ExportUserExtension') or hasattr(sys
.modules
[addon_name
], 'glTF2ExportUserExtensions'):
483 extension_panel_unregister_functors
.append(sys
.modules
[addon_name
].register_panel())
487 self
.has_active_extensions
= len(extension_panel_unregister_functors
) > 0
488 return ExportHelper
.invoke(self
, context
, event
)
490 def save_settings(self
, context
):
491 # find all props to save
493 # options that don't start with 'export_'
497 'use_active_collection',
501 all_props
= self
.properties
503 x
: getattr(self
, x
) for x
in dir(all_props
)
504 if (x
.startswith("export_") or x
in exceptional
) and all_props
.get(x
) is not None
507 context
.scene
[self
.scene_key
] = export_props
509 def execute(self
, context
):
512 from .blender
.exp
import gltf2_blender_export
514 if self
.will_save_settings
:
515 self
.save_settings(context
)
517 self
.check(context
) # ensure filepath has the right extension
519 # All custom export settings are stored in this container.
522 export_settings
['timestamp'] = datetime
.datetime
.now()
524 export_settings
['gltf_filepath'] = self
.filepath
525 export_settings
['gltf_filedirectory'] = os
.path
.dirname(export_settings
['gltf_filepath']) + '/'
526 export_settings
['gltf_texturedirectory'] = os
.path
.join(
527 export_settings
['gltf_filedirectory'],
528 self
.export_texture_dir
,
530 export_settings
['gltf_keep_original_textures'] = self
.export_keep_originals
532 export_settings
['gltf_format'] = self
.export_format
533 export_settings
['gltf_image_format'] = self
.export_image_format
534 export_settings
['gltf_copyright'] = self
.export_copyright
535 export_settings
['gltf_texcoords'] = self
.export_texcoords
536 export_settings
['gltf_normals'] = self
.export_normals
537 export_settings
['gltf_tangents'] = self
.export_tangents
and self
.export_normals
538 export_settings
['gltf_loose_edges'] = self
.use_mesh_edges
539 export_settings
['gltf_loose_points'] = self
.use_mesh_vertices
541 if self
.is_draco_available
:
542 export_settings
['gltf_draco_mesh_compression'] = self
.export_draco_mesh_compression_enable
543 export_settings
['gltf_draco_mesh_compression_level'] = self
.export_draco_mesh_compression_level
544 export_settings
['gltf_draco_position_quantization'] = self
.export_draco_position_quantization
545 export_settings
['gltf_draco_normal_quantization'] = self
.export_draco_normal_quantization
546 export_settings
['gltf_draco_texcoord_quantization'] = self
.export_draco_texcoord_quantization
547 export_settings
['gltf_draco_color_quantization'] = self
.export_draco_color_quantization
548 export_settings
['gltf_draco_generic_quantization'] = self
.export_draco_generic_quantization
550 export_settings
['gltf_draco_mesh_compression'] = False
552 export_settings
['gltf_materials'] = self
.export_materials
553 export_settings
['gltf_colors'] = self
.export_colors
554 export_settings
['gltf_cameras'] = self
.export_cameras
556 # compatibility after renaming export_selected to use_selection
557 if self
.export_selected
is True:
558 self
.report({"WARNING"}, "export_selected is now renamed use_selection, and will be deleted in a few release")
559 export_settings
['gltf_selected'] = self
.export_selected
561 export_settings
['gltf_selected'] = self
.use_selection
563 export_settings
['gltf_visible'] = self
.use_visible
564 export_settings
['gltf_renderable'] = self
.use_renderable
565 export_settings
['gltf_active_collection'] = self
.use_active_collection
567 # export_settings['gltf_selected'] = self.use_selection This can be uncomment when removing compatibility of export_selected
568 export_settings
['gltf_layers'] = True # self.export_layers
569 export_settings
['gltf_extras'] = self
.export_extras
570 export_settings
['gltf_yup'] = self
.export_yup
571 export_settings
['gltf_apply'] = self
.export_apply
572 export_settings
['gltf_current_frame'] = self
.export_current_frame
573 export_settings
['gltf_animations'] = self
.export_animations
574 if self
.export_animations
:
575 export_settings
['gltf_frame_range'] = self
.export_frame_range
576 export_settings
['gltf_force_sampling'] = self
.export_force_sampling
577 if self
.export_force_sampling
:
578 export_settings
['gltf_def_bones'] = self
.export_def_bones
580 export_settings
['gltf_def_bones'] = False
581 export_settings
['gltf_nla_strips'] = self
.export_nla_strips
583 export_settings
['gltf_frame_range'] = False
584 export_settings
['gltf_move_keyframes'] = False
585 export_settings
['gltf_force_sampling'] = False
586 export_settings
['gltf_def_bones'] = False
587 export_settings
['gltf_skins'] = self
.export_skins
588 if self
.export_skins
:
589 export_settings
['gltf_all_vertex_influences'] = self
.export_all_influences
591 export_settings
['gltf_all_vertex_influences'] = False
592 export_settings
['gltf_frame_step'] = self
.export_frame_step
593 export_settings
['gltf_morph'] = self
.export_morph
594 if self
.export_morph
:
595 export_settings
['gltf_morph_normal'] = self
.export_morph_normal
597 export_settings
['gltf_morph_normal'] = False
598 if self
.export_morph
and self
.export_morph_normal
:
599 export_settings
['gltf_morph_tangent'] = self
.export_morph_tangent
601 export_settings
['gltf_morph_tangent'] = False
603 export_settings
['gltf_lights'] = self
.export_lights
604 export_settings
['gltf_displacement'] = self
.export_displacement
606 export_settings
['gltf_binary'] = bytearray()
607 export_settings
['gltf_binaryfilename'] = (
608 os
.path
.splitext(os
.path
.basename(self
.filepath
))[0] + '.bin'
612 pre_export_callbacks
= []
613 post_export_callbacks
= []
616 preferences
= bpy
.context
.preferences
617 for addon_name
in preferences
.addons
.keys():
619 module
= sys
.modules
[addon_name
]
622 if hasattr(module
, 'glTF2ExportUserExtension'):
623 extension_ctor
= module
.glTF2ExportUserExtension
624 user_extensions
.append(extension_ctor())
625 if hasattr(module
, 'glTF2ExportUserExtensions'):
626 extension_ctors
= module
.glTF2ExportUserExtensions
627 for extension_ctor
in extension_ctors
:
628 user_extensions
.append(extension_ctor())
629 if hasattr(module
, 'glTF2_pre_export_callback'):
630 pre_export_callbacks
.append(module
.glTF2_pre_export_callback
)
631 if hasattr(module
, 'glTF2_post_export_callback'):
632 post_export_callbacks
.append(module
.glTF2_post_export_callback
)
633 export_settings
['gltf_user_extensions'] = user_extensions
634 export_settings
['pre_export_callbacks'] = pre_export_callbacks
635 export_settings
['post_export_callbacks'] = post_export_callbacks
637 return gltf2_blender_export
.save(context
, export_settings
)
639 def draw(self
, context
):
640 pass # Is needed to get panels available
643 class GLTF_PT_export_main(bpy
.types
.Panel
):
644 bl_space_type
= 'FILE_BROWSER'
645 bl_region_type
= 'TOOL_PROPS'
647 bl_parent_id
= "FILE_PT_operator"
648 bl_options
= {'HIDE_HEADER'}
651 def poll(cls
, context
):
652 sfile
= context
.space_data
653 operator
= sfile
.active_operator
655 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
657 def draw(self
, context
):
659 layout
.use_property_split
= True
660 layout
.use_property_decorate
= False # No animation.
662 sfile
= context
.space_data
663 operator
= sfile
.active_operator
665 layout
.prop(operator
, 'export_format')
666 if operator
.export_format
== 'GLTF_SEPARATE':
667 layout
.prop(operator
, 'export_keep_originals')
668 if operator
.export_keep_originals
is False:
669 layout
.prop(operator
, 'export_texture_dir', icon
='FILE_FOLDER')
671 layout
.prop(operator
, 'export_copyright')
672 layout
.prop(operator
, 'will_save_settings')
675 class GLTF_PT_export_include(bpy
.types
.Panel
):
676 bl_space_type
= 'FILE_BROWSER'
677 bl_region_type
= 'TOOL_PROPS'
679 bl_parent_id
= "FILE_PT_operator"
680 bl_options
= {'DEFAULT_CLOSED'}
683 def poll(cls
, context
):
684 sfile
= context
.space_data
685 operator
= sfile
.active_operator
687 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
689 def draw(self
, context
):
691 layout
.use_property_split
= True
692 layout
.use_property_decorate
= False # No animation.
694 sfile
= context
.space_data
695 operator
= sfile
.active_operator
697 col
= layout
.column(heading
= "Limit to", align
= True)
698 col
.prop(operator
, 'use_selection')
699 col
.prop(operator
, 'use_visible')
700 col
.prop(operator
, 'use_renderable')
701 col
.prop(operator
, 'use_active_collection')
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')
876 row
.active
= operator
.export_force_sampling
877 row
.prop(operator
, 'export_def_bones')
880 class GLTF_PT_export_animation_shapekeys(bpy
.types
.Panel
):
881 bl_space_type
= 'FILE_BROWSER'
882 bl_region_type
= 'TOOL_PROPS'
883 bl_label
= "Shape Keys"
884 bl_parent_id
= "GLTF_PT_export_animation"
885 bl_options
= {'DEFAULT_CLOSED'}
888 def poll(cls
, context
):
889 sfile
= context
.space_data
890 operator
= sfile
.active_operator
892 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
894 def draw_header(self
, context
):
895 sfile
= context
.space_data
896 operator
= sfile
.active_operator
897 self
.layout
.prop(operator
, "export_morph", text
="")
899 def draw(self
, context
):
901 layout
.use_property_split
= True
902 layout
.use_property_decorate
= False # No animation.
904 sfile
= context
.space_data
905 operator
= sfile
.active_operator
907 layout
.active
= operator
.export_morph
909 layout
.prop(operator
, 'export_morph_normal')
910 col
= layout
.column()
911 col
.active
= operator
.export_morph_normal
912 col
.prop(operator
, 'export_morph_tangent')
915 class GLTF_PT_export_animation_skinning(bpy
.types
.Panel
):
916 bl_space_type
= 'FILE_BROWSER'
917 bl_region_type
= 'TOOL_PROPS'
918 bl_label
= "Skinning"
919 bl_parent_id
= "GLTF_PT_export_animation"
920 bl_options
= {'DEFAULT_CLOSED'}
923 def poll(cls
, context
):
924 sfile
= context
.space_data
925 operator
= sfile
.active_operator
927 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf"
929 def draw_header(self
, context
):
930 sfile
= context
.space_data
931 operator
= sfile
.active_operator
932 self
.layout
.prop(operator
, "export_skins", text
="")
934 def draw(self
, context
):
936 layout
.use_property_split
= True
937 layout
.use_property_decorate
= False # No animation.
939 sfile
= context
.space_data
940 operator
= sfile
.active_operator
942 layout
.active
= operator
.export_skins
943 layout
.prop(operator
, 'export_all_influences')
945 class GLTF_PT_export_user_extensions(bpy
.types
.Panel
):
946 bl_space_type
= 'FILE_BROWSER'
947 bl_region_type
= 'TOOL_PROPS'
948 bl_label
= "Extensions"
949 bl_parent_id
= "FILE_PT_operator"
950 bl_options
= {'DEFAULT_CLOSED'}
953 def poll(cls
, context
):
954 sfile
= context
.space_data
955 operator
= sfile
.active_operator
957 return operator
.bl_idname
== "EXPORT_SCENE_OT_gltf" and operator
.has_active_extensions
959 def draw(self
, context
):
961 layout
.use_property_split
= True
962 layout
.use_property_decorate
= False # No animation.
965 class ExportGLTF2(bpy
.types
.Operator
, ExportGLTF2_Base
, ExportHelper
):
966 """Export scene as glTF 2.0 file"""
967 bl_idname
= 'export_scene.gltf'
968 bl_label
= 'Export glTF 2.0'
972 filter_glob
: StringProperty(default
='*.glb;*.gltf', options
={'HIDDEN'})
975 def menu_func_export(self
, context
):
976 self
.layout
.operator(ExportGLTF2
.bl_idname
, text
='glTF 2.0 (.glb/.gltf)')
979 class ImportGLTF2(Operator
, ImportHelper
):
980 """Load a glTF 2.0 file"""
981 bl_idname
= 'import_scene.gltf'
982 bl_label
= 'Import glTF 2.0'
983 bl_options
= {'REGISTER', 'UNDO'}
985 filter_glob
: StringProperty(default
="*.glb;*.gltf", options
={'HIDDEN'})
987 files
: CollectionProperty(
989 type=bpy
.types
.OperatorFileListElement
,
992 loglevel
: IntProperty(
994 description
="Log Level")
996 import_pack_images
: BoolProperty(
998 description
='Pack all images into .blend file',
1002 merge_vertices
: BoolProperty(
1003 name
='Merge Vertices',
1005 'The glTF format requires discontinuous normals, UVs, and '
1006 'other vertex attributes to be stored as separate vertices, '
1007 'as required for rendering on typical graphics hardware. '
1008 'This option attempts to combine co-located vertices where possible. '
1009 'Currently cannot combine verts with different normals'
1014 import_shading
: EnumProperty(
1016 items
=(("NORMALS", "Use Normal Data", ""),
1017 ("FLAT", "Flat Shading", ""),
1018 ("SMOOTH", "Smooth Shading", "")),
1019 description
="How normals are computed during import",
1022 bone_heuristic
: EnumProperty(
1025 ("BLENDER", "Blender (best for re-importing)",
1026 "Good for re-importing glTFs exported from Blender. "
1027 "Bone tips are placed on their local +Y axis (in glTF space)"),
1028 ("TEMPERANCE", "Temperance (average)",
1029 "Decent all-around strategy. "
1030 "A bone with one child has its tip placed on the local axis "
1031 "closest to its child"),
1032 ("FORTUNE", "Fortune (may look better, less accurate)",
1033 "Might look better than Temperance, but also might have errors. "
1034 "A bone with one child has its tip placed at its child's root. "
1035 "Non-uniform scalings may get messed up though, so beware"),
1037 description
="Heuristic for placing bones. Tries to make bones pretty",
1038 default
="TEMPERANCE",
1041 guess_original_bind_pose
: BoolProperty(
1042 name
='Guess Original Bind Pose',
1044 'Try to guess the original bind pose for skinned meshes from '
1045 'the inverse bind matrices. '
1046 'When off, use default/rest pose as bind pose'
1051 def draw(self
, context
):
1052 layout
= self
.layout
1054 layout
.use_property_split
= True
1055 layout
.use_property_decorate
= False # No animation.
1057 layout
.prop(self
, 'import_pack_images')
1058 layout
.prop(self
, 'merge_vertices')
1059 layout
.prop(self
, 'import_shading')
1060 layout
.prop(self
, 'guess_original_bind_pose')
1061 layout
.prop(self
, 'bone_heuristic')
1063 def execute(self
, context
):
1064 return self
.import_gltf2(context
)
1066 def import_gltf2(self
, context
):
1069 self
.set_debug_log()
1070 import_settings
= self
.as_keywords()
1073 # Multiple file import
1075 dirname
= os
.path
.dirname(self
.filepath
)
1076 for file in self
.files
:
1077 path
= os
.path
.join(dirname
, file.name
)
1078 if self
.unit_import(path
, import_settings
) == {'FINISHED'}:
1082 # Single file import
1083 return self
.unit_import(self
.filepath
, import_settings
)
1085 def unit_import(self
, filename
, import_settings
):
1087 from .io
.imp
.gltf2_io_gltf
import glTFImporter
, ImportError
1088 from .blender
.imp
.gltf2_blender_gltf
import BlenderGlTF
1091 gltf_importer
= glTFImporter(filename
, import_settings
)
1092 gltf_importer
.read()
1093 gltf_importer
.checks()
1095 print("Data are loaded, start creating Blender stuff")
1097 start_time
= time
.time()
1098 BlenderGlTF
.create(gltf_importer
)
1099 elapsed_s
= "{:.2f}s".format(time
.time() - start_time
)
1100 print("glTF import finished in " + elapsed_s
)
1102 gltf_importer
.log
.removeHandler(gltf_importer
.log_handler
)
1106 except ImportError as e
:
1107 self
.report({'ERROR'}, e
.args
[0])
1108 return {'CANCELLED'}
1110 def set_debug_log(self
):
1112 if bpy
.app
.debug_value
== 0:
1113 self
.loglevel
= logging
.CRITICAL
1114 elif bpy
.app
.debug_value
== 1:
1115 self
.loglevel
= logging
.ERROR
1116 elif bpy
.app
.debug_value
== 2:
1117 self
.loglevel
= logging
.WARNING
1118 elif bpy
.app
.debug_value
== 3:
1119 self
.loglevel
= logging
.INFO
1121 self
.loglevel
= logging
.NOTSET
1124 def menu_func_import(self
, context
):
1125 self
.layout
.operator(ImportGLTF2
.bl_idname
, text
='glTF 2.0 (.glb/.gltf)')
1130 GLTF_PT_export_main
,
1131 GLTF_PT_export_include
,
1132 GLTF_PT_export_transform
,
1133 GLTF_PT_export_geometry
,
1134 GLTF_PT_export_geometry_compression
,
1135 GLTF_PT_export_animation
,
1136 GLTF_PT_export_animation_export
,
1137 GLTF_PT_export_animation_shapekeys
,
1138 GLTF_PT_export_animation_skinning
,
1139 GLTF_PT_export_user_extensions
,
1146 bpy
.utils
.register_class(c
)
1147 # bpy.utils.register_module(__name__)
1149 # add to the export / import menu
1150 bpy
.types
.TOPBAR_MT_file_export
.append(menu_func_export
)
1151 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
1156 bpy
.utils
.unregister_class(c
)
1157 for f
in extension_panel_unregister_functors
:
1159 extension_panel_unregister_functors
.clear()
1161 # bpy.utils.unregister_module(__name__)
1163 # remove from the export / import menu
1164 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_func_export
)
1165 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)