Example #1
0
        private IEnumerator UpdateCoroutine()
        {
            // Update MovementComponent
            _mc.Update();

            // Add Point to Trajectory, removing the oldest point
            if (_currentFrame % FramesPerPoint == 0)
            {
                this._trajectory.points.Add(
                    new Trajectory.Point(
                        new Vector2(this._model.position.x, this._model.position.z),
                        this._model.rotation
                        )
                    );
                this._trajectory.points.RemoveAt(0);

                // Reset current Frame
                _currentFrame = 0;
            }

            _currentFrame++;

            // Load new Animation.Clip
            if (_ac.IsOver())
            {
                // Find and load next Animation.Clip
                Trajectory.Snippet snippet = GetCurrentSnippet();
                _ac.LoadClip(this._rc.QueryClip(snippet));
            }

            // Play Animation.Frame
            _ac.Step();

            yield return(null);
        }
Example #2
0
        public void DrawPath(Trajectory.Snippet snippet)
        {
            GameObject.Destroy(_path);
            _path      = new GameObject();
            _path.name = "Path";
            _path.transform.position = new Vector3(this._model.position.x, 0, this._model.position.z);
            _path.transform.rotation = Quaternion.Euler(0, this._model.rotation.eulerAngles.y, 0);

            foreach (Trajectory.Point point in snippet.points)
            {
                CreateDot(
                    new Vector3(point.position.x, 0, point.position.y),
                    DotScale,
                    _path.transform,
                    Color.red
                    );
            }
        }
Example #3
0
        public void DrawAlternativePath(Trajectory.Snippet snippet, int offset, float weight)
        {
            GameObject.Destroy(_altPathArray[offset]);
            _altPathArray[offset]                    = new GameObject();
            _altPathArray[offset].name               = "Path " + offset;
            _altPathArray[offset].transform.parent   = _altPaths.transform;
            _altPathArray[offset].transform.position = new Vector3(this._model.position.x, 0, this._model.position.z);
            _altPathArray[offset].transform.rotation = Quaternion.Euler(0, this._model.rotation.eulerAngles.y, 0);

            foreach (Trajectory.Point point in snippet.points)
            {
                CreateDot(
                    new Vector3(point.position.x, 0, point.position.y),
                    AlternativeDotScale,
                    _altPathArray[offset].transform,
                    Color.green
                    );
            }
        }
Example #4
0
        public Animation.Clip QueryClip(Trajectory.Snippet currentSnippet)
        {
            // 1. Reduce cooldowns (after the previous Clip has finished)
            ReduceCooldowns();

            // 2. Check if the next Clip is fitting (or the first one, if we reach the end)
            // The next Clip is NOT necesserily the product of the next Feature
            this._currentFeature = (this._currentFeature + SalamanderController.FeatureStep) % this._anim[this._currentAnimation].featureList.Count;

            this._maxTrajectoryDiff = currentSnippet.CalcDiff(this._anim[this._currentAnimation].featureList[this._currentFeature].snippet);

            if (this._maxTrajectoryDiff > SalamanderController.RecalculationThreshold)
            {
                (this._currentAnimation, this._currentFeature) = QueryFeature(currentSnippet);

                //Debug.Log("Recalculating");
                //Debug.Log("File: " + this._currentAnimation + " Clip: " +  this._currentFeature);
            }
            else
            {
                //Debug.Log("Not Recalculating");
            }

            // 3. Construct the Clip, blend it with the current one and return it
            Animation.Clip nextClip = new Animation.Clip(
                this._anim[this._currentAnimation].frameList.GetRange(
                    this._anim[this._currentAnimation].featureList[this._currentFeature].frameNum + SalamanderController.FramesPerPoint,
                    SalamanderController.FramesPerPoint * (SalamanderController.FeaturePoints + SalamanderController.ClipBlendPoints)
                    )
                );

            nextClip.BlendWith(_currentClip);
            _currentClip = nextClip;

            // 4. Put the current Feature on cooldown
            PutOnCooldown(this._anim[this._currentAnimation].featureList[this._currentFeature]);

            return(nextClip);
        }
Example #5
0
 public Feature(int frameNum, Trajectory.Snippet snippet, Pose pose)
 {
     this.frameNum = frameNum;
     this.snippet  = snippet;
     this.pose     = pose;
 }
Example #6
0
        private (int, int) QueryFeature(Trajectory.Snippet currentSnippet)
        {
            List <CandidateFeature>         candidateFeatures = new List <CandidateFeature>();
            Tuple <float, CandidateFeature> winnerFeature     = new Tuple <float, CandidateFeature>(Mathf.Infinity, null);
            Pose  currentPose         = _anim[_currentAnimation].featureList[_currentFeature].pose;
            float maxPosePositionDiff = 0;
            float maxPoseVelocityDiff = 0;

            // Draw current snippet
            _fc?.DrawPath(currentSnippet);

            // Initialize candidate features to the next clip
            for (int i = 0; i < SalamanderController.CandidateFramesSize; i++)
            {
                candidateFeatures.Add(new CandidateFeature(
                                          _anim[_currentAnimation].featureList[_currentFeature],
                                          _maxTrajectoryDiff,
                                          _currentAnimation,
                                          _currentFeature)
                                      );
            }

            // 1. Find the Clips with the most fitting Trajectories
            for (int i = 0; i < _anim.Count; i++)
            {
                for (int j = 0; j < _anim[i].featureList.Count; j++)
                {
                    Feature feature = _anim[i].featureList[j];

                    // Consider only active Frames (not on cooldown)
                    if (feature.cooldownTimer == 0)
                    {
                        // A. Add candidate Feature to the best candidates list
                        float diff = currentSnippet.CalcDiff(feature.snippet);

                        // Experiment
                        // If the Trajectory is good enough to consider
                        if (diff <= _maxTrajectoryDiff)
                        {
                            // Remove worst candidate
                            candidateFeatures.RemoveAt(candidateFeatures.Count - 1);
                            _maxTrajectoryDiff = candidateFeatures[candidateFeatures.Count - 1].trajectoryDiff;


                            // Add candidate to the right position
                            for (int k = 0; k < candidateFeatures.Count; k++)
                            {
                                if (candidateFeatures[k].trajectoryDiff > diff)
                                {
                                    candidateFeatures.Insert(k, new CandidateFeature(feature, diff, i, j));
                                    break;
                                }
                            }
                        }



                        /*
                         * if (diff <= this._maxTrajectoryDiff)
                         * {
                         *  CandidateFeature candidateFeature = new CandidateFeature(
                         *      feature, diff, i, j
                         *      );
                         *  candidateFeatures.Add(candidateFeature);
                         * }
                         *
                         * // B. Sort candidates based on their diff
                         * candidateFeatures.Sort(
                         *  (firstObj, secondObj) =>
                         *  {
                         *      return firstObj.trajectoryDiff.CompareTo(secondObj.trajectoryDiff);
                         *  }
                         * );
                         */
                    }
                }
            }

            //// C. Keep only a predefined number of best candidates
            //if (candidateFeatures.Count <= 0)
            //{
            //    Debug.LogError("Unable to find any Animation Frame to transition to");
            //    return (0, 0);
            //}
            //else if (candidateFeatures.Count > SalamanderController.CandidateFramesSize)
            //{
            //    candidateFeatures.RemoveRange(SalamanderController.CandidateFramesSize, candidateFeatures.Count - SalamanderController.CandidateFramesSize);
            //}

            // 2. Compute the difference in Pose for each Clip (position and velocity)
            for (int i = 0; i < candidateFeatures.Count; i++)
            {
                (float posePositionDiff, float poseVelocityDiff) = currentPose.CalcDiff(candidateFeatures[i].feature.pose);
                candidateFeatures[i].posePositionDiff            = posePositionDiff;
                candidateFeatures[i].poseVelocityDiff            = poseVelocityDiff;

                // Keep the maximum values of the differences, in order to normalise
                maxPosePositionDiff = posePositionDiff > maxPosePositionDiff ?
                                      posePositionDiff :
                                      maxPosePositionDiff;

                maxPoseVelocityDiff = poseVelocityDiff > maxPoseVelocityDiff ?
                                      poseVelocityDiff :
                                      maxPoseVelocityDiff;

                // Draw all alternative paths
                //this._fc.DrawAlternativePath(candidateFeatures[i].feature.snippet, i, candidateFeatures[i].trajectoryDiff);
            }

            // 3. Normalize and add differences
            for (int i = 0; i < candidateFeatures.Count; i++)
            {
                if (maxPosePositionDiff > 0)
                {
                    candidateFeatures[i].posePositionDiff /= maxPosePositionDiff;
                }
                if (maxPoseVelocityDiff > 0)
                {
                    candidateFeatures[i].poseVelocityDiff /= maxPoseVelocityDiff;
                }

                float totalPostDiff = candidateFeatures[i].posePositionDiff + candidateFeatures[i].poseVelocityDiff;

                winnerFeature = winnerFeature.Item1 > totalPostDiff ?
                                new Tuple <float, CandidateFeature>(totalPostDiff, candidateFeatures[i]) :
                                winnerFeature;
            }

            //Debug.Log("Playing animation from \"" + this._anim[winnerFeature.Item2.animationNum].animationName + "\"");

            // Draw picked animation's path
            this._fc?.DrawAlternativePath(winnerFeature.Item2.feature.snippet, 1, winnerFeature.Item2.trajectoryDiff);

            // 4. Return the Feature's index
            return(winnerFeature.Item2.animationNum, winnerFeature.Item2.clipNum);
        }
        private (int, int) QueryFeature(Trajectory.Snippet currentSnippet)
        {
            List <CandidateFeature>         candidateFeatures = new List <CandidateFeature>();
            Tuple <float, CandidateFeature> winnerFeature     = new Tuple <float, CandidateFeature>(Mathf.Infinity, null);
            Pose  currentPose         = this._anim[this._currentAnimation].featureList[this._currentFeature].pose;
            float maxPosePositionDiff = 0;
            float maxPoseVelocityDiff = 0;

            // TODO remove
            this._fc.DrawPath(currentSnippet);

            // 1. Find the Clips with the most fitting Trajectories
            for (int i = 0; i < this._anim.Count; i++)
            {
                for (int j = 0; j < this._anim[i].featureList.Count; j++)
                {
                    Feature feature = this._anim[i].featureList[j];

                    // Consider only active Frames (not on cooldown)
                    if (feature.cooldownTimer == 0)
                    {
                        // A. Add candidate Feature to the best candidates list
                        float diff = currentSnippet.CalcDiff(feature.snippet);
                        //Debug.Log("diff: " + diff);
                        if (diff < CharacterController.MaxTrajectoryDiff)
                        {
                            CandidateFeature candidateFeature = new CandidateFeature(
                                feature, diff, i, j
                                );
                            candidateFeatures.Add(candidateFeature);
                        }

                        // B. Sort candidates based on their diff
                        candidateFeatures.Sort(
                            (firstObj, secondObj) =>
                        {
                            return(firstObj.trajectoryDiff.CompareTo(secondObj.trajectoryDiff));
                        }
                            );

                        // C. Keep only a predefined number of best candidates
                        if (candidateFeatures.Count <= 0)
                        {
                            Debug.LogError("Unable to find any Animation Frame to transition to");
                            return(0, 0);
                        }
                        else if (candidateFeatures.Count > CharacterController.CandidateFramesSize)
                        {
                            candidateFeatures.RemoveRange(CharacterController.CandidateFramesSize, candidateFeatures.Count - CharacterController.CandidateFramesSize);
                        }
                    }
                }
            }

            // 2. Compute the difference in Pose for each Clip (position and velocity)
            for (int i = 0; i < candidateFeatures.Count; i++)
            {
                (float posePositionDiff, float poseVelocityDiff) = currentPose.CalcDiff(candidateFeatures[i].feature.pose);
                candidateFeatures[i].posePositionDiff            = posePositionDiff;
                candidateFeatures[i].poseVelocityDiff            = poseVelocityDiff;

                // Keep the maximum values of the differences, in order to normalise
                maxPosePositionDiff = posePositionDiff > maxPosePositionDiff ?
                                      posePositionDiff :
                                      maxPosePositionDiff;

                maxPoseVelocityDiff = poseVelocityDiff > maxPoseVelocityDiff ?
                                      poseVelocityDiff :
                                      maxPoseVelocityDiff;

                // TODO remove
                //this._fc.DrawAlternativePath(candidateFeatures[i].feature.snippet, i, candidateFeatures[i].trajectoryDiff);
            }

            // 3. Normalize and add differences
            for (int i = 0; i < candidateFeatures.Count; i++)
            {
                candidateFeatures[i].posePositionDiff /= maxPosePositionDiff;
                candidateFeatures[i].poseVelocityDiff /= maxPoseVelocityDiff;

                float totalPostDiff = candidateFeatures[i].posePositionDiff + candidateFeatures[i].poseVelocityDiff;

                winnerFeature = winnerFeature.Item1 > totalPostDiff ?
                                new Tuple <float, CandidateFeature>(totalPostDiff, candidateFeatures[i]) :
                                winnerFeature;
            }

            Debug.Log("Starting animation: " + this._anim[winnerFeature.Item2.animationNum].animationName);

            // TODO remove
            this._fc.DrawAlternativePath(winnerFeature.Item2.feature.snippet, 1, winnerFeature.Item2.trajectoryDiff);

            // 4. Return the Feature's index
            return(winnerFeature.Item2.animationNum, winnerFeature.Item2.clipNum);
        }