MouthMovement (Cocos Creator)

업데이트: 2023/03/14

개요

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

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

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

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

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

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

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

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

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

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

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

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

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

  public refresh() {
    const model = CoreComponentExtensionMethods.findCubismModel(this);

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

    // Cache destinations.
    const tags = ComponentExtensionMethods.getComponentsMany(
      model.parameters,
      CubismMouthParameter
    );

    this.destinations = new Array(tags.length);

    for (let i = 0; i < tags.length; ++i) {
      this.destinations[i] = tags[i].getComponent(CubismParameter);
    }

    // Get cubism update controller.
    this.hasUpdateController = this.getComponent(CubismUpdateController) ! = null;
  }

...

  protected start() {
    // Initialize cache.
    this.refresh();
  }

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

  protected onLateUpdate(deltaTime: number) {
    // Fail silently.
    if (!this.enabled || this.destinations == null) {
      return;
    }

    // Apply value.
    CubismParameterExtensionMethods.blendToValueArray(
      this.destinations,
      this.blendMode,
      this.mouthOpening
    );
  }

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

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

  @property({ type: CCFloat, slide: true, range: [0.0, 1.0, 0.01] })
  public mouthOpening: number = 1.0;

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

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

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

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

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

Tips

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

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

모션으로 값 조작

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

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

주기적으로 값 조작

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

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

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

  • Timescale

    사인파의 주기가 바뀝니다.
  @property(CCFloat)
  public Timescale: number = 10.0;
  lateUpdate(deltaTime: number) {
    // Fail silently.
    if (this.Controller == null) {
      return;
    }

    // Progress time.
    this.T += deltaTime * this.Timescale;

    // Evaluate.
    this.Controller.mouthOpening = Math.abs(Math.sin(this.T));
  }

오디오에서 샘플링하여 값 조작

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

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

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

  protected update(deltaTime: number) {
    const { audioInput, samples, target, sampleRate, gain, smoothing } = this;

    // 'Fail' silently.
    if (audioInput == null || target == null || samples == null || sampleRate == 0) {
      return;
    }
    const { trunc, sqrt } = Math;

    const { currentTime } = audioInput;
    const pos = trunc(currentTime * this.sampleRate);
    let length = 256;
    switch (this.samplingQuality) {
      case CubismAudioSamplingQuality.veryHigh:
        length = 256;
        break;
      case CubismAudioSamplingQuality.maximum:
        length = 512;
        break;
      default:
        length = 256;
        break;
    }

    // Sample audio.
    let total = 0.0;

    for (let i = 0; i < length; i++) {
      const sample = samples.getData((pos + i) % samples.length);
      total += sample * sample;
    }

    // Compute root mean square over samples.
    let rms = sqrt(total / length) * gain;

    // Clamp root mean square.
    rms = math.clamp01(rms);

    // Smooth rms.
    const output = MathExtensions.Float.smoothDamp(
      this.lastRms,
      rms,
      this.velocityBuffer,
      smoothing * 0.1,
      undefined,
      deltaTime
    );

    rms = output[0];
    this.velocityBuffer = output[1];

    // Set rms as mouth opening and store it for next evaluation.
    target.mouthOpening = rms;

    this.lastRms = rms;
  }

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

  @property(AudioSource)
  public audioInput: AudioSource | null = null;

  @property({ type: Enum(CubismAudioSamplingQuality) })
  public samplingQuality: CubismAudioSamplingQuality = CubismAudioSamplingQuality.high;

  @property({ type: CCFloat, slide: true, range: [1.0, 10.0, 0.01] })
  public gain: number = 1.0;

  @property({ type: CCFloat, slide: true, range: [0.0, 1.0, 0.01] })
  public smoothing: number = 0.0;
  • audioInput

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

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

    샘플링한 값의 배율입니다.

    1로 1배, 값을 크게 할수록 립싱크의 값도 커집니다.
  • smoothing

    샘플링한 값의 스무딩 양입니다.

    값이 클수록 립싱크 값이 매끄럽게 변합니다.
이 기사가 도움이 되었나요?
아니요
이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.