io_scene_gltf2: quiet warning
[blender-addons.git] / io_scene_gltf2 / __init__.py
blobde2462be5a1994a742dc384fa65859432aaa4ecc
1 # Copyright 2018 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 # Imports
19 import os
20 import bpy
21 from bpy_extras.io_utils import ImportHelper, ExportHelper
22 from bpy.types import Operator, AddonPreferences
24 from .io.com.gltf2_io_debug import Log
26 from bpy.props import (CollectionProperty,
27 StringProperty,
28 BoolProperty,
29 EnumProperty,
30 FloatProperty,
31 IntProperty)
34 # Globals
37 bl_info = {
38 'name': 'glTF 2.0 format',
39 'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann & Moritz Becher',
40 "version": (0, 0, 1),
41 'blender': (2, 80, 0),
42 'location': 'File > Import-Export',
43 'description': 'Import-Export as glTF 2.0',
44 'warning': '',
45 'wiki_url': "https://github.com/KhronosGroup/glTF-Blender-IO",
46 'tracker_url': "https://github.com/KhronosGroup/glTF-Blender-IO/issues/",
47 'support': 'OFFICIAL',
48 'category': 'Import-Export'}
52 # Functions / Classes.
56 class GLTF2ExportSettings(bpy.types.Operator):
57 """Save the export settings on export (saved in .blend). """
58 """Toggle off to clear settings"""
59 bl_label = "Save Settings"
60 bl_idname = "scene.gltf2_export_settings_set"
62 def execute(self, context):
63 operator = context.active_operator
64 operator.will_save_settings = not operator.will_save_settings
65 if not operator.will_save_settings:
66 # clear settings
67 context.scene.pop(operator.scene_key)
68 return {"FINISHED"}
71 class ExportGLTF2_Base:
73 # TODO: refactor to avoid boilerplate
75 export_format: EnumProperty(
76 name='Format',
77 items=(('GLB', 'glTF Binary (.glb)',
78 'Exports a single file, with all data packed in binary form. '
79 'Most efficient and portable, but more difficult to edit later'),
80 ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
81 'Exports a single file, with all data packed in JSON. '
82 'Less efficient than binary, but easier to edit later'),
83 ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
84 'Exports multiple files, with separate JSON, binary and texture data. '
85 'Easiest to edit later')),
86 description=(
87 'Output format and embedding options. Binary is most efficient, '
88 'but JSON (embedded or separate) may be easier to edit later'
90 default='GLB'
93 export_copyright: StringProperty(
94 name='Copyright',
95 description='Legal rights and conditions for the model',
96 default=''
99 export_texcoords: BoolProperty(
100 name='UVs',
101 description='Export UVs (texture coordinates) with meshes',
102 default=True
105 export_normals: BoolProperty(
106 name='Normals',
107 description='Export vertex normals with meshes',
108 default=True
111 export_tangents: BoolProperty(
112 name='Tangents',
113 description='Export vertex tangents with meshes',
114 default=False
117 export_materials: BoolProperty(
118 name='Materials',
119 description='Export materials',
120 default=True
123 export_colors: BoolProperty(
124 name='Vertex Colors',
125 description='Export vertex colors with meshes',
126 default=True
129 export_cameras: BoolProperty(
130 name='Cameras',
131 description='Export cameras',
132 default=False
135 export_selected: BoolProperty(
136 name='Selected Objects',
137 description='Export selected objects only',
138 default=False
141 # export_layers: BoolProperty(
142 # name='All layers',
143 # description='Export all layers, rather than just the first',
144 # default=True
147 export_extras: BoolProperty(
148 name='Custom Properties',
149 description='Export custom properties as glTF extras',
150 default=False
153 export_yup: BoolProperty(
154 name='+Y Up',
155 description='Export using glTF convention, +Y up',
156 default=True
159 export_apply: BoolProperty(
160 name='Apply Modifiers',
161 description='Apply modifiers to mesh objects',
162 default=False
165 export_animations: BoolProperty(
166 name='Animations',
167 description='Exports active actions and NLA tracks as glTF animations',
168 default=True
171 export_frame_range: BoolProperty(
172 name='Limit to Playback Range',
173 description='Clips animations to selected playback range',
174 default=True
177 export_frame_step: IntProperty(
178 name='Sampling Rate',
179 description='How often to evaluate animated values (in frames)',
180 default=1,
181 min=1,
182 max=120
185 export_move_keyframes: BoolProperty(
186 name='Keyframes Start at 0',
187 description='Keyframes start at 0, instead of 1',
188 default=True
191 export_force_sampling: BoolProperty(
192 name='Always Sample Animations',
193 description='Apply sampling to all animations',
194 default=False
197 export_current_frame: BoolProperty(
198 name='Use Current Frame',
199 description='Export the scene in the current animation frame',
200 default=True
203 export_skins: BoolProperty(
204 name='Skinning',
205 description='Export skinning (armature) data',
206 default=True
209 export_bake_skins: BoolProperty(
210 name='Bake Skinning Constraints',
211 description='Apply skinning constraints to armatures',
212 default=False
215 export_all_influences: BoolProperty(
216 name='Include All Bone Influences',
217 description='Allow >4 joint vertex influences. Models may appear' \
218 ' incorrectly in many viewers',
219 default=False
222 export_morph: BoolProperty(
223 name='Shape Keys',
224 description='Export shape keys (morph targets)',
225 default=True
228 export_morph_normal: BoolProperty(
229 name='Shape Key Normals',
230 description='Export vertex normals with shape keys (morph targets)',
231 default=True
234 export_morph_tangent: BoolProperty(
235 name='Shape Key Tangents',
236 description='Export vertex tangents with shape keys (morph targets)',
237 default=False
240 export_lights: BoolProperty(
241 name='Punctual Lights',
242 description='Export directional, point, and spot lights. Uses ' \
243 ' "KHR_lights_punctual" glTF extension',
244 default=False
247 export_texture_transform: BoolProperty(
248 name='Texture Transforms',
249 description='Export texture or UV position, rotation, and scale.' \
250 ' Uses "KHR_texture_transform" glTF extension',
251 default=False
254 export_displacement: BoolProperty(
255 name='Displacement Textures (EXPERIMENTAL)',
256 description='EXPERIMENTAL: Export displacement textures. Uses' \
257 ' incomplete "KHR_materials_displacement" glTF extension',
258 default=False
261 will_save_settings: BoolProperty(default=False)
263 # Custom scene property for saving settings
264 scene_key = "glTF2ExportSettings"
268 def invoke(self, context, event):
269 settings = context.scene.get(self.scene_key)
270 self.will_save_settings = False
271 if settings:
272 try:
273 for (k, v) in settings.items():
274 setattr(self, k, v)
275 self.will_save_settings = True
277 except AttributeError:
278 self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
279 del context.scene[self.scene_key]
281 return ExportHelper.invoke(self, context, event)
283 def save_settings(self, context):
284 # find all export_ props
285 all_props = self.properties
286 export_props = {x: all_props.get(x) for x in dir(all_props)
287 if x.startswith("export_") and all_props.get(x) is not None}
289 context.scene[self.scene_key] = export_props
291 def execute(self, context):
292 import datetime
293 from .blender.exp import gltf2_blender_export
295 if self.will_save_settings:
296 self.save_settings(context)
298 if self.export_format == 'GLB':
299 self.filename_ext = '.glb'
300 else:
301 self.filename_ext = '.gltf'
303 # All custom export settings are stored in this container.
304 export_settings = {}
306 export_settings['timestamp'] = datetime.datetime.now()
308 export_settings['gltf_filepath'] = bpy.path.ensure_ext(self.filepath, self.filename_ext)
309 export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
311 export_settings['gltf_format'] = self.export_format
312 export_settings['gltf_copyright'] = self.export_copyright
313 export_settings['gltf_texcoords'] = self.export_texcoords
314 export_settings['gltf_normals'] = self.export_normals
315 export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
316 export_settings['gltf_materials'] = self.export_materials
317 export_settings['gltf_colors'] = self.export_colors
318 export_settings['gltf_cameras'] = self.export_cameras
319 export_settings['gltf_selected'] = self.export_selected
320 export_settings['gltf_layers'] = True #self.export_layers
321 export_settings['gltf_extras'] = self.export_extras
322 export_settings['gltf_yup'] = self.export_yup
323 export_settings['gltf_apply'] = self.export_apply
324 export_settings['gltf_animations'] = self.export_animations
325 if self.export_animations:
326 export_settings['gltf_current_frame'] = False
327 export_settings['gltf_frame_range'] = self.export_frame_range
328 export_settings['gltf_move_keyframes'] = self.export_move_keyframes
329 export_settings['gltf_force_sampling'] = self.export_force_sampling
330 else:
331 export_settings['gltf_current_frame'] = self.export_current_frame
332 export_settings['gltf_frame_range'] = False
333 export_settings['gltf_move_keyframes'] = False
334 export_settings['gltf_force_sampling'] = False
335 export_settings['gltf_skins'] = self.export_skins
336 if self.export_skins:
337 export_settings['gltf_bake_skins'] = self.export_bake_skins
338 export_settings['gltf_all_vertex_influences'] = self.export_all_influences
339 else:
340 export_settings['gltf_bake_skins'] = False
341 export_settings['gltf_all_vertex_influences'] = False
342 export_settings['gltf_frame_step'] = self.export_frame_step
343 export_settings['gltf_morph'] = self.export_morph
344 if self.export_morph:
345 export_settings['gltf_morph_normal'] = self.export_morph_normal
346 else:
347 export_settings['gltf_morph_normal'] = False
348 if self.export_morph and self.export_morph_normal:
349 export_settings['gltf_morph_tangent'] = self.export_morph_tangent
350 else:
351 export_settings['gltf_morph_tangent'] = False
353 export_settings['gltf_lights'] = self.export_lights
354 export_settings['gltf_texture_transform'] = self.export_texture_transform
355 export_settings['gltf_displacement'] = self.export_displacement
357 export_settings['gltf_binary'] = bytearray()
358 export_settings['gltf_binaryfilename'] = os.path.splitext(os.path.basename(self.filepath))[0] + '.bin'
360 return gltf2_blender_export.save(context, export_settings)
362 def draw(self, context):
363 layout = self.layout
367 col = layout.box().column()
368 col.label(text='General:', icon='PREFERENCES')
369 col.prop(self, 'export_format')
370 col.prop(self, 'export_selected')
371 #col.prop(self, 'export_layers')
372 col.prop(self, 'export_apply')
373 col.prop(self, 'export_yup')
374 col.prop(self, 'export_extras')
375 col.prop(self, 'export_copyright')
377 col = layout.box().column()
378 col.label(text='Meshes:', icon='MESH_DATA')
379 col.prop(self, 'export_texcoords')
380 col.prop(self, 'export_normals')
381 if self.export_normals:
382 col.prop(self, 'export_tangents')
383 col.prop(self, 'export_colors')
385 col = layout.box().column()
386 col.label(text='Objects:', icon='OBJECT_DATA')
387 col.prop(self, 'export_cameras')
388 col.prop(self, 'export_lights')
390 col = layout.box().column()
391 col.label(text='Materials:', icon='MATERIAL_DATA')
392 col.prop(self, 'export_materials')
393 col.prop(self, 'export_texture_transform')
395 col = layout.box().column()
396 col.label(text='Animation:', icon='ARMATURE_DATA')
397 col.prop(self, 'export_animations')
398 if self.export_animations:
399 col.prop(self, 'export_frame_range')
400 col.prop(self, 'export_frame_step')
401 col.prop(self, 'export_move_keyframes')
402 col.prop(self, 'export_force_sampling')
403 else:
404 col.prop(self, 'export_current_frame')
405 col.prop(self, 'export_skins')
406 if self.export_skins:
407 col.prop(self, 'export_bake_skins')
408 col.prop(self, 'export_all_influences')
409 col.prop(self, 'export_morph')
410 if self.export_morph:
411 col.prop(self, 'export_morph_normal')
412 if self.export_morph_normal:
413 col.prop(self, 'export_morph_tangent')
415 row = layout.row()
416 row.operator(
417 GLTF2ExportSettings.bl_idname,
418 text=GLTF2ExportSettings.bl_label,
419 icon="%s" % "PINNED" if self.will_save_settings else "UNPINNED")
422 class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
423 """Export scene as glTF 2.0 file"""
424 bl_idname = 'export_scene.gltf'
425 bl_label = 'glTF 2.0 (.glb/.gltf)'
427 filename_ext = ''
429 filter_glob: StringProperty(default='*.glb;*.gltf', options={'HIDDEN'})
432 def menu_func_export(self, context):
433 self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
436 class ImportGLTF2(Operator, ImportHelper):
437 bl_idname = 'import_scene.gltf'
438 bl_label = 'glTF 2.0 (.glb/.gltf)'
440 filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
442 loglevel: EnumProperty(
443 items=Log.get_levels(),
444 name="Log Level",
445 description="Set level of log to display",
446 default=Log.default())
448 import_pack_images: BoolProperty(
449 name='Pack images',
450 description='Pack all images into .blend file',
451 default=True
454 import_shading: EnumProperty(
455 name="Shading",
456 items=(("NORMALS", "Use Normal Data", ""),
457 ("FLAT", "Flat Shading", ""),
458 ("SMOOTH", "Smooth Shading", "")),
459 description="How normals are computed during import",
460 default="NORMALS")
462 def draw(self, context):
463 layout = self.layout
465 layout.prop(self, 'loglevel')
466 layout.prop(self, 'import_pack_images')
467 layout.prop(self, 'import_shading')
469 def execute(self, context):
470 return self.import_gltf2(context)
472 def import_gltf2(self, context):
473 from .io.imp.gltf2_io_gltf import glTFImporter
474 from .blender.imp.gltf2_blender_gltf import BlenderGlTF
476 import_settings = self.as_keywords()
478 self.gltf_importer = glTFImporter(self.filepath, import_settings)
479 success, txt = self.gltf_importer.read()
480 if not success:
481 self.report({'ERROR'}, txt)
482 return {'CANCELLED'}
483 success, txt = self.gltf_importer.checks()
484 if not success:
485 self.report({'ERROR'}, txt)
486 return {'CANCELLED'}
487 self.gltf_importer.log.critical("Data are loaded, start creating Blender stuff")
488 BlenderGlTF.create(self.gltf_importer)
489 self.gltf_importer.log.critical("glTF import is now finished")
490 self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler)
492 return {'FINISHED'}
495 def menu_func_import(self, context):
496 self.layout.operator(ImportGLTF2.bl_idname, text=ImportGLTF2.bl_label)
499 classes = (
500 GLTF2ExportSettings,
501 ExportGLTF2,
502 ImportGLTF2
506 def register():
507 for c in classes:
508 bpy.utils.register_class(c)
509 # bpy.utils.register_module(__name__)
511 # add to the export / import menu
512 bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
513 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
516 def unregister():
517 for c in classes:
518 bpy.utils.unregister_class(c)
519 # bpy.utils.unregister_module(__name__)
521 # remove from the export / import menu
522 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
523 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)