コード例 #1
0
ファイル: XFileImporter.cs プロジェクト: oguna/AssimpSharp
        /// <summary>
        /// Converts the animations from the given imported data and creates
        ///  them in the scene.
        /// </summary>
        /// <param name="scene">The scene to hold to converted animations</param>
        /// <param name="data">The data to read the animations from</param>
        protected void CreateAnimations(AssimpSharp.Scene scene, AssimpSharp.XFile.Scene data)
        {
            var newAnims = new List<AssimpSharp.Animation>();

            for (int a = 0; a < data.Anims.Count; a++)
            {
                var anim = data.Anims[a];
                if (anim.Anims.Count == 0)
                {
                    continue;
                }

                var nanim = new AssimpSharp.Animation();
                newAnims.Add(nanim);
                nanim.Name = anim.Name;
                nanim.Duration = 0;
                nanim.TicksPreSecond = data.AnimTicksPerSecond;
                nanim.Channels = new AssimpSharp.NodeAnim[anim.Anims.Count];

                for (int b = 0; b < anim.Anims.Count; b++)
                {
                    var bone = anim.Anims[b];
                    var nbone = new AssimpSharp.NodeAnim();
                    nbone.NodeName = bone.BoneName;
                    nanim.Channels[b] = nbone;

                    if (bone.TrafoKeys.Count > 0)
                    {
                        nbone.PositionKeys = new VectorKey[bone.TrafoKeys.Count];
                        nbone.RotationKeys = new QuatKey[bone.TrafoKeys.Count];
                        nbone.ScalingKeys = new VectorKey[bone.TrafoKeys.Count];

                        for (int c = 0; c < bone.TrafoKeys.Count; c++)
                        {
                            var time = bone.TrafoKeys[c].Key;
                            var trafo = bone.TrafoKeys[c].Value;

                            var pos = trafo.TranslationVector;

                            nbone.PositionKeys[c].Time = time;
                            nbone.PositionKeys[c].Value = pos;

                            Vector3 scale;
                            scale.X = new Vector3(trafo[0, 0], trafo[0, 1], trafo[0, 2]).Length();
                            scale.Y = new Vector3(trafo[1, 0], trafo[1, 1], trafo[1, 2]).Length();
                            scale.Z = new Vector3(trafo[2, 0], trafo[2, 1], trafo[2, 2]).Length();
                            nbone.ScalingKeys[c].Time = time;
                            nbone.ScalingKeys[c].Value = scale;

                            var rotmat = new Matrix3x3(
                        trafo[0, 0] / scale.X, trafo[0, 1] / scale.Y, trafo[0, 2] / scale.Z,
                        trafo[1, 0] / scale.X, trafo[1, 1] / scale.Y, trafo[1, 2] / scale.Z,
                        trafo[2, 0] / scale.X, trafo[2, 1] / scale.Y, trafo[2, 2] / scale.Z);

                            nbone.RotationKeys[c].Time = time;
                            throw (new NotImplementedException());
                            //nbone.RotationKeys[c].Value = ;
                        }
                        nanim.Duration = Math.Max(nanim.Duration, bone.TrafoKeys[bone.TrafoKeys.Count].Key);
                    }
                    else
                    {
                        // separate key sequences for position, rotation, scaling
                        nbone.PositionKeys = new VectorKey[bone.PosKeys.Count];
                        for (int c = 0; c < nbone.PositionKeys.Length; c++)
                        {
                            var pos = bone.PosKeys[c].Value;
                            nbone.PositionKeys[c].Time = bone.PosKeys[c].Time;
                            nbone.PositionKeys[c].Value = pos;
                        }

                        // rotation
                        nbone.RotationKeys = new QuatKey[bone.RotKeys.Count];
                        for (int c = 0; c < nbone.RotationKeys.Length; c++)
                        {
                            var rotmat = Matrix3x3.RotationQuaternion(bone.RotKeys[c].Value);
                            nbone.RotationKeys[c].Time = bone.RotKeys[c].Time;
                            Quaternion.RotationMatrix(ref rotmat, out nbone.RotationKeys[c].Value);
                            nbone.RotationKeys[c].Value.W *= -1.0f;
                        }

                        // longest lasting key sequence determines duration
                        nbone.ScalingKeys = new VectorKey[bone.ScaleKeys.Count];
                        for (int c = 0; c < nbone.ScalingKeys.Length; c++)
                        {
                            nbone.ScalingKeys[c] = bone.ScaleKeys[c];
                        }

                        // longest lasting key sequence determines duration
                        if (bone.PosKeys.Count > 0)
                        {
                            nanim.Duration = Math.Max(nanim.Duration, bone.PosKeys[bone.PosKeys.Count - 1].Time);
                        }
                        if (bone.RotKeys.Count > 0)
                        {
                            nanim.Duration = Math.Max(nanim.Duration, bone.RotKeys[bone.RotKeys.Count - 1].Time);
                        }
                        if (bone.ScaleKeys.Count > 0)
                        {
                            nanim.Duration = Math.Max(nanim.Duration, bone.ScaleKeys[bone.ScaleKeys.Count - 1].Time);
                        }
                    }
                }
            }

            // store all converted animations in the scene
            if (newAnims.Count > 0)
            {
                scene.Animations.Clear();
                scene.Animations.AddRange(newAnims);
            }
        }
コード例 #2
0
ファイル: FbxConverter.cs プロジェクト: oguna/AssimpSharp
        private void ConvertAnimationStack(AnimationStack st)
        {
            var layers = st.Layers;
            if (layers.Count == 0)
            {
                return;
            }

            var anim = new AssimpSharp.Animation();
            Animations.Add(anim);

            // strip AnimationStack:: prefix
            var name = st.Name;
            if (name.StartsWith("AnimationStack::"))
            {
                name = name.Substring(16);
            }
            else if (name.StartsWith("AnimStack::"))
            {
                name = name.Substring(11);
            }

            anim.Name = name;

            // need to find all nodes for which we need to generate node animations -
            // it may happen that we need to merge multiple layers, though.
            var nodeMap = new NodeMap();

            // reverse mapping from curves to layers, much faster than querying
            // the FBX DOM for it.
            var layerMap = new LayerMap();

            var propWhitelist = new string[] { "Lcl Scaling", "Lcl Rotation", "Lcl Translation" };
            foreach (var layer in layers)
            {
                Debug.Assert(layer != null);
                var nodes = layer.Nodes(propWhitelist);
                foreach (var node in nodes)
                {
                    var model = node.Target as Model;
                    // this can happen - it could also be a NodeAttribute (i.e. for camera animations)
                    if (model == null)
                    {
                        continue;
                    }

                    var name_ = FixNodeName(model.Name);
                    if (nodeMap.ContainsKey(name))
                    {
                        nodeMap[name].Add(node);
                    }
                    else
                    {
                        nodeMap[name] = new List<AnimationCurveNode>() { node };
                    }

                    layerMap[node] = layer;
                }
            }

            // generate node animations
            var nodeAnims = new List<AssimpSharp.NodeAnim>();

            double minTime = 1e10;
            double maxTime = -1e10;

            long startTime = st.LocalStart.Value;
            long stopTime = st.LocalStop.Value;
            double startTimeF = CONVERT_FBX_TIME(startTime);
            double stopTimeF = CONVERT_FBX_TIME(stopTime);

            try
            {
                foreach (var kv in nodeMap)
                {
                    GenerateNodeAnimations(nodeAnims, kv.Key, kv.Value, layerMap, startTime, stopTime, ref maxTime, ref minTime);
                }
            }
            catch (Exception e)
            {
                nodeAnims.Clear();
                throw e;
            }

            if (nodeAnims.Count > 0)
            {
                anim.Channels = nodeAnims.ToArray();
            }
            else
            {
                // empty animations would fail validation, so drop them
                Animations.RemoveAt(Animations.Count - 1);
                FBXImporter.LogInfo("ignoring empty AnimationStack (using IK?): " + name);
                return;
            }

            //adjust relative timing for animation
            {
                var startFps = startTimeF * AnimFps;
                for (int c = 0; c < anim.Channels.Length; c++)
                {
                    var channel = anim.Channels[c];
                    for (int i = 0; i < channel.PositionKeys.Length; i++)
                    {
                        channel.PositionKeys[i].Time -= startFps;
                    }
                    for (int i = 0; i < channel.RotationKeys.Length; i++)
                    {
                        channel.RotationKeys[i].Time -= startFps;
                    }
                    for (int i = 0; i < channel.ScalingKeys.Length; i++)
                    {
                        channel.ScalingKeys[i].Time -= startFps;
                    }
                }
                maxTime -= minTime;
            }

            // for some mysterious reason, mDuration is simply the maximum key -- the
            // validator always assumes animations to start at zero.
            anim.Duration = (stopTimeF - startTimeF) * AnimFps;
            anim.TicksPreSecond = AnimFps;
        }