モデルについて(Java)
最終更新: 2023年1月26日
モデル情報の編集について
モデル情報は基本的にCubism Editorのモデルワークスペースで作成されます。
パラメータに対する頂点などの動きは.moc3ファイルに記録されます。
その他の物理演算やアートメッシュにつけられるユーザデータなどは別のファイルとして出力され、モデルに関するすべてのファイルの参照を記録しておくものが.model3.jsonファイルになります。
これらは、.moc3ファイルの出力を行う際に同時に出力ができます。「組込み用データの書き出し」
また、Cubism Viewer(for OW)を使うことで、モーションや表情ファイル、ポーズファイルの組み込み設定を追加することができます。
Frameworkを使った.model3.jsonファイルからの読み込み
Frameworkを利用した読み込みでは、モデルに必要な情報を.model3.jsonファイルから抽出して、CubismUserModelクラスを継承したインスタンスを整備して利用することを想定しています。
// Java final String dir = "example/"; final String fileName = "example.model3.json"; final String jsonpath = dir + fileName; byte[] buffer = createBuffer(jsonpath); ICubismModelSetting setting = new CubismModelSettingJson(buffer);
ICubismModelSettingクラスに抽出した各要素はCubismUserModel.load~~系関数で読み込むことができます。
// Java // Cubism Model if (setting.getModelFileName() == ""){ String path = setting.getModelFileName(); path = dir + path; if (debugMode){ LAppPal.printLog("[APP]create model" + setting.getModelFileName()); } byte[] buffer = createBuffer(path); loadModel(buffer); }
.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をすべて破棄しておく必要があります。
// Java String path = "example.moc3"; path = dir + path; byte[] buffer = createBuffer(path); CubismMoc moc = CubismMoc.create(buffer); CubismModel model = moc.createModel();
グラフィック環境の関連付け
Frameworkはモデルのテクスチャ情報をグラフィックスAPIに依存させないためにCubismRendererクラスからの派生クラスを使っています。
モデルに関連するグラフィック関連の情報は全てCubismRendererクラスからの派生クラスが管理します。
SDK for Java R1 alpha1時点ではAndroidのみに対応しているため派生クラスが管理する必要性はありませんが、将来的なグラフィックスAPI追加の可能性、及び既存SDKとの仕様統一の面を考慮してこのような仕様にしています。
まず生成したいグラフィック環境の種類をRendererType列挙型で指定し、CubismUserModel.createRenderer関数の引数にして呼び出します。
(SDK for Java R1 alpha1においてはAndroidのみに対応しております。)
createRenderer関数内部では、引数に対応したグラフィックスAPIに対する派生クラスを生成し、CubismRenderer.initialize関数でCubismModelインスタンスを登録することでCubismRendererインスタンスとCubismModelインスタンスが紐づけされます。
// Java public void setupRenderer(CubismRenderer renderer, int maskBufferCount) { this.renderer = renderer; this.renderer.initialize(model, maskBufferCount); }
テクスチャの関連付け
Frameworkでモデルが持つテクスチャはCubismRendererクラスの派生クラスが管理します。
Android OpenGL ES 2.0の処理ではCubismRendererクラスの派生クラスであるCubismRendererAndroidクラス内のCubismRendererAndroid.bindTexture関数を使って登録しています。
一つ目の引数はモデルのテクスチャ番号、Editor上ではテクスチャアトラスの番号で確認できます。
二つ目の引数はテクスチャのOpenGL ES 2.0での管理番号です。
// Java // Android OpenGL ES 2.0のテクスチャユニットにテクスチャをロードする String texturePath = modelSetting.getTextureFileName(modelTextureNumber); texturepath = modelHomeDir + texturePath; LAppTextureManager.textureInfo texture = LAppDelegate.getInstance().getTextureManager().createTextureFromPngFile(texturePath); final int glTextureNumber = texture.id; this.<CubismRendererAndroid>getRenderer().bindTexture(modelTextureNumber, glTextureNumber);
表示位置と大きさの指定
これまでの設定を行えば、モデルを描画することはできますが、多くの場合表示位置や縮尺が違いすぎてそのままでは画面には表示されません。
CubismModel.getDrawableVertexPositions関数で返ってくる頂点範囲に関しては、「DrawableVertexPositionsの範囲」をご覧ください。
サイズを調整するためにCubismModelMatrixクラスとCubismModel.getCanvasWidth関数、CubismModel.getCanvasHeight関数を使います。
// Java // modelMatrixは、LAppModelクラス内にCubismModelMatrix型として定義 modelMatrix = CubismModelMatrix.create(model.getCanvasWidth(), model.getCanvasHeight());
この行列は描画前にProjectionマトリクスに乗算されてMVPマトリクスとしてレンダラーに渡されます。
// Java public void onUpdate() { int width = LAppDelegate.getInstance().getWindowWidth(); int height = LAppDelegate.getInstance().getWindowHeight(); ... CubismMatrix4x4 projectionMatrix = CubismMatrix4x4.create(); ... projectionMatrix.scale(1.0f, (float) height / (float) width); ... model.draw(projectionMatrix); }
// Java public void draw(CubismMatrix4x4 matrix) { ... matrix.multiplyByMatrix(modelMatrix); this.<CubismRendererAndroid>getRenderer().setMvpMatrix(matrix); ... }
頂点の更新
CubismModelインスタンスに対するパラメータ操作をアートメッシュの頂点に反映するためにCubismModel.update関数を実行します。
// Java) model.update()
描画
描画はCubismModelインスタンスからは実行せず、紐づけされているレンダラーに命令して行います。
// Java this.<CubismRendererAndroid>getRenderer.drawModel();
破棄
インスタンスの破棄では、全てのCubismModelを破棄してからCubismMocを破棄する必要があります。
この順番を守るため、CubismModelの破棄はCubismMoc.deleteModel関数で削除します。
この関数を経由しない場合はCubismMoc内部で確認しているモデルの数が一致しないため警告が出ます。
// Java protected void delete() { if (moc == null || model == null) { return; } moc.deleteModel(model); moc.delete(); model.close(); renderer.close(); moc = null; model = null; renderer = null; }
// Java public void delete() { assert (modelCount == 0); if (moc != null) { moc.close(); } moc = null; } public void deleteModel(CubismModel model) { model.close(); modelCount--; }
CubismModelクラスでモデルに存在しないパラメータIDを使う
CubismModelクラスのパラメータ、パーツ不透明度の操作では、.mocファイルに存在しないIDでも取り扱いを行う機能があります。
この機能はCubismMotionクラス、CubismPoseクラスなどが利用しており、利用して新たな機構を作成するときには既存の機能と衝突しないように使用するIDを注意してください。
また、Frameworkを読み解くときにも作成されたパラメータを使って他の機能と連携している可能性について留意してください。
※存在しない最大値、最小値、初期値へのアクセスはエラーが発生します
パラメータIDからパラメータIndexを生成する際に存在しないパラメータは新設される
// Java public int getParameterIndex(CubismId parameterId) { final CubismParameterView parameterView = model.findParameterView(parameterId.getString()); if (parameterView != null) { return parameterView.getIndex(); } // If the parameter does not exist in the model, it searches for it in the non-existent parameter ID list and returns its index. if (notExistParameterIds.containsKey(parameterId)) { final Integer index = notExistParameterIds.get(parameterId); assert index != null; return index; } // If the parameter does not exist in the non-existent parameter ID list, add newly the element. final int parameterCount = parameterValues.length; final int parameterIndex = parameterCount + notExistParameterIds.size(); notExistParameterIds.put(parameterId, parameterIndex); notExistParameterIndices.add(parameterIndex); float[] tmp = new float[notExistParameterIndices.size()]; System.arraycopy(notExistParameterValues, 0, tmp, 0, notExistParameterIndices.size() - 1); tmp[notExistParameterIndices.size() - 1] = 0.0f; notExistParameterValues = new float[notExistParameterIndices.size()]; System.arraycopy(tmp, 0, notExistParameterValues, 0, notExistParameterIndices.size()); return parameterIndex; }