CubismMotionApplier

最終更新: 2023年3月14日

概要

CubismMotionApplier コンポーネントを使用することで、Cocos Creator の AnimationController (AnimationGraph) によるアニメーション行うことができるようになります。

使用するには同じ Node に CubismMotionApplier, CubismModel コンポーネントと Cocos Creator の AnimationController が必要です。
AnimationController コンポーネントには AnimationGraph を設定する必要があります。

該当のチュートリアル記事は こちら をご覧ください。

CubismModel のパラメータとパーツに AnimationController (AnimationGraph) でのアニメーションを反映させるため、以下の処理を行っています。

操作するパラメータとパーツの参照を取得

CubismMotionApplier.start で AnimationController (AnimationGraph) に設定された AnimationClip により操作する CubismModel のパラメータとパーツへの参照をキャッシュします。

その際、AnimationClip に記録された Path 情報を元に操作対象を探すため Path 情報を元に Map でキャッシュを行います。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
if (parameters != null) {
for (let i = 0; i < parameters.length; i++) {
const path = makePath(parameters[i], model);
this.parameters.set(path, new ValueCache(parameters[i]));
}
}
if (parts != null) {
for (let i = 0; i < parts.length; i++) {
const path = makePath(parts[i], model);
this.parts.set(path, new ValueCache(parts[i]));
}
}
if (parameters != null) { for (let i = 0; i < parameters.length; i++) { const path = makePath(parameters[i], model); this.parameters.set(path, new ValueCache(parameters[i])); } } if (parts != null) { for (let i = 0; i < parts.length; i++) { const path = makePath(parts[i], model); this.parts.set(path, new ValueCache(parts[i])); } }
if (parameters != null) {
  for (let i = 0; i < parameters.length; i++) {
    const path = makePath(parameters[i], model);
    this.parameters.set(path, new ValueCache(parameters[i]));
  }
}
if (parts != null) {
  for (let i = 0; i < parts.length; i++) {
    const path = makePath(parts[i], model);
    this.parts.set(path, new ValueCache(parts[i]));
  }
}

この処理は CubismMotionApplier.refresh で行っています。

値の反映

毎フレーム CubismMotionApplier.onLateUpdate で値計算と反映を行っています。

次の処理をレイヤーの数だけ繰り返しています。

現在の再生状況に応じて処理を呼び出します。

また、遷移中の場合は追加ので処理を行います。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this.valueUpdate(currentClipStatuses, currentStateStatus.progress);
this.valueUpdate(currentClipStatuses, currentStateStatus.progress);
this.valueUpdate(currentClipStatuses, currentStateStatus.progress);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this.valueUpdate(nextClipStatuses, nextStateStatus.progress, transProgress);
this.valueUpdate(nextClipStatuses, nextStateStatus.progress, transProgress);
this.valueUpdate(nextClipStatuses, nextStateStatus.progress, transProgress);

AnimationClip から 値の回収

CubismMotionApplier.setCache で AnimationClip から変更先の Path と現在の値を取得し、

CubismMotionApplier.setParameterCache, CubismMotionApplier.setPartCache を呼び分けています。

CubismMotionApplier.setParameterCache, CubismMotionApplier.setPartCache ではその AnimationClip から得られた情報を計算用にキャッシュします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const cache = this.parameters.get(nodePath);
if (cache == null) {
return;
}
if (Number.isNaN(cache.calcValue)) {
cache.calcValue = value;
} else {
cache.calcValue = math.lerp(cache.calcValue, value, transProgress);
}
const cache = this.parameters.get(nodePath); if (cache == null) { return; } if (Number.isNaN(cache.calcValue)) { cache.calcValue = value; } else { cache.calcValue = math.lerp(cache.calcValue, value, transProgress); }
const cache = this.parameters.get(nodePath);
if (cache == null) {
  return;
}
if (Number.isNaN(cache.calcValue)) {
  cache.calcValue = value;
} else {
  cache.calcValue = math.lerp(cache.calcValue, value, transProgress);
}

レイヤーウェイトを反映

現在のレイヤーのウェイト値で前処理のレイヤーと現在処理レイヤーをブレンドします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
this.parameters.forEach((cache, _key, _map) => {
if (Number.isNaN(cache.value)) {
cache.value = cache.calcValue;
} else if (!Number.isNaN(cache.calcValue)) {
cache.value = math.lerp(cache.value, cache.calcValue, layerWeight);
}
cache.calcValue = Number.NaN;
});
this.parts.forEach((cache, _key, _map) => {
if (Number.isNaN(cache.value)) {
cache.value = cache.calcValue;
} else if (!Number.isNaN(cache.calcValue)) {
cache.value = math.lerp(cache.value, cache.calcValue, layerWeight);
}
cache.calcValue = Number.NaN;
});
this.parameters.forEach((cache, _key, _map) => { if (Number.isNaN(cache.value)) { cache.value = cache.calcValue; } else if (!Number.isNaN(cache.calcValue)) { cache.value = math.lerp(cache.value, cache.calcValue, layerWeight); } cache.calcValue = Number.NaN; }); this.parts.forEach((cache, _key, _map) => { if (Number.isNaN(cache.value)) { cache.value = cache.calcValue; } else if (!Number.isNaN(cache.calcValue)) { cache.value = math.lerp(cache.value, cache.calcValue, layerWeight); } cache.calcValue = Number.NaN; });
this.parameters.forEach((cache, _key, _map) => {
  if (Number.isNaN(cache.value)) {
    cache.value = cache.calcValue;
  } else if (!Number.isNaN(cache.calcValue)) {
    cache.value = math.lerp(cache.value, cache.calcValue, layerWeight);
  }
  cache.calcValue = Number.NaN;
});
this.parts.forEach((cache, _key, _map) => {
  if (Number.isNaN(cache.value)) {
    cache.value = cache.calcValue;
  } else if (!Number.isNaN(cache.calcValue)) {
    cache.value = math.lerp(cache.value, cache.calcValue, layerWeight);
  }
  cache.calcValue = Number.NaN;
});

この処理は CubismMotionApplier.calcCache で行っています。

この記事はお役に立ちましたか?
はいいいえ
この記事に関するご意見・
ご要望をお聞かせください。