Newer
Older
def draw_header(self, context):
sfile = context.space_data
operator = sfile.active_operator
self.layout.prop(operator, "export_skins", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
sfile = context.space_data
operator = sfile.active_operator
layout.active = operator.export_skins
layout.prop(operator, 'export_all_influences')
row = layout.row()
row.active = operator.export_force_sampling
row.prop(operator, 'export_def_bones')
if operator.export_force_sampling is False and operator.export_def_bones is True:
layout.label(text="Export only deformation bones is not possible when not sampling animation")
class GLTF_PT_export_user_extensions(bpy.types.Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOL_PROPS'
bl_label = "Exporter Extensions"
bl_parent_id = "FILE_PT_operator"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sfile = context.space_data
operator = sfile.active_operator
return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_exporter_extensions
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
class GLTF_PT_import_user_extensions(bpy.types.Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOL_PROPS'
bl_label = "Importer Extensions"
bl_parent_id = "FILE_PT_operator"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sfile = context.space_data
operator = sfile.active_operator
return operator.bl_idname == "IMPORT_SCENE_OT_gltf" and operator.has_active_importer_extensions
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
"""Export scene as glTF 2.0 file"""
bl_idname = 'export_scene.gltf'
bl_label = 'Export glTF 2.0'
filename_ext = ''
filter_glob: StringProperty(default='*.glb;*.gltf', options={'HIDDEN'})
def menu_func_export(self, context):
self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
class ImportGLTF2(Operator, ImportHelper):
"""Load a glTF 2.0 file"""
bl_idname = 'import_scene.gltf'
bl_label = 'Import glTF 2.0'
bl_options = {'REGISTER', 'UNDO'}
filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
files: CollectionProperty(
name="File Path",
type=bpy.types.OperatorFileListElement,
)
loglevel: IntProperty(
name='Log Level',
description="Log Level")
import_pack_images: BoolProperty(
name='Pack Images',
description='Pack all images into .blend file',
default=True
)
merge_vertices: BoolProperty(
name='Merge Vertices',
description=(
'The glTF format requires discontinuous normals, UVs, and '
'other vertex attributes to be stored as separate vertices, '
'as required for rendering on typical graphics hardware. '
'This option attempts to combine co-located vertices where possible. '
'Currently cannot combine verts with different normals'
),
default=False,
)
import_shading: EnumProperty(
name="Shading",
items=(("NORMALS", "Use Normal Data", ""),
("FLAT", "Flat Shading", ""),
("SMOOTH", "Smooth Shading", "")),
description="How normals are computed during import",
default="NORMALS")
bone_heuristic: EnumProperty(
name="Bone Dir",
items=(
("BLENDER", "Blender (best for re-importing)",
"Good for re-importing glTFs exported from Blender. "
"Bone tips are placed on their local +Y axis (in glTF space)"),
("TEMPERANCE", "Temperance (average)",
"Decent all-around strategy. "
"A bone with one child has its tip placed on the local axis "
"closest to its child"),
("FORTUNE", "Fortune (may look better, less accurate)",
"Might look better than Temperance, but also might have errors. "
"A bone with one child has its tip placed at its child's root. "
"Non-uniform scalings may get messed up though, so beware"),
),
description="Heuristic for placing bones. Tries to make bones pretty",
default="TEMPERANCE",
)
guess_original_bind_pose: BoolProperty(
name='Guess Original Bind Pose',
description=(
'Try to guess the original bind pose for skinned meshes from '
'When off, use default/rest pose as bind pose'
),
default=True,
)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
layout.prop(self, 'import_pack_images')
layout.prop(self, 'merge_vertices')
layout.prop(self, 'import_shading')
layout.prop(self, 'guess_original_bind_pose')
layout.prop(self, 'bone_heuristic')
def invoke(self, context, event):
import sys
preferences = bpy.context.preferences
for addon_name in preferences.addons.keys():
try:
if hasattr(sys.modules[addon_name], 'glTF2ImportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ImportUserExtensions'):
importer_extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
except Exception:
pass
self.has_active_importer_extensions = len(importer_extension_panel_unregister_functors) > 0
return ImportHelper.invoke(self, context, event)
def execute(self, context):
return self.import_gltf2(context)
def import_gltf2(self, context):
import os
self.set_debug_log()
import_settings = self.as_keywords()
user_extensions = []
import sys
preferences = bpy.context.preferences
for addon_name in preferences.addons.keys():
try:
module = sys.modules[addon_name]
except Exception:
continue
if hasattr(module, 'glTF2ImportUserExtension'):
extension_ctor = module.glTF2ImportUserExtension
user_extensions.append(extension_ctor())
import_settings['import_user_extensions'] = user_extensions
if self.files:
# Multiple file import
ret = {'CANCELLED'}
dirname = os.path.dirname(self.filepath)
for file in self.files:
path = os.path.join(dirname, file.name)
if self.unit_import(path, import_settings) == {'FINISHED'}:
ret = {'FINISHED'}
return ret
else:
# Single file import
return self.unit_import(self.filepath, import_settings)
def unit_import(self, filename, import_settings):
import time
from .io.imp.gltf2_io_gltf import glTFImporter, ImportError
from .blender.imp.gltf2_blender_gltf import BlenderGlTF
try:
gltf_importer = glTFImporter(filename, import_settings)
gltf_importer.read()
gltf_importer.checks()
print("Data are loaded, start creating Blender stuff")
start_time = time.time()
BlenderGlTF.create(gltf_importer)
elapsed_s = "{:.2f}s".format(time.time() - start_time)
print("glTF import finished in " + elapsed_s)
gltf_importer.log.removeHandler(gltf_importer.log_handler)
return {'FINISHED'}
except ImportError as e:
self.report({'ERROR'}, e.args[0])
return {'CANCELLED'}
def set_debug_log(self):
import logging
if bpy.app.debug_value == 0:
self.loglevel = logging.CRITICAL
elif bpy.app.debug_value == 1:
self.loglevel = logging.ERROR
elif bpy.app.debug_value == 2:
self.loglevel = logging.WARNING
elif bpy.app.debug_value == 3:
self.loglevel = logging.INFO
else:
self.loglevel = logging.NOTSET
Julien Duroure
committed
def gltf_variant_ui_update(self, context):
from .blender.com.gltf2_blender_ui import variant_register, variant_unregister
if self.KHR_materials_variants_ui is True:
# register all needed types
variant_register()
else:
variant_unregister()
class GLTF_AddonPreferences(bpy.types.AddonPreferences):
bl_idname = __package__
settings_node_ui : bpy.props.BoolProperty(
default= False,
description="Displays glTF Settings node in Shader Editor (Menu Add > Output)"
Julien Duroure
committed
KHR_materials_variants_ui : bpy.props.BoolProperty(
default= False,
description="Displays glTF UI to manage material variants",
update=gltf_variant_ui_update
)
def draw(self, context):
layout = self.layout
row = layout.row()
row.prop(self, "settings_node_ui", text="Shader Editor Add-ons")
Julien Duroure
committed
row.prop(self, "KHR_materials_variants_ui", text="Material Variants")
def menu_func_import(self, context):
self.layout.operator(ImportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
classes = (
ExportGLTF2,
GLTF_PT_export_main,
GLTF_PT_export_include,
GLTF_PT_export_transform,
GLTF_PT_export_geometry,
Julien Duroure
committed
GLTF_PT_export_geometry_mesh,
GLTF_PT_export_geometry_material,
GLTF_PT_export_geometry_original_pbr,
GLTF_PT_export_geometry_compression,
GLTF_PT_export_animation,
GLTF_PT_export_animation_export,
GLTF_PT_export_animation_shapekeys,
GLTF_PT_export_animation_skinning,
GLTF_PT_export_user_extensions,
GLTF_PT_import_user_extensions,
GLTF_AddonPreferences
import io_scene_gltf2.blender.com.gltf2_blender_ui as blender_ui
for c in classes:
bpy.utils.register_class(c)
# bpy.utils.register_module(__name__)
blender_ui.register()
Julien Duroure
committed
if bpy.context.preferences.addons['io_scene_gltf2'].preferences.KHR_materials_variants_ui is True:
blender_ui.variant_register()
# add to the export / import menu
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
def unregister():
import io_scene_gltf2.blender.com.gltf2_blender_ui as blender_ui
Julien Duroure
committed
blender_ui.unregister()
if bpy.context.preferences.addons['io_scene_gltf2'].preferences.KHR_materials_variants_ui is True:
blender_ui.variant_unregister()
for c in classes:
bpy.utils.unregister_class(c)
for f in exporter_extension_panel_unregister_functors:
f()
exporter_extension_panel_unregister_functors.clear()
for f in importer_extension_panel_unregister_functors:
importer_extension_panel_unregister_functors.clear()
# bpy.utils.unregister_module(__name__)
# remove from the export / import menu
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)