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
샘플링한 값의 스무딩 양입니다.
값이 클수록 립싱크 값이 매끄럽게 변합니다.