MouthMovement
업데이트: 2020/01/30
개요
MouthMovement는 립싱크 파라미터의 현재 값에 개폐 상태 값을 적용하는 기능입니다.
모션으로 설정된 립싱크용의 커브나 재생하고 있는 음성 파일로부터 실시간으로 샘플링한 값 등을 모델에 적용하는 것이 가능합니다.
모델에 립싱크 파라미터를 설정하는 방법에 대해서는 여기를 참조하세요.
MouthMovement에서 설정하는 것은 입의 개폐 상태뿐입니다.
입의 모양을 모음에 맞추는 것과 같은 조작을 할 수는 없습니다.
Unity에서 립싱크용 파라미터를 지정하려면 Cubism 에디터에서 모델로 설정해 두는 것 외에도 Unity에서 사용자가 임의로 지정할 수 있습니다.
Cubism SDK for Unity의 MouthMovement는 세 가지 요소로 구성됩니다.
- 파라미터 지정용 컴포넌트
- 각 파라미터에 값을 적용하는 컴포넌트
- 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
샘플링한 값의 스무딩 양입니다.
값이 클수록 립싱크 값이 매끄럽게 변합니다.