Пример #1
0
        public static List <AnimationClip> ImportAnimationClip(ImporterContext ctx)
        {
            List <AnimationClip> animationClips = new List <AnimationClip>();

            for (int i = 0; i < ctx.GLTF.animations.Count; ++i)
            {
                var clip = new AnimationClip();
                clip.ClearCurves();
                clip.legacy = true;
                clip.name   = ctx.GLTF.animations[i].name;
                if (string.IsNullOrEmpty(clip.name))
                {
                    clip.name = "legacy_" + i;
                }
                clip.wrapMode = WrapMode.Loop;

                var animation = ctx.GLTF.animations[i];
                if (string.IsNullOrEmpty(animation.name))
                {
                    animation.name = string.Format("animation:{0}", i);
                }

                foreach (var channel in animation.channels)
                {
                    var targetTransform = ctx.Nodes[channel.target.node];
                    var relativePath    = targetTransform.RelativePathFrom(ctx.Root.transform);
                    switch (channel.target.path)
                    {
                    case glTFAnimationTarget.PATH_TRANSLATION:
                    {
                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);

                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            new string[] { "localPosition.x", "localPosition.y", "localPosition.z" },
                            input,
                            output,
                            sampler.interpolation,
                            typeof(Transform),
                            (values, last) =>
                            {
                                Vector3 temp = new Vector3(values[0], values[1], values[2]);
                                return(temp.ReverseZ().ToArray());
                            }
                            );
                    }
                    break;

                    case glTFAnimationTarget.PATH_ROTATION:
                    {
                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);

                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" },
                            input,
                            output,
                            sampler.interpolation,
                            typeof(Transform),
                            (values, last) =>
                            {
                                Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]);
                                Quaternion lastQuaternion    = new Quaternion(last[0], last[1], last[2], last[3]);
                                return(AnimationImporter.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray());
                            }
                            );

                        clip.EnsureQuaternionContinuity();
                    }
                    break;

                    case glTFAnimationTarget.PATH_SCALE:
                    {
                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);

                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            new string[] { "localScale.x", "localScale.y", "localScale.z" },
                            input,
                            output,
                            sampler.interpolation,
                            typeof(Transform),
                            (values, last) => values);
                    }
                    break;

                    case glTFAnimationTarget.PATH_WEIGHT:
                    {
                        var node = ctx.GLTF.nodes[channel.target.node];
                        var mesh = ctx.GLTF.meshes[node.mesh];
                        //var primitive = mesh.primitives.FirstOrDefault();
                        //var targets = primitive.targets;

                        List <string> blendShapeNames     = new List <string>();
                        var           transform           = ctx.Nodes[channel.target.node];
                        var           skinnedMeshRenderer = transform.GetComponent <SkinnedMeshRenderer>();
                        if (skinnedMeshRenderer == null)
                        {
                            continue;
                        }

                        for (int j = 0; j < skinnedMeshRenderer.sharedMesh.blendShapeCount; j++)
                        {
                            blendShapeNames.Add(skinnedMeshRenderer.sharedMesh.GetBlendShapeName(j));
                        }

                        var keyNames = blendShapeNames
                                       .Where(x => !string.IsNullOrEmpty(x))
                                       .Select(x => "blendShape." + x)
                                       .ToArray();

                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessor <float>(sampler.output);
                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            keyNames,
                            input,
                            output,
                            sampler.interpolation,
                            typeof(SkinnedMeshRenderer),
                            (values, last) =>
                            {
                                for (int j = 0; j < values.Length; j++)
                                {
                                    values[j] *= 100.0f;
                                }
                                return(values);
                            });
                    }
                    break;

                    default:
                        Debug.LogWarningFormat("unknown path: {0}", channel.target.path);
                        break;
                    }
                }
                animationClips.Add(clip);
            }

            return(animationClips);
        }
Пример #2
0
        protected virtual Schedulable <Unit> LoadAsync()
        {
            return
                (Schedulable.Create()
                 .AddTask(Scheduler.ThreadPool, () =>
            {
                if (m_textures.Count == 0)
                {
                    //
                    // runtime
                    //
                    CreateTextureItems();
                }
                else
                {
                    //
                    // already CreateTextures(by assetPostProcessor or editor menu)
                    //
                }
            })
                 .ContinueWithCoroutine(Scheduler.ThreadPool, () =>
            {
                using (MeasureTime("TexturesProcessOnAnyThread"))
                {
                    return TexturesProcessOnAnyThread();
                }
            })
                 .ContinueWithCoroutine(Scheduler.MainThread, () =>
            {
                using (MeasureTime("TexturesProcessOnMainThread"))
                {
                    return TexturesProcessOnMainThread();
                }
            })
                 .ContinueWithCoroutine(Scheduler.MainThread, () =>
            {
                using (MeasureTime("LoadMaterials"))
                {
                    return LoadMaterials();
                }
            })
                 .OnExecute(Scheduler.ThreadPool, parent =>
            {
                if (GLTF.meshes
                    .SelectMany(x => x.primitives)
                    .Any(x => x.extensions.KHR_draco_mesh_compression != null))
                {
                    throw new UniGLTFNotSupportedException("draco is not supported");
                }

                // meshes
                var meshImporter = new MeshImporter();
                for (int i = 0; i < GLTF.meshes.Count; ++i)
                {
                    var index = i;
                    parent.AddTask(Scheduler.ThreadPool,
                                   () =>
                    {
                        using (MeasureTime("ReadMesh"))
                        {
                            return meshImporter.ReadMesh(this, index);
                        }
                    })
                    .ContinueWith(Scheduler.MainThread, x =>
                    {
                        using (MeasureTime("BuildMesh"))
                        {
                            var meshWithMaterials = MeshImporter.BuildMesh(this, x);

                            var mesh = meshWithMaterials.Mesh;

                            // mesh name
                            if (string.IsNullOrEmpty(mesh.name))
                            {
                                mesh.name = string.Format("UniGLTF import#{0}", i);
                            }
                            var originalName = mesh.name;
                            for (int j = 1; Meshes.Any(y => y.Mesh.name == mesh.name); ++j)
                            {
                                mesh.name = string.Format("{0}({1})", originalName, j);
                            }

                            return meshWithMaterials;
                        }
                    })
                    .ContinueWith(Scheduler.ThreadPool, x => Meshes.Add(x))
                    ;
                }
            })
                 .ContinueWithCoroutine(Scheduler.MainThread, () =>
            {
                using (MeasureTime("LoadNodes"))
                {
                    return LoadNodes();
                }
            })
                 .ContinueWithCoroutine(Scheduler.MainThread, () =>
            {
                using (MeasureTime("BuildHierarchy"))
                {
                    return BuildHierarchy();
                }
            })
                 .ContinueWith(Scheduler.MainThread, _ =>
            {
                AnimationImporter.ImportAnimation(this);
            })
                 .ContinueWith(Scheduler.CurrentThread,
                               _ =>
            {
                OnLoadModel();
                Debug.Log(GetSpeedLog());
                return Unit.Default;
            }));
        }
        protected virtual Schedulable <Unit> LoadAsync()
        {
            return
                (Schedulable.Create()
                 .AddTask(Scheduler.ThreadPool, () =>
            {
                if (m_textures.Count == 0)
                {
                    //
                    // runtime
                    //
                    CreateTextureItems();
                }
                else
                {
                    //
                    // already CreateTextures(by assetPostProcessor or editor menu)
                    //
                }
            })
                 .ContinueWithCoroutine(Scheduler.ThreadPool, TexturesProcessOnAnyThread)
                 .ContinueWithCoroutine(Scheduler.MainThread, TexturesProcessOnMainThread)
                 .ContinueWithCoroutine(Scheduler.MainThread, LoadMaterials)
                 .OnExecute(Scheduler.ThreadPool, parent =>
            {
                // UniGLTF does not support draco
                // https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md#conformance
                if (GLTF.extensionsRequired.Contains("KHR_draco_mesh_compression"))
                {
                    throw new UniGLTFNotSupportedException("draco is not supported");
                }

                // meshes
                var meshImporter = new MeshImporter();
                for (int i = 0; i < GLTF.meshes.Count; ++i)
                {
                    var index = i;
                    parent.AddTask(Scheduler.ThreadPool,
                                   () =>
                    {
                        using (MeasureTime("ReadMesh"))
                        {
                            return meshImporter.ReadMesh(this, index);
                        }
                    })
                    .ContinueWith(Scheduler.MainThread, x =>
                    {
                        using (MeasureTime("BuildMesh"))
                        {
                            var meshWithMaterials = MeshImporter.BuildMesh(this, x);

                            var mesh = meshWithMaterials.Mesh;

                            // mesh name
                            if (string.IsNullOrEmpty(mesh.name))
                            {
                                mesh.name = string.Format("UniGLTF import#{0}", i);
                            }
                            var originalName = mesh.name;
                            for (int j = 1; Meshes.Any(y => y.Mesh.name == mesh.name); ++j)
                            {
                                mesh.name = string.Format("{0}({1})", originalName, j);
                            }

                            return meshWithMaterials;
                        }
                    })
                    .ContinueWith(Scheduler.ThreadPool, x => Meshes.Add(x))
                    ;
                }
            })
                 .ContinueWithCoroutine(Scheduler.MainThread, LoadNodes)
                 .ContinueWithCoroutine(Scheduler.MainThread, BuildHierarchy)
                 .ContinueWith(Scheduler.MainThread, _ =>
            {
                using (MeasureTime("AnimationImporter"))
                {
                    AnimationImporter.ImportAnimation(this);
                }
            })
                 .ContinueWith(Scheduler.CurrentThread,
                               _ =>
            {
                OnLoadModel();
                if (m_showSpeedLog)
                {
                    Debug.Log(GetSpeedLog());
                }
                return Unit.Default;
            }));
        }
Пример #4
0
        public static void ImportAnimation(ImporterContext ctx, AnimationClip clip)
        {
            for (int i = 0; i < ctx.GLTF.animations.Count; ++i)
            {
                var animation = ctx.GLTF.animations[i];
                if (string.IsNullOrEmpty(animation.name))
                {
                    animation.name = string.Format("animation:{0}", i);
                }

                foreach (var channel in animation.channels)
                {
                    var targetTransform = ctx.Nodes[channel.target.node];
                    var relativePath    = targetTransform.RelativePathFrom(ctx.Root.transform);
                    switch (channel.target.path)
                    {
                    case glTFAnimationTarget.PATH_TRANSLATION:
                    {
                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);

                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            new string[] { "localPosition.x", "localPosition.y", "localPosition.z" },
                            input,
                            output,
                            sampler.interpolation,
                            (values, last) =>
                            {
                                Vector3 temp = new Vector3(values[0], values[1], values[2]);
                                return(temp.ReverseZ().ToArray());
                            }
                            );
                    }
                    break;

                    case glTFAnimationTarget.PATH_ROTATION:
                    {
                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);

                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" },
                            input,
                            output,
                            sampler.interpolation,
                            (values, last) =>
                            {
                                Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]);
                                Quaternion lastQuaternion    = new Quaternion(last[0], last[1], last[2], last[3]);
                                return(AnimationImporter.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray());
                            }
                            );

                        clip.EnsureQuaternionContinuity();
                    }
                    break;

                    case glTFAnimationTarget.PATH_SCALE:
                    {
                        var sampler = animation.samplers[channel.sampler];
                        var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                        var output  = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);

                        AnimationImporter.SetAnimationCurve(
                            clip,
                            relativePath,
                            new string[] { "localScale.x", "localScale.y", "localScale.z" },
                            input,
                            output,
                            sampler.interpolation,
                            (values, last) => values);
                    }
                    break;

                    case glTFAnimationTarget.PATH_WEIGHT:
                    {
                        var node = ctx.GLTF.nodes[channel.target.node];
                        var mesh = ctx.GLTF.meshes[node.mesh];
                        for (int k = 0; k < mesh.weights.Length; ++k)
                        {
                            //var weight = mesh.weights[k];
                            var curve   = new AnimationCurve();
                            var sampler = animation.samplers[channel.sampler];
                            var input   = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input);
                            var output  = ctx.GLTF.GetArrayFromAccessor <float>(sampler.output);
                            for (int j = 0, l = k; j < input.Length; ++j, l += mesh.weights.Length)
                            {
                                curve.AddKey(input[j], output[l] * 100);
                            }

                            clip.SetCurve(relativePath, typeof(SkinnedMeshRenderer), "blendShape." + k, curve);
                        }
                    }
                    break;

                    default:
                        Debug.LogWarningFormat("unknown path: {0}", channel.target.path);
                        break;
                    }
                }
            }
        }