glTF exporter: fix shapekeys animation export
Animation channels must be sorted in exactly same order than shapekeys
This commit is contained in:
parent
3c3c2243db
commit
fc320ea236
|
@ -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": (0, 9, 48),
|
||||
"version": (0, 9, 49),
|
||||
'blender': (2, 80, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
|
|
@ -499,14 +499,14 @@ def extract_primitives(glTF, blender_mesh, blender_vertex_groups, modifiers, exp
|
|||
blender_shape_keys = []
|
||||
|
||||
if blender_mesh.shape_keys is not None:
|
||||
morph_max = len(blender_mesh.shape_keys.key_blocks) - 1
|
||||
|
||||
for blender_shape_key in blender_mesh.shape_keys.key_blocks:
|
||||
if blender_shape_key != blender_shape_key.relative_key:
|
||||
blender_shape_keys.append(ShapeKey(
|
||||
blender_shape_key,
|
||||
blender_shape_key.normals_vertex_get(), # calculate vertex normals for this shape key
|
||||
blender_shape_key.normals_polygon_get())) # calculate polygon normals for this shape key
|
||||
if blender_shape_key.mute is False:
|
||||
morph_max += 1
|
||||
blender_shape_keys.append(ShapeKey(
|
||||
blender_shape_key,
|
||||
blender_shape_key.normals_vertex_get(), # calculate vertex normals for this shape key
|
||||
blender_shape_key.normals_polygon_get())) # calculate polygon normals for this shape key
|
||||
|
||||
#
|
||||
# Convert polygon to primitive indices and eliminate invalid ones. Assign to material.
|
||||
|
|
|
@ -64,12 +64,35 @@ def gather_animation_channels(blender_action: bpy.types.Action,
|
|||
channels.append(channel)
|
||||
else:
|
||||
for channel_group in __get_channel_groups(blender_action, blender_object, export_settings):
|
||||
channel = __gather_animation_channel(channel_group, blender_object, export_settings, None, None, None, None, blender_action.name)
|
||||
channel_group_sorted = __get_channel_group_sorted(channel_group, blender_object)
|
||||
channel = __gather_animation_channel(channel_group_sorted, blender_object, export_settings, None, None, None, None, blender_action.name)
|
||||
if channel is not None:
|
||||
channels.append(channel)
|
||||
|
||||
return channels
|
||||
|
||||
def __get_channel_group_sorted(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object):
|
||||
# if this is shapekey animation, we need to sort in same order than shapekeys
|
||||
# else, no need to sort
|
||||
if blender_object.type == "MESH":
|
||||
first_channel = channels[0]
|
||||
object_path = get_target_object_path(first_channel.data_path)
|
||||
if object_path:
|
||||
# This is shapekeys, we need to sort channels
|
||||
shapekeys_idx = {}
|
||||
cpt_sk = 0
|
||||
for sk in blender_object.data.shape_keys.key_blocks:
|
||||
if sk == sk.relative_key:
|
||||
continue
|
||||
if sk.mute is True:
|
||||
continue
|
||||
shapekeys_idx[sk.name] = cpt_sk
|
||||
cpt_sk += 1
|
||||
|
||||
return tuple(sorted(channels, key=lambda x: shapekeys_idx[blender_object.data.shape_keys.path_resolve(get_target_object_path(x.data_path)).name]))
|
||||
|
||||
# if not shapekeys, stay in same order, because order doesn't matter
|
||||
return channels
|
||||
|
||||
def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve],
|
||||
blender_object: bpy.types.Object,
|
||||
|
@ -164,12 +187,17 @@ def __get_channel_groups(blender_action: bpy.types.Action, blender_object: bpy.t
|
|||
else:
|
||||
try:
|
||||
target = gltf2_blender_get.get_object_from_datapath(blender_object, object_path)
|
||||
if blender_object.type == "MESH":
|
||||
shape_key = blender_object.data.shape_keys.path_resolve(object_path)
|
||||
if shape_key.mute is True:
|
||||
continue
|
||||
except ValueError as e:
|
||||
# if the object is a mesh and the action target path can not be resolved, we know that this is a morph
|
||||
# animation.
|
||||
if blender_object.type == "MESH":
|
||||
# if you need the specific shape key for some reason, this is it:
|
||||
# shape_key = blender_object.data.shape_keys.path_resolve(object_path)
|
||||
shape_key = blender_object.data.shape_keys.path_resolve(object_path)
|
||||
if shape_key.mute is True:
|
||||
continue
|
||||
target = blender_object.data.shape_keys
|
||||
else:
|
||||
gltf2_io_debug.print_console("WARNING", "Animation target {} not found".format(object_path))
|
||||
|
|
|
@ -83,7 +83,8 @@ def __gather_extras(blender_mesh: bpy.types.Mesh,
|
|||
target_names = []
|
||||
for blender_shape_key in blender_mesh.shape_keys.key_blocks:
|
||||
if blender_shape_key != blender_shape_key.relative_key:
|
||||
target_names.append(blender_shape_key.name)
|
||||
if blender_shape_key.mute is False:
|
||||
target_names.append(blender_shape_key.name)
|
||||
extras['targetNames'] = target_names
|
||||
|
||||
if extras:
|
||||
|
@ -130,7 +131,8 @@ def __gather_weights(blender_mesh: bpy.types.Mesh,
|
|||
|
||||
for blender_shape_key in blender_mesh.shape_keys.key_blocks:
|
||||
if blender_shape_key != blender_shape_key.relative_key:
|
||||
weights.append(blender_shape_key.value)
|
||||
if blender_shape_key.mute is False:
|
||||
weights.append(blender_shape_key.value)
|
||||
|
||||
return weights
|
||||
|
||||
|
|
|
@ -143,87 +143,91 @@ def __gather_targets(blender_primitive, blender_mesh, modifiers, export_settings
|
|||
if blender_mesh.shape_keys is not None:
|
||||
morph_index = 0
|
||||
for blender_shape_key in blender_mesh.shape_keys.key_blocks:
|
||||
if blender_shape_key != blender_shape_key.relative_key:
|
||||
if blender_shape_key == blender_shape_key.relative_key:
|
||||
continue
|
||||
|
||||
target_position_id = 'MORPH_POSITION_' + str(morph_index)
|
||||
target_normal_id = 'MORPH_NORMAL_' + str(morph_index)
|
||||
target_tangent_id = 'MORPH_TANGENT_' + str(morph_index)
|
||||
if blender_shape_key.mute is True:
|
||||
continue
|
||||
|
||||
if blender_primitive["attributes"].get(target_position_id):
|
||||
target = {}
|
||||
internal_target_position = blender_primitive["attributes"][target_position_id]
|
||||
target_position_id = 'MORPH_POSITION_' + str(morph_index)
|
||||
target_normal_id = 'MORPH_NORMAL_' + str(morph_index)
|
||||
target_tangent_id = 'MORPH_TANGENT_' + str(morph_index)
|
||||
|
||||
if blender_primitive["attributes"].get(target_position_id):
|
||||
target = {}
|
||||
internal_target_position = blender_primitive["attributes"][target_position_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_target_position,
|
||||
gltf2_io_constants.ComponentType.Float
|
||||
)
|
||||
target["POSITION"] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_position) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=gltf2_blender_utils.max_components(
|
||||
internal_target_position, gltf2_io_constants.DataType.Vec3),
|
||||
min=gltf2_blender_utils.min_components(
|
||||
internal_target_position, gltf2_io_constants.DataType.Vec3),
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
)
|
||||
|
||||
if export_settings[NORMALS] \
|
||||
and export_settings[MORPH_NORMAL] \
|
||||
and blender_primitive["attributes"].get(target_normal_id):
|
||||
|
||||
internal_target_normal = blender_primitive["attributes"][target_normal_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_target_position,
|
||||
gltf2_io_constants.ComponentType.Float
|
||||
internal_target_normal,
|
||||
gltf2_io_constants.ComponentType.Float,
|
||||
)
|
||||
target["POSITION"] = gltf2_io.Accessor(
|
||||
target['NORMAL'] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_position) // gltf2_io_constants.DataType.num_elements(
|
||||
count=len(internal_target_normal) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=gltf2_blender_utils.max_components(
|
||||
internal_target_position, gltf2_io_constants.DataType.Vec3),
|
||||
min=gltf2_blender_utils.min_components(
|
||||
internal_target_position, gltf2_io_constants.DataType.Vec3),
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
)
|
||||
|
||||
if export_settings[NORMALS] \
|
||||
and export_settings[MORPH_NORMAL] \
|
||||
and blender_primitive["attributes"].get(target_normal_id):
|
||||
|
||||
internal_target_normal = blender_primitive["attributes"][target_normal_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_target_normal,
|
||||
gltf2_io_constants.ComponentType.Float,
|
||||
)
|
||||
target['NORMAL'] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_normal) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
)
|
||||
|
||||
if export_settings[TANGENTS] \
|
||||
and export_settings[MORPH_TANGENT] \
|
||||
and blender_primitive["attributes"].get(target_tangent_id):
|
||||
internal_target_tangent = blender_primitive["attributes"][target_tangent_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_target_tangent,
|
||||
gltf2_io_constants.ComponentType.Float,
|
||||
)
|
||||
target['TANGENT'] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_tangent) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
)
|
||||
targets.append(target)
|
||||
morph_index += 1
|
||||
if export_settings[TANGENTS] \
|
||||
and export_settings[MORPH_TANGENT] \
|
||||
and blender_primitive["attributes"].get(target_tangent_id):
|
||||
internal_target_tangent = blender_primitive["attributes"][target_tangent_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_target_tangent,
|
||||
gltf2_io_constants.ComponentType.Float,
|
||||
)
|
||||
target['TANGENT'] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_tangent) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
)
|
||||
targets.append(target)
|
||||
morph_index += 1
|
||||
return targets
|
||||
return None
|
||||
|
||||
|
|
Loading…
Reference in New Issue