Merge branch 'blender-v3.5-release'
[blender-addons.git] / io_scene_gltf2 / __init__.py
blob49252dffe25bca2f05b76ae5c7e5a0ef9bbee6e9
1 # SPDX-License-Identifier: Apache-2.0
2 # Copyright 2018-2021 The glTF-Blender-IO authors.
4 bl_info = {
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',
7 "version": (3, 6, 4),
8 'blender': (3, 5, 0),
9 'location': 'File > Import-Export',
10 'description': 'Import-Export as glTF 2.0',
11 'warning': '',
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):
26 import importlib
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:
32 continue
34 if path.is_file() and path.suffix == ".py":
35 importlib.reload(module_dict[path.stem])
36 elif path.is_dir():
37 reload_package_recursive(path, module_dict[path.stem].__dict__)
39 reload_package_recursive(Path(__file__).parent, module_dict_main)
42 if "bpy" in locals():
43 reload_package(locals())
45 import bpy
46 from bpy.props import (StringProperty,
47 BoolProperty,
48 EnumProperty,
49 IntProperty,
50 CollectionProperty)
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):
64 import os
65 filename = os.path.basename(filepath)
66 if not filename:
67 return filepath
69 stem, ext = os.path.splitext(filename)
70 if stem.startswith('.') and not ext:
71 stem, ext = '', stem
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
80 else:
81 return filepath
84 def on_export_format_changed(self, context):
85 # Update the filename in the file browser when the format (.glb/.gltf)
86 # changes
87 sfile = context.space_data
88 if not isinstance(sfile, bpy.types.SpaceFileBrowser):
89 return
90 if not sfile.active_operator:
91 return
92 if sfile.active_operator.bl_idname != "EXPORT_SCENE_OT_gltf":
93 return
95 sfile.params.filename = ensure_filepath_matches_export_format(
96 sfile.params.filename,
97 self.export_format,
100 # Also change the filter
101 sfile.params.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf'
102 # Force update of file list, has update the filter does not update the real file list
103 bpy.ops.file.refresh()
106 class ConvertGLTF2_Base:
107 """Base class containing options that should be exposed during both import and export."""
109 convert_lighting_mode: EnumProperty(
110 name='Lighting Mode',
111 items=(
112 ('SPEC', 'Standard', 'Physically-based glTF lighting units (cd, lx, nt)'),
113 ('COMPAT', 'Unitless', 'Non-physical, unitless lighting. Useful when exposure controls are not available'),
114 ('RAW', 'Raw (Deprecated)', 'Blender lighting strengths with no conversion'),
116 description='Optional backwards compatibility for non-standard render engines. Applies to lights',# TODO: and emissive materials',
117 default='SPEC'
120 class ExportGLTF2_Base(ConvertGLTF2_Base):
121 # TODO: refactor to avoid boilerplate
123 def __init__(self):
124 from .io.com import gltf2_io_draco_compression_extension
125 self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists()
127 bl_options = {'PRESET'}
129 # Don't use export_ prefix here, I don't want it to be saved with other export settings
130 gltf_export_id: StringProperty(
131 name='Identifier',
132 description=(
133 'Identifier of caller (in case of add-on calling this exporter). '
134 'Can be useful in case of Extension added by other add-ons'
136 default=''
139 export_format: EnumProperty(
140 name='Format',
141 items=(('GLB', 'glTF Binary (.glb)',
142 'Exports a single file, with all data packed in binary form. '
143 'Most efficient and portable, but more difficult to edit later'),
144 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
145 'Exports multiple files, with separate JSON, binary and texture data. '
146 'Easiest to edit later'),
147 ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
148 'Exports a single file, with all data packed in JSON. '
149 'Less efficient than binary, but easier to edit later')),
150 description=(
151 'Output format and embedding options. Binary is most efficient, '
152 'but JSON (embedded or separate) may be easier to edit later'
154 default='GLB', #Warning => If you change the default, need to change the default filter too
155 update=on_export_format_changed,
158 ui_tab: EnumProperty(
159 items=(('GENERAL', "General", "General settings"),
160 ('MESHES', "Meshes", "Mesh settings"),
161 ('OBJECTS', "Objects", "Object settings"),
162 ('ANIMATION', "Animation", "Animation settings")),
163 name="ui_tab",
164 description="Export setting categories",
167 export_copyright: StringProperty(
168 name='Copyright',
169 description='Legal rights and conditions for the model',
170 default=''
173 export_image_format: EnumProperty(
174 name='Images',
175 items=(('AUTO', 'Automatic',
176 'Save PNGs as PNGs and JPEGs as JPEGs. '
177 'If neither one, use PNG'),
178 ('JPEG', 'JPEG Format (.jpg)',
179 'Save images as JPEGs. (Images that need alpha are saved as PNGs though.) '
180 'Be aware of a possible loss in quality'),
181 ('NONE', 'None',
182 'Don\'t export images'),
184 description=(
185 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
186 'applications due to the smaller file size. Alternatively they can be omitted if they are not needed'
188 default='AUTO'
191 export_texture_dir: StringProperty(
192 name='Textures',
193 description='Folder to place texture files in. Relative to the .gltf file',
194 default='',
197 export_jpeg_quality: IntProperty(
198 name='JPEG quality',
199 description='Quality of JPEG export',
200 default=75,
201 min=0,
202 max=100
205 export_keep_originals: BoolProperty(
206 name='Keep original',
207 description=('Keep original textures files if possible. '
208 'WARNING: if you use more than one texture, '
209 'where pbr standard requires only one, only one texture will be used. '
210 'This can lead to unexpected results'
212 default=False,
215 export_texcoords: BoolProperty(
216 name='UVs',
217 description='Export UVs (texture coordinates) with meshes',
218 default=True
221 export_normals: BoolProperty(
222 name='Normals',
223 description='Export vertex normals with meshes',
224 default=True
227 export_draco_mesh_compression_enable: BoolProperty(
228 name='Draco mesh compression',
229 description='Compress mesh using Draco',
230 default=False
233 export_draco_mesh_compression_level: IntProperty(
234 name='Compression level',
235 description='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
236 default=6,
237 min=0,
238 max=10
241 export_draco_position_quantization: IntProperty(
242 name='Position quantization bits',
243 description='Quantization bits for position values (0 = no quantization)',
244 default=14,
245 min=0,
246 max=30
249 export_draco_normal_quantization: IntProperty(
250 name='Normal quantization bits',
251 description='Quantization bits for normal values (0 = no quantization)',
252 default=10,
253 min=0,
254 max=30
257 export_draco_texcoord_quantization: IntProperty(
258 name='Texcoord quantization bits',
259 description='Quantization bits for texture coordinate values (0 = no quantization)',
260 default=12,
261 min=0,
262 max=30
265 export_draco_color_quantization: IntProperty(
266 name='Color quantization bits',
267 description='Quantization bits for color values (0 = no quantization)',
268 default=10,
269 min=0,
270 max=30
273 export_draco_generic_quantization: IntProperty(
274 name='Generic quantization bits',
275 description='Quantization bits for generic coordinate values like weights or joints (0 = no quantization)',
276 default=12,
277 min=0,
278 max=30
281 export_tangents: BoolProperty(
282 name='Tangents',
283 description='Export vertex tangents with meshes',
284 default=False
287 export_materials: EnumProperty(
288 name='Materials',
289 items=(('EXPORT', 'Export',
290 'Export all materials used by included objects'),
291 ('PLACEHOLDER', 'Placeholder',
292 'Do not export materials, but write multiple primitive groups per mesh, keeping material slot information'),
293 ('NONE', 'No export',
294 'Do not export materials, and combine mesh primitive groups, losing material slot information')),
295 description='Export materials',
296 default='EXPORT'
299 export_original_specular: BoolProperty(
300 name='Export original PBR Specular',
301 description=(
302 'Export original glTF PBR Specular, instead of Blender Principled Shader Specular'
304 default=False,
307 export_colors: BoolProperty(
308 name='Vertex Colors',
309 description='Export vertex colors with meshes',
310 default=True
313 export_attributes: BoolProperty(
314 name='Attributes',
315 description='Export Attributes (when starting with underscore)',
316 default=False
319 use_mesh_edges: BoolProperty(
320 name='Loose Edges',
321 description=(
322 'Export loose edges as lines, using the material from the first material slot'
324 default=False,
327 use_mesh_vertices: BoolProperty(
328 name='Loose Points',
329 description=(
330 'Export loose points as glTF points, using the material from the first material slot'
332 default=False,
335 export_cameras: BoolProperty(
336 name='Cameras',
337 description='Export cameras',
338 default=False
341 use_selection: BoolProperty(
342 name='Selected Objects',
343 description='Export selected objects only',
344 default=False
347 use_visible: BoolProperty(
348 name='Visible Objects',
349 description='Export visible objects only',
350 default=False
353 use_renderable: BoolProperty(
354 name='Renderable Objects',
355 description='Export renderable objects only',
356 default=False
359 use_active_collection_with_nested: BoolProperty(
360 name='Include Nested Collections',
361 description='Include active collection and nested collections',
362 default=True
365 use_active_collection: BoolProperty(
366 name='Active Collection',
367 description='Export objects in the active collection only',
368 default=False
371 use_active_scene: BoolProperty(
372 name='Active Scene',
373 description='Export active scene only',
374 default=False
377 export_extras: BoolProperty(
378 name='Custom Properties',
379 description='Export custom properties as glTF extras',
380 default=False
383 export_yup: BoolProperty(
384 name='+Y Up',
385 description='Export using glTF convention, +Y up',
386 default=True
389 export_apply: BoolProperty(
390 name='Apply Modifiers',
391 description='Apply modifiers (excluding Armatures) to mesh objects -'
392 'WARNING: prevents exporting shape keys',
393 default=False
396 export_animations: BoolProperty(
397 name='Animations',
398 description='Exports active actions and NLA tracks as glTF animations',
399 default=True
402 export_frame_range: BoolProperty(
403 name='Limit to Playback Range',
404 description='Clips animations to selected playback range',
405 default=False
408 export_frame_step: IntProperty(
409 name='Sampling Rate',
410 description='How often to evaluate animated values (in frames)',
411 default=1,
412 min=1,
413 max=120
416 export_force_sampling: BoolProperty(
417 name='Always Sample Animations',
418 description='Apply sampling to all animations',
419 default=True
422 export_animation_mode: EnumProperty(
423 name='Animation mode',
424 items=(('ACTIONS', 'Actions',
425 'Export actions (actives and on NLA tracks) as separate animations'),
426 ('ACTIVE_ACTIONS', 'Active actions merged',
427 'All the currently assigned actions become one glTF animation'),
428 ('NLA_TRACKS', 'NLA Tracks',
429 'Export individual NLA Tracks as separate animation'),
430 ('SCENE', 'Scene',
431 'Export baked scene as a single animation')
433 description='Export Animation mode',
434 default='ACTIONS'
437 export_nla_strips_merged_animation_name: StringProperty(
438 name='Merged Animation Name',
439 description=(
440 "Name of single glTF animation to be exported"
442 default='Animation'
445 export_def_bones: BoolProperty(
446 name='Export Deformation Bones Only',
447 description='Export Deformation bones only',
448 default=False
451 export_hierarchy_flatten_bones: BoolProperty(
452 name='Flatten Bone Hierarchy',
453 description='Flatten Bone Hierarchy. Usefull in case of non decomposable TRS matrix',
454 default=False
457 export_optimize_animation_size: BoolProperty(
458 name='Optimize Animation Size',
459 description=(
460 "Reduce exported file size by removing duplicate keyframes "
461 "(can cause problems with stepped animation)"
463 default=True
466 export_optimize_animation_keep_anim_armature: BoolProperty(
467 name='Force keeping channel for armature / bones',
468 description=(
469 "if all keyframes are identical in a rig "
470 "force keeping the minimal animation"
472 default=True
475 export_optimize_animation_keep_anim_object: BoolProperty(
476 name='Force keeping channel for objects',
477 description=(
478 "if all keyframes are identical for object transformations "
479 "force keeping the minimal animation"
481 default=False
484 export_negative_frame: EnumProperty(
485 name='Negative Frames',
486 items=(('SLIDE', 'Slide',
487 'Slide animation to start at frame 0'),
488 ('CROP', 'Crop',
489 'Keep only frames above frame 0'),
491 description='Negative Frames are slided or cropped',
492 default='SLIDE'
495 export_anim_slide_to_zero: BoolProperty(
496 name='Set all glTF Animation starting at 0',
497 description=(
498 "Set all glTF animation starting at 0.0s. "
499 "Can be usefull for looping animations"
501 default=False
504 export_bake_animation: BoolProperty(
505 name='Bake All Objects Animations',
506 description=(
507 "Force exporting animation on every objects. "
508 "Can be usefull when using constraints or driver. "
509 "Also useful when exporting only selection"
511 default=False
514 export_anim_single_armature: BoolProperty(
515 name='Export all Armature Actions',
516 description=(
517 "Export all actions, bound to a single armature. "
518 "WARNING: Option does not support exports including multiple armatures"
520 default=True
523 export_reset_pose_bones: BoolProperty(
524 name='Reset pose bones between actions',
525 description=(
526 "Reset pose bones between each action exported. "
527 "This is needed when some bones are not keyed on some animations"
529 default=True
532 export_current_frame: BoolProperty(
533 name='Use Current Frame as Object Rest Transformations',
534 description=(
535 'Export the scene in the current animation frame. '
536 'When off, frame O is used as rest transformations for objects'
538 default=False
541 export_rest_position_armature: BoolProperty(
542 name='Use Rest Position Armature',
543 description=(
544 "Export armatures using rest position as joins rest pose. "
545 "When off, current frame pose is used as rest pose"
547 default=True
550 export_anim_scene_split_object: BoolProperty(
551 name='Split Animation by Object',
552 description=(
553 "Export Scene as seen in Viewport, "
554 "But split animation by Object"
556 default=True
559 export_skins: BoolProperty(
560 name='Skinning',
561 description='Export skinning (armature) data',
562 default=True
565 export_all_influences: BoolProperty(
566 name='Include All Bone Influences',
567 description='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
568 default=False
571 export_morph: BoolProperty(
572 name='Shape Keys',
573 description='Export shape keys (morph targets)',
574 default=True
577 export_morph_normal: BoolProperty(
578 name='Shape Key Normals',
579 description='Export vertex normals with shape keys (morph targets)',
580 default=True
583 export_morph_tangent: BoolProperty(
584 name='Shape Key Tangents',
585 description='Export vertex tangents with shape keys (morph targets)',
586 default=False
589 export_morph_animation: BoolProperty(
590 name='Shape Key Animations',
591 description='Export shape keys animations (morph targets)',
592 default=True
595 export_lights: BoolProperty(
596 name='Punctual Lights',
597 description='Export directional, point, and spot lights. '
598 'Uses "KHR_lights_punctual" glTF extension',
599 default=False
602 will_save_settings: BoolProperty(
603 name='Remember Export Settings',
604 description='Store glTF export settings in the Blender project',
605 default=False)
607 # Custom scene property for saving settings
608 scene_key = "glTF2ExportSettings"
612 def check(self, _context):
613 # Ensure file extension matches format
614 old_filepath = self.filepath
615 self.filepath = ensure_filepath_matches_export_format(
616 self.filepath,
617 self.export_format,
619 return self.filepath != old_filepath
621 def invoke(self, context, event):
622 settings = context.scene.get(self.scene_key)
623 self.will_save_settings = False
624 if settings:
625 try:
626 for (k, v) in settings.items():
627 setattr(self, k, v)
628 self.will_save_settings = True
630 except (AttributeError, TypeError):
631 self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
632 del context.scene[self.scene_key]
634 import sys
635 preferences = bpy.context.preferences
636 for addon_name in preferences.addons.keys():
637 try:
638 if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ExportUserExtensions'):
639 exporter_extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
640 except Exception:
641 pass
643 self.has_active_exporter_extensions = len(exporter_extension_panel_unregister_functors) > 0
644 return ExportHelper.invoke(self, context, event)
646 def save_settings(self, context):
647 # find all props to save
648 exceptional = [
649 # options that don't start with 'export_'
650 'use_selection',
651 'use_visible',
652 'use_renderable',
653 'use_active_collection_with_nested',
654 'use_active_collection',
655 'use_mesh_edges',
656 'use_mesh_vertices',
657 'use_active_scene',
659 all_props = self.properties
660 export_props = {
661 x: getattr(self, x) for x in dir(all_props)
662 if (x.startswith("export_") or x in exceptional) and all_props.get(x) is not None
664 context.scene[self.scene_key] = export_props
666 def execute(self, context):
667 import os
668 import datetime
669 from .blender.exp import gltf2_blender_export
670 from .io.com.gltf2_io_path import path_to_uri
672 if self.will_save_settings:
673 self.save_settings(context)
675 self.check(context) # ensure filepath has the right extension
677 # All custom export settings are stored in this container.
678 export_settings = {}
680 export_settings['timestamp'] = datetime.datetime.now()
681 export_settings['gltf_export_id'] = self.gltf_export_id
682 export_settings['gltf_filepath'] = self.filepath
683 export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
684 export_settings['gltf_texturedirectory'] = os.path.join(
685 export_settings['gltf_filedirectory'],
686 self.export_texture_dir,
688 export_settings['gltf_keep_original_textures'] = self.export_keep_originals
690 export_settings['gltf_format'] = self.export_format
691 export_settings['gltf_image_format'] = self.export_image_format
692 export_settings['gltf_jpeg_quality'] = self.export_jpeg_quality
693 export_settings['gltf_copyright'] = self.export_copyright
694 export_settings['gltf_texcoords'] = self.export_texcoords
695 export_settings['gltf_normals'] = self.export_normals
696 export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
697 export_settings['gltf_loose_edges'] = self.use_mesh_edges
698 export_settings['gltf_loose_points'] = self.use_mesh_vertices
700 if self.is_draco_available:
701 export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
702 export_settings['gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level
703 export_settings['gltf_draco_position_quantization'] = self.export_draco_position_quantization
704 export_settings['gltf_draco_normal_quantization'] = self.export_draco_normal_quantization
705 export_settings['gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization
706 export_settings['gltf_draco_color_quantization'] = self.export_draco_color_quantization
707 export_settings['gltf_draco_generic_quantization'] = self.export_draco_generic_quantization
708 else:
709 export_settings['gltf_draco_mesh_compression'] = False
711 export_settings['gltf_materials'] = self.export_materials
712 export_settings['gltf_colors'] = self.export_colors
713 export_settings['gltf_attributes'] = self.export_attributes
714 export_settings['gltf_cameras'] = self.export_cameras
716 export_settings['gltf_original_specular'] = self.export_original_specular
718 export_settings['gltf_visible'] = self.use_visible
719 export_settings['gltf_renderable'] = self.use_renderable
721 export_settings['gltf_active_collection'] = self.use_active_collection
722 if self.use_active_collection:
723 export_settings['gltf_active_collection_with_nested'] = self.use_active_collection_with_nested
724 else:
725 export_settings['gltf_active_collection_with_nested'] = False
726 export_settings['gltf_active_scene'] = self.use_active_scene
728 export_settings['gltf_selected'] = self.use_selection
729 export_settings['gltf_layers'] = True # self.export_layers
730 export_settings['gltf_extras'] = self.export_extras
731 export_settings['gltf_yup'] = self.export_yup
732 export_settings['gltf_apply'] = self.export_apply
733 export_settings['gltf_current_frame'] = self.export_current_frame
734 export_settings['gltf_animations'] = self.export_animations
735 export_settings['gltf_def_bones'] = self.export_def_bones
736 export_settings['gltf_flatten_bones_hierarchy'] = self.export_hierarchy_flatten_bones
737 if self.export_animations:
738 export_settings['gltf_frame_range'] = self.export_frame_range
739 export_settings['gltf_force_sampling'] = self.export_force_sampling
740 if not self.export_force_sampling:
741 export_settings['gltf_def_bones'] = False
742 export_settings['gltf_bake_animation'] = False
743 export_settings['gltf_animation_mode'] = self.export_animation_mode
744 if export_settings['gltf_animation_mode'] == "NLA_TRACKS":
745 export_settings['gltf_force_sampling'] = True
746 if export_settings['gltf_animation_mode'] == "SCENE":
747 export_settings['gltf_anim_scene_split_object'] = self.export_anim_scene_split_object
748 else:
749 export_settings['gltf_anim_scene_split_object'] = False
751 export_settings['gltf_nla_strips_merged_animation_name'] = self.export_nla_strips_merged_animation_name
752 export_settings['gltf_optimize_animation'] = self.export_optimize_animation_size
753 export_settings['gltf_optimize_animation_keep_armature'] = self.export_optimize_animation_keep_anim_armature
754 export_settings['gltf_optimize_animation_keep_object'] = self.export_optimize_animation_keep_anim_object
755 export_settings['gltf_export_anim_single_armature'] = self.export_anim_single_armature
756 export_settings['gltf_export_reset_pose_bones'] = self.export_reset_pose_bones
757 export_settings['gltf_bake_animation'] = self.export_bake_animation
758 export_settings['gltf_negative_frames'] = self.export_negative_frame
759 export_settings['gltf_anim_slide_to_zero'] = self.export_anim_slide_to_zero
760 else:
761 export_settings['gltf_frame_range'] = False
762 export_settings['gltf_force_sampling'] = False
763 export_settings['gltf_bake_animation'] = False
764 export_settings['gltf_optimize_animation'] = False
765 export_settings['gltf_optimize_animation_keep_armature'] = False
766 export_settings['gltf_optimize_animation_keep_object'] = False
767 export_settings['gltf_export_anim_single_armature'] = False
768 export_settings['gltf_export_reset_pose_bones'] = False
769 export_settings['gltf_skins'] = self.export_skins
770 if self.export_skins:
771 export_settings['gltf_all_vertex_influences'] = self.export_all_influences
772 else:
773 export_settings['gltf_all_vertex_influences'] = False
774 export_settings['gltf_def_bones'] = False
775 export_settings['gltf_rest_position_armature'] = self.export_rest_position_armature
776 export_settings['gltf_frame_step'] = self.export_frame_step
778 export_settings['gltf_morph'] = self.export_morph
779 if self.export_morph:
780 export_settings['gltf_morph_normal'] = self.export_morph_normal
781 export_settings['gltf_morph_tangent'] = self.export_morph_tangent
782 export_settings['gltf_morph_anim'] = self.export_morph_animation
783 else:
784 export_settings['gltf_morph_normal'] = False
785 export_settings['gltf_morph_tangent'] = False
786 export_settings['gltf_morph_anim'] = False
788 export_settings['gltf_lights'] = self.export_lights
789 export_settings['gltf_lighting_mode'] = self.convert_lighting_mode
791 export_settings['gltf_binary'] = bytearray()
792 export_settings['gltf_binaryfilename'] = (
793 path_to_uri(os.path.splitext(os.path.basename(self.filepath))[0] + '.bin')
796 user_extensions = []
797 pre_export_callbacks = []
798 post_export_callbacks = []
800 import sys
801 preferences = bpy.context.preferences
802 for addon_name in preferences.addons.keys():
803 try:
804 module = sys.modules[addon_name]
805 except Exception:
806 continue
807 if hasattr(module, 'glTF2ExportUserExtension'):
808 extension_ctor = module.glTF2ExportUserExtension
809 user_extensions.append(extension_ctor())
810 if hasattr(module, 'glTF2ExportUserExtensions'):
811 extension_ctors = module.glTF2ExportUserExtensions
812 for extension_ctor in extension_ctors:
813 user_extensions.append(extension_ctor())
814 if hasattr(module, 'glTF2_pre_export_callback'):
815 pre_export_callbacks.append(module.glTF2_pre_export_callback)
816 if hasattr(module, 'glTF2_post_export_callback'):
817 post_export_callbacks.append(module.glTF2_post_export_callback)
818 export_settings['gltf_user_extensions'] = user_extensions
819 export_settings['pre_export_callbacks'] = pre_export_callbacks
820 export_settings['post_export_callbacks'] = post_export_callbacks
822 return gltf2_blender_export.save(context, export_settings)
824 def draw(self, context):
825 pass # Is needed to get panels available
828 class GLTF_PT_export_main(bpy.types.Panel):
829 bl_space_type = 'FILE_BROWSER'
830 bl_region_type = 'TOOL_PROPS'
831 bl_label = ""
832 bl_parent_id = "FILE_PT_operator"
833 bl_options = {'HIDE_HEADER'}
835 @classmethod
836 def poll(cls, context):
837 sfile = context.space_data
838 operator = sfile.active_operator
840 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
842 def draw(self, context):
843 layout = self.layout
844 layout.use_property_split = True
845 layout.use_property_decorate = False # No animation.
847 sfile = context.space_data
848 operator = sfile.active_operator
850 layout.prop(operator, 'export_format')
851 if operator.export_format == 'GLTF_SEPARATE':
852 layout.prop(operator, 'export_keep_originals')
853 if operator.export_keep_originals is False:
854 layout.prop(operator, 'export_texture_dir', icon='FILE_FOLDER')
856 layout.prop(operator, 'export_copyright')
857 layout.prop(operator, 'will_save_settings')
860 class GLTF_PT_export_include(bpy.types.Panel):
861 bl_space_type = 'FILE_BROWSER'
862 bl_region_type = 'TOOL_PROPS'
863 bl_label = "Include"
864 bl_parent_id = "FILE_PT_operator"
865 bl_options = {'DEFAULT_CLOSED'}
867 @classmethod
868 def poll(cls, context):
869 sfile = context.space_data
870 operator = sfile.active_operator
872 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
874 def draw(self, context):
875 layout = self.layout
876 layout.use_property_split = True
877 layout.use_property_decorate = False # No animation.
879 sfile = context.space_data
880 operator = sfile.active_operator
882 col = layout.column(heading = "Limit to", align = True)
883 col.prop(operator, 'use_selection')
884 col.prop(operator, 'use_visible')
885 col.prop(operator, 'use_renderable')
886 col.prop(operator, 'use_active_collection')
887 if operator.use_active_collection:
888 col.prop(operator, 'use_active_collection_with_nested')
889 col.prop(operator, 'use_active_scene')
891 col = layout.column(heading = "Data", align = True)
892 col.prop(operator, 'export_extras')
893 col.prop(operator, 'export_cameras')
894 col.prop(operator, 'export_lights')
897 class GLTF_PT_export_transform(bpy.types.Panel):
898 bl_space_type = 'FILE_BROWSER'
899 bl_region_type = 'TOOL_PROPS'
900 bl_label = "Transform"
901 bl_parent_id = "FILE_PT_operator"
902 bl_options = {'DEFAULT_CLOSED'}
904 @classmethod
905 def poll(cls, context):
906 sfile = context.space_data
907 operator = sfile.active_operator
909 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
911 def draw(self, context):
912 layout = self.layout
913 layout.use_property_split = True
914 layout.use_property_decorate = False # No animation.
916 sfile = context.space_data
917 operator = sfile.active_operator
919 layout.prop(operator, 'export_yup')
922 class GLTF_PT_export_data(bpy.types.Panel):
923 bl_space_type = 'FILE_BROWSER'
924 bl_region_type = 'TOOL_PROPS'
925 bl_label = "Data"
926 bl_parent_id = "FILE_PT_operator"
927 bl_options = {'DEFAULT_CLOSED'}
929 @classmethod
930 def poll(cls, context):
931 sfile = context.space_data
932 operator = sfile.active_operator
934 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
936 def draw(self, context):
937 pass
939 class GLTF_PT_export_data_mesh(bpy.types.Panel):
940 bl_space_type = 'FILE_BROWSER'
941 bl_region_type = 'TOOL_PROPS'
942 bl_label = "Mesh"
943 bl_parent_id = "GLTF_PT_export_data"
944 bl_options = {'DEFAULT_CLOSED'}
946 @classmethod
947 def poll(cls, context):
948 sfile = context.space_data
949 operator = sfile.active_operator
950 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
952 def draw(self, context):
953 layout = self.layout
954 layout.use_property_split = True
955 layout.use_property_decorate = False # No animation.
957 sfile = context.space_data
958 operator = sfile.active_operator
960 layout.prop(operator, 'export_apply')
961 layout.prop(operator, 'export_texcoords')
962 layout.prop(operator, 'export_normals')
963 col = layout.column()
964 col.active = operator.export_normals
965 col.prop(operator, 'export_tangents')
966 layout.prop(operator, 'export_colors')
967 layout.prop(operator, 'export_attributes')
969 col = layout.column()
970 col.prop(operator, 'use_mesh_edges')
971 col.prop(operator, 'use_mesh_vertices')
974 class GLTF_PT_export_data_material(bpy.types.Panel):
975 bl_space_type = 'FILE_BROWSER'
976 bl_region_type = 'TOOL_PROPS'
977 bl_label = "Material"
978 bl_parent_id = "GLTF_PT_export_data"
979 bl_options = {'DEFAULT_CLOSED'}
981 @classmethod
982 def poll(cls, context):
983 sfile = context.space_data
984 operator = sfile.active_operator
985 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
987 def draw(self, context):
988 layout = self.layout
989 layout.use_property_split = True
990 layout.use_property_decorate = False # No animation.
992 sfile = context.space_data
993 operator = sfile.active_operator
995 layout.prop(operator, 'export_materials')
996 col = layout.column()
997 col.active = operator.export_materials == "EXPORT"
998 col.prop(operator, 'export_image_format')
999 if operator.export_image_format in ["AUTO", "JPEG"]:
1000 col.prop(operator, 'export_jpeg_quality')
1002 class GLTF_PT_export_data_original_pbr(bpy.types.Panel):
1003 bl_space_type = 'FILE_BROWSER'
1004 bl_region_type = 'TOOL_PROPS'
1005 bl_label = "PBR Extensions"
1006 bl_parent_id = "GLTF_PT_export_data_material"
1007 bl_options = {'DEFAULT_CLOSED'}
1009 @classmethod
1010 def poll(cls, context):
1011 sfile = context.space_data
1012 operator = sfile.active_operator
1013 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1015 def draw(self, context):
1016 layout = self.layout
1017 layout.use_property_split = True
1018 layout.use_property_decorate = False # No animation.
1020 sfile = context.space_data
1021 operator = sfile.active_operator
1023 layout.prop(operator, 'export_original_specular')
1025 class GLTF_PT_export_data_lighting(bpy.types.Panel):
1026 bl_space_type = 'FILE_BROWSER'
1027 bl_region_type = 'TOOL_PROPS'
1028 bl_label = "Lighting"
1029 bl_parent_id = "GLTF_PT_export_data"
1030 bl_options = {'DEFAULT_CLOSED'}
1032 @classmethod
1033 def poll(cls, context):
1034 sfile = context.space_data
1035 operator = sfile.active_operator
1036 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1038 def draw(self, context):
1039 layout = self.layout
1040 layout.use_property_split = True
1041 layout.use_property_decorate = False # No animation.
1043 sfile = context.space_data
1044 operator = sfile.active_operator
1046 layout.prop(operator, 'convert_lighting_mode')
1048 class GLTF_PT_export_data_shapekeys(bpy.types.Panel):
1049 bl_space_type = 'FILE_BROWSER'
1050 bl_region_type = 'TOOL_PROPS'
1051 bl_label = "Shape Keys"
1052 bl_parent_id = "GLTF_PT_export_data"
1053 bl_options = {'DEFAULT_CLOSED'}
1055 @classmethod
1056 def poll(cls, context):
1057 sfile = context.space_data
1058 operator = sfile.active_operator
1060 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1062 def draw_header(self, context):
1063 sfile = context.space_data
1064 operator = sfile.active_operator
1065 self.layout.prop(operator, "export_morph", text="")
1067 def draw(self, context):
1068 layout = self.layout
1069 layout.use_property_split = True
1070 layout.use_property_decorate = False # No animation.
1072 sfile = context.space_data
1073 operator = sfile.active_operator
1075 layout.active = operator.export_morph
1077 layout.prop(operator, 'export_morph_normal')
1078 col = layout.column()
1079 col.active = operator.export_morph_normal
1080 col.prop(operator, 'export_morph_tangent')
1083 class GLTF_PT_export_data_skinning(bpy.types.Panel):
1084 bl_space_type = 'FILE_BROWSER'
1085 bl_region_type = 'TOOL_PROPS'
1086 bl_label = "Skinning"
1087 bl_parent_id = "GLTF_PT_export_data"
1088 bl_options = {'DEFAULT_CLOSED'}
1090 @classmethod
1091 def poll(cls, context):
1092 sfile = context.space_data
1093 operator = sfile.active_operator
1095 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1097 def draw_header(self, context):
1098 sfile = context.space_data
1099 operator = sfile.active_operator
1100 self.layout.prop(operator, "export_skins", text="")
1102 def draw(self, context):
1103 layout = self.layout
1104 layout.use_property_split = True
1105 layout.use_property_decorate = False # No animation.
1107 sfile = context.space_data
1108 operator = sfile.active_operator
1110 layout.active = operator.export_skins
1112 layout.prop(operator, 'export_all_influences')
1115 class GLTF_PT_export_data_armature(bpy.types.Panel):
1116 bl_space_type = 'FILE_BROWSER'
1117 bl_region_type = 'TOOL_PROPS'
1118 bl_label = "Armature"
1119 bl_parent_id = "GLTF_PT_export_data"
1120 bl_options = {'DEFAULT_CLOSED'}
1122 @classmethod
1123 def poll(cls, context):
1124 sfile = context.space_data
1125 operator = sfile.active_operator
1127 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1129 def draw(self, context):
1130 layout = self.layout
1131 layout.use_property_split = True
1132 layout.use_property_decorate = False # No animation.
1134 sfile = context.space_data
1135 operator = sfile.active_operator
1137 layout.active = operator.export_skins
1139 layout.prop(operator, 'export_rest_position_armature')
1141 row = layout.row()
1142 row.active = operator.export_force_sampling
1143 row.prop(operator, 'export_def_bones')
1144 if operator.export_force_sampling is False and operator.export_def_bones is True:
1145 layout.label(text="Export only deformation bones is not possible when not sampling animation")
1146 row = layout.row()
1147 row.prop(operator, 'export_hierarchy_flatten_bones')
1149 class GLTF_PT_export_data_compression(bpy.types.Panel):
1150 bl_space_type = 'FILE_BROWSER'
1151 bl_region_type = 'TOOL_PROPS'
1152 bl_label = "Compression"
1153 bl_parent_id = "GLTF_PT_export_data"
1154 bl_options = {'DEFAULT_CLOSED'}
1156 def __init__(self):
1157 from .io.com import gltf2_io_draco_compression_extension
1158 self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists(quiet=True)
1160 @classmethod
1161 def poll(cls, context):
1162 sfile = context.space_data
1163 operator = sfile.active_operator
1164 if operator.is_draco_available:
1165 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1167 def draw_header(self, context):
1168 sfile = context.space_data
1169 operator = sfile.active_operator
1170 self.layout.prop(operator, "export_draco_mesh_compression_enable", text="")
1172 def draw(self, context):
1173 layout = self.layout
1174 layout.use_property_split = True
1175 layout.use_property_decorate = False # No animation.
1177 sfile = context.space_data
1178 operator = sfile.active_operator
1180 layout.active = operator.export_draco_mesh_compression_enable
1181 layout.prop(operator, 'export_draco_mesh_compression_level')
1183 col = layout.column(align=True)
1184 col.prop(operator, 'export_draco_position_quantization', text="Quantize Position")
1185 col.prop(operator, 'export_draco_normal_quantization', text="Normal")
1186 col.prop(operator, 'export_draco_texcoord_quantization', text="Tex Coord")
1187 col.prop(operator, 'export_draco_color_quantization', text="Color")
1188 col.prop(operator, 'export_draco_generic_quantization', text="Generic")
1191 class GLTF_PT_export_animation(bpy.types.Panel):
1192 bl_space_type = 'FILE_BROWSER'
1193 bl_region_type = 'TOOL_PROPS'
1194 bl_label = "Animation"
1195 bl_parent_id = "FILE_PT_operator"
1196 bl_options = {'DEFAULT_CLOSED'}
1198 @classmethod
1199 def poll(cls, context):
1200 sfile = context.space_data
1201 operator = sfile.active_operator
1203 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1205 def draw_header(self, context):
1206 sfile = context.space_data
1207 operator = sfile.active_operator
1208 self.layout.prop(operator, "export_animations", text="")
1210 def draw(self, context):
1211 layout = self.layout
1212 layout.use_property_split = True
1213 layout.use_property_decorate = False # No animation.
1215 sfile = context.space_data
1216 operator = sfile.active_operator
1218 layout.active = operator.export_animations
1220 layout.prop(operator, 'export_animation_mode')
1221 if operator.export_animation_mode == "ACTIVE_ACTIONS":
1222 layout.prop(operator, 'export_nla_strips_merged_animation_name')
1224 row = layout.row()
1225 row.active = operator.export_morph is True
1226 row.prop(operator, 'export_morph_animation')
1227 row = layout.row()
1228 row.active = operator.export_force_sampling
1229 row.prop(operator, 'export_bake_animation')
1230 if operator.export_animation_mode == "SCENE":
1231 layout.prop(operator, 'export_anim_scene_split_object')
1234 class GLTF_PT_export_animation_ranges(bpy.types.Panel):
1235 bl_space_type = 'FILE_BROWSER'
1236 bl_region_type = 'TOOL_PROPS'
1237 bl_label = "Rest & Ranges"
1238 bl_parent_id = "GLTF_PT_export_animation"
1239 bl_options = {'DEFAULT_CLOSED'}
1241 @classmethod
1242 def poll(cls, context):
1243 sfile = context.space_data
1244 operator = sfile.active_operator
1246 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1248 def draw(self, context):
1249 layout = self.layout
1250 layout.use_property_split = True
1251 layout.use_property_decorate = False # No animation.
1253 sfile = context.space_data
1254 operator = sfile.active_operator
1256 layout.active = operator.export_animations
1258 layout.prop(operator, 'export_current_frame')
1259 layout.prop(operator, 'export_frame_range')
1260 layout.prop(operator, 'export_anim_slide_to_zero')
1261 layout.prop(operator, 'export_negative_frame')
1263 class GLTF_PT_export_animation_armature(bpy.types.Panel):
1264 bl_space_type = 'FILE_BROWSER'
1265 bl_region_type = 'TOOL_PROPS'
1266 bl_label = "Armature"
1267 bl_parent_id = "GLTF_PT_export_animation"
1268 bl_options = {'DEFAULT_CLOSED'}
1270 @classmethod
1271 def poll(cls, context):
1272 sfile = context.space_data
1273 operator = sfile.active_operator
1275 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1277 def draw(self, context):
1278 layout = self.layout
1279 layout.use_property_split = True
1280 layout.use_property_decorate = False # No animation.
1282 sfile = context.space_data
1283 operator = sfile.active_operator
1285 layout.active = operator.export_animations
1287 layout.prop(operator, 'export_anim_single_armature')
1288 layout.prop(operator, 'export_reset_pose_bones')
1290 class GLTF_PT_export_animation_sampling(bpy.types.Panel):
1291 bl_space_type = 'FILE_BROWSER'
1292 bl_region_type = 'TOOL_PROPS'
1293 bl_label = "Sampling Animations"
1294 bl_parent_id = "GLTF_PT_export_animation"
1295 bl_options = {'DEFAULT_CLOSED'}
1297 @classmethod
1298 def poll(cls, context):
1299 sfile = context.space_data
1300 operator = sfile.active_operator
1302 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1304 def draw_header(self, context):
1305 sfile = context.space_data
1306 operator = sfile.active_operator
1307 self.layout.active = operator.export_animations
1308 self.layout.prop(operator, "export_force_sampling", text="")
1310 def draw(self, context):
1311 layout = self.layout
1312 layout.use_property_split = True
1313 layout.use_property_decorate = False # No animation.
1315 sfile = context.space_data
1316 operator = sfile.active_operator
1318 layout.active = operator.export_animations
1320 layout.prop(operator, 'export_frame_step')
1323 class GLTF_PT_export_animation_optimize(bpy.types.Panel):
1324 bl_space_type = 'FILE_BROWSER'
1325 bl_region_type = 'TOOL_PROPS'
1326 bl_label = "Optimize Animations"
1327 bl_parent_id = "GLTF_PT_export_animation"
1328 bl_options = {'DEFAULT_CLOSED'}
1330 @classmethod
1331 def poll(cls, context):
1332 sfile = context.space_data
1333 operator = sfile.active_operator
1335 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
1337 def draw(self, context):
1338 layout = self.layout
1339 layout.use_property_split = True
1340 layout.use_property_decorate = False # No animation.
1342 sfile = context.space_data
1343 operator = sfile.active_operator
1345 layout.active = operator.export_animations
1347 layout.prop(operator, 'export_optimize_animation_size')
1349 row = layout.row()
1350 row.active = operator.export_optimize_animation_size
1351 row.prop(operator, 'export_optimize_animation_keep_anim_armature')
1353 row = layout.row()
1354 row.active = operator.export_optimize_animation_size
1355 row.prop(operator, 'export_optimize_animation_keep_anim_object')
1358 class GLTF_PT_export_user_extensions(bpy.types.Panel):
1359 bl_space_type = 'FILE_BROWSER'
1360 bl_region_type = 'TOOL_PROPS'
1361 bl_label = "Exporter Extensions"
1362 bl_parent_id = "FILE_PT_operator"
1363 bl_options = {'DEFAULT_CLOSED'}
1365 @classmethod
1366 def poll(cls, context):
1367 sfile = context.space_data
1368 operator = sfile.active_operator
1370 return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_exporter_extensions
1372 def draw(self, context):
1373 layout = self.layout
1374 layout.use_property_split = True
1375 layout.use_property_decorate = False # No animation.
1377 class GLTF_PT_import_user_extensions(bpy.types.Panel):
1378 bl_space_type = 'FILE_BROWSER'
1379 bl_region_type = 'TOOL_PROPS'
1380 bl_label = "Importer Extensions"
1381 bl_parent_id = "FILE_PT_operator"
1382 bl_options = {'DEFAULT_CLOSED'}
1384 @classmethod
1385 def poll(cls, context):
1386 sfile = context.space_data
1387 operator = sfile.active_operator
1388 return operator.bl_idname == "IMPORT_SCENE_OT_gltf" and operator.has_active_importer_extensions
1390 def draw(self, context):
1391 layout = self.layout
1392 layout.use_property_split = True
1393 layout.use_property_decorate = False # No animation.
1395 class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
1396 """Export scene as glTF 2.0 file"""
1397 bl_idname = 'export_scene.gltf'
1398 bl_label = 'Export glTF 2.0'
1400 filename_ext = ''
1402 filter_glob: StringProperty(default='*.glb', options={'HIDDEN'})
1405 def menu_func_export(self, context):
1406 self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
1409 class ImportGLTF2(Operator, ConvertGLTF2_Base, ImportHelper):
1410 """Load a glTF 2.0 file"""
1411 bl_idname = 'import_scene.gltf'
1412 bl_label = 'Import glTF 2.0'
1413 bl_options = {'REGISTER', 'UNDO'}
1415 filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
1417 files: CollectionProperty(
1418 name="File Path",
1419 type=bpy.types.OperatorFileListElement,
1422 loglevel: IntProperty(
1423 name='Log Level',
1424 description="Log Level")
1426 import_pack_images: BoolProperty(
1427 name='Pack Images',
1428 description='Pack all images into .blend file',
1429 default=True
1432 merge_vertices: BoolProperty(
1433 name='Merge Vertices',
1434 description=(
1435 'The glTF format requires discontinuous normals, UVs, and '
1436 'other vertex attributes to be stored as separate vertices, '
1437 'as required for rendering on typical graphics hardware. '
1438 'This option attempts to combine co-located vertices where possible. '
1439 'Currently cannot combine verts with different normals'
1441 default=False,
1444 import_shading: EnumProperty(
1445 name="Shading",
1446 items=(("NORMALS", "Use Normal Data", ""),
1447 ("FLAT", "Flat Shading", ""),
1448 ("SMOOTH", "Smooth Shading", "")),
1449 description="How normals are computed during import",
1450 default="NORMALS")
1452 bone_heuristic: EnumProperty(
1453 name="Bone Dir",
1454 items=(
1455 ("BLENDER", "Blender (best for re-importing)",
1456 "Good for re-importing glTFs exported from Blender. "
1457 "Bone tips are placed on their local +Y axis (in glTF space)"),
1458 ("TEMPERANCE", "Temperance (average)",
1459 "Decent all-around strategy. "
1460 "A bone with one child has its tip placed on the local axis "
1461 "closest to its child"),
1462 ("FORTUNE", "Fortune (may look better, less accurate)",
1463 "Might look better than Temperance, but also might have errors. "
1464 "A bone with one child has its tip placed at its child's root. "
1465 "Non-uniform scalings may get messed up though, so beware"),
1467 description="Heuristic for placing bones. Tries to make bones pretty",
1468 default="TEMPERANCE",
1471 guess_original_bind_pose: BoolProperty(
1472 name='Guess Original Bind Pose',
1473 description=(
1474 'Try to guess the original bind pose for skinned meshes from '
1475 'the inverse bind matrices. '
1476 'When off, use default/rest pose as bind pose'
1478 default=True,
1481 def draw(self, context):
1482 layout = self.layout
1484 layout.use_property_split = True
1485 layout.use_property_decorate = False # No animation.
1487 layout.prop(self, 'import_pack_images')
1488 layout.prop(self, 'merge_vertices')
1489 layout.prop(self, 'import_shading')
1490 layout.prop(self, 'guess_original_bind_pose')
1491 layout.prop(self, 'bone_heuristic')
1492 layout.prop(self, 'convert_lighting_mode')
1494 def invoke(self, context, event):
1495 import sys
1496 preferences = bpy.context.preferences
1497 for addon_name in preferences.addons.keys():
1498 try:
1499 if hasattr(sys.modules[addon_name], 'glTF2ImportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ImportUserExtensions'):
1500 importer_extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
1501 except Exception:
1502 pass
1504 self.has_active_importer_extensions = len(importer_extension_panel_unregister_functors) > 0
1505 return ImportHelper.invoke(self, context, event)
1507 def execute(self, context):
1508 return self.import_gltf2(context)
1510 def import_gltf2(self, context):
1511 import os
1513 self.set_debug_log()
1514 import_settings = self.as_keywords()
1516 user_extensions = []
1518 import sys
1519 preferences = bpy.context.preferences
1520 for addon_name in preferences.addons.keys():
1521 try:
1522 module = sys.modules[addon_name]
1523 except Exception:
1524 continue
1525 if hasattr(module, 'glTF2ImportUserExtension'):
1526 extension_ctor = module.glTF2ImportUserExtension
1527 user_extensions.append(extension_ctor())
1528 import_settings['import_user_extensions'] = user_extensions
1530 if self.files:
1531 # Multiple file import
1532 ret = {'CANCELLED'}
1533 dirname = os.path.dirname(self.filepath)
1534 for file in self.files:
1535 path = os.path.join(dirname, file.name)
1536 if self.unit_import(path, import_settings) == {'FINISHED'}:
1537 ret = {'FINISHED'}
1538 return ret
1539 else:
1540 # Single file import
1541 return self.unit_import(self.filepath, import_settings)
1543 def unit_import(self, filename, import_settings):
1544 import time
1545 from .io.imp.gltf2_io_gltf import glTFImporter, ImportError
1546 from .blender.imp.gltf2_blender_gltf import BlenderGlTF
1548 try:
1549 gltf_importer = glTFImporter(filename, import_settings)
1550 gltf_importer.read()
1551 gltf_importer.checks()
1553 print("Data are loaded, start creating Blender stuff")
1555 start_time = time.time()
1556 BlenderGlTF.create(gltf_importer)
1557 elapsed_s = "{:.2f}s".format(time.time() - start_time)
1558 print("glTF import finished in " + elapsed_s)
1560 gltf_importer.log.removeHandler(gltf_importer.log_handler)
1562 return {'FINISHED'}
1564 except ImportError as e:
1565 self.report({'ERROR'}, e.args[0])
1566 return {'CANCELLED'}
1568 def set_debug_log(self):
1569 import logging
1570 if bpy.app.debug_value == 0:
1571 self.loglevel = logging.CRITICAL
1572 elif bpy.app.debug_value == 1:
1573 self.loglevel = logging.ERROR
1574 elif bpy.app.debug_value == 2:
1575 self.loglevel = logging.WARNING
1576 elif bpy.app.debug_value == 3:
1577 self.loglevel = logging.INFO
1578 else:
1579 self.loglevel = logging.NOTSET
1582 def gltf_variant_ui_update(self, context):
1583 from .blender.com.gltf2_blender_ui import variant_register, variant_unregister
1584 if self.KHR_materials_variants_ui is True:
1585 # register all needed types
1586 variant_register()
1587 else:
1588 variant_unregister()
1590 def gltf_animation_ui_update(self, context):
1591 from .blender.com.gltf2_blender_ui import anim_ui_register, anim_ui_unregister
1592 if self.animation_ui is True:
1593 # register all needed types
1594 anim_ui_register()
1595 else:
1596 anim_ui_unregister()
1598 class GLTF_AddonPreferences(bpy.types.AddonPreferences):
1599 bl_idname = __package__
1601 settings_node_ui : bpy.props.BoolProperty(
1602 default= False,
1603 description="Displays glTF Material Output node in Shader Editor (Menu Add > Output)"
1606 KHR_materials_variants_ui : bpy.props.BoolProperty(
1607 default= False,
1608 description="Displays glTF UI to manage material variants",
1609 update=gltf_variant_ui_update
1612 animation_ui: bpy.props.BoolProperty(
1613 default=False,
1614 description="Display glTF UI to manage animations",
1615 update=gltf_animation_ui_update
1618 def draw(self, context):
1619 layout = self.layout
1620 row = layout.row()
1621 row.prop(self, "settings_node_ui", text="Shader Editor Add-ons")
1622 row.prop(self, "KHR_materials_variants_ui", text="Material Variants")
1623 row.prop(self, "animation_ui", text="Animation UI")
1625 def menu_func_import(self, context):
1626 self.layout.operator(ImportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
1629 classes = (
1630 ExportGLTF2,
1631 GLTF_PT_export_main,
1632 GLTF_PT_export_include,
1633 GLTF_PT_export_transform,
1634 GLTF_PT_export_data,
1635 GLTF_PT_export_data_mesh,
1636 GLTF_PT_export_data_material,
1637 GLTF_PT_export_data_original_pbr,
1638 GLTF_PT_export_data_shapekeys,
1639 GLTF_PT_export_data_armature,
1640 GLTF_PT_export_data_skinning,
1641 GLTF_PT_export_data_lighting,
1642 GLTF_PT_export_data_compression,
1643 GLTF_PT_export_animation,
1644 GLTF_PT_export_animation_ranges,
1645 GLTF_PT_export_animation_armature,
1646 GLTF_PT_export_animation_sampling,
1647 GLTF_PT_export_animation_optimize,
1648 GLTF_PT_export_user_extensions,
1649 ImportGLTF2,
1650 GLTF_PT_import_user_extensions,
1651 GLTF_AddonPreferences
1655 def register():
1656 from .blender.com import gltf2_blender_ui as blender_ui
1657 for c in classes:
1658 bpy.utils.register_class(c)
1659 # bpy.utils.register_module(__name__)
1661 blender_ui.register()
1662 if bpy.context.preferences.addons['io_scene_gltf2'].preferences.KHR_materials_variants_ui is True:
1663 blender_ui.variant_register()
1664 if bpy.context.preferences.addons['io_scene_gltf2'].preferences.animation_ui is True:
1665 blender_ui.anim_ui_register()
1667 # add to the export / import menu
1668 bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
1669 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
1672 def unregister():
1673 from .blender.com import gltf2_blender_ui as blender_ui
1674 blender_ui.unregister()
1675 if bpy.context.preferences.addons['io_scene_gltf2'].preferences.KHR_materials_variants_ui is True:
1676 blender_ui.variant_unregister()
1678 for c in classes:
1679 bpy.utils.unregister_class(c)
1680 for f in exporter_extension_panel_unregister_functors:
1682 exporter_extension_panel_unregister_functors.clear()
1684 for f in importer_extension_panel_unregister_functors:
1686 importer_extension_panel_unregister_functors.clear()
1688 # bpy.utils.unregister_module(__name__)
1690 # remove from the export / import menu
1691 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
1692 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)