first
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
}}}
|
||||
Reference in New Issue
Block a user