glTF: bump to 1.1.46 for 2.82a
[blender-addons.git] / io_scene_gltf2 / __init__.py
blob445bd9aabb550cb613454c0ea15f932693e233a0
1 # Copyright 2018-2019 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.
15 bl_info = {
16 'name': 'glTF 2.0 format',
17 'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
18 "version": (1, 1, 46),
19 'blender': (2, 81, 6),
20 'location': 'File > Import-Export',
21 'description': 'Import-Export as glTF 2.0',
22 'warning': '',
23 'wiki_url': "https://docs.blender.org/manual/en/2.82/addons/import_export/io_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):
37 import importlib
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:
43 continue
45 if path.is_file() and path.suffix == ".py":
46 importlib.reload(module_dict[path.stem])
47 elif path.is_dir():
48 reload_package_recursive(path, module_dict[path.stem].__dict__)
50 reload_package_recursive(Path(__file__).parent, module_dict_main)
53 if "bpy" in locals():
54 reload_package(locals())
56 import bpy
57 from bpy.props import (StringProperty,
58 BoolProperty,
59 EnumProperty,
60 IntProperty,
61 CollectionProperty)
62 from bpy.types import Operator
63 from bpy_extras.io_utils import ImportHelper, ExportHelper
67 # Functions / Classes.
70 extension_panel_unregister_functors = []
72 class ExportGLTF2_Base:
73 # TODO: refactor to avoid boilerplate
75 def __init__(self):
76 from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension
77 self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists()
79 bl_options = {'UNDO', 'PRESET'}
81 export_format: EnumProperty(
82 name='Format',
83 items=(('GLB', 'glTF Binary (.glb)',
84 'Exports a single file, with all data packed in binary form. '
85 'Most efficient and portable, but more difficult to edit later'),
86 ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
87 'Exports a single file, with all data packed in JSON. '
88 'Less efficient than binary, but easier to edit later'),
89 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
90 'Exports multiple files, with separate JSON, binary and texture data. '
91 'Easiest to edit later')),
92 description=(
93 'Output format and embedding options. Binary is most efficient, '
94 'but JSON (embedded or separate) may be easier to edit later'
96 default='GLB'
99 ui_tab: EnumProperty(
100 items=(('GENERAL', "General", "General settings"),
101 ('MESHES', "Meshes", "Mesh settings"),
102 ('OBJECTS', "Objects", "Object settings"),
103 ('ANIMATION', "Animation", "Animation settings")),
104 name="ui_tab",
105 description="Export setting categories",
108 export_copyright: StringProperty(
109 name='Copyright',
110 description='Legal rights and conditions for the model',
111 default=''
114 export_image_format: EnumProperty(
115 name='Images',
116 items=(('NAME', 'Automatic',
117 'Determine the image format from the blender image name'),
118 ('JPEG', 'JPEG Format (.jpg)',
119 'Encode and save textures as .jpg files. Be aware of a possible loss in quality'),
120 ('PNG', 'PNG Format (.png)',
121 'Encode and save textures as .png files')
123 description=(
124 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
125 'applications due to the smaller file size'
127 default='NAME'
130 export_texture_dir: StringProperty(
131 name='Textures',
132 description='Folder to place texture files in. Relative to the .gltf file',
133 default='',
136 export_texcoords: BoolProperty(
137 name='UVs',
138 description='Export UVs (texture coordinates) with meshes',
139 default=True
142 export_normals: BoolProperty(
143 name='Normals',
144 description='Export vertex normals with meshes',
145 default=True
148 export_draco_mesh_compression_enable: BoolProperty(
149 name='Draco mesh compression',
150 description='Compress mesh using Draco',
151 default=False
154 export_draco_mesh_compression_level: IntProperty(
155 name='Compression level',
156 description='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
157 default=6,
158 min=0,
159 max=6
162 export_draco_position_quantization: IntProperty(
163 name='Position quantization bits',
164 description='Quantization bits for position values (0 = no quantization)',
165 default=14,
166 min=0,
167 max=30
170 export_draco_normal_quantization: IntProperty(
171 name='Normal quantization bits',
172 description='Quantization bits for normal values (0 = no quantization)',
173 default=10,
174 min=0,
175 max=30
178 export_draco_texcoord_quantization: IntProperty(
179 name='Texcoord quantization bits',
180 description='Quantization bits for texture coordinate values (0 = no quantization)',
181 default=12,
182 min=0,
183 max=30
186 export_draco_generic_quantization: IntProperty(
187 name='Generic quantization bits',
188 description='Quantization bits for generic coordinate values like weights or joints (0 = no quantization)',
189 default=12,
190 min=0,
191 max=30
194 export_tangents: BoolProperty(
195 name='Tangents',
196 description='Export vertex tangents with meshes',
197 default=False
200 export_materials: BoolProperty(
201 name='Materials',
202 description='Export materials',
203 default=True
206 export_colors: BoolProperty(
207 name='Vertex Colors',
208 description='Export vertex colors with meshes',
209 default=True
212 export_cameras: BoolProperty(
213 name='Cameras',
214 description='Export cameras',
215 default=False
218 export_selected: BoolProperty(
219 name='Selected Objects',
220 description='Export selected objects only',
221 default=False
224 export_extras: BoolProperty(
225 name='Custom Properties',
226 description='Export custom properties as glTF extras',
227 default=False
230 export_yup: BoolProperty(
231 name='+Y Up',
232 description='Export using glTF convention, +Y up',
233 default=True
236 export_apply: BoolProperty(
237 name='Apply Modifiers',
238 description='Apply modifiers (excluding Armatures) to mesh objects -'
239 'WARNING: prevents exporting shape keys',
240 default=False
243 export_animations: BoolProperty(
244 name='Animations',
245 description='Exports active actions and NLA tracks as glTF animations',
246 default=True
249 export_frame_range: BoolProperty(
250 name='Limit to Playback Range',
251 description='Clips animations to selected playback range',
252 default=True
255 export_frame_step: IntProperty(
256 name='Sampling Rate',
257 description='How often to evaluate animated values (in frames)',
258 default=1,
259 min=1,
260 max=120
263 export_force_sampling: BoolProperty(
264 name='Always Sample Animations',
265 description='Apply sampling to all animations',
266 default=True
269 export_nla_strips: BoolProperty(
270 name='NLA Strips',
271 description='Export NLA Strip animations',
272 default=True
275 export_def_bones: BoolProperty(
276 name='Export Deformation bones only',
277 description='Export Deformation bones only (and needed bones for hierarchy)',
278 default=False
281 export_current_frame: BoolProperty(
282 name='Use Current Frame',
283 description='Export the scene in the current animation frame',
284 default=False
287 export_skins: BoolProperty(
288 name='Skinning',
289 description='Export skinning (armature) data',
290 default=True
293 export_all_influences: BoolProperty(
294 name='Include All Bone Influences',
295 description='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
296 default=False
299 export_morph: BoolProperty(
300 name='Shape Keys',
301 description='Export shape keys (morph targets)',
302 default=True
305 export_morph_normal: BoolProperty(
306 name='Shape Key Normals',
307 description='Export vertex normals with shape keys (morph targets)',
308 default=True
311 export_morph_tangent: BoolProperty(
312 name='Shape Key Tangents',
313 description='Export vertex tangents with shape keys (morph targets)',
314 default=False
317 export_lights: BoolProperty(
318 name='Punctual Lights',
319 description='Export directional, point, and spot lights. '
320 'Uses "KHR_lights_punctual" glTF extension',
321 default=False
324 export_displacement: BoolProperty(
325 name='Displacement Textures (EXPERIMENTAL)',
326 description='EXPERIMENTAL: Export displacement textures. '
327 'Uses incomplete "KHR_materials_displacement" glTF extension',
328 default=False
331 will_save_settings: BoolProperty(
332 name='Remember Export Settings',
333 description='Store glTF export settings in the Blender project',
334 default=False)
336 # Custom scene property for saving settings
337 scene_key = "glTF2ExportSettings"
341 def invoke(self, context, event):
342 settings = context.scene.get(self.scene_key)
343 self.will_save_settings = False
344 self.has_active_extenions = False
345 if settings:
346 try:
347 for (k, v) in settings.items():
348 setattr(self, k, v)
349 self.will_save_settings = True
351 except (AttributeError, TypeError):
352 self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
353 del context.scene[self.scene_key]
355 import sys
356 preferences = bpy.context.preferences
357 for addon_name in preferences.addons.keys():
358 try:
359 if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ExportUserExtensions'):
360 extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
361 self.has_active_extenions = True
362 except Exception:
363 pass
365 return ExportHelper.invoke(self, context, event)
367 def save_settings(self, context):
368 # find all export_ props
369 all_props = self.properties
370 export_props = {x: getattr(self, x) for x in dir(all_props)
371 if x.startswith("export_") and all_props.get(x) is not None}
373 context.scene[self.scene_key] = export_props
375 def execute(self, context):
376 import os
377 import datetime
378 from .blender.exp import gltf2_blender_export
380 if self.will_save_settings:
381 self.save_settings(context)
383 if self.export_format == 'GLB':
384 self.filename_ext = '.glb'
385 else:
386 self.filename_ext = '.gltf'
388 # All custom export settings are stored in this container.
389 export_settings = {}
391 export_settings['timestamp'] = datetime.datetime.now()
393 export_settings['gltf_filepath'] = bpy.path.ensure_ext(self.filepath, self.filename_ext)
394 export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
395 export_settings['gltf_texturedirectory'] = os.path.join(
396 export_settings['gltf_filedirectory'],
397 self.export_texture_dir,
400 export_settings['gltf_format'] = self.export_format
401 export_settings['gltf_image_format'] = self.export_image_format
402 export_settings['gltf_copyright'] = self.export_copyright
403 export_settings['gltf_texcoords'] = self.export_texcoords
404 export_settings['gltf_normals'] = self.export_normals
405 export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
407 if self.is_draco_available:
408 export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
409 export_settings['gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level
410 export_settings['gltf_draco_position_quantization'] = self.export_draco_position_quantization
411 export_settings['gltf_draco_normal_quantization'] = self.export_draco_normal_quantization
412 export_settings['gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization
413 export_settings['gltf_draco_generic_quantization'] = self.export_draco_generic_quantization
414 else:
415 export_settings['gltf_draco_mesh_compression'] = False
417 export_settings['gltf_materials'] = self.export_materials
418 export_settings['gltf_colors'] = self.export_colors
419 export_settings['gltf_cameras'] = self.export_cameras
420 export_settings['gltf_selected'] = self.export_selected
421 export_settings['gltf_layers'] = True # self.export_layers
422 export_settings['gltf_extras'] = self.export_extras
423 export_settings['gltf_yup'] = self.export_yup
424 export_settings['gltf_apply'] = self.export_apply
425 export_settings['gltf_current_frame'] = self.export_current_frame
426 export_settings['gltf_animations'] = self.export_animations
427 if self.export_animations:
428 export_settings['gltf_frame_range'] = self.export_frame_range
429 export_settings['gltf_force_sampling'] = self.export_force_sampling
430 if self.export_force_sampling:
431 export_settings['gltf_def_bones'] = self.export_def_bones
432 else:
433 export_settings['gltf_def_bones'] = False
434 export_settings['gltf_nla_strips'] = self.export_nla_strips
435 else:
436 export_settings['gltf_frame_range'] = False
437 export_settings['gltf_move_keyframes'] = False
438 export_settings['gltf_force_sampling'] = False
439 export_settings['gltf_def_bones'] = False
440 export_settings['gltf_skins'] = self.export_skins
441 if self.export_skins:
442 export_settings['gltf_all_vertex_influences'] = self.export_all_influences
443 else:
444 export_settings['gltf_all_vertex_influences'] = False
445 export_settings['gltf_frame_step'] = self.export_frame_step
446 export_settings['gltf_morph'] = self.export_morph
447 if self.export_morph:
448 export_settings['gltf_morph_normal'] = self.export_morph_normal
449 else:
450 export_settings['gltf_morph_normal'] = False
451 if self.export_morph and self.export_morph_normal:
452 export_settings['gltf_morph_tangent'] = self.export_morph_tangent
453 else:
454 export_settings['gltf_morph_tangent'] = False
456 export_settings['gltf_lights'] = self.export_lights
457 export_settings['gltf_displacement'] = self.export_displacement
459 export_settings['gltf_binary'] = bytearray()
460 export_settings['gltf_binaryfilename'] = os.path.splitext(os.path.basename(
461 bpy.path.ensure_ext(self.filepath,self.filename_ext)))[0] + '.bin'
463 user_extensions = []
465 import sys
466 preferences = bpy.context.preferences
467 for addon_name in preferences.addons.keys():
468 try:
469 module = sys.modules[addon_name]
470 except Exception:
471 continue
472 if hasattr(module, 'glTF2ExportUserExtension'):
473 extension_ctor = module.glTF2ExportUserExtension
474 user_extensions.append(extension_ctor())
475 if hasattr(module, 'glTF2ExportUserExtensions'):
476 extension_ctors = module.glTF2ExportUserExtensions
477 for extension_ctor in extension_ctors:
478 user_extensions.append(extension_ctor())
479 export_settings['gltf_user_extensions'] = user_extensions
481 return gltf2_blender_export.save(context, export_settings)
488 def draw(self, context):
489 pass
492 class GLTF_PT_export_main(bpy.types.Panel):
493 bl_space_type = 'FILE_BROWSER'
494 bl_region_type = 'TOOL_PROPS'
495 bl_label = ""
496 bl_parent_id = "FILE_PT_operator"
497 bl_options = {'HIDE_HEADER'}
499 @classmethod
500 def poll(cls, context):
501 sfile = context.space_data
502 operator = sfile.active_operator
504 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
506 def draw(self, context):
507 layout = self.layout
508 layout.use_property_split = True
509 layout.use_property_decorate = False # No animation.
511 sfile = context.space_data
512 operator = sfile.active_operator
514 layout.prop(operator, 'export_format')
515 if operator.export_format == 'GLTF_SEPARATE':
516 layout.prop(operator, 'export_texture_dir', icon='FILE_FOLDER')
517 layout.prop(operator, 'export_copyright')
518 layout.prop(operator, 'will_save_settings')
521 class GLTF_PT_export_include(bpy.types.Panel):
522 bl_space_type = 'FILE_BROWSER'
523 bl_region_type = 'TOOL_PROPS'
524 bl_label = "Include"
525 bl_parent_id = "FILE_PT_operator"
526 bl_options = {'DEFAULT_CLOSED'}
528 @classmethod
529 def poll(cls, context):
530 sfile = context.space_data
531 operator = sfile.active_operator
533 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
535 def draw(self, context):
536 layout = self.layout
537 layout.use_property_split = True
538 layout.use_property_decorate = False # No animation.
540 sfile = context.space_data
541 operator = sfile.active_operator
543 layout.prop(operator, 'export_selected')
544 layout.prop(operator, 'export_extras')
545 layout.prop(operator, 'export_cameras')
546 layout.prop(operator, 'export_lights')
549 class GLTF_PT_export_transform(bpy.types.Panel):
550 bl_space_type = 'FILE_BROWSER'
551 bl_region_type = 'TOOL_PROPS'
552 bl_label = "Transform"
553 bl_parent_id = "FILE_PT_operator"
554 bl_options = {'DEFAULT_CLOSED'}
556 @classmethod
557 def poll(cls, context):
558 sfile = context.space_data
559 operator = sfile.active_operator
561 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
563 def draw(self, context):
564 layout = self.layout
565 layout.use_property_split = True
566 layout.use_property_decorate = False # No animation.
568 sfile = context.space_data
569 operator = sfile.active_operator
571 layout.prop(operator, 'export_yup')
574 class GLTF_PT_export_geometry(bpy.types.Panel):
575 bl_space_type = 'FILE_BROWSER'
576 bl_region_type = 'TOOL_PROPS'
577 bl_label = "Geometry"
578 bl_parent_id = "FILE_PT_operator"
579 bl_options = {'DEFAULT_CLOSED'}
581 @classmethod
582 def poll(cls, context):
583 sfile = context.space_data
584 operator = sfile.active_operator
586 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
588 def draw(self, context):
589 layout = self.layout
590 layout.use_property_split = True
591 layout.use_property_decorate = False # No animation.
593 sfile = context.space_data
594 operator = sfile.active_operator
596 layout.prop(operator, 'export_apply')
597 layout.prop(operator, 'export_texcoords')
598 layout.prop(operator, 'export_normals')
599 col = layout.column()
600 col.active = operator.export_normals
601 col.prop(operator, 'export_tangents')
602 layout.prop(operator, 'export_colors')
603 layout.prop(operator, 'export_materials')
604 col = layout.column()
605 col.active = operator.export_materials
606 col.prop(operator, 'export_image_format')
609 class GLTF_PT_export_geometry_compression(bpy.types.Panel):
610 bl_space_type = 'FILE_BROWSER'
611 bl_region_type = 'TOOL_PROPS'
612 bl_label = "Compression"
613 bl_parent_id = "GLTF_PT_export_geometry"
614 bl_options = {'DEFAULT_CLOSED'}
616 def __init__(self):
617 from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension
618 self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists(quiet=True)
620 @classmethod
621 def poll(cls, context):
622 sfile = context.space_data
623 operator = sfile.active_operator
624 if operator.is_draco_available:
625 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
627 def draw_header(self, context):
628 sfile = context.space_data
629 operator = sfile.active_operator
630 self.layout.prop(operator, "export_draco_mesh_compression_enable", text="")
632 def draw(self, context):
633 layout = self.layout
634 layout.use_property_split = True
635 layout.use_property_decorate = False # No animation.
637 sfile = context.space_data
638 operator = sfile.active_operator
640 layout.active = operator.export_draco_mesh_compression_enable
641 layout.prop(operator, 'export_draco_mesh_compression_level')
643 col = layout.column(align=True)
644 col.prop(operator, 'export_draco_position_quantization', text="Quantize Position")
645 col.prop(operator, 'export_draco_normal_quantization', text="Normal")
646 col.prop(operator, 'export_draco_texcoord_quantization', text="Tex Coords")
647 col.prop(operator, 'export_draco_generic_quantization', text="Generic")
650 class GLTF_PT_export_animation(bpy.types.Panel):
651 bl_space_type = 'FILE_BROWSER'
652 bl_region_type = 'TOOL_PROPS'
653 bl_label = "Animation"
654 bl_parent_id = "FILE_PT_operator"
655 bl_options = {'DEFAULT_CLOSED'}
657 @classmethod
658 def poll(cls, context):
659 sfile = context.space_data
660 operator = sfile.active_operator
662 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
664 def draw(self, context):
665 layout = self.layout
666 layout.use_property_split = True
667 layout.use_property_decorate = False # No animation.
669 sfile = context.space_data
670 operator = sfile.active_operator
672 layout.prop(operator, 'export_current_frame')
675 class GLTF_PT_export_animation_export(bpy.types.Panel):
676 bl_space_type = 'FILE_BROWSER'
677 bl_region_type = 'TOOL_PROPS'
678 bl_label = "Animation"
679 bl_parent_id = "GLTF_PT_export_animation"
680 bl_options = {'DEFAULT_CLOSED'}
682 @classmethod
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_header(self, context):
690 sfile = context.space_data
691 operator = sfile.active_operator
692 self.layout.prop(operator, "export_animations", text="")
694 def draw(self, context):
695 layout = self.layout
696 layout.use_property_split = True
697 layout.use_property_decorate = False # No animation.
699 sfile = context.space_data
700 operator = sfile.active_operator
702 layout.active = operator.export_animations
704 layout.prop(operator, 'export_frame_range')
705 layout.prop(operator, 'export_frame_step')
706 layout.prop(operator, 'export_force_sampling')
707 layout.prop(operator, 'export_nla_strips')
709 row = layout.row()
710 row.active = operator.export_force_sampling
711 row.prop(operator, 'export_def_bones')
714 class GLTF_PT_export_animation_shapekeys(bpy.types.Panel):
715 bl_space_type = 'FILE_BROWSER'
716 bl_region_type = 'TOOL_PROPS'
717 bl_label = "Shape Keys"
718 bl_parent_id = "GLTF_PT_export_animation"
719 bl_options = {'DEFAULT_CLOSED'}
721 @classmethod
722 def poll(cls, context):
723 sfile = context.space_data
724 operator = sfile.active_operator
726 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
728 def draw_header(self, context):
729 sfile = context.space_data
730 operator = sfile.active_operator
731 self.layout.prop(operator, "export_morph", text="")
733 def draw(self, context):
734 layout = self.layout
735 layout.use_property_split = True
736 layout.use_property_decorate = False # No animation.
738 sfile = context.space_data
739 operator = sfile.active_operator
741 layout.active = operator.export_morph
743 layout.prop(operator, 'export_morph_normal')
744 col = layout.column()
745 col.active = operator.export_morph_normal
746 col.prop(operator, 'export_morph_tangent')
749 class GLTF_PT_export_animation_skinning(bpy.types.Panel):
750 bl_space_type = 'FILE_BROWSER'
751 bl_region_type = 'TOOL_PROPS'
752 bl_label = "Skinning"
753 bl_parent_id = "GLTF_PT_export_animation"
754 bl_options = {'DEFAULT_CLOSED'}
756 @classmethod
757 def poll(cls, context):
758 sfile = context.space_data
759 operator = sfile.active_operator
761 return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
763 def draw_header(self, context):
764 sfile = context.space_data
765 operator = sfile.active_operator
766 self.layout.prop(operator, "export_skins", text="")
768 def draw(self, context):
769 layout = self.layout
770 layout.use_property_split = True
771 layout.use_property_decorate = False # No animation.
773 sfile = context.space_data
774 operator = sfile.active_operator
776 layout.active = operator.export_skins
777 layout.prop(operator, 'export_all_influences')
779 class GLTF_PT_export_user_extensions(bpy.types.Panel):
780 bl_space_type = 'FILE_BROWSER'
781 bl_region_type = 'TOOL_PROPS'
782 bl_label = "Extensions"
783 bl_parent_id = "FILE_PT_operator"
784 bl_options = {'DEFAULT_CLOSED'}
786 @classmethod
787 def poll(cls, context):
788 sfile = context.space_data
789 operator = sfile.active_operator
791 return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_extenions
793 def draw(self, context):
794 layout = self.layout
795 layout.use_property_split = True
796 layout.use_property_decorate = False # No animation.
799 class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
800 """Export scene as glTF 2.0 file"""
801 bl_idname = 'export_scene.gltf'
802 bl_label = 'Export glTF 2.0'
804 filename_ext = ''
806 filter_glob: StringProperty(default='*.glb;*.gltf', options={'HIDDEN'})
809 def menu_func_export(self, context):
810 self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
813 class ImportGLTF2(Operator, ImportHelper):
814 """Load a glTF 2.0 file"""
815 bl_idname = 'import_scene.gltf'
816 bl_label = 'Import glTF 2.0'
818 filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
820 files: CollectionProperty(
821 name="File Path",
822 type=bpy.types.OperatorFileListElement,
825 loglevel: IntProperty(
826 name='Log Level',
827 description="Log Level")
829 import_pack_images: BoolProperty(
830 name='Pack images',
831 description='Pack all images into .blend file',
832 default=True
835 import_shading: EnumProperty(
836 name="Shading",
837 items=(("NORMALS", "Use Normal Data", ""),
838 ("FLAT", "Flat Shading", ""),
839 ("SMOOTH", "Smooth Shading", "")),
840 description="How normals are computed during import",
841 default="NORMALS")
843 def draw(self, context):
844 layout = self.layout
846 layout.prop(self, 'import_pack_images')
847 layout.prop(self, 'import_shading')
849 def execute(self, context):
850 return self.import_gltf2(context)
852 def import_gltf2(self, context):
853 import os
855 self.set_debug_log()
856 import_settings = self.as_keywords()
858 if self.files:
859 # Multiple file import
860 ret = {'CANCELLED'}
861 dirname = os.path.dirname(self.filepath)
862 for file in self.files:
863 path = os.path.join(dirname, file.name)
864 if self.unit_import(path, import_settings) == {'FINISHED'}:
865 ret = {'FINISHED'}
866 return ret
867 else:
868 # Single file import
869 return self.unit_import(self.filepath, import_settings)
871 def unit_import(self, filename, import_settings):
872 import time
873 from .io.imp.gltf2_io_gltf import glTFImporter
874 from .blender.imp.gltf2_blender_gltf import BlenderGlTF
876 self.gltf_importer = glTFImporter(filename, import_settings)
877 success, txt = self.gltf_importer.read()
878 if not success:
879 self.report({'ERROR'}, txt)
880 return {'CANCELLED'}
881 success, txt = self.gltf_importer.checks()
882 if not success:
883 self.report({'ERROR'}, txt)
884 return {'CANCELLED'}
885 self.gltf_importer.log.critical("Data are loaded, start creating Blender stuff")
886 start_time = time.time()
887 BlenderGlTF.create(self.gltf_importer)
888 elapsed_s = "{:.2f}s".format(time.time() - start_time)
889 self.gltf_importer.log.critical("glTF import finished in " + elapsed_s)
890 self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler)
892 return {'FINISHED'}
894 def set_debug_log(self):
895 import logging
896 if bpy.app.debug_value == 0:
897 self.loglevel = logging.CRITICAL
898 elif bpy.app.debug_value == 1:
899 self.loglevel = logging.ERROR
900 elif bpy.app.debug_value == 2:
901 self.loglevel = logging.WARNING
902 elif bpy.app.debug_value == 3:
903 self.loglevel = logging.INFO
904 else:
905 self.loglevel = logging.NOTSET
908 def menu_func_import(self, context):
909 self.layout.operator(ImportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
912 classes = (
913 ExportGLTF2,
914 GLTF_PT_export_main,
915 GLTF_PT_export_include,
916 GLTF_PT_export_transform,
917 GLTF_PT_export_geometry,
918 GLTF_PT_export_geometry_compression,
919 GLTF_PT_export_animation,
920 GLTF_PT_export_animation_export,
921 GLTF_PT_export_animation_shapekeys,
922 GLTF_PT_export_animation_skinning,
923 GLTF_PT_export_user_extensions,
924 ImportGLTF2
928 def register():
929 for c in classes:
930 bpy.utils.register_class(c)
931 # bpy.utils.register_module(__name__)
933 # add to the export / import menu
934 bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
935 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
938 def unregister():
939 for c in classes:
940 bpy.utils.unregister_class(c)
941 for f in extension_panel_unregister_functors:
943 extension_panel_unregister_functors.clear()
945 # bpy.utils.unregister_module(__name__)
947 # remove from the export / import menu
948 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
949 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)