HarmonicMotion

Updated: 01/30/2020

Summary

HarmonicMotion is a function that periodically iterates the values of specified parameters.
It is used primarily for things that are in constant motion, such as breathing.
Click here for more information on how to set up HarmonicMotion.

HarmonicMotion in Cubism SDK for Unity consists of two elements.

  1. Components for specifying parameters to operate
  2. Components that manipulate the value of each parameter

1. Components for Specifying Parameters to Operate

Use CustomHarmonicMotionParameter to specify the parameters to be used for HarmonicMotion.

CustomHarmonicMotionParameter is a component that inherits from MonoBehaviour and attaches to GameObjects placed under [Prefab root]/Parameters/.

It will cycle through the values of the parameters with the same ID as the GameObject to which it is attached.

CustomHarmonicMotionParameter has five setting items.

        /// <summary>
        /// Timescale channel.
        /// </summary>
        [SerializeField]
        public int Channel;

        /// <summary>
        /// Motion direction.
        /// </summary>
        [SerializeField]
        public CubismHarmonicMotionDirection Direction;

        /// <summary>
        /// Normalized origin of motion.
        /// </summary>
        /// <remarks>
        /// The actual origin used for evaluating the motion depends limits of the <see cref="CubismParameter"/>.
        /// </remarks>
        [SerializeField, Range(0f, 1f)]
        public float NormalizedOrigin = 0.5f;

        /// <summary>
        /// Normalized range of motion.
        /// </summary>
        /// <remarks>
        /// The actual origin used for evaluating the motion depends limits of the <see cref="CubismParameter"/>.
        /// </remarks>
        [SerializeField, Range(0f, 1f)]
        public float NormalizedRange = 0.5f;

        /// <summary>
        /// Duration of one motion cycle in seconds.
        /// </summary>
        [SerializeField, Range(0.01f, 10f)]
        public float Duration = 3f;
  • Channel

Specifies the multiplier for the sine wave period set by the CubismHarmonicMotionController.
HarmonicMotion allows multiple periods for a single model, which can be set with the CustomHarmonicMotionController.
Here, set the index of the CustomHarmonicMotionController.ChannelTimescales.

  • Direction

Sets the range of periodic operation with respect to the center of the parameter.
There are three setting items.

– Left: It works only in the left half of the range from the center of the parameter.
– Right: It works only in the right half of the range from the center of the parameter.
– Centric: It works across the entire range of parameters.

  • NormalizedOrigin

Sets the center of the parameter to be referenced by Direction.
The center will be set to the value when the minimum value of that parameter is set to 0 and the maximum value of that parameter is set to 1.

  • NormalizedRange

Sets the amplitude at which to operate the value from the center of the value set in NormalizedOrigin.
Set the distance traveled from the center when the minimum value of that parameter is 0 and the maximum value is 1.
This value can only range from the center position set by NormalizedOrigin to the minimum or maximum value of the parameter.

  • Duration

Adjusts the duration of the parameter.

        /// <summary>
        /// Evaluates the parameter.
        /// </summary>
        /// <returns>Parameter value.</returns>
        internal float Evaluate()
        {
            // Lazily initialize.
            if (!IsInitialized)
            {
                Initialize();
            }


            // Restore origin and range.
            var origin = MinimumValue + (NormalizedOrigin * ValueRange);
            var range  = NormalizedRange * ValueRange;


            // Clamp the range so that it stays within the limits.
            Clamp(ref origin, ref range);


            // Return result.
            return origin + (range * Mathf.Sin(T * (2 * Mathf.PI) / Duration));
        }

        /// <summary>
        /// Clamp origin and range based on <see cref="Direction"/>.
        /// </summary>
        /// <param name="origin">Origin to clamp.</param>
        /// <param name="range">Range to clamp.</param>
        private void Clamp(ref float origin, ref float range)
        {
            switch (Direction)
            {
                case CubismHarmonicMotionDirection.Left:
                {
                    if ((origin - range) >= MinimumValue)
                    {
                        range /= 2;
                        origin -= range;
                    }
                    else
                    {
                        range           = (origin - MinimumValue) / 2f;
                        origin          = MinimumValue + range;
                        NormalizedRange = (range * 2f)/ValueRange;
                    }


                    break;
                }
                case CubismHarmonicMotionDirection.Right:
                {
                    if ((origin + range) <= MaximumValue)
                    {
                        range  /= 2f;
                        origin += range;
                    }
                    else
                    {
                        range           = (MaximumValue - origin) / 2f;
                        origin          = MaximumValue - range;
                        NormalizedRange = (range * 2f)/ValueRange;
                    }


                    break;
                }
                default:
                {
                    break;
                }
            }


            // Clamp both range and NormalizedRange.
            if ((origin - range) < MinimumValue)
            {
                range           = origin - MinimumValue;
                NormalizedRange = range / ValueRange;
            }
            else if ((origin + range) > MaximumValue)
            {
                range           = MaximumValue - origin;
                NormalizedRange = range / ValueRange;
            }
        }

The CustomHarmonicMotionParameter is also used as a marker for the CustomHarmonicMotionController to obtain references.

2. Components that Manipulate the Value of Each Parameter

Use the CustomHarmonicMotionController to apply opening and closing values to each parameter.
This is a component that inherits from MonoBehaviour and attaches to the root of Cubism’s Prefab when used.

At initialization, obtains a reference to all CubismHarmonicMotionParameters attached to the Prefab.
If you add/remove a parameter whose value is to operate cyclically during execution, call CustomHarmonicMotionController.Refresh() to get the reference again.

        /// <summary>
        /// Refreshes the controller. Call this method after adding and/or removing <see cref="CubismHarmonicMotionParameter"/>.
        /// </summary>
        public void Refresh()
        {
            var model = this.FindCubismModel();


            // Catch sources and destinations.
            Sources = model
                .Parameters
                .GetComponentsMany<CubismHarmonicMotionParameter>();
            Destinations = new CubismParameter[Sources.Length];


            for (var i = 0; i < Sources.Length; ++i)
            {
                Destinations[i] = Sources[i].GetComponent<CubismParameter>();
            }

            // Get cubism update controller.
            HasUpdateController = (GetComponent<CubismUpdateController>() != null);
        }

        ...
        
        /// <summary>
        /// Called by Unity. Makes sure cache is initialized.
        /// </summary>
        private void Start()
        {
            // Initialize cache.
            Refresh();
        }

CustomHarmonicMotionController applies the calculated values for the parameters marked by CustomHarmonicMotionParameter at the timing of LateUpdate() in every frame.

        /// <summary>
        /// Called by Unity. Makes sure cache is initialized.
        /// </summary>
        private void Start()
        {
            // Initialize cache.
            Refresh();
        }

CustomHarmonicMotionController has two setting items.

        /// <summary>
        /// Blend mode.
        /// </summary>
        [SerializeField]
        public CubismParameterBlendMode BlendMode = CubismParameterBlendMode.Additive;


        /// <summary>
        /// The timescales for each channel.
        /// </summary>
        [SerializeField]
        public float[] ChannelTimescales;
  • BlendMode

Blend Mode for applying values to parameters.
The following three values can be set.

– Override: Overwrite the current value.
– Additive: Add to the current value.
– Multiply: Multiply by the current value.

  • ChannelTimescales

Set the period of the sine wave.
Multiple cycles can be set.

Please let us know what you think about this article.