glTF importer: performance: create bones in batches instead of switching edit/pose mode for each bone

This commit is contained in:
Julien Duroure 2020-01-29 21:49:29 +01:00
parent d8aa24a932
commit 39e2149b6c
2 changed files with 52 additions and 30 deletions

View File

@ -15,7 +15,7 @@
bl_info = {
'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
"version": (1, 2, 14),
"version": (1, 2, 15),
'blender': (2, 81, 6),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',

View File

@ -37,9 +37,12 @@ class BlenderNode():
if vnode.type == VNode.Object:
BlenderNode.create_object(gltf, vnode_id)
if vnode.is_arma:
BlenderNode.create_bones(gltf, vnode_id)
elif vnode.type == VNode.Bone:
BlenderNode.create_bone(gltf, vnode_id)
# These are created with their armature
pass
elif vnode.type == VNode.DummyRoot:
# Don't actually create this
@ -101,49 +104,68 @@ class BlenderNode():
return obj
@staticmethod
def create_bone(gltf, vnode_id):
vnode = gltf.vnodes[vnode_id]
blender_arma = gltf.vnodes[vnode.bone_arma].blender_object
def create_bones(gltf, arma_id):
arma = gltf.vnodes[arma_id]
blender_arma = arma.blender_object
armature = blender_arma.data
# Switch into edit mode to create edit bone
# Find all bones for this arma
bone_ids = []
def visit(id): # Depth-first walk
if gltf.vnodes[id].type == VNode.Bone:
bone_ids.append(id)
for child in gltf.vnodes[id].children:
visit(child)
for child in arma.children:
visit(child)
# Switch into edit mode to create all edit bones
if bpy.context.mode != 'OBJECT':
bpy.ops.object.mode_set(mode='OBJECT')
bpy.context.window.scene = bpy.data.scenes[gltf.blender_scene]
bpy.context.view_layer.objects.active = blender_arma
bpy.ops.object.mode_set(mode="EDIT")
editbone = armature.edit_bones.new(vnode.name)
vnode.blender_bone_name = editbone.name
# Set extras (if came from a glTF node)
if isinstance(vnode_id, int):
pynode = gltf.data.nodes[vnode_id]
set_extras(editbone, pynode.extras)
for id in bone_ids:
vnode = gltf.vnodes[id]
editbone = armature.edit_bones.new(vnode.name)
vnode.blender_bone_name = editbone.name
editbone.use_connect = False # TODO?
# TODO
editbone.use_connect = False
# Give the position of the bone in armature space
arma_mat = vnode.bone_arma_mat
editbone.head = arma_mat @ Vector((0, 0, 0))
editbone.tail = arma_mat @ Vector((0, 1, 0))
editbone.align_roll(arma_mat @ Vector((0, 0, 1)) - editbone.head)
# Give the position of the bone in armature space
arma_mat = vnode.bone_arma_mat
editbone.head = arma_mat @ Vector((0, 0, 0))
editbone.tail = arma_mat @ Vector((0, 1, 0))
editbone.align_roll(arma_mat @ Vector((0, 0, 1)) - editbone.head)
if isinstance(id, int):
pynode = gltf.data.nodes[id]
set_extras(editbone, pynode.extras)
# Set parent
parent_vnode = gltf.vnodes[vnode.parent]
if parent_vnode.type == VNode.Bone:
editbone.parent = armature.edit_bones[parent_vnode.blender_bone_name]
# Set all bone parents
for id in bone_ids:
vnode = gltf.vnodes[id]
parent_vnode = gltf.vnodes[vnode.parent]
if parent_vnode.type == VNode.Bone:
editbone = armature.edit_bones[vnode.blender_bone_name]
parent_editbone = armature.edit_bones[parent_vnode.blender_bone_name]
editbone.parent = parent_editbone
# Switch back to object mode and do pose bones
bpy.ops.object.mode_set(mode="OBJECT")
pose_bone = blender_arma.pose.bones[vnode.blender_bone_name]
# Put scale on the pose bone (can't go on the edit bone)
_, _, s = vnode.trs
pose_bone.scale = s
for id in bone_ids:
vnode = gltf.vnodes[id]
pose_bone = blender_arma.pose.bones[vnode.blender_bone_name]
if isinstance(vnode_id, int):
pynode = gltf.data.nodes[vnode_id]
set_extras(pose_bone, pynode.extras)
# Put scale on pose bone (edit bones have no scale)
_, _, s = vnode.trs
pose_bone.scale = s
if isinstance(id, int):
pynode = gltf.data.nodes[id]
set_extras(pose_bone, pynode.extras)
@staticmethod
def create_mesh_object(gltf, pynode, name):