モデルについて(Native)

最終更新: 2019年11月7日

モデル情報の編集について

モデル情報は基本的にModelerで作成されます。
パラメータに対する頂点などの動きは.moc3ファイルに記録されます。
その他の物理演算やアートメッシュにつけられるユーザデータなどは別のファイルとして出力され、
モデルに関するすべてのファイルの参照を記録しておくものが.model3.jsonファイルになります。

Modelerから.moc3ファイルの出力を行う際に同時に出力ができます。「組み込み用データの書き出し」
また、Cubism Viewer (for OW)を使うことで、モーションや表情ファイル、ポーズファイルの組み込み設定を追加することができます。

Frameworkを使った.model3.jsonファイルからの読み込み

Frameworkを利用した読み込みでは、モデルに必要な情報を.model3.jsonファイルから抽出して、
CubismUserModelクラスを継承したインスタンスを整備して利用することを想定しています。

// C++
const csmChar* dir = "example/";
const csmChar* fileName = "example.model3.json";
const csmString jsonpath = csmString(dir) + fileName;
csmSizeInt size;
csmByte* buffer = CreateBuffer(jsonpath.GetRawString(), &size);
ICubismModelSetting* setting = new CubismModelSettingJson(buffer, size);
DeleteBuffer(buffer, jsonpath.GetRawString());

ICubismModelSettingクラスに抽出した各要素はCubismUserModel::Load~~系関数で読み込むことができます。

// C++
    csmSizeInt size;
    //Cubism Model
    if (strcmp(setting->GetModelFileName(), "") != 0)
    {
        csmString path = setting->GetModelFileName();
        path = dir + path;

        if (_debugMode)LAppPal::PrintLog("[APP]create model: %s", setting->GetModelFileName());

        csmByte* buffer = CreateBuffer(path.GetRawString(), &size);
        LoadModel(buffer, size);
        DeleteBuffer(buffer, path.GetRawString());

    }

.model3.jsonファイルからの全体的なロードの流れはサンプル内のLAppModel::LoadAssets関数から
LAppModel::SetupModel関数、CubismUserModel::CreateRenderer関数、LAppModel::SetupTextures関数の流れを追っていくと把握しやすいです。


インスタンスの作成(.moc3ファイルの読み込み)

始めに.moc3ファイルをメモリ上に読み込みます。
読み込んだバッファとサイズをCubismMoc::Create関数に渡し、まずはCubismMocインスタンスを作成します。
次にCubismMoc::CreateModel関数を呼び出してCubismModelインスタンスを作成します。
このCubismModelインスタンスからパラメータの操作や描画のための情報取得などを行います。

CubismMoc::CreateModel関数ではCubismMoc内部で関数によって生成したModel数を数えており、
CubismMocを破棄するときにはすべての破棄するCubismMocから生成したCubismModelをすべて破棄しておく必要があります。

// C++
csmString path = "example.moc3";
path = dir + path;
csmSizeInt size;
csmByte* buffer = CreateBuffer(path.GetRawString(), &size);
CubismMoc* moc = CubismMoc::Create(buffer, size);
CubismModel* model = _moc->CreateModel();

グラフィック環境の関連付け

Frameworkはモデルのテクスチャ情報をグラフィックスAPIに依存させないためにCubismRendererクラスからの派生クラスを使っています。
モデルに関連するグラフィック関連の情報はすべてCubismRendererクラスからの派生クラスが管理します。
CubismRendererクラスからのグラフィックスAPIに対する派生クラスを生成し、
CubismRenderer::Initialize関数でCubismModelインスタンスを登録することでCubismRendererインスタンスとCubismModelインスタンスが紐づけされます。

// C++
Rendering::CubismRenderer* renderer = Rendering::CubismRenderer::Create();

renderer->Initialize(model);

テクスチャの関連付け

Frameworkでモデルが持つテクスチャはCubismRendererクラスの派生クラスが管理します。
しかしその機能はグラフィックスAPIへの依存を避けるため、CubismRendererクラスにそのメソッドの登録はされていません。
対象とするグラフィックスAPIによってメソッドの仕様の変化に注意してください。
OpenGLの処理ではCubismRendererクラスの派生CubismRenderer_OpenGLES2クラス内のCubismRenderer_OpenGLES2::BindTexture関数を使って登録しています。
一つ目の引数はモデルのテクスチャ番号、Editor上ではテクスチャアトラスの番号で確認できます。
二つ目の引数はテクスチャのOpenGLでの管理番号です。

下の例はCocos2d-xでのテクスチャの読み込みです。

// C++
//OpenGLのテクスチャユニットにテクスチャをロードする
csmInt32 modelTextureNumber = 0;
csmString texturePath = "example.2048/texture_00.png";
texturePath = dir + texturePath;

//cocos2d
Texture2D* texture = Director::getInstance()->getTextureCache()->addImage(std::string(texturePath.GetRawString()));
const csmInt32 glTextureNumber = texture->getName();
const Texture2D::TexParams texParams = { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE };
texture->setTexParameters(texParams);
texture->generateMipmap();

//OpenGL
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->BindTexture(modelTextureNumber, glTextureNumber);

Cocos2d-xによるTextureの管理をしない、OpenGL単体の場合はアプリケーション側の管理を通して登録します。

// C++
//OpenGLのテクスチャユニットにテクスチャをロードする
csmString texturePath = _modelSetting->GetTextureFileName(modelTextureNumber);
texturePath = _modelHomeDir + texturePath;

LAppTextureManager::TextureInfo* texture = LAppDelegate::GetInstance()->GetTextureManager()->CreateTextureFromPngFile(texturePath.GetRawString());
const csmInt32 glTextureNumber = texture->id;

//OpenGL
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->BindTexture(modelTextureNumber, glTextureNumber);

表示位置と大きさの指定

これまでの設定を行えば、モデルを描画することはできますが
多くの場合表示位置や縮尺が違いすぎてそのままでは画面には表示されません。
csmGetDrawableVertexPositions関数で返ってくる頂点範囲に関しては「DrawableVertexPositionsの範囲」をご覧ください。
サイズを調整するためにCubismModelMatrixクラスとCubismModel::GetCanvasWidth関数、CubismModel::GetCanvasHeight関数をつかいます。

// C++
CubismModelMatrix* modelMatrix = CSM_NEW CubismModelMatrix(_model->GetCanvasWidth(), _model->GetCanvasHeight());

この行列は描画前にProjectionマトリクスに乗算されてMVPマトリクスとしてレンダラーに渡されます。

// C++
CubismMatrix44 projectionMatrix;
projectionMatrix.Scale(1, window.width / window.height);
projectionMatrix.MultiplyByMatrix(modelMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->SetMvpMatrix(&projectionMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->DrawModel();

頂点の更新

CubismModelインスタンスに対するパラメータ操作をアートメッシュの頂点に反映するためにCubismModel::Update関数を実行します。

// C++
model->Update();

描画

描画はCubismModelインスタンスからは実行せず、紐づけされているレンダラーに命令しておこないます。

// C++
CubismMatrix44 projectionMatrix;
projectionMatrix.Scale(1, window.width / window.height);
projectionMatrix.MultiplyByMatrix(modelMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->SetMvpMatrix(&projectionMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->DrawModel();

破棄

インスタンスの破棄ではすべてのCubismlModelを破棄してからCubismMocを破棄する必要があります。
この順番をまもるため、CubismModelの破棄はCubismMoc::DeleteModelで削除します。
この関数を経由しない場合はCubismMoc内部で確認しているモデルの数が一致しないため警告がでます。

// C++
CubismUserModel::~CubismUserModel()
{
    CSM_DELETE(_motionManager);
    CSM_DELETE(_expressionManager);
    _moc->DeleteModel(_model); // <<<
    CubismMoc::Delete(_moc); // <<<
    CSM_DELETE(_modelMatrix);
    CubismPose::Delete(_pose);
    CubismEyeBlink::Delete(_eyeBlink);
    CubismBreath::Delete(_breath);
    CSM_DELETE(_dragManager);
    CubismPhysics::Delete(_physics);
    CubismModelUserData::Delete(_modelUserData);

    DeleteRenderer();
}
// C++
CubismMoc::~CubismMoc()
{
    CSM_ASSERT(_modelCount == 0);

    CSM_FREE_ALLIGNED(_moc);
}

void CubismMoc::DeleteModel(CubismModel* model)
{
    CSM_DELETE_SELF(CubismModel, model);
    --_modelCount;
}

CubismModelクラスでモデルに存在しないパラメータIDを使う

CubismModelクラスのパラメータ、パーツ不透明度の操作では、.moc3ファイルに存在しないIDでも取り扱いを行う機能があります。
この機能はCubismMotionクラス、CubismPoseクラスなどが利用しており、
利用して新たな機構を作成するときには既存の機能と衝突しないように使用するIDを注意してください。
また、Frameworkを読み解くときにも作成されたパラメータを使って他の機能と連携している可能性について留意してください。
※存在しない最大値、最小値、初期値へのアクセスはエラーが発生します

// C++
csmInt32 CubismModel::GetParameterIndex(CubismIdHandle parameterId)
{
    csmInt32            parameterIndex;
    const csmChar**     idArray = Core::csmGetParameterIds(_model);
    csmInt32            idCount = Core::csmGetParameterCount(_model);


    for (parameterIndex = 0; parameterIndex < idCount; ++parameterIndex)
    {
        if (parameterId != _parameterIds[parameterIndex])
        {
            continue;
        }

        return parameterIndex;
    }

    // モデルに存在していない場合、非存在パラメータIDリスト内を検索し、そのインデックスを返す
    if (_notExistParameterId.IsExist(parameterId))
    {
        return _notExistParameterId[parameterId];
    }

    // 非存在パラメータIDリストにない場合、新しく要素を追加する
    parameterIndex = Core::csmGetParameterCount(_model) + _notExistParameterId.GetSize();

    _notExistParameterId[parameterId] = parameterIndex;
    _notExistParameterValues.AppendKey(parameterIndex);

    return parameterIndex;
}
この記事に関するご意見・
ご要望をお聞かせください。