Files
Yosuga/3rdparty/Live2D/Src/Framework/src/Effect/CubismPose.cpp
T
Misaki bb600bbbc4 first
2025-12-04 19:11:29 +08:00

331 lines
9.1 KiB
C++

/**
* 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 "CubismPose.hpp"
#include "Id/CubismIdManager.hpp"
using namespace Live2D::Cubism::Framework;
namespace Live2D { namespace Cubism { namespace Framework {
namespace {
const csmFloat32 Epsilon= 0.001f;
const csmFloat32 DefaultFadeInSeconds = 0.5f;
// Pose.jsonのタグ
const csmChar* FadeIn = "FadeInTime";
const csmChar* Link = "Link";
const csmChar* Groups = "Groups";
const csmChar* Id = "Id";
}
CubismPose::PartData::PartData()
{ }
CubismPose::PartData::~PartData()
{ }
CubismPose::PartData::PartData(const PartData& v)
: ParameterIndex(0)
, PartIndex(0)
{
PartId = v.PartId;
for (csmVector<PartData>::const_iterator ite = v.Link.Begin(); ite != v.Link.End(); ++ite)
{
Link.PushBack(*ite);
}
}
CubismPose::PartData& CubismPose::PartData::operator=(const PartData& v)
{
PartId = v.PartId;
for (csmVector<PartData>::const_iterator ite = v.Link.Begin(); ite != v.Link.End(); ++ite)
{
Link.PushBack(*ite);
}
return (*this);
}
void CubismPose::PartData::Initialize(CubismModel* model)
{
ParameterIndex = model->GetParameterIndex(PartId);
PartIndex = model->GetPartIndex(PartId);
model->SetParameterValue(ParameterIndex, 1);
}
CubismPose::CubismPose() : _fadeTimeSeconds(DefaultFadeInSeconds)
, _lastModel(NULL)
{ }
CubismPose::~CubismPose()
{ }
CubismPose* CubismPose::Create(const csmByte* pose3json, csmSizeInt size)
{
Utils::CubismJson* json = Utils::CubismJson::Create(pose3json, size);
if (!json)
{
return NULL;
}
CubismPose* ret = CSM_NEW CubismPose();
Utils::Value& root = json->GetRoot();
// フェード時間の指定
if (!root[FadeIn].IsNull())
{
ret->_fadeTimeSeconds = root[FadeIn].ToFloat(DefaultFadeInSeconds);
if (ret->_fadeTimeSeconds < 0.0f)
{
ret->_fadeTimeSeconds = DefaultFadeInSeconds;
}
}
// パーツグループ
Utils::Value& poseListInfo = root[Groups];
const csmInt32 poseCount = poseListInfo.GetSize();
for (csmInt32 poseIndex = 0; poseIndex < poseCount; ++poseIndex)
{
Utils::Value& idListInfo = poseListInfo[poseIndex];
const csmInt32 idCount = idListInfo.GetSize();
csmInt32 groupCount = 0;
for (csmInt32 groupIndex = 0; groupIndex < idCount; ++groupIndex)
{
Utils::Value& partInfo = idListInfo[groupIndex];
PartData partData;
const CubismIdHandle parameterId = CubismFramework::GetIdManager()->GetId(partInfo[Id].GetRawString());
partData.PartId = parameterId;
// リンクするパーツの設定
if (!partInfo[Link].IsNull())
{
Utils::Value& linkListInfo = partInfo[Link];
const csmInt32 linkCount = linkListInfo.GetSize();
for (csmInt32 linkIndex = 0; linkIndex < linkCount; ++linkIndex)
{
PartData linkPart;
const CubismIdHandle linkId = CubismFramework::GetIdManager()->GetId(linkListInfo[linkIndex].GetString());
linkPart.PartId = linkId;
partData.Link.PushBack(linkPart);
}
}
ret->_partGroups.PushBack(partData);
++groupCount;
}
ret->_partGroupCounts.PushBack(groupCount);
}
Utils::CubismJson::Delete(json);
return ret;
}
void CubismPose::Delete(CubismPose* pose)
{
CSM_DELETE_SELF(CubismPose, pose);
}
void CubismPose::Reset(CubismModel* model)
{
csmInt32 beginIndex = 0;
for (csmUint32 i = 0; i < _partGroupCounts.GetSize(); ++i)
{
const csmInt32 groupCount = _partGroupCounts[i];
for (csmInt32 j = beginIndex; j < beginIndex + groupCount; ++j)
{
_partGroups[j].Initialize(model);
const csmInt32 partsIndex = _partGroups[j].PartIndex;
const csmInt32 paramIndex = _partGroups[j].ParameterIndex;
if (partsIndex < 0)
{
continue;
}
model->SetPartOpacity( partsIndex, (j == beginIndex ? 1.0f : 0.0f));
model->SetParameterValue( paramIndex, (j == beginIndex ? 1.0f : 0.0f));
for (csmUint32 k = 0; k < _partGroups[j].Link.GetSize(); ++k)
{
_partGroups[j].Link[k].Initialize(model);
}
}
beginIndex += groupCount;
}
}
void CubismPose::CopyPartOpacities(CubismModel* model)
{
for (csmUint32 groupIndex = 0; groupIndex < _partGroups.GetSize(); ++groupIndex)
{
PartData& partData = _partGroups[groupIndex];
if (partData.Link.GetSize() == 0)
{
continue; // 連動するパラメータはない
}
const csmInt32 partIndex = _partGroups[groupIndex].PartIndex;
const csmFloat32 opacity = model->GetPartOpacity(partIndex);
for (csmUint32 linkIndex = 0; linkIndex < partData.Link.GetSize(); ++linkIndex)
{
PartData& linkPart = partData.Link[linkIndex];
const csmInt32 linkPartIndex = linkPart.PartIndex;
if (linkPartIndex < 0)
{
continue;
}
model->SetPartOpacity(linkPartIndex, opacity);
}
}
}
void CubismPose::DoFade(CubismModel* model, csmFloat32 deltaTimeSeconds, csmInt32 beginIndex, csmInt32 partGroupCount)
{
csmInt32 visiblePartIndex = -1;
csmFloat32 newOpacity = 1.0f;
const csmFloat32 Phi = 0.5f;
const csmFloat32 BackOpacityThreshold = 0.15f;
// 現在、表示状態になっているパーツを取得
for (csmInt32 i = beginIndex; i < beginIndex + partGroupCount; ++i)
{
const csmInt32 partIndex = _partGroups[i].PartIndex;
const csmInt32 paramIndex = _partGroups[i].ParameterIndex;
if (model->GetParameterValue(paramIndex) > Epsilon)
{
if (visiblePartIndex >= 0)
{
break;
}
visiblePartIndex = i;
if (_fadeTimeSeconds == 0.0f)
{
newOpacity = 1.0f;
continue;
}
newOpacity = model->GetPartOpacity(partIndex);
// 新しい不透明度を計算
newOpacity += (deltaTimeSeconds / _fadeTimeSeconds);
if (newOpacity > 1.0f)
{
newOpacity = 1.0f;
}
}
}
if (visiblePartIndex < 0)
{
visiblePartIndex = 0;
newOpacity = 1.0f;
}
// 表示パーツ、非表示パーツの不透明度を設定する
for (csmInt32 i = beginIndex; i < beginIndex + partGroupCount; ++i)
{
const csmInt32 partsIndex = _partGroups[i].PartIndex;
// 表示パーツの設定
if (visiblePartIndex == i)
{
model->SetPartOpacity(partsIndex, newOpacity); // 先に設定
}
// 非表示パーツの設定
else
{
csmFloat32 opacity = model->GetPartOpacity(partsIndex);
csmFloat32 a1; // 計算によって求められる不透明度
if (newOpacity < Phi)
{
a1 = newOpacity * (Phi - 1) / Phi + 1.0f; // (0,1),(phi,phi)を通る直線式
}
else
{
a1 = (1 - newOpacity) * Phi / (1.0f - Phi); // (1,0),(phi,phi)を通る直線式
}
// 背景の見える割合を制限する場合
const csmFloat32 backOpacity = (1.0f - a1) * (1.0f - newOpacity);
if (backOpacity > BackOpacityThreshold)
{
a1 = 1.0f - BackOpacityThreshold / (1.0f - newOpacity);
}
if (opacity > a1)
{
opacity = a1; // 計算の不透明度よりも大きければ(濃ければ)不透明度を上げる
}
model->SetPartOpacity(partsIndex, opacity);
}
}
}
void CubismPose::UpdateParameters(CubismModel* model, csmFloat32 deltaTimeSeconds)
{
// 前回のモデルと同じではないときは初期化が必要
if (model != _lastModel)
{
// パラメータインデックスの初期化
Reset(model);
}
_lastModel = model;
// 設定から時間を変更すると、経過時間がマイナスになることがあるので、経過時間0として対応。
if (deltaTimeSeconds < 0.0f)
{
deltaTimeSeconds = 0.0f;
}
csmInt32 beginIndex = 0;
for (csmUint32 i = 0; i < _partGroupCounts.GetSize(); i++)
{
const csmInt32 partGroupCount = _partGroupCounts[i];
DoFade(model, deltaTimeSeconds, beginIndex, partGroupCount);
beginIndex += partGroupCount;
}
CopyPartOpacities(model);
}
}}}