diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index 0548f2ec10eb0fb54755cfab936e8c3aec2879ab..36fda5ce247c5ab167834726e60600238054fafb 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -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, 0, 3),
+    "version": (1, 0, 4),
     'blender': (2, 81, 6),
     'location': 'File > Import-Export',
     'description': 'Import-Export as glTF 2.0',
@@ -834,3 +834,4 @@ def unregister():
     # 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)
+
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py
index 2c4587420acb207a7c0d6fc7cc92a2b1151a56f6..04028d20805e4b5453636348d4b9f603e93a0806 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channel_target.py
@@ -78,7 +78,8 @@ def __gather_path(channels: typing.Tuple[bpy.types.FCurve],
                   bake_channel: typing.Union[str, None]
                   ) -> str:
     if bake_channel is None:
-        target = channels[0].data_path.split('.')[-1]
+        # Note: channels has some None items only for SK if some SK are not animated
+        target = [c for c in channels if c is not None][0].data_path.split('.')[-1]
     else:
         target = bake_channel
     path = {
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py
index da963eab49f0059057b5335b1133b4c55df223ce..edee0971627e3e3a521d938f9990271a599dee3f 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py
@@ -37,16 +37,17 @@ def gather_animation_channels(blender_action: bpy.types.Action,
     bake_range_start = None
     bake_range_end = None
     groups = __get_channel_groups(blender_action, blender_object, export_settings)
+    # Note: channels has some None items only for SK if some SK are not animated
     for chans in groups:
-        ranges = [channel.range() for channel in chans]
+        ranges = [channel.range() for channel in chans  if channel is not None]
         if bake_range_start is None:
-            bake_range_start = min([channel.range()[0] for channel in chans])
+            bake_range_start = min([channel.range()[0] for channel in chans  if channel is not None])
         else:
-            bake_range_start = min(bake_range_start, min([channel.range()[0] for channel in chans]))
+            bake_range_start = min(bake_range_start, min([channel.range()[0] for channel in chans  if channel is not None]))
         if bake_range_end is None:
-            bake_range_end = max([channel.range()[1] for channel in chans])
+            bake_range_end = max([channel.range()[1] for channel in chans  if channel is not None])
         else:
-            bake_range_end = max(bake_range_end, max([channel.range()[1] for channel in chans]))
+            bake_range_end = max(bake_range_end, max([channel.range()[1] for channel in chans  if channel is not None]))
 
 
     if blender_object.type == "ARMATURE" and export_settings['gltf_force_sampling'] is True:
@@ -55,7 +56,7 @@ def gather_animation_channels(blender_action: bpy.types.Action,
         # Check that there are some anim in this action
         if bake_range_start is None:
             return []
-            
+
         # Then bake all bones
         for bone in blender_object.data.bones:
             for p in ["location", "rotation_quaternion", "scale"]:
@@ -96,7 +97,21 @@ def __get_channel_group_sorted(channels: typing.Tuple[bpy.types.FCurve], blender
                 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]))
+            # Note: channels will have some None items only for SK if some SK are not animated
+            idx_channel_mapping = []
+            all_sorted_channels = []
+            for sk_c in channels:
+                sk_name = blender_object.data.shape_keys.path_resolve(get_target_object_path(sk_c.data_path)).name
+                idx = shapekeys_idx[sk_name]
+                idx_channel_mapping.append((shapekeys_idx[sk_name], sk_c))
+            existing_idx = dict(idx_channel_mapping)
+            for i in range(0, cpt_sk):
+                if i not in existing_idx.keys():
+                    all_sorted_channels.append(None)
+                else:
+                    all_sorted_channels.append(existing_idx[i])
+
+            return tuple(all_sorted_channels)
 
     # if not shapekeys, stay in same order, because order doesn't matter
     return channels
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
index 8a4f011a5a487063527b790716be0101d9187bac..8b6f0db6a058582bf2579118b3c6266daf0d3dd1 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
@@ -29,9 +29,15 @@ class Keyframe:
         self.seconds = frame / bpy.context.scene.render.fps
         self.frame = frame
         self.fps = bpy.context.scene.render.fps
+        self.__length_morph = 0
+        # Note: channels has some None items only for SK if some SK are not animated
         if bake_channel is None:
-            self.target = channels[0].data_path.split('.')[-1]
-            self.__indices = [c.array_index for c in channels]
+            self.target = [c for c in channels if c is not None][0].data_path.split('.')[-1]
+            if self.target != "value":
+                self.__indices = [c.array_index for c in channels]
+            else:
+                self.__indices = [i for i, c in enumerate(channels) if c is not None]
+                self.__length_morph = len(channels)
         else:
             self.target = bake_channel
             self.__indices = []
@@ -53,7 +59,7 @@ class Keyframe:
             "rotation_euler": 3,
             "rotation_quaternion": 4,
             "scale": 3,
-            "value": 1
+            "value": self.__length_morph
         }.get(self.target)
 
         if length is None:
@@ -62,17 +68,18 @@ class Keyframe:
         return length
 
     def __set_indexed(self, value):
-        # 'value' targets don't use keyframe.array_index
-        if self.target == "value":
-            return value
         # Sometimes blender animations only reference a subset of components of a data target. Keyframe should always
         # contain a complete Vector/ Quaternion --> use the array_index value of the keyframe to set components in such
         # structures
+        # For SK, must contains all SK values
         result = [0.0] * self.get_target_len()
         for i, v in zip(self.__indices, value):
             result[i] = v
-        result = gltf2_blender_math.list_to_mathutils(result, self.target)
-        return result
+        if self.target == "value":
+            return result
+        else:
+            result = gltf2_blender_math.list_to_mathutils(result, self.target)
+            return result
 
     def get_indices(self):
         return self.__indices
@@ -164,10 +171,11 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
     """Convert the blender action groups' fcurves to keyframes for use in glTF."""
     if bake_bone is None:
         # Find the start and end of the whole action group
-        ranges = [channel.range() for channel in channels]
+        # Note: channels has some None items only for SK if some SK are not animated
+        ranges = [channel.range() for channel in channels if channel is not None]
 
-        start_frame = min([channel.range()[0] for channel in channels])
-        end_frame = max([channel.range()[1] for channel in channels])
+        start_frame = min([channel.range()[0] for channel in channels  if channel is not None])
+        end_frame = max([channel.range()[1] for channel in channels  if channel is not None])
     else:
         start_frame = bake_range_start
         end_frame = bake_range_end
@@ -218,25 +226,27 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
                     "scale": scale
                 }[target_property]
             else:
-                key.value = [c.evaluate(frame) for c in channels]
+                # Note: channels has some None items only for SK if some SK are not animated
+                key.value = [c.evaluate(frame) for c in channels if c is not None]
                 complete_key(key, non_keyed_values)
             keyframes.append(key)
             frame += step
     else:
         # Just use the keyframes as they are specified in blender
-        frames = [keyframe.co[0] for keyframe in channels[0].keyframe_points]
+        # Note: channels has some None items only for SK if some SK are not animated
+        frames = [keyframe.co[0] for keyframe in [c for c in channels if c is not None][0].keyframe_points]
         # some weird files have duplicate frame at same time, removed them
         frames = sorted(set(frames))
         for i, frame in enumerate(frames):
             key = Keyframe(channels, frame, bake_channel)
             # key.value = [c.keyframe_points[i].co[0] for c in action_group.channels]
-            key.value = [c.evaluate(frame) for c in channels]
+            key.value = [c.evaluate(frame) for c in channels if c is not None]
             # Complete key with non keyed values, if needed
-            if len(channels) != key.get_target_len():
+            if len([c for c in channels if c is not None]) != key.get_target_len():
                 complete_key(key, non_keyed_values)
 
             # compute tangents for cubic spline interpolation
-            if channels[0].keyframe_points[0].interpolation == "BEZIER":
+            if [c for c in channels if c is not None][0].keyframe_points[0].interpolation == "BEZIER":
                 # Construct the in tangent
                 if frame == frames[0]:
                     # start in-tangent should become all zero
@@ -248,7 +258,7 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
                     key.in_tangent = [
                         c.keyframe_points[i].co[1] + ((c.keyframe_points[i].co[1] - c.keyframe_points[i].handle_left[1]
                                                        ) / (frame - frames[i - 1]))
-                        for c in channels
+                        for c in channels if c is not None
                     ]
                 # Construct the out tangent
                 if frame == frames[-1]:
@@ -261,7 +271,7 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
                     key.out_tangent = [
                         c.keyframe_points[i].co[1] + ((c.keyframe_points[i].handle_right[1] - c.keyframe_points[i].co[1]
                                                        ) / (frames[i + 1] - frame))
-                        for c in channels
+                        for c in channels if c is not None
                     ]
 
             keyframes.append(key)
@@ -273,12 +283,9 @@ def complete_key(key: Keyframe, non_keyed_values: typing.Tuple[typing.Optional[f
     """
     Complete keyframe with non keyed values
     """
-
-    if key.target == "value":
-        return # No array_index
     for i in range(0, key.get_target_len()):
         if i in key.get_indices():
-            continue # this is a keyed array_index
+            continue # this is a keyed array_index or a SK animated
         key.set_value_index(i, non_keyed_values[i])
 
 def needs_baking(blender_object_if_armature: typing.Optional[bpy.types.Object],
@@ -293,12 +300,14 @@ def needs_baking(blender_object_if_armature: typing.Optional[bpy.types.Object],
     def all_equal(lst):
         return lst[1:] == lst[:-1]
 
+    # Note: channels has some None items only for SK if some SK are not animated
+
     # Sampling is forced
     if export_settings[gltf2_blender_export_keys.FORCE_SAMPLING]:
         return True
 
     # Sampling due to unsupported interpolation
-    interpolation = channels[0].keyframe_points[0].interpolation
+    interpolation = [c for c in channels if c is not None][0].keyframe_points[0].interpolation
     if interpolation not in ["BEZIER", "LINEAR", "CONSTANT"]:
         gltf2_io_debug.print_console("WARNING",
                                      "Baking animation because of an unsupported interpolation method: {}".format(
@@ -306,7 +315,7 @@ def needs_baking(blender_object_if_armature: typing.Optional[bpy.types.Object],
                                      )
         return True
 
-    if any(any(k.interpolation != interpolation for k in c.keyframe_points) for c in channels):
+    if any(any(k.interpolation != interpolation for k in c.keyframe_points) for c in channels if c is not None):
         # There are different interpolation methods in one action group
         gltf2_io_debug.print_console("WARNING",
                                      "Baking animation because there are keyframes with different "
@@ -314,24 +323,24 @@ def needs_baking(blender_object_if_armature: typing.Optional[bpy.types.Object],
                                      )
         return True
 
-    if not all_equal([len(c.keyframe_points) for c in channels]):
+    if not all_equal([len(c.keyframe_points) for c in channels if c is not None]):
         gltf2_io_debug.print_console("WARNING",
                                      "Baking animation because the number of keyframes is not "
                                      "equal for all channel tracks")
         return True
 
-    if len(channels[0].keyframe_points) <= 1:
+    if len([c for c in channels if c is not None][0].keyframe_points) <= 1:
         # we need to bake to 'STEP', as at least two keyframes are required to interpolate
         return True
 
-    if not all_equal(list(zip([[k.co[0] for k in c.keyframe_points] for c in channels]))):
+    if not all_equal(list(zip([[k.co[0] for k in c.keyframe_points] for c in channels if c is not None]))):
         # The channels have differently located keyframes
         gltf2_io_debug.print_console("WARNING",
                                      "Baking animation because of differently located keyframes in one channel")
         return True
 
     if blender_object_if_armature is not None:
-        animation_target = gltf2_blender_get.get_object_from_datapath(blender_object_if_armature, channels[0].data_path)
+        animation_target = gltf2_blender_get.get_object_from_datapath(blender_object_if_armature, [c for c in channels if c is not None][0].data_path)
         if isinstance(animation_target, bpy.types.PoseBone):
             if len(animation_target.constraints) != 0:
                 # Constraints such as IK act on the bone -> can not be represented in glTF atm
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py
index 16346729374938d0e16249d47b6203eca9833f5a..5d5d310cdcb7e496842b20cf1e15f50ecb5c42fc 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py
@@ -82,45 +82,38 @@ def __gather_non_keyed_values(channels: typing.Tuple[bpy.types.FCurve],
 
     non_keyed_values = []
 
-    if bake_channel is None:
-        target = channels[0].data_path.split('.')[-1]
-    else:
-        target = bake_channel
-    if target == "value":
-        return ()
-
-    indices = [c.array_index for c in channels]
-    indices.sort()
-    length = {
-        "delta_location": 3,
-        "delta_rotation_euler": 3,
-        "location": 3,
-        "rotation_axis_angle": 4,
-        "rotation_euler": 3,
-        "rotation_quaternion": 4,
-        "scale": 3,
-        "value": 1
-    }.get(target)
-
-    if length is None:
-        # This is not a known target
-        return ()
-
-    for i in range(0, length):
-        if bake_channel is not None:
-            non_keyed_values.append({
-                "delta_location" : blender_object.delta_location,
-                "delta_rotation_euler" : blender_object.delta_rotation_euler,
-                "location" : blender_object.location,
-                "rotation_axis_angle" : blender_object.rotation_axis_angle,
-                "rotation_euler" : blender_object.rotation_euler,
-                "rotation_quaternion" : blender_object.rotation_quaternion,
-                "scale" : blender_object.scale
-            }[target][i])
-        elif i in indices:
-            non_keyed_values.append(None)
+    # Note: channels has some None items only for SK if some SK are not animated
+    if None not in channels:
+        # classic case for object TRS or bone TRS
+        # Or if all morph target are animated
+
+        if bake_channel is None:
+            target = channels[0].data_path.split('.')[-1]
         else:
-            if blender_object_if_armature is None:
+            target = bake_channel
+        if target == "value":
+            # All morph targets are animated
+            return tuple([None] * len(channels))
+
+        indices = [c.array_index for c in channels]
+        indices.sort()
+        length = {
+            "delta_location": 3,
+            "delta_rotation_euler": 3,
+            "location": 3,
+            "rotation_axis_angle": 4,
+            "rotation_euler": 3,
+            "rotation_quaternion": 4,
+            "scale": 3,
+            "value": len(channels)
+        }.get(target)
+
+        if length is None:
+            # This is not a known target
+            return ()
+
+        for i in range(0, length):
+            if bake_channel is not None:
                 non_keyed_values.append({
                     "delta_location" : blender_object.delta_location,
                     "delta_rotation_euler" : blender_object.delta_rotation_euler,
@@ -130,18 +123,55 @@ def __gather_non_keyed_values(channels: typing.Tuple[bpy.types.FCurve],
                     "rotation_quaternion" : blender_object.rotation_quaternion,
                     "scale" : blender_object.scale
                 }[target][i])
+            elif i in indices:
+                non_keyed_values.append(None)
             else:
-                 # TODO, this is not working if the action is not active (NLA case for example)
-                 trans, rot, scale = pose_bone_if_armature.matrix_basis.decompose()
-                 non_keyed_values.append({
-                    "location": trans,
-                    "rotation_axis_angle": rot,
-                    "rotation_euler": rot,
-                    "rotation_quaternion": rot,
-                    "scale": scale
+                if blender_object_if_armature is None:
+                    non_keyed_values.append({
+                        "delta_location" : blender_object.delta_location,
+                        "delta_rotation_euler" : blender_object.delta_rotation_euler,
+                        "location" : blender_object.location,
+                        "rotation_axis_angle" : blender_object.rotation_axis_angle,
+                        "rotation_euler" : blender_object.rotation_euler,
+                        "rotation_quaternion" : blender_object.rotation_quaternion,
+                        "scale" : blender_object.scale
                     }[target][i])
+                else:
+                     # TODO, this is not working if the action is not active (NLA case for example)
+                     trans, rot, scale = pose_bone_if_armature.matrix_basis.decompose()
+                     non_keyed_values.append({
+                        "location": trans,
+                        "rotation_axis_angle": rot,
+                        "rotation_euler": rot,
+                        "rotation_quaternion": rot,
+                        "scale": scale
+                        }[target][i])
+
+        return tuple(non_keyed_values)
+
+    else:
+        # We are in case of morph target, where all targets are not animated
+        # So channels has some None items
+        first_channel = [c for c in channels if c is not None][0]
+        object_path = get_target_object_path(first_channel.data_path)
+        if object_path:
+            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[cpt_sk] = sk.name
+                cpt_sk += 1
+
+        for idx_c, channel in enumerate(channels):
+            if channel is None:
+                non_keyed_values.append(blender_object.data.shape_keys.key_blocks[shapekeys_idx[idx_c]].value)
+            else:
+                non_keyed_values.append(None)
 
-    return tuple(non_keyed_values)
+        return tuple(non_keyed_values)
 
 def __gather_extensions(channels: typing.Tuple[bpy.types.FCurve],
                         blender_object_if_armature: typing.Optional[bpy.types.Object],
@@ -201,17 +231,18 @@ def __gather_interpolation(channels: typing.Tuple[bpy.types.FCurve],
                            bake_bone: typing.Union[str, None],
                            bake_channel: typing.Union[str, None]
                            ) -> str:
+    # Note: channels has some None items only for SK if some SK are not animated
     if gltf2_blender_gather_animation_sampler_keyframes.needs_baking(blender_object_if_armature,
                                                                      channels,
                                                                      export_settings):
         if bake_bone is not None:
             return 'LINEAR'
         else:
-            max_keyframes = max([len(ch.keyframe_points) for ch in channels])
+            max_keyframes = max([len(ch.keyframe_points) for ch in channels if ch is not None])
             # If only single keyframe revert to STEP
             return 'STEP' if max_keyframes < 2 else 'LINEAR'
 
-    blender_keyframe = channels[0].keyframe_points[0]
+    blender_keyframe = [c for c in channels if c is not None][0].keyframe_points[0]
 
     # Select the interpolation method. Any unsupported method will fallback to STEP
     return {
@@ -246,7 +277,7 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
     if bake_bone is not None:
         target_datapath = "pose.bones['" + bake_bone + "']." + bake_channel
     else:
-        target_datapath = channels[0].data_path
+        target_datapath = [c for c in channels if c is not None][0].data_path
 
     is_yup = export_settings[gltf2_blender_export_keys.YUP]