EyeBlink (Cocos Creator)

最終更新: 2023年3月14日

概要

EyeBlinkは、まばたき用パラメータの現在の値に対して開閉状態の値を適用する機能です。
モデルにまばたきのパラメータを設定する方法については こちら をご覧ください。

まばたき用のパラメータの指定は、モデル自体に設定しておく他、Cocos Creator上でユーザが任意に指定することができます。

Cubism SDK for Cocos Creator におけるEyeBlinkは3種類の要素によって構成されています。

  1. パラメータ指定用のコンポーネント
  2. 各パラメータに値を適用するコンポーネント
  3. 2で適用する値の操作

1. パラメータ指定用のコンポーネント

EyeBlinkに使用するパラメータを指定するには、CubismEyeBlinkParameterを使用します。

CubismEyeBlinkParameterはComponentを継承したコンポーネントで、
[Prefabのルート]/Parameters/ 以下に配置されたGameObjectにアタッチして使用します。
これがアタッチされたGameObjectと同じIDのパラメータをまばたき用のパラメータとして扱います。

モデル自体にまばたき用のパラメータが設定されている場合、インポートの際にそのパラメータのGameObjectにCubismEyeBlinkParameterがアタッチされます。

CubismEyeBlinkParameterは参照先を取得するためのマーカーとして使用しているので、内部では何も処理を行っておらず、データも持っていません。

2. 各パラメータに値を適用するコンポーネント

各パラメータに開閉の値を適用するには、CubismEyeBlinkControllerを使用します。
これはComponentを継承したコンポーネントで、使用する際はCubismのPrefabのルートにアタッチします。

初期化時に、PrefabにアタッチされたすべてのCubismEyeBlinkParameterの参照を取得します。
実行中にまばたき用のパラメータを追加/削除した場合、CubismEyeBlinkController.refresh()を呼んで参照を取得し直します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/** Refreshes controller. Call this method after adding and/or removing <see cref="CubismEyeBlinkParameter"/>s. */
public refresh(): void {
const model = CoreComponentExtensionMethods.findCubismModel(this);
// Fail silently...
if (model == null) {
return;
}
// Cache destinations.
const tags =
model.parameters != null
? ComponentExtensionMethods.getComponentsMany(model.parameters, CubismEyeBlinkParameter)
: null;
this.destinations = new Array(tags?.length ?? 0);
for (var i = 0; i < this.destinations.length; i++) {
this.destinations[i] = tags![i].getComponent(CubismParameter);
}
// Get cubism update controller.
this.hasUpdateController = this.getComponent(CubismUpdateController) != null;
}
...
/** Called by Cocos Creator. Makes sure cache is initialized. */
protected start(): void {
// Initialize cache.
this.refresh();
}
/** Refreshes controller. Call this method after adding and/or removing <see cref="CubismEyeBlinkParameter"/>s. */ public refresh(): void { const model = CoreComponentExtensionMethods.findCubismModel(this); // Fail silently... if (model == null) { return; } // Cache destinations. const tags = model.parameters != null ? ComponentExtensionMethods.getComponentsMany(model.parameters, CubismEyeBlinkParameter) : null; this.destinations = new Array(tags?.length ?? 0); for (var i = 0; i < this.destinations.length; i++) { this.destinations[i] = tags![i].getComponent(CubismParameter); } // Get cubism update controller. this.hasUpdateController = this.getComponent(CubismUpdateController) != null; } ... /** Called by Cocos Creator. Makes sure cache is initialized. */ protected start(): void { // Initialize cache. this.refresh(); }
  /** Refreshes controller. Call this method after adding and/or removing <see cref="CubismEyeBlinkParameter"/>s. */
  public refresh(): void {
    const model = CoreComponentExtensionMethods.findCubismModel(this);

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

    // Cache destinations.
    const tags =
      model.parameters != null
        ? ComponentExtensionMethods.getComponentsMany(model.parameters, CubismEyeBlinkParameter)
        : null;

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

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

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

...

  /** Called by Cocos Creator. Makes sure cache is initialized. */
  protected start(): void {
    // Initialize cache.
    this.refresh();
  }

CubismEyeBlinkControllerは、毎フレームのonLateUpdate()のタイミングで、CubismEyeBlinkParameterでマーキングされたパラメータに対してCubismEyeBlinkController.eyeOpeningの値を適用します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Apply value.
CubismParameterExtensionMethods.blendToValueArray(
this.destinations,
this.blendMode,
this.eyeOpening
);
// Apply value. CubismParameterExtensionMethods.blendToValueArray( this.destinations, this.blendMode, this.eyeOpening );
// Apply value.
CubismParameterExtensionMethods.blendToValueArray(
  this.destinations,
  this.blendMode,
  this.eyeOpening
);

EyeOpeningに設定する値は0.0f~1.0fの範囲です。
CubismEyeBlinkControllerはこの値を対象のパラメータに対して、CubismEyeBlinkController.blendModeで設定された計算方式で適用します。

このEyeOpeningの値を外から操作することで、モデルの目を開閉させることができます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/** Opening of the eyes. */
@property({ type: CCFloat, visible: true, serializable: true, range: [0.0, 1.0, 0.01] })
public eyeOpening: number = 1.0;
/** Opening of the eyes. */ @property({ type: CCFloat, visible: true, serializable: true, range: [0.0, 1.0, 0.01] }) public eyeOpening: number = 1.0;
/** Opening of the eyes. */
@property({ type: CCFloat, visible: true, serializable: true, range: [0.0, 1.0, 0.01] })
public eyeOpening: number = 1.0;

3. 2で適用する値の操作

「2. 各パラメータに値を適用するコンポーネント」で説明した通り、CubismEyeBlinkController.eyeOpeningの値を操作することで、まばたき用のパラメータに値を適用できます。
Cubism SDK for Cocos Creator には、以下の2種類の方法でこの値を操作することができます。

  • モーションによって値を操作
  • コンポーネントによって値を操作

また、ユーザ側でこの値を操作する処理を実装していただくことで、まばたきの速度やタイミング等を独自にカスタマイズすることができます。

TIPS

CubismEyeBlinkController.eyeOpeningを操作するコンポーネントの実行順がCubismEyeBlinkControllerよりも後である場合、意図した動作にならない可能性があります。
もし動作に問題が生じた、ユーザ側で明示的にコンポーネントの実行順を制御することで回避が可能です。
Cubism SDK for Cocos Creator では各コンポーネントの実行順をのCubismUpdateControllerで制御しているので、これを利用することもできます。

また、上記2種類の設定方法はそれぞれ異なるタイミングで同じ値を操作しているため、工夫無しで一つのモデルに両方を共存させることは難しくなっております。

モーションによって値を操作

まばたき用のパラメータを設定したモデルを使用してCubismのAnimatorでモーションを作成する場合、まばたき用のカーブを設定することが可能です。

まばたき用のカーブが設定された.motion3.jsonをプロジェクトにインポートした場合、AnimationClipにはCubismEyeBlinkController.eyeOpeningの値を対象としてそのカーブが生成されます。
そのため、そのAnimationClipをAnimatorコンポーネントなどで再生することでCubismEyeBlinkController.eyeOpeningの値が操作されます。

コンポーネントによって値を操作

Cubism SDK for Cocos Creator では、CubismAutoEyeBlinkInput コンポーネントによってもまばたき用の値を操作することができます。

CubismAutoEyeBlinkInputは、Inspectorから設定した速度や間隔、間隔に加えるランダムな揺らぎの幅からまばたき用の値を算出して設定します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
protected lateUpdate(dt: number): void {
// Fail silently.
if (this.controller == null) {
return;
}
// Wait for time until blink.
if (this.currentPhase == Phase.Idling) {
this.t -= dt;
if (this.t < 0) {
this.t = Math.PI * -0.5;
this.lastValue = 1;
this.currentPhase = Phase.ClosingEyes;
} else {
return;
}
}
// Evaluate eye blinking.
this.t += dt * this.timescale;
let value = Math.abs(Math.sin(this.t));
if (this.currentPhase == Phase.ClosingEyes && value > this.lastValue) {
this.currentPhase = Phase.OpeningEyes;
} else if (this.currentPhase == Phase.OpeningEyes && value < this.lastValue) {
value = 1;
this.currentPhase = Phase.Idling;
const range = this.maximumDeviation * 2;
this.t = this.mean + random() * range - this.maximumDeviation;
}
this.controller.eyeOpening = value;
this.lastValue = value;
}
protected lateUpdate(dt: number): void { // Fail silently. if (this.controller == null) { return; } // Wait for time until blink. if (this.currentPhase == Phase.Idling) { this.t -= dt; if (this.t < 0) { this.t = Math.PI * -0.5; this.lastValue = 1; this.currentPhase = Phase.ClosingEyes; } else { return; } } // Evaluate eye blinking. this.t += dt * this.timescale; let value = Math.abs(Math.sin(this.t)); if (this.currentPhase == Phase.ClosingEyes && value > this.lastValue) { this.currentPhase = Phase.OpeningEyes; } else if (this.currentPhase == Phase.OpeningEyes && value < this.lastValue) { value = 1; this.currentPhase = Phase.Idling; const range = this.maximumDeviation * 2; this.t = this.mean + random() * range - this.maximumDeviation; } this.controller.eyeOpening = value; this.lastValue = value; }
protected lateUpdate(dt: number): void {
  // Fail silently.
  if (this.controller == null) {
    return;
  }

  // Wait for time until blink.
  if (this.currentPhase == Phase.Idling) {
    this.t -= dt;

    if (this.t < 0) {
      this.t = Math.PI * -0.5;
      this.lastValue = 1;
      this.currentPhase = Phase.ClosingEyes;
    } else {
      return;
    }
  }

  // Evaluate eye blinking.
  this.t += dt * this.timescale;
  let value = Math.abs(Math.sin(this.t));

  if (this.currentPhase == Phase.ClosingEyes && value > this.lastValue) {
    this.currentPhase = Phase.OpeningEyes;
  } else if (this.currentPhase == Phase.OpeningEyes && value < this.lastValue) {
    value = 1;
    this.currentPhase = Phase.Idling;
    const range = this.maximumDeviation * 2;
    this.t = this.mean + random() * range - this.maximumDeviation;
  }

  this.controller.eyeOpening = value;
  this.lastValue = value;
}

CubismAutoEyeBlinkInputには3つの設定項目があります。

  • mean
  • maximumDeviation
  • timescale
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/** Mean time between eye blinks in seconds. */
@property({ type: CCFloat, serializable: true, range: [1.0, 10.0, 0.001] })
public mean: number = 2.5;
/** Maximum deviation from {@link mean} in seconds. */
@property({ type: CCFloat, serializable: true, range: [0.5, 5.0, 0.001] })
public maximumDeviation: number = 2.0;
/** Timescale. */
@property({ type: CCFloat, serializable: true, range: [1.0, 20.0, 0.001] })
public timescale: number = 10.0;
/** Mean time between eye blinks in seconds. */ @property({ type: CCFloat, serializable: true, range: [1.0, 10.0, 0.001] }) public mean: number = 2.5; /** Maximum deviation from {@link mean} in seconds. */ @property({ type: CCFloat, serializable: true, range: [0.5, 5.0, 0.001] }) public maximumDeviation: number = 2.0; /** Timescale. */ @property({ type: CCFloat, serializable: true, range: [1.0, 20.0, 0.001] }) public timescale: number = 10.0;
/** Mean time between eye blinks in seconds. */
@property({ type: CCFloat, serializable: true, range: [1.0, 10.0, 0.001] })
public mean: number = 2.5;

/** Maximum deviation from {@link mean} in seconds. */
@property({ type: CCFloat, serializable: true, range: [0.5, 5.0, 0.001] })
public maximumDeviation: number = 2.0;

/** Timescale. */
@property({ type: CCFloat, serializable: true, range: [1.0, 20.0, 0.001] })
public timescale: number = 10.0;
  • mean
    まばたきを行うまでの時間を設定します。

    単位は秒になります。

    実際は、この値に Maximum Deviationによる誤差を足した時間が使われます。
  • maximumDeviation
    Meanに設定した時間に加えるランダムな揺らぎの幅を設定します。

    これらは以下のように値を計算されます。
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const range = this.maximumDeviation * 2;
this.t = this.mean + random() * range - this.maximumDeviation;
const range = this.maximumDeviation * 2; this.t = this.mean + random() * range - this.maximumDeviation;
const range = this.maximumDeviation * 2;
this.t = this.mean + random() * range - this.maximumDeviation;
  • timescale
    まばたきを行う速度になります。

    前フレームからの経過時間に対して乗算されます。
この記事はお役に立ちましたか?
はいいいえ
この記事に関するご意見・
ご要望をお聞かせください。