MouthMovement

업데이트: 2020/01/30

개요

MouthMovement는 립싱크 파라미터의 현재 값에 개폐 상태 값을 적용하는 기능입니다.
모션으로 설정된 립싱크용의 커브나 재생하고 있는 음성 파일로부터 실시간으로 샘플링한 값 등을 모델에 적용하는 것이 가능합니다.
모델에 립싱크 파라미터를 설정하는 방법에 대해서는 여기를 참조하세요. 

MouthMovement에서 설정하는 것은 입의 개폐 상태뿐입니다.
입의 모양을 모음에 맞추는 것과 같은 조작을 할 수는 없습니다.

Unity에서 립싱크용 파라미터를 지정하려면 Cubism 에디터에서 모델로 설정해 두는 것 외에도 Unity에서 사용자가 임의로 지정할 수 있습니다.

Cubism SDK for Unity의 MouthMovement는 세 가지 요소로 구성됩니다.

  1. 파라미터 지정용 컴포넌트
  2. 각 파라미터에 값을 적용하는 컴포넌트
  3. 2에서 적용하는 값 조작

1. 파라미터 지정용 컴포넌트

MouthMovement에 사용할 파라미터를 지정하려면 CubismMouthParameter를 사용합니다.

CubismMouthParameter는 MonoBehaviour를 상속한 컴포넌트로,
[Prefab 루트]/Parameters/ 아래에 배치된 GameObject에 연결하여 사용합니다.
이것이 연결된 GameObject와 같은 ID의 파라미터를 립싱크용 파라미터로서 취급합니다.

모델 자체에 립싱크용 파라미터가 설정되어 있는 경우 가져오기 시에 그 파라미터의 GameObject에 CubismMouthParameter가 연결됩니다.

CubismMouthParameter는 참조처를 취득하기 위한 마커로 사용하고 있으므로, 내부에서는 아무것도 처리를 실시하고 있지 않고 데이터도 가지고 있지 않습니다.

2. 각 파라미터에 값을 적용하는 컴포넌트

각 파라미터에 개폐 값을 적용하려면 CubismMouthController를 사용합니다.
이것은 MonoBehaviour를 상속받은 컴포넌트이며, 사용할 때 Cubism의 Prefab 루트에 연결됩니다.

초기화 시 Prefab에 연결된 모든 CubismMouthParameter에 대한 참조를 가져옵니다.
실행 중에 눈 깜빡임용 파라미터를 추가/삭제한 경우 CubismMouthController.Refresh()를 호출해 참조를 다시 취득합니다.

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


            // Fail silently...
            if (model == null)
            {
                return;
            }


            // Cache destinations.
            var tags = model
                .Parameters
                .GetComponentsMany<CubismMouthParameter>();


            Destinations = new CubismParameter[tags.Length];


            for (var i = 0; i < tags.Length; ++i)
            {
                Destinations[i] = tags[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();
        }

CubismMouthController는 매 프레임의 LateUpdate() 타이밍에 CubismMouthParameter로 표시된 파라미터에 CubismMouthController.MouthOpening의 값을 적용합니다.

        /// <summary>
        /// Called by cubism update controller. Updates controller.
        /// </summary>
        /// <remarks>
        /// Make sure this method is called after any animations are evaluated.
        /// </remarks>
        public void OnLateUpdate()
        {
            // Fail silently.
            if (!enabled || Destinations == null)
            {
                return;
            }


            // Apply value.
            Destinations.BlendToValue(BlendMode, MouthOpening);
        }

MouthOpening으로 설정하는 값은 0.0f~1.0f 범위입니다.
CubismMouthController는 이 값을 대상 파라미터에 CubismMouthController.BlendMode에서 설정된 계산 방식으로 적용합니다.

이 MouthOpening의 값을 외부에서 조작하여 모델의 입을 열고 닫을 수 있습니다.

        /// <summary>
        /// The opening of the mouth.
        /// </summary>
        [SerializeField, Range(0f, 1f)]
        public float MouthOpening = 1f;

3. 2에서 적용하는 값의 조작

「2. 각 파라미터에 값을 적용하는 컴포넌트」에서 설명한 대로 CubismMouthController.MouthOpening의 값을 조작하여 립싱크용 파라미터에 값을 적용할 수 있습니다.

Cubism SDK for Unity에서는 다음 세 가지 방법으로 이 값을 조작할 수 있습니다.

  • 모션으로 값 조작
  • 주기적으로 값 조작
  • AudioClip에서 샘플링하여 값 조작

또 유저 측에서 이 값을 조작하는 처리를 구현함으로써 립싱크의 속도나 타이밍 등을 독자적으로 커스터마이즈 할 수 있습니다.

Tips

CubismMouthController.MouthOpening을 조작하는 컴포넌트의 실행 순서가 CubismMouthController보다 나중인 경우 의도한 동작이 되지 않을 가능성이 있습니다.
만약 동작에 문제가 생겼다면 유저 측에서 명시적으로 컴포넌트의 실행 순서를 제어하여 회피할 수 있습니다.
Cubism SDK for Unity는 각 컴포넌트의 실행 순서를 CubismUpdateController로 제어하므로 이를 활용할 수도 있습니다.

또한 상기 3종류의 설정 방법은 각각이 같은 값을 조작하고 있기 때문에, 궁리 없이 하나의 모델에 공존시키는 것은 어렵습니다.

모션으로 값 조작

눈 깜빡임용 파라미터를 설정한 모델을 사용하여 Cubism의 Animator에서 모션을 만들 경우 눈 깜빡임용 커브를 설정할 수 있습니다.

눈 깜빡임용 커브가 설정된 .motion3.json을 Unity 프로젝트로 가져온 경우 AnimationClip은 CubismMouthController.MouthOpening의 값을 대상으로 커브를 생성합니다.
그 때문에, AnimationClip을 Animator 컴포넌트 등에서 재생하면 CubismMouthController.MouthOpening의 값이 조작됩니다.

주기적으로 값 조작

주기적으로 립싱크의 값을 조작하려면 CubismAutoMouthInput을 사용합니다.
CubismAutoMouthInput은 사인파로 립싱크 값을 산출하고 설정하는 컴포넌트입니다.

CubismAutoMouthInput을 사용하려면 Cubism의 Prefab 루트에 연결합니다.

CubismAutoMouthInput에는 하나의 설정 항목이 있습니다.

  • Timescale

사인파의 주기가 바뀝니다.

        /// <summary>
        /// Timescale.
        /// </summary>
        [SerializeField]
        public float Timescale = 10f;
        /// <summary>
        /// Called by Unity. Updates controller.
        /// </summary>
        /// <remarks>
        /// Make sure this method is called after any animations are evaluated.
        /// </remarks>
        private void LateUpdate()
        {
            // Fail silently.
            if (Controller == null)
            {
                return;
            }


            // Progress time.
            T += (Time.deltaTime * Timescale);


            // Evaluate.
            Controller.MouthOpening = Mathf.Abs(Mathf.Sin(T));
        }

AudioClip에서 샘플링하여 값 조작

Unity에서 재생되는 오디오에서 립싱크 값을 설정하려면 CubismAudioMouthInput을 사용합니다.

CubismAudioMouthInput은 AudioSource에서 취득한 재생 중인 오디오 정보에서 샘플링하여 실시간으로 립싱크 값을 생성하고 설정합니다.

CubismAudioMouthInput을 사용하려면 Cubism의 Prefab 루트에 연결합니다.

        /// <summary>
        /// Samples audio input and applies it to mouth controller.
        /// </summary>
        private void Update()
        {
            // 'Fail' silently.
            if (AudioInput == null)
            {
                return;
            }


            // Sample audio.
            var total = 0f;


            AudioInput.GetOutputData(Samples, 0);


            for (var i = 0; i < Samples.Length; ++i)
            {
                var sample = Samples[i];


                total += (sample * sample);
            }


            // Compute root mean square over samples.
            var rms = Mathf.Sqrt(total / Samples.Length) * Gain;


            // Clamp root mean square.
            rms = Mathf.Clamp(rms, 0.0f, 1.0f);


            // Smooth rms.
            rms = Mathf.SmoothDamp(LastRms, rms, ref VelocityBuffer, Smoothing * 0.1f);


            // Set rms as mouth opening and store it for next evaluation.
            Target.MouthOpening = rms;


            LastRms = rms;
        }

CubismAudioMouthInput에는 네 가지 설정 항목이 있습니다.

        /// <summary>
        /// Audio source to sample.
        /// </summary>
        [SerializeField]
        public AudioSource AudioInput;


        /// <summary>
        /// Sampling quality.
        /// </summary>
        [SerializeField]
        public CubismAudioSamplingQuality SamplingQuality;


        /// <summary>
        /// Audio gain.
        /// </summary>
        [Range(1.0f, 10.0f)]
        public float Gain = 1.0f;

        /// <summary>
        /// Smoothing.
        /// </summary>
        [Range(0.0f, 1.0f)]
        public float Smoothing;
  • AudioInput

샘플링하는 AudioSource의 참조입니다.

  • SamplingQuality

샘플링하는 음성의 정밀도입니다.

  • Gain

샘플링한 값의 배율입니다.
1로 1배, 값을 크게 할수록 립싱크의 값도 커집니다.

  • Smoothing

샘플링한 값의 스무딩 양입니다.
값이 클수록 립싱크 값이 매끄럽게 변합니다.

이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.