みんからきりまで

きりみんです。

Live2Dに入門してAndroidで動かしたりして遊んだ

Live2Dという技術があります。 http://www.live2d.com/

二次元のイラストを3D化せずにそのまま動かせるという夢の技術。
最近だとFaceRigと組み合わせたこんなのが話題になったりした。

www.4gamer.net

3年くらい前にYoutubeで紹介動画を見た時からずっと応援している技術なんだけど、このLive2Dでキャラを動かすのを自分でも試してみた。

Cubism EditorでLive2Dモデルを作ってみる

Cubism Editor | Live2D

どうやらこのCubism EditorというソフトウェアでLive2Dモデルが作成出来るようなので、インストールした。
とりあえず公式のチュートリアルページを見ながら見よう見まねでやってみる。

入門チュートリアル - Live2D Cubism 2 マニュアル

元の絵はこんな感じです。

Live2Dの仕組みをざっくり説明すると、イラストのパーツ(目とか髪とか)を福笑いのように別テクスチャとして配置して、それをずらしたり歪ませたりする動きを設定する…という感じ。
なので、まずはパーツの切り出しを行う必要があります。
行いました。

実際には作り始めて見ないとどんな風に切り分ければいいのかよく分からなかったので5回くらい作業やり直してる。
(フリーモードだとパーツのサイズとかに色々制限があったりもする)

切り出したパーツをテクスチャとして取り込み、頑張って歪ませたりして動きのパターンを設定していく。

Cubism Animatorでアニメーションを作ってみる

上で作成したモデルを付属のCubism Animatorというソフトウェアに読み込ませると、モデルを動かしたアニメーションが作成出来る。

こんな感じ。
動画のコマごとにモデルのパラメータを設定するだけで簡単にアニメーションが作れます。

そして実際に完成したアニメーションGifがこちらになります。

アニメーションや3Dの知識が全くなくても半日くらいでなんかそれっぽい動く絵が出来たぞ!
やったね!

Androidで動かしてみる

と、アニメーションGifを作っただけで終わってしまったらAndroidエンジニアとしては面白くないので、Androidアプリとして動かしてみる。

AndroidSDKがあったのでこれを使おう。

Android - Live2D Cubism 2 マニュアル

なんかサンプルがEclipseプロジェクトだったり、説明の殆どがEclipseの使い方でAPIの使い方についての説明が全然なかったりして不安になるが…。
とりあえずモデルが表示されるだけだったサンプルコードをちょっと書き換えてタッチイベントに反応するようにしてみた。

public class Live2dSurfaceView extends GLSurfaceView {
    private SampleGLRenderer renderer;

    public Live2dSurfaceView(Context context) {
        super(context);

        renderer = new SampleGLRenderer();
        setRenderer(renderer);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        renderer.updateAngle(event.getX());
        return true;
    }

    class SampleGLRenderer implements Renderer {
        private Live2DModelAndroid live2DModel;
        private final String MODEL_PATH = "live2d/model.moc";
        private final String TEXTURE_PATHS[] = {"live2d/model.2048/texture_00.png"};

        @Override
        public void onDrawFrame(GL10 gl) {
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
            gl.glEnable(GL10.GL_BLEND);
            gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
            gl.glDisable(GL10.GL_DEPTH_TEST);
            gl.glDisable(GL10.GL_CULL_FACE);

            live2DModel.setGL(gl);
            live2DModel.update();
            live2DModel.draw();
        }


        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);

            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();

            float modelWidth = live2DModel.getCanvasWidth();
            float visibleWidth = modelWidth * (3.0f / 4.0f);
            float margin = 0.5f * (modelWidth / 4.0f);

            gl.glOrthof(margin, margin + visibleWidth, visibleWidth * height / width, 0, 0.5f, -0.5f);
        }


        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            try {
                InputStream in = getContext().getAssets().open(MODEL_PATH);
                live2DModel = Live2DModelAndroid.loadModel(in);
                in.close();

                for (int i = 0; i < TEXTURE_PATHS.length; i++) {
                    InputStream tin = getContext().getAssets().open(TEXTURE_PATHS[i]);
                    int texNo = UtOpenGL.loadTexture(gl, tin, true);
                    live2DModel.setTexture(i, texNo);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void updateAngle(float param){
            Log.d("test", param / 30 + "");
            live2DModel.setParamFloat("PARAM_ANGLE_Z", param / 30);
        }
    }
}

こんな感じ

一応なんとなく動かせたけど、多分ほとんどの人はUnity用SDKを使ってるんだろうなぁ。

おまけ

決まった動きするキャラを表示させたいだけだったら、↓のライブラリとかでgifをそのまま画像として表示させた方が楽な気がした。

https://github.com/koral--/android-gif-drawable

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="me.kirimin.live2dsample.MainActivity">

    <pl.droidsonroids.gif.GifImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/girl"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Live2Dだよ!!!!!!!"
        android:minLines="4"
        android:background="#CCCCCCCC"
        android:padding="8dp"
        android:layout_alignBottom="@+id/image"/>
</RelativeLayout>

こんな感じで。