Пример #1
0
        private void UpdateTimer(object sender, EventArgs e)
        {
            if (Mode == AnimationMode.Spin)
            {
                if (MoveMultiplier < 1.0f)
                {
                    MoveMultiplier += _moveAcceleration;
                }
                else
                {
                    MoveMultiplier = 1.0f;
                }
            }
            else if (Mode != AnimationMode.Idle)
            {
                _autoMoveCurrent += _autoMoveStep;

                // Allow timer to overflow for 2 subsequent frames, so we
                // get finalizing 1.0 value at all times

                if (_autoMoveCurrent >= 1.0f + (_autoMoveStep * 2))
                {
                    Stop(true);
                }
                else
                {
                    var newMultiplier = MathC.SmoothStep(0.0, 1.0, _autoMoveCurrent);
                    MoveMultiplier = (float)MathC.Clamp(newMultiplier, 0.0, 1.0);
                }
            }
            else
            {
                Stop(true);
            }
        }
Пример #2
0
        public void UpdateTransform(int meshIndex, Vector3 newRot, Vector3 newPos)
        {
            if (CurrentAnim == null || CurrentKeyFrame == null)
            {
                return;
            }

            // Backup everything and push undo on first occurence of editing
            if (!MadeChanges || _backupPos.Count == 0 || _backupRot.Count == 0)
            {
                _initialPos = CurrentKeyFrame.Translations[0];
                _initialRot = CurrentKeyFrame.Rotations[meshIndex];

                _backupPos.Clear();
                _backupRot.Clear();

                ActiveFrames.ForEach(f => { _backupRot.Add(f.Rotations[meshIndex]); _backupPos.Add(f.Translations[0]); });

                Tool.UndoManager.PushAnimationChanged(this, CurrentAnim);
                MadeChanges = true;
            }

            // Calculate deltas for other frames processing
            var deltaPos = newPos - _initialPos;
            var deltaRot = newRot - _initialRot;

            // Define animation properties
            bool evolve  = TransformMode != AnimTransformMode.Simple && ActiveFrames.Count > 1;
            bool smooth  = TransformMode == AnimTransformMode.Smooth || TransformMode == AnimTransformMode.SmoothReverse || TransformMode == AnimTransformMode.Symmetric;
            bool reverse = TransformMode == AnimTransformMode.LinearReverse || TransformMode == AnimTransformMode.SmoothReverse;
            bool loop    = TransformMode == AnimTransformMode.Symmetric || TransformMode == AnimTransformMode.SymmetricLinear;

            // Calculate evolution
            float frameCount  = loop || reverse ? Selection.Y - Selection.X : CurrentFrameIndex - Selection.X;
            float currentStep = 0;

            int index = 0;

            foreach (var keyframe in ActiveFrames)
            {
                float midFrame = loop ? CurrentFrameIndex - Selection.X : (reverse ? CurrentFrameIndex : frameCount);
                float bias     = (currentStep <= midFrame) ? (reverse ? 1.0f : currentStep / midFrame) : (frameCount - currentStep) / (frameCount - midFrame);

                // Single-pass smoothstep doesn't look organic on fast animations, hence we're using 2-pass smootherstep here.
                float weight = smooth ? (float)MathC.SmoothStep(0, 1, MathC.SmoothStep(0, 1, bias)) : bias;

                // Apply deltas to backed-up transforms
                var currPos = _backupPos[index] + deltaPos;
                var currRot = _backupRot[index] + deltaRot;

                var translationVector = currPos;

                if (evolve)
                {
                    translationVector = Vector3.Lerp(_backupPos[index], translationVector, weight);
                }

                // Foolproof stuff in case user hardly messes with transform during playback...
                if (float.IsNaN(translationVector.X))
                {
                    translationVector.X = _backupPos[index].X;
                }
                if (float.IsNaN(translationVector.Y))
                {
                    translationVector.Y = _backupPos[index].Y;
                }
                if (float.IsNaN(translationVector.Z))
                {
                    translationVector.Z = _backupPos[index].Z;
                }

                keyframe.Translations[0]         = translationVector;
                keyframe.TranslationsMatrices[0] = Matrix4x4.CreateTranslation(translationVector);

                var        rotVector = currRot;
                Quaternion finalQuat;
                if (evolve)
                {
                    // Calculate source and destination quats and decide on direction based on dot product.
                    var srcQuat  = Quaternion.CreateFromYawPitchRoll(_backupRot[index].Y, _backupRot[index].X, _backupRot[index].Z);
                    var destQuat = Quaternion.CreateFromYawPitchRoll(currRot.Y, currRot.X, currRot.Z);
                    if (Quaternion.Dot(srcQuat, destQuat) < 0)
                    {
                        Quaternion.Negate(srcQuat);
                    }
                    finalQuat = Quaternion.Lerp(srcQuat, destQuat, weight);
                }
                else
                {
                    finalQuat = Quaternion.CreateFromYawPitchRoll(rotVector.Y, rotVector.X, rotVector.Z);
                }

                // We're not converting quat to rotations because we have to check-up for NaNs
                var rotationVector = MathC.QuaternionToEuler(finalQuat);

                // Foolproof stuff in case user hardly messes with transform during playback...
                if (float.IsNaN(rotationVector.X))
                {
                    rotationVector.X = _backupRot[index].X;
                }
                if (float.IsNaN(rotationVector.Y))
                {
                    rotationVector.Y = _backupRot[index].Y;
                }
                if (float.IsNaN(rotationVector.Z))
                {
                    rotationVector.Z = _backupRot[index].Z;
                }

                // NaNs filtered out, now we can put actual data.
                keyframe.Quaternions[meshIndex] = Quaternion.CreateFromYawPitchRoll(rotationVector.Y, rotationVector.X, rotationVector.Z);
                keyframe.Rotations[meshIndex]   = rotationVector;

                index++;
                currentStep++; if (currentStep > frameCount)
                {
                    currentStep = frameCount;
                }
            }
        }