Help us understand the problem. What is going on with this article?

Cubism 4 SDK for Web でモデルを表示する

はじめに

Cusibm 4 SDK for Web を触る事になったのですが、まだあまり情報がなさそうなので、自分が手探りで使ってみて分かったことをまとめます。

今は、モデルを表示するだけのサンプルしかありませんが、徐々に増やしていく予定です。

モデルを表示するのに、最低限必要なファイル

表示するために最低限必要なファイルは以下の2種類
* .moc3
* .png(テクスチャ)
これらのパスはmodel3.jsonに記述されています。

モデルを一回だけ描画する(Sample_01

以下は、モデルを一回だけ描画する流れです。
ファイルのロード、WebGLコンテキストの初期化などは省略しています。

フレームワークの初期化

まず始めに、フレームワークを初期化します。

import { Live2DCubismFramework } from '../../../Framework/live2dcubismframework';
import CubismFramework = Live2DCubismFramework.CubismFramework;

CubismFramework.startUp();
CubismFramework.initialize();

model3.jsonから、CubismModelSettingJsonオブジェクトを作成

modelSetting には、model3.json に記述されている情報が入ります。

import { Live2DCubismFramework as icubismmodelsetting } from '../../../Framework/icubismmodelsetting';
import ICubismModelSetting = icubismmodelsetting.ICubismModelSetting;

import { Live2DCubismFramework as cubismmodelsettingjson } from '../../../Framework/cubismmodelsettingjson';
import CubismModelSettingJson = cubismmodelsettingjson.CubismModelSettingJson;


const modelSetting = new CubismModelSettingJson(model3JsonArrayBuffer, model3JsonArrayBuffer.byteLength) as ICubismModelSetting;

CubismModelSettingJson の getModelFileName 関数や getTextureFileName 関数を使って、必要なファイル名を取得できます。

const moc3FilePath = `${resourcesDir}${modelSetting.getModelFileName()}`;

CubismUserModelの作成

CubismUserModel クラスは派生させて使うようなので、ここでは AppCubismUserModel 派生クラスを作って、モデルオブジェクトを作成しています。

moc3ArrayBuffer、pose3ArrayBuffer には、.moc3、pose3.json を ArrayBuffer として読み込んだデータが入っています。
これらのデータをそれぞれ、loadModel 関数、loadPose 関数に渡してあげます。

pose3.jsonは必須というわけではないのですが、非表示のパーツが全部表示されてしまうので使ってます。

// CubismUserModelの派生クラス
import AppCubismUserModel from './class/AppCubismUserModel';

const model = new AppCubismUserModel();
// モデルデータをロード
model.loadModel(moc3ArrayBuffer);
// ポーズデータをロード
if (pose3ArrayBuffer !== null)
    model.loadPose(pose3ArrayBuffer, pose3ArrayBuffer.byteLength);

テクスチャをバインド

CubismUserModel のレンダラにテクスチャをバインドします。
バインドする前に、CubismUserModelのcreateRenderer 関数で、モデルオブジェクトにレンダラを作成しておきます。

textures には WebGLTexture オブジェクトが入っています。
gl は HTMLCanvasElement から作成した、WebGLRenderingContext オブジェクトです。

// レンダラの作成(bindTextureより先にやっておく)
model.createRenderer();
// テクスチャをレンダラに設定
textures.forEach((texture: WebGLTexture, index: number) => {
    model.getRenderer()
        .bindTexture(index, texture);
});

// そのほかレンダラの設定
model.getRenderer().setIsPremultipliedAlpha(false);
model.getRenderer().startUp(gl);

Live2Dモデルのサイズ調整

この辺は理解できていないです…。こうやったら調節できた、といった感じです。

キャンバスが長方形だとモデルがゆがむので調整します。

調整しない場合、1:1の枠に収まっているモデルが、1:(キャンバス高さ/キャンバス幅)に変形されるみたいなので、高さだけを(キャンバス幅/キャンバス高さ)倍して、モデルの比を戻すようなスケールを projectionMatrix に設定してみました。
公式のマニュアルもこんな感じですが、理解が正しいかどうかは微妙です…。
また、比を直すだけだと、モデルが小さかったので、適当に大きくしています。

最後に、モデルのレンダラに計算済みのマトリクスを設定しています。

const modelMatrix = model.getModelMatrix();
const projectionMatrix = new CubismMatrix44();
const scale = 2;

projectionMatrix.scale(1, canvas.width / canvas.height);

// モデルが良い感じの大きさになるように拡大・縮小
projectionMatrix.scaleRelative(scale, scale);

projectionMatrix.multiplyByMatrix(modelMatrix);
model.getRenderer().setMvpMatrix(projectionMatrix);

モデルの描画

ついにモデルの描画です。
まず、CubismUserModel の update 関数を呼んで、モデルの頂点情報を更新します。
パラメータの更新やMVPマトリクスの設定等をする場合は、この関数よりも前に行います。

最後に、モデルのレンダラの drawModel 関数を呼んであげると、モデルが表示されます。

// NOTE: フレームワークの更新に伴う変更
// フレームバッファを用意
const frameBuffer: WebGLFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);

// 省略

//  頂点の更新
model.update();

// NOTE: フレームワークの更新に伴う変更
// フレームバッファとビューポートを、フレームワーク設定
const viewport: number[] = [
    0, 
    0, 
    canvas.width,
    canvas.height
];
model.getRenderer().setRenderState(frameBuffer, viewport);

// モデルの描画
model.getRenderer().drawModel();

Samle_01.png

モデルのレスポンシブ対応(Sample_02

canvasをウィンドウいっぱいに広げて、サイズを変えるとそれに合わせてモデルもリサイズするようにします。
主な変更点や注意点は以下。

canvasの比に合わせてモデルの比も調整

まず、canvasのサイズが変わっても、width と height は更新されないので、width と height を clientWidth、clientHeight を元に更新します。
この時、スマートフォン用に、devicePixelRatio倍しておきます。これを忘れるとスマホでぼやけます。

canvas.width = canvas.clientWidth * devicePixelRatio;
canvas.height = canvas.clientHeight * devicePixelRatio;

requestAnimationFrame で更新

window.onresize でcanvasとモデルサイズが調整されたら、すぐに反映するため、
モデルの更新を requestAnimationFrame のループで行うようにします。

const loop = (time: number) => {

  // 頂点の更新
  model.update();

  viewport[2] = canvas.width;
  viewport[3] = canvas.height;
  model.getRenderer().setRenderState(frameBuffer, viewport);

  // モデルの描画
  model.getRenderer().drawModel();

  requestAnimationFrame(loop);

};
requestAnimationFrame(loop);

responsive.gif

モーション、物理演算、自動目ぱち対応(Sample_03

サンプルコード

SDKのバージョンアップとは無関係ですが、前回と構成を変えました。
主な変更点は以下です。

Cubism 4 SDK for Web をサブモジュールとして取り込む
このようにしておくと、SDKが更新された時は、チェックアウト先を変えるだけで対応できます。
この Sample_01 では、/l2dsdkフォルダにサブモジュールとして取り込んであります。

SDKからのインポートを一つのファイルにまとめて、必要なものをエクスポートする
SDK からのインポートをすべて/src/index.tsにまとめました。
他のファイルは/src/index.tsから必要なクラスなどをインポートする形になっています。
このようにすることで、仮にSDKの場所を変えることになっても、/src/index.tsだけ変更すれば対応できます。

また、Cubism 4 SDK for Web は他のフレームワークと合わせるため名前空間で切っているので、

import { Live2DCubismFramework as icubismmodelsetting } from '../l2dsdk/Framework/icubismmodelsetting';
import ICubismModelSetting = icubismmodelsetting.ICubismModelSetting;

という形で、少し長くなりがちですが、/src/index.tsにまとめておくと、他のファイルのインポート部分はシンプルになるかと思います。

ファイルのロードはPromise.allでまとめて行う
説明ではファイルを一つずつロードして、オブジェクトを作成していますが、
サンプルではまとめてダウンロードしてから各オブジェクトを作成しています。

GitHubにサンプルコードを上げておきました。
各サンプルごとのプロジェクトはタグで分けてあります。
Cubism4WebGL_Samples

参考

Cubism SDK Manual

最後に

使い方を探りつつ、サンプルコードを増やしていく予定です。
また、自分の理解と共に、この記事も修正していこうと思います。

tatsuteb
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした