axmol/extensions/Live2D/Framework/src/Math/CubismTargetPoint.cpp

134 lines
4.8 KiB
C++
Raw Normal View History

/**
* 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.
*/
#include "CubismTargetPoint.hpp"
#include "Math/CubismMath.hpp"
namespace Live2D { namespace Cubism { namespace Framework {
const csmInt32 FrameRate = 30;
const csmFloat32 Epsilon = 0.01f;
CubismTargetPoint::CubismTargetPoint()
: _faceTargetX(0.0f)
, _faceTargetY(0.0f)
, _faceX(0.0f)
, _faceY(0.0f)
, _faceVX(0.0f)
, _faceVY(0.0f)
, _lastTimeSeconds(0.0f)
, _userTimeSeconds(0.0f)
{ }
CubismTargetPoint::~CubismTargetPoint()
{ }
void CubismTargetPoint::Update(csmFloat32 deltaTimeSeconds)
{
// デルタ時間を加算する
_userTimeSeconds += deltaTimeSeconds;
// 首を中央から左右に振るときの平均的な早さは 秒程度。加速・減速を考慮して、その2倍を最高速度とする
// 顔のふり具合を、中央(0.0)から、左右は(+-1.0)とする
const csmFloat32 FaceParamMaxV = 40.0 / 10.0f; // 7.5秒間に40分移動5.3/sc)
const csmFloat32 MaxV = FaceParamMaxV * 1.0f / static_cast<csmFloat32>(FrameRate); // 1frameあたりに変化できる速度の上限
if (_lastTimeSeconds == 0.0f)
{
_lastTimeSeconds = _userTimeSeconds;
return;
}
const csmFloat32 deltaTimeWeight = (_userTimeSeconds - _lastTimeSeconds) * static_cast<csmFloat32>(FrameRate);
_lastTimeSeconds = _userTimeSeconds;
// 最高速度になるまでの時間を
const csmFloat32 TimeToMaxSpeed = 0.15f;
const csmFloat32 FrameToMaxSpeed = TimeToMaxSpeed * static_cast<csmFloat32>(FrameRate); // sec * frame/sec
const csmFloat32 MaxA = deltaTimeWeight * MaxV / FrameToMaxSpeed; // 1frameあたりの加速度
// 目指す向きは、(dx, dy)方向のベクトルとなる
const csmFloat32 dx = _faceTargetX - _faceX;
const csmFloat32 dy = _faceTargetY - _faceY;
if (CubismMath::AbsF(dx) <= Epsilon && CubismMath::AbsF(dy) <= Epsilon)
{
return; // 変化なし
}
// 速度の最大よりも大きい場合は、速度を落とす
const csmFloat32 d = CubismMath::SqrtF((dx * dx) + (dy * dy));
// 進行方向の最大速度ベクトル
const csmFloat32 vx = MaxV * dx / d;
const csmFloat32 vy = MaxV * dy / d;
// 現在の速度から、新規速度への変化(加速度)を求める
csmFloat32 ax = vx - _faceVX;
csmFloat32 ay = vy - _faceVY;
const csmFloat32 a = CubismMath::SqrtF((ax * ax) + (ay * ay));
// 加速のとき
if (a < -MaxA || a > MaxA)
{
ax *= MaxA / a;
ay *= MaxA / a;
}
// 加速度を元の速度に足して、新速度とする
_faceVX += ax;
_faceVY += ay;
// 目的の方向に近づいたとき、滑らかに減速するための処理
// 設定された加速度で止まることのできる距離と速度の関係から
// 現在とりうる最高速度を計算し、それ以上のときは速度を落とす
// ※本来、人間は筋力で力(加速度)を調整できるため、より自由度が高いが、簡単な処理ですませている
{
// 加速度、速度、距離の関係式。
// 2 6 2 3
// sqrt(a t + 16 a h t - 8 a h) - a t
// v = --------------------------------------
// 2
// 4 t - 2
// (t=1)
// 時刻tは、あらかじめ加速度、速度を1/60(フレームレート、単位なし)で
// 考えているので、tとして消してよい※未検証
const csmFloat32 maxV = 0.5f * (CubismMath::SqrtF((MaxA * MaxA) + 16.0f * MaxA * d - 8.0f * MaxA * d) - MaxA);
const csmFloat32 curV = CubismMath::SqrtF((_faceVX * _faceVX) + (_faceVY * _faceVY));
if (curV > maxV)
{
// 現在の速度 > 最高速度のとき、最高速度まで減速
_faceVX *= maxV / curV;
_faceVY *= maxV / curV;
}
}
_faceX += _faceVX;
_faceY += _faceVY;
}
void CubismTargetPoint::Set(csmFloat32 x, csmFloat32 y)
{
this->_faceTargetX = x;
this->_faceTargetY = y;
}
csmFloat32 CubismTargetPoint::GetX() const
{
return this->_faceX;
}
csmFloat32 CubismTargetPoint::GetY() const
{
return this->_faceY;
}
}}}