UNPKG

@petkoneo/phaser3-rex-plugins

Version:
1,087 lines (921 loc) 33.9 kB
/** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ import { CubismIdHandle } from '../id/cubismid'; import { CubismFramework } from '../live2dcubismframework'; import { CubismMath } from '../math/cubismmath'; import { CubismModel } from '../model/cubismmodel'; import { csmString } from '../type/csmstring'; import { csmVector } from '../type/csmvector'; import { CSM_ASSERT, CubismLogDebug, CubismLogWarning, } from '../utils/cubismdebug'; import { ACubismMotion, FinishedMotionCallback } from './acubismmotion'; import { CubismMotionCurve, CubismMotionCurveTarget, CubismMotionData, CubismMotionEvent, CubismMotionPoint, CubismMotionSegment, CubismMotionSegmentType, } from './cubismmotioninternal'; import { CubismMotionJson, EvaluationOptionFlag } from './cubismmotionjson'; import { CubismMotionQueueEntry } from './cubismmotionqueueentry'; const EffectNameEyeBlink = 'EyeBlink'; const EffectNameLipSync = 'LipSync'; const TargetNameModel = 'Model'; const TargetNameParameter = 'Parameter'; const TargetNamePartOpacity = 'PartOpacity'; // Id const IdNameOpacity = 'Opacity'; /** * Cubism SDK R2 以前のモーションを再現させるなら true 、アニメータのモーションを正しく再現するなら false 。 */ const UseOldBeziersCurveMotion = false; function lerpPoints( a: CubismMotionPoint, b: CubismMotionPoint, t: number ): CubismMotionPoint { const result: CubismMotionPoint = new CubismMotionPoint(); result.time = a.time + (b.time - a.time) * t; result.value = a.value + (b.value - a.value) * t; return result; } function linearEvaluate(points: CubismMotionPoint[], time: number): number { let t: number = (time - points[0].time) / (points[1].time - points[0].time); if (t < 0.0) { t = 0.0; } return points[0].value + (points[1].value - points[0].value) * t; } function bezierEvaluate(points: CubismMotionPoint[], time: number): number { let t: number = (time - points[0].time) / (points[3].time - points[0].time); if (t < 0.0) { t = 0.0; } const p01: CubismMotionPoint = lerpPoints(points[0], points[1], t); const p12: CubismMotionPoint = lerpPoints(points[1], points[2], t); const p23: CubismMotionPoint = lerpPoints(points[2], points[3], t); const p012: CubismMotionPoint = lerpPoints(p01, p12, t); const p123: CubismMotionPoint = lerpPoints(p12, p23, t); return lerpPoints(p012, p123, t).value; } function bezierEvaluateBinarySearch( points: CubismMotionPoint[], time: number ): number { const x_error = 0.01; const x: number = time; let x1: number = points[0].time; let x2: number = points[3].time; let cx1: number = points[1].time; let cx2: number = points[2].time; let ta = 0.0; let tb = 1.0; let t = 0.0; let i = 0; for (let var33 = true; i < 20; ++i) { if (x < x1 + x_error) { t = ta; break; } if (x2 - x_error < x) { t = tb; break; } let centerx: number = (cx1 + cx2) * 0.5; cx1 = (x1 + cx1) * 0.5; cx2 = (x2 + cx2) * 0.5; const ctrlx12: number = (cx1 + centerx) * 0.5; const ctrlx21: number = (cx2 + centerx) * 0.5; centerx = (ctrlx12 + ctrlx21) * 0.5; if (x < centerx) { tb = (ta + tb) * 0.5; if (centerx - x_error < x) { t = tb; break; } x2 = centerx; cx2 = ctrlx12; } else { ta = (ta + tb) * 0.5; if (x < centerx + x_error) { t = ta; break; } x1 = centerx; cx1 = ctrlx21; } } if (i == 20) { t = (ta + tb) * 0.5; } if (t < 0.0) { t = 0.0; } if (t > 1.0) { t = 1.0; } const p01: CubismMotionPoint = lerpPoints(points[0], points[1], t); const p12: CubismMotionPoint = lerpPoints(points[1], points[2], t); const p23: CubismMotionPoint = lerpPoints(points[2], points[3], t); const p012: CubismMotionPoint = lerpPoints(p01, p12, t); const p123: CubismMotionPoint = lerpPoints(p12, p23, t); return lerpPoints(p012, p123, t).value; } function bezierEvaluateCardanoInterpretation( points: CubismMotionPoint[], time: number ): number { const x: number = time; const x1: number = points[0].time; const x2: number = points[3].time; const cx1: number = points[1].time; const cx2: number = points[2].time; const a: number = x2 - 3.0 * cx2 + 3.0 * cx1 - x1; const b: number = 3.0 * cx2 - 6.0 * cx1 + 3.0 * x1; const c: number = 3.0 * cx1 - 3.0 * x1; const d: number = x1 - x; const t: number = CubismMath.cardanoAlgorithmForBezier(a, b, c, d); const p01: CubismMotionPoint = lerpPoints(points[0], points[1], t); const p12: CubismMotionPoint = lerpPoints(points[1], points[2], t); const p23: CubismMotionPoint = lerpPoints(points[2], points[3], t); const p012: CubismMotionPoint = lerpPoints(p01, p12, t); const p123: CubismMotionPoint = lerpPoints(p12, p23, t); return lerpPoints(p012, p123, t).value; } function steppedEvaluate(points: CubismMotionPoint[], time: number): number { return points[0].value; } function inverseSteppedEvaluate( points: CubismMotionPoint[], time: number ): number { return points[1].value; } function evaluateCurve( motionData: CubismMotionData, index: number, time: number ): number { // Find segment to evaluate. const curve: CubismMotionCurve = motionData.curves.at(index); let target = -1; const totalSegmentCount: number = curve.baseSegmentIndex + curve.segmentCount; let pointPosition = 0; for (let i: number = curve.baseSegmentIndex; i < totalSegmentCount; ++i) { // Get first point of next segment. pointPosition = motionData.segments.at(i).basePointIndex + (motionData.segments.at(i).segmentType == CubismMotionSegmentType.CubismMotionSegmentType_Bezier ? 3 : 1); // Break if time lies within current segment. if (motionData.points.at(pointPosition).time > time) { target = i; break; } } if (target == -1) { return motionData.points.at(pointPosition).value; } const segment: CubismMotionSegment = motionData.segments.at(target); return segment.evaluate(motionData.points.get(segment.basePointIndex), time); } /** * モーションクラス * * モーションのクラス。 */ export class CubismMotion extends ACubismMotion { /** * インスタンスを作成する * * @param buffer motion3.jsonが読み込まれているバッファ * @param size バッファのサイズ * @param onFinishedMotionHandler モーション再生終了時に呼び出されるコールバック関数 * @return 作成されたインスタンス */ public static create( buffer: ArrayBuffer, size: number, onFinishedMotionHandler?: FinishedMotionCallback ): CubismMotion { const ret = new CubismMotion(); ret.parse(buffer, size); ret._sourceFrameRate = ret._motionData.fps; ret._loopDurationSeconds = ret._motionData.duration; ret._onFinishedMotion = onFinishedMotionHandler; // NOTE: Editorではループありのモーション書き出しは非対応 // ret->_loop = (ret->_motionData->Loop > 0); return ret; } /** * モデルのパラメータの更新の実行 * @param model 対象のモデル * @param userTimeSeconds 現在の時刻[秒] * @param fadeWeight モーションの重み * @param motionQueueEntry CubismMotionQueueManagerで管理されているモーション */ public doUpdateParameters( model: CubismModel, userTimeSeconds: number, fadeWeight: number, motionQueueEntry: CubismMotionQueueEntry ): void { if (this._modelCurveIdEyeBlink == null) { this._modelCurveIdEyeBlink = CubismFramework.getIdManager().getId(EffectNameEyeBlink); } if (this._modelCurveIdLipSync == null) { this._modelCurveIdLipSync = CubismFramework.getIdManager().getId(EffectNameLipSync); } if (this._modelCurveIdOpacity == null) { this._modelCurveIdOpacity = CubismFramework.getIdManager().getId(IdNameOpacity); } let timeOffsetSeconds: number = userTimeSeconds - motionQueueEntry.getStartTime(); if (timeOffsetSeconds < 0.0) { timeOffsetSeconds = 0.0; // エラー回避 } let lipSyncValue: number = Number.MAX_VALUE; let eyeBlinkValue: number = Number.MAX_VALUE; //まばたき、リップシンクのうちモーションの適用を検出するためのビット(maxFlagCount個まで const MaxTargetSize = 64; let lipSyncFlags = 0; let eyeBlinkFlags = 0; //瞬き、リップシンクのターゲット数が上限を超えている場合 if (this._eyeBlinkParameterIds.getSize() > MaxTargetSize) { CubismLogDebug( 'too many eye blink targets : {0}', this._eyeBlinkParameterIds.getSize() ); } if (this._lipSyncParameterIds.getSize() > MaxTargetSize) { CubismLogDebug( 'too many lip sync targets : {0}', this._lipSyncParameterIds.getSize() ); } const tmpFadeIn: number = this._fadeInSeconds <= 0.0 ? 1.0 : CubismMath.getEasingSine( (userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / this._fadeInSeconds ); const tmpFadeOut: number = this._fadeOutSeconds <= 0.0 || motionQueueEntry.getEndTime() < 0.0 ? 1.0 : CubismMath.getEasingSine( (motionQueueEntry.getEndTime() - userTimeSeconds) / this._fadeOutSeconds ); let value: number; let c: number, parameterIndex: number; // 'Repeat' time as necessary. let time: number = timeOffsetSeconds; if (this._isLoop) { while (time > this._motionData.duration) { time -= this._motionData.duration; } } const curves: csmVector<CubismMotionCurve> = this._motionData.curves; // Evaluate model curves. for ( c = 0; c < this._motionData.curveCount && curves.at(c).type == CubismMotionCurveTarget.CubismMotionCurveTarget_Model; ++c ) { // Evaluate curve and call handler. value = evaluateCurve(this._motionData, c, time); if (curves.at(c).id == this._modelCurveIdEyeBlink) { eyeBlinkValue = value; } else if (curves.at(c).id == this._modelCurveIdLipSync) { lipSyncValue = value; } else if (curves.at(c).id == this._modelCurveIdOpacity) { this._modelOpacity = value; model.setModelOapcity(this.getModelOpacityValue()); } } let parameterMotionCurveCount = 0; for ( ; c < this._motionData.curveCount && curves.at(c).type == CubismMotionCurveTarget.CubismMotionCurveTarget_Parameter; ++c ) { parameterMotionCurveCount++; // Find parameter index. parameterIndex = model.getParameterIndex(curves.at(c).id); // Skip curve evaluation if no value in sink. if (parameterIndex == -1) { continue; } const sourceValue: number = model.getParameterValueByIndex(parameterIndex); // Evaluate curve and apply value. value = evaluateCurve(this._motionData, c, time); if (eyeBlinkValue != Number.MAX_VALUE) { for ( let i = 0; i < this._eyeBlinkParameterIds.getSize() && i < MaxTargetSize; ++i ) { if (this._eyeBlinkParameterIds.at(i) == curves.at(c).id) { value *= eyeBlinkValue; eyeBlinkFlags |= 1 << i; break; } } } if (lipSyncValue != Number.MAX_VALUE) { for ( let i = 0; i < this._lipSyncParameterIds.getSize() && i < MaxTargetSize; ++i ) { if (this._lipSyncParameterIds.at(i) == curves.at(c).id) { value += lipSyncValue; lipSyncFlags |= 1 << i; break; } } } let v: number; // パラメータごとのフェード if (curves.at(c).fadeInTime < 0.0 && curves.at(c).fadeOutTime < 0.0) { // モーションのフェードを適用 v = sourceValue + (value - sourceValue) * fadeWeight; } else { // パラメータに対してフェードインかフェードアウトが設定してある場合はそちらを適用 let fin: number; let fout: number; if (curves.at(c).fadeInTime < 0.0) { fin = tmpFadeIn; } else { fin = curves.at(c).fadeInTime == 0.0 ? 1.0 : CubismMath.getEasingSine( (userTimeSeconds - motionQueueEntry.getFadeInStartTime()) / curves.at(c).fadeInTime ); } if (curves.at(c).fadeOutTime < 0.0) { fout = tmpFadeOut; } else { fout = curves.at(c).fadeOutTime == 0.0 || motionQueueEntry.getEndTime() < 0.0 ? 1.0 : CubismMath.getEasingSine( (motionQueueEntry.getEndTime() - userTimeSeconds) / curves.at(c).fadeOutTime ); } const paramWeight: number = this._weight * fin * fout; // パラメータごとのフェードを適用 v = sourceValue + (value - sourceValue) * paramWeight; } model.setParameterValueByIndex(parameterIndex, v, 1.0); } { if (eyeBlinkValue != Number.MAX_VALUE) { for ( let i = 0; i < this._eyeBlinkParameterIds.getSize() && i < MaxTargetSize; ++i ) { const sourceValue: number = model.getParameterValueById( this._eyeBlinkParameterIds.at(i) ); // モーションでの上書きがあった時にはまばたきは適用しない if ((eyeBlinkFlags >> i) & 0x01) { continue; } const v: number = sourceValue + (eyeBlinkValue - sourceValue) * fadeWeight; model.setParameterValueById(this._eyeBlinkParameterIds.at(i), v); } } if (lipSyncValue != Number.MAX_VALUE) { for ( let i = 0; i < this._lipSyncParameterIds.getSize() && i < MaxTargetSize; ++i ) { const sourceValue: number = model.getParameterValueById( this._lipSyncParameterIds.at(i) ); // モーションでの上書きがあった時にはリップシンクは適用しない if ((lipSyncFlags >> i) & 0x01) { continue; } const v: number = sourceValue + (lipSyncValue - sourceValue) * fadeWeight; model.setParameterValueById(this._lipSyncParameterIds.at(i), v); } } } for ( ; c < this._motionData.curveCount && curves.at(c).type == CubismMotionCurveTarget.CubismMotionCurveTarget_PartOpacity; ++c ) { // Find parameter index. parameterIndex = model.getParameterIndex(curves.at(c).id); // Skip curve evaluation if no value in sink. if (parameterIndex == -1) { continue; } // Evaluate curve and apply value. value = evaluateCurve(this._motionData, c, time); model.setParameterValueByIndex(parameterIndex, value); } if (timeOffsetSeconds >= this._motionData.duration) { if (this._isLoop) { motionQueueEntry.setStartTime(userTimeSeconds); // 最初の状態へ if (this._isLoopFadeIn) { // ループ内でループ用フェードインが有効の時は、フェードイン設定し直し motionQueueEntry.setFadeInStartTime(userTimeSeconds); } } else { if (this._onFinishedMotion) { this._onFinishedMotion(this); } motionQueueEntry.setIsFinished(true); } } this._lastWeight = fadeWeight; } /** * ループ情報の設定 * @param loop ループ情報 */ public setIsLoop(loop: boolean): void { this._isLoop = loop; } /** * ループ情報の取得 * @return true ループする * @return false ループしない */ public isLoop(): boolean { return this._isLoop; } /** * ループ時のフェードイン情報の設定 * @param loopFadeIn ループ時のフェードイン情報 */ public setIsLoopFadeIn(loopFadeIn: boolean): void { this._isLoopFadeIn = loopFadeIn; } /** * ループ時のフェードイン情報の取得 * * @return true する * @return false しない */ public isLoopFadeIn(): boolean { return this._isLoopFadeIn; } /** * モーションの長さを取得する。 * * @return モーションの長さ[秒] */ public getDuration(): number { return this._isLoop ? -1.0 : this._loopDurationSeconds; } /** * モーションのループ時の長さを取得する。 * * @return モーションのループ時の長さ[秒] */ public getLoopDuration(): number { return this._loopDurationSeconds; } /** * パラメータに対するフェードインの時間を設定する。 * * @param parameterId パラメータID * @param value フェードインにかかる時間[秒] */ public setParameterFadeInTime( parameterId: CubismIdHandle, value: number ): void { const curves: csmVector<CubismMotionCurve> = this._motionData.curves; for (let i = 0; i < this._motionData.curveCount; ++i) { if (parameterId == curves.at(i).id) { curves.at(i).fadeInTime = value; return; } } } /** * パラメータに対するフェードアウトの時間の設定 * @param parameterId パラメータID * @param value フェードアウトにかかる時間[秒] */ public setParameterFadeOutTime( parameterId: CubismIdHandle, value: number ): void { const curves: csmVector<CubismMotionCurve> = this._motionData.curves; for (let i = 0; i < this._motionData.curveCount; ++i) { if (parameterId == curves.at(i).id) { curves.at(i).fadeOutTime = value; return; } } } /** * パラメータに対するフェードインの時間の取得 * @param parameterId パラメータID * @return フェードインにかかる時間[秒] */ public getParameterFadeInTime(parameterId: CubismIdHandle): number { const curves: csmVector<CubismMotionCurve> = this._motionData.curves; for (let i = 0; i < this._motionData.curveCount; ++i) { if (parameterId == curves.at(i).id) { return curves.at(i).fadeInTime; } } return -1; } /** * パラメータに対するフェードアウトの時間を取得 * * @param parameterId パラメータID * @return フェードアウトにかかる時間[秒] */ public getParameterFadeOutTime(parameterId: CubismIdHandle): number { const curves: csmVector<CubismMotionCurve> = this._motionData.curves; for (let i = 0; i < this._motionData.curveCount; ++i) { if (parameterId == curves.at(i).id) { return curves.at(i).fadeOutTime; } } return -1; } /** * 自動エフェクトがかかっているパラメータIDリストの設定 * @param eyeBlinkParameterIds 自動まばたきがかかっているパラメータIDのリスト * @param lipSyncParameterIds リップシンクがかかっているパラメータIDのリスト */ public setEffectIds( eyeBlinkParameterIds: csmVector<CubismIdHandle>, lipSyncParameterIds: csmVector<CubismIdHandle> ): void { this._eyeBlinkParameterIds = eyeBlinkParameterIds; this._lipSyncParameterIds = lipSyncParameterIds; } /** * コンストラクタ */ public constructor() { super(); this._sourceFrameRate = 30.0; this._loopDurationSeconds = -1.0; this._isLoop = false; // trueから false へデフォルトを変更 this._isLoopFadeIn = true; // ループ時にフェードインが有効かどうかのフラグ this._lastWeight = 0.0; this._motionData = null; this._modelCurveIdEyeBlink = null; this._modelCurveIdLipSync = null; this._modelCurveIdOpacity = null; this._eyeBlinkParameterIds = null; this._lipSyncParameterIds = null; this._modelOpacity = 1.0; } /** * デストラクタ相当の処理 */ public release(): void { this._motionData = void 0; this._motionData = null; } /** * motion3.jsonをパースする。 * * @param motionJson motion3.jsonが読み込まれているバッファ * @param size バッファのサイズ */ public parse(motionJson: ArrayBuffer, size: number): void { this._motionData = new CubismMotionData(); let json: CubismMotionJson = new CubismMotionJson(motionJson, size); this._motionData.duration = json.getMotionDuration(); this._motionData.loop = json.isMotionLoop(); this._motionData.curveCount = json.getMotionCurveCount(); this._motionData.fps = json.getMotionFps(); this._motionData.eventCount = json.getEventCount(); const areBeziersRestructed: boolean = json.getEvaluationOptionFlag( EvaluationOptionFlag.EvaluationOptionFlag_AreBeziersRistricted ); if (json.isExistMotionFadeInTime()) { this._fadeInSeconds = json.getMotionFadeInTime() < 0.0 ? 1.0 : json.getMotionFadeInTime(); } else { this._fadeInSeconds = 1.0; } if (json.isExistMotionFadeOutTime()) { this._fadeOutSeconds = json.getMotionFadeOutTime() < 0.0 ? 1.0 : json.getMotionFadeOutTime(); } else { this._fadeOutSeconds = 1.0; } this._motionData.curves.updateSize( this._motionData.curveCount, CubismMotionCurve, true ); this._motionData.segments.updateSize( json.getMotionTotalSegmentCount(), CubismMotionSegment, true ); this._motionData.points.updateSize( json.getMotionTotalPointCount(), CubismMotionPoint, true ); this._motionData.events.updateSize( this._motionData.eventCount, CubismMotionEvent, true ); let totalPointCount = 0; let totalSegmentCount = 0; // Curves for ( let curveCount = 0; curveCount < this._motionData.curveCount; ++curveCount ) { if (json.getMotionCurveTarget(curveCount) == TargetNameModel) { this._motionData.curves.at(curveCount).type = CubismMotionCurveTarget.CubismMotionCurveTarget_Model; } else if (json.getMotionCurveTarget(curveCount) == TargetNameParameter) { this._motionData.curves.at(curveCount).type = CubismMotionCurveTarget.CubismMotionCurveTarget_Parameter; } else if ( json.getMotionCurveTarget(curveCount) == TargetNamePartOpacity ) { this._motionData.curves.at(curveCount).type = CubismMotionCurveTarget.CubismMotionCurveTarget_PartOpacity; } else { CubismLogWarning( 'Warning : Unable to get segment type from Curve! The number of "CurveCount" may be incorrect!' ); } this._motionData.curves.at(curveCount).id = json.getMotionCurveId(curveCount); this._motionData.curves.at(curveCount).baseSegmentIndex = totalSegmentCount; this._motionData.curves.at(curveCount).fadeInTime = json.isExistMotionCurveFadeInTime(curveCount) ? json.getMotionCurveFadeInTime(curveCount) : -1.0; this._motionData.curves.at(curveCount).fadeOutTime = json.isExistMotionCurveFadeOutTime(curveCount) ? json.getMotionCurveFadeOutTime(curveCount) : -1.0; // Segments for ( let segmentPosition = 0; segmentPosition < json.getMotionCurveSegmentCount(curveCount); ) { if (segmentPosition == 0) { this._motionData.segments.at(totalSegmentCount).basePointIndex = totalPointCount; this._motionData.points.at(totalPointCount).time = json.getMotionCurveSegment(curveCount, segmentPosition); this._motionData.points.at(totalPointCount).value = json.getMotionCurveSegment(curveCount, segmentPosition + 1); totalPointCount += 1; segmentPosition += 2; } else { this._motionData.segments.at(totalSegmentCount).basePointIndex = totalPointCount - 1; } const segment: number = json.getMotionCurveSegment( curveCount, segmentPosition ); switch (segment) { case CubismMotionSegmentType.CubismMotionSegmentType_Linear: { this._motionData.segments.at(totalSegmentCount).segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Linear; this._motionData.segments.at(totalSegmentCount).evaluate = linearEvaluate; this._motionData.points.at(totalPointCount).time = json.getMotionCurveSegment(curveCount, segmentPosition + 1); this._motionData.points.at(totalPointCount).value = json.getMotionCurveSegment(curveCount, segmentPosition + 2); totalPointCount += 1; segmentPosition += 3; break; } case CubismMotionSegmentType.CubismMotionSegmentType_Bezier: { this._motionData.segments.at(totalSegmentCount).segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Bezier; if (areBeziersRestructed || UseOldBeziersCurveMotion) { this._motionData.segments.at(totalSegmentCount).evaluate = bezierEvaluate; } else { this._motionData.segments.at(totalSegmentCount).evaluate = bezierEvaluateCardanoInterpretation; } this._motionData.points.at(totalPointCount).time = json.getMotionCurveSegment(curveCount, segmentPosition + 1); this._motionData.points.at(totalPointCount).value = json.getMotionCurveSegment(curveCount, segmentPosition + 2); this._motionData.points.at(totalPointCount + 1).time = json.getMotionCurveSegment(curveCount, segmentPosition + 3); this._motionData.points.at(totalPointCount + 1).value = json.getMotionCurveSegment(curveCount, segmentPosition + 4); this._motionData.points.at(totalPointCount + 2).time = json.getMotionCurveSegment(curveCount, segmentPosition + 5); this._motionData.points.at(totalPointCount + 2).value = json.getMotionCurveSegment(curveCount, segmentPosition + 6); totalPointCount += 3; segmentPosition += 7; break; } case CubismMotionSegmentType.CubismMotionSegmentType_Stepped: { this._motionData.segments.at(totalSegmentCount).segmentType = CubismMotionSegmentType.CubismMotionSegmentType_Stepped; this._motionData.segments.at(totalSegmentCount).evaluate = steppedEvaluate; this._motionData.points.at(totalPointCount).time = json.getMotionCurveSegment(curveCount, segmentPosition + 1); this._motionData.points.at(totalPointCount).value = json.getMotionCurveSegment(curveCount, segmentPosition + 2); totalPointCount += 1; segmentPosition += 3; break; } case CubismMotionSegmentType.CubismMotionSegmentType_InverseStepped: { this._motionData.segments.at(totalSegmentCount).segmentType = CubismMotionSegmentType.CubismMotionSegmentType_InverseStepped; this._motionData.segments.at(totalSegmentCount).evaluate = inverseSteppedEvaluate; this._motionData.points.at(totalPointCount).time = json.getMotionCurveSegment(curveCount, segmentPosition + 1); this._motionData.points.at(totalPointCount).value = json.getMotionCurveSegment(curveCount, segmentPosition + 2); totalPointCount += 1; segmentPosition += 3; break; } default: { CSM_ASSERT(0); break; } } ++this._motionData.curves.at(curveCount).segmentCount; ++totalSegmentCount; } } for ( let userdatacount = 0; userdatacount < json.getEventCount(); ++userdatacount ) { this._motionData.events.at(userdatacount).fireTime = json.getEventTime(userdatacount); this._motionData.events.at(userdatacount).value = json.getEventValue(userdatacount); } json.release(); json = void 0; json = null; } /** * モデルのパラメータ更新 * * イベント発火のチェック。 * 入力する時間は呼ばれるモーションタイミングを0とした秒数で行う。 * * @param beforeCheckTimeSeconds 前回のイベントチェック時間[秒] * @param motionTimeSeconds 今回の再生時間[秒] */ public getFiredEvent( beforeCheckTimeSeconds: number, motionTimeSeconds: number ): csmVector<csmString> { this._firedEventValues.updateSize(0); // イベントの発火チェック for (let u = 0; u < this._motionData.eventCount; ++u) { if ( this._motionData.events.at(u).fireTime > beforeCheckTimeSeconds && this._motionData.events.at(u).fireTime <= motionTimeSeconds ) { this._firedEventValues.pushBack( new csmString(this._motionData.events.at(u).value.s) ); } } return this._firedEventValues; } /** * 透明度のカーブが存在するかどうかを確認する * * @returns true -> キーが存在する * false -> キーが存在しない */ public isExistModelOpacity(): boolean { for (let i = 0; i < this._motionData.curveCount; i++) { const curve: CubismMotionCurve = this._motionData.curves.at(i); if (curve.type != CubismMotionCurveTarget.CubismMotionCurveTarget_Model) { continue; } if (curve.id.getString().s.localeCompare(IdNameOpacity) == 0) { return true; } } return false; } /** * 透明度のカーブのインデックスを返す * * @returns success:透明度のカーブのインデックス */ public getModelOpacityIndex(): number { if (this.isExistModelOpacity()) { for (let i = 0; i < this._motionData.curveCount; i++) { const curve: CubismMotionCurve = this._motionData.curves.at(i); if ( curve.type != CubismMotionCurveTarget.CubismMotionCurveTarget_Model ) { continue; } if (curve.id.getString().s.localeCompare(IdNameOpacity) == 0) { return i; } } } return -1; } /** * 透明度のIdを返す * * @param index モーションカーブのインデックス * @returns success:透明度のカーブのインデックス */ public getModelOpacityId(index: number): CubismIdHandle { if (index != -1) { const curve: CubismMotionCurve = this._motionData.curves.at(index); if (curve.type == CubismMotionCurveTarget.CubismMotionCurveTarget_Model) { if (curve.id.getString().s.localeCompare(IdNameOpacity) == 0) { return CubismFramework.getIdManager().getId(curve.id.getString().s); } } } return null; } /** * 現在時間の透明度の値を返す * * @returns success:モーションの当該時間におけるOpacityの値 */ public getModelOpacityValue(): number { return this._modelOpacity; } public _sourceFrameRate: number; // ロードしたファイルのFPS。記述が無ければデフォルト値15fpsとなる public _loopDurationSeconds: number; // mtnファイルで定義される一連のモーションの長さ public _isLoop: boolean; // ループするか? public _isLoopFadeIn: boolean; // ループ時にフェードインが有効かどうかのフラグ。初期値では有効。 public _lastWeight: number; // 最後に設定された重み public _motionData: CubismMotionData; // 実際のモーションデータ本体 public _eyeBlinkParameterIds: csmVector<CubismIdHandle>; // 自動まばたきを適用するパラメータIDハンドルのリスト。 モデル(モデルセッティング)とパラメータを対応付ける。 public _lipSyncParameterIds: csmVector<CubismIdHandle>; // リップシンクを適用するパラメータIDハンドルのリスト。 モデル(モデルセッティング)とパラメータを対応付ける。 public _modelCurveIdEyeBlink: CubismIdHandle; // モデルが持つ自動まばたき用パラメータIDのハンドル。 モデルとモーションを対応付ける。 public _modelCurveIdLipSync: CubismIdHandle; // モデルが持つリップシンク用パラメータIDのハンドル。 モデルとモーションを対応付ける。 public _modelCurveIdOpacity: CubismIdHandle; // モデルが持つ不透明度用パラメータIDのハンドル。 モデルとモーションを対応付ける。 public _modelOpacity: number; // モーションから取得した不透明度 } // Namespace definition for compatibility. import * as $ from './cubismmotion'; // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Live2DCubismFramework { export const CubismMotion = $.CubismMotion; export type CubismMotion = $.CubismMotion; }