CubismNativeFrameworkを直接利用する方法

最終更新: 2020年1月30日

Cubism SDK for Nativeに同梱されているサンプルプロジェクトは、CubismNativeFramework(SDKパッケージの /Framework/ 以下)を用いてCubismモデルを扱っています。
Cubismモデルを扱うプロジェクトを作成する場合はサンプルプロジェクトを基礎にご利用いただくのがよろしいかと思われますが、既存のアプリケーションやユーザ独自のエンジンなどに実装するときはCubismNativeFrameworkのAPIを直接扱いたい場合がございます。
しかし、同梱されているサンプルプロジェクトは高機能なため、そちらを参考にするだけでは構造の理解と切り分けが容易ではありません。

以下では、上記のようなユーザを対象として、CubismFrameworkを直接呼び出してモデルを扱う最小のスニペットを紹介します。

CubismFrameworkのサイクル

CubismFrameworkを扱うための手順は以下のとおりです。

  1. CubismFrameworkの初期化
  2. モデルファイルのパスを取得
  3. モデルの読み込み
  4. アップデート処理
  5. モデルの破棄
  6. CubismFrameworkの終了処理

CubismFrameworkの初期化

CubismFrameworkの初期化処理は以下のとおりです。

CubismFrameworkは、CubismFramework::StartUp()の第一引数に渡したアロケータを用いてメモリの確保を行います。
Cubism SDK for Nativeには、CubismNativeSamplesにアロケータのサンプルがございます。
CubismFrameworkで使用するアロケータはアライメントを指定して確保する実装も必要となっております。
そのため、基本的にはサンプルのものを利用していただくのが素早く組み込めるためよろしいかと思われますが、メモリの確保も独自なものにカスタマイズしたい場合はユーザ側で独自に実装したものに置き換えたり、サンプルを改造して組み込むことも可能です。

アロケータの具体的な実装につきましては こちら を、カスタムメモリアロケーターの作成上の注意に関しましては こちら をご覧ください。

    // ログ等のオプション設定。
    CubismFramework::Option _cubismOption;
    
    // アロケータ。
    LAppAllocator _cubismAllocator;
    
    // メッセージ出力関数。
    static void PrintMessage(const Csm::csmChar* message);
    // ログ出力のレベルを設定。LogLevel_Verboseの場合は詳細ログを出力させる。
    _cubismOption.LoggingLevel = CubismFramework::Option::LogLevel_Verbose;
    _cubismOption.LogFunction = PrintMessage;
    
    // CubismNativeFrameworkの初期化に必要なパラメータを設定する。
    CubismFramework::StartUp(&_cubismAllocator, &_cubismOption);
    
    // CubismFrameworkを初期化する。
    CubismFramework::Initialize();
Tips

CubismFramework::Initialize() を呼び出すのは初期化時に一度のみで、その後はCubismFrameworkが破棄されない限り、連続で呼び出してもスキップします。 ただし、一度CubismFrameworkを破棄した後であれば、再度初期化を行う場合には CubismFramework::Initialize() を呼び出します。

モデルファイルのパスを取得

Cubismの組み込み用データ一式は、model3.jsonにそれぞれの相対パスが記述されています。
.moc3ファイルやテクスチャなどを直接指定して読み込ませても構いませんが、基本的にはmodel3.jsonからパスを取得して読み込むことを推奨します。

model3.jsonのパースは、CubismFrameworkのCubismModelSettingJsonクラスを使用します。

    csmByte* CreateBuffer(const csmChar* path, csmSizeInt* size)
    {
        if (DebugLogEnable)
        {
            LAppPal::PrintLog("[APP]create buffer: %s ", path);
        }
        return LAppPal::LoadFileAsBytes(path, size);
    }

    void DeleteBuffer(csmByte* buffer, const csmChar* path = "")
    {
        if (DebugLogEnable)
        {
            LAppPal::PrintLog("[APP]delete buffer: %s", path);
        }
        LAppPal::ReleaseBytes(buffer);
    }
    // model3.jsonを読み込み。
    csmSizeInt size;
    const csmString modelSettingJsonPath = _modelHomeDir + modelSettingJsonName;
    csmByte* buffer = CreateBuffer(modelSettingJsonPath, &size);
    ICubismModelSetting* setting = new CubismModelSettingJson(buffer, size);
    DeleteBuffer(buffer, modelSettingJsonPath.GetRawString());
    
    // model3.jsonに記述されたモデルのパスを取得。
    csmString moc3Path = _modelSetting->GetModelFileName();
    moc3Path = _modelHomeDir + moc3Path;

モデルの読み込み

モデルの読み込みには、CubismModelのインターフェースによって行います。

CubismModelのインスタンスは、CubismNativeFrameworkではCubismUserModel::_modelが保持しております。
こちらを利用する場合、CubismUserModelを継承したクラスから扱うことを推奨しております。

また、テクスチャやモーション、表情モーション等のリソース管理は外部で行うことも可能です。

ここでは、例としてCubismUserModelを継承したCubismUserModelExtendを用いて説明いたします。

    // モデルのインスタンスを作成。
    CubismUserModelExtend* userModel = new CubismUserModelExtend();
	
    // moc3ファイル読み込み。
    buffer = CreateBuffer(moc3Path.GetRawString(), &size);
    userModel->LoadModel(mocBuffer, mocSize);
    DeleteBuffer(buffer, moc3Path.GetRawString());


読み込むmoc3ファイルのパスは上記の通りmodel3.jsonで取得できますが、同様にmodel3.jsonから表情、物理演算、ポーズ、まばたき、リップシンク、ユーザデータ、モーションのパスも取得できます。
SDKのサンプルではモデルの読み込みと同時にこれらの読み込みも行っております。
それぞれの読み込み方法につきましては以下を参考にしてください。

Tips

上記のスニペットは、画面にモデルを1体表示することを前提としたものです。 画面上に同時に複数体のモデルを表示する場合、表示するモデルと同数のCubismUserModelの派生クラスのインスタンスを生成します。

アップデート処理

Cubismモデルのアップデート処理は、モデルの初期化と同様にCubismModelのインターフェースであるCubismModel::Update()を呼び出すことで行います。
CubismModel::Update()を呼び出すとCubism Coreの更新処理が行われ、それまでに設定されたパラメータやパーツの値から頂点情報を更新します。

    void CubismUserModelExtend::Update()
    {
        // パラメータ操作。
        _model->SetParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), value);
        
        // パーツ不透明度操作。
        _model->SetPartOpacity(CubismFramework::GetIdManager()->GetId("PartArmL"), opacity);
        
        // モデルの頂点情報を更新
        _model->Update();
    }

アップデート処理では必ずUpdate()以前に、視線追従や物理演算、モーション再生などを行います。

CubismModel::Update()よりも後にパラメータの値を操作しても反映されません。
その後に再度CubismModel::Update()を呼べば反映されますが、この処理は負荷が高いため一つにまとめることを推奨します。

    // 頂点に反映される
    _model->SetParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), value);
    
    // モデルの頂点情報を更新
    _model->Update();
    
    // 頂点に反映されない
    _model->SetParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), value);


モーションを再生するCubismMotionManager::UpdateMotion()は、再生するモーションに使用されているIDのパラメータの値をすべて上書きします。
そのため、この処理以前にパラメータの値を操作してもすべてCubismMotionManager::UpdateMotion()によって上書きされてしまいます。
視線追従などの値操作や物理演算などは、先にモーションの再生処理を行い、その後に行うことを推奨します。

    // 再生中のモーションをモデルに反映
    _motionManager->UpdateMotion(_model, deltaTimeSeconds);
    
    // 視線追従などの値操作や物理演算処理
    
    // モデルの頂点情報を更新
    _model->Update();


また、再生するモーションにすべてのパラメータが使用されていない場合や、モーションの再生が停止しているなどの理由からパラメータの値を操作しない場合、前のフレームで行った値操作の結果が残ったままになります。
そのため、その後に行う相対的なパラメータの値操作の結果が意図しないものになる可能性があります。
これは、モーションをモデルに反映させる処理の前後にCubismModel::LoadParameter()、CubismModel::SaveParameter()を呼び出すことで、その後に行う相対的な値操作をリセットすることが可能です。

    // すべてのパラメータの値を保存時の状態に復元
    _model->LoadParameters();
    
    // 再生中のモーションをモデルに反映
    _motionManager->UpdateMotion(_model, deltaTimeSeconds);
    
    // すべてのパラメータの値を保存
    _model->SaveParameters();
    
    
    // 相対的な値操作処理
    
    
    // モデルの頂点情報を更新
    _model->Update();


視線追従や物理演算、モーションの再生などの処理自体についてはそれぞれのドキュメントを参照してください。

この更新後の頂点情報などをレンダラに渡すことで、Cubismモデルを画面に描画することができます。

モデルの破棄

モデルを破棄するには、生成したCubismUserModelの派生クラスのインスタンスを破棄します。
これにより、このモデルが保持しているモーションや表情、物理演算などの情報がCubismUserModelのデストラクタから破棄されます。

    // モデルデータの破棄
    delete userModel;

Cubism Frameworkの終了処理

CubismFrameworkが確保した共通部分のリソースを解放するには、CubismFramework::Dispose() を呼び出します。
CubismFramework::Dispose() は、 CubismFramework::Initialize() を呼ぶ前には呼び出さないでください。

また、CubismFramework::Dispose() を呼ぶ場合、あらかじめすべてのモデルを破棄しておく必要があります。
これは、モデルを破棄する処理がアロケータのDeallocate()を利用しているためです。

    // CubismFrameworkの破棄
    CubismFramework::Dispose();
Tips

CubismFrameworkで初期化したデータはstaticな領域に配置されており、モデルデータには依存していません。 そのため複数のモデル間で使い回すことができ、モデルの切り替えだけであればCubismFramework::Dispose()を呼び出す必要はありません。

この記事はお役に立ちましたか?
はいいいえ
この記事に関するご意見・
ご要望をお聞かせください。