UnityでLWFを使ってみた

  • 21
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

Unity上でLWFを再生するにあたって
実際にあれこれと試してみたことについて書いていきます。

環境

system version
Mac OS X 10.9
Unity 4.3.1
LWF 1.0.2
LWFS 20131119-1217
Adobe Flash CS6 12.0.2.529
TexturePacker 3.2.1

準備する

LWF

本体。これがないと始まらない。

ダウンロード

https://github.com/gree/lwf
ここから git clone もしくはZIPファイルで取得する。

ビルド

ソースコードのままでも問題ないけど
私は dll にしたものを使用しているのでビルドします。

$ cd lwf/csharp/unity/build
$ ls

Packager
Rakefile

$ rake
$ ls

Packager
Rakefile
lwf.dll
lwf.dll.mdb
lwf_editor.dll
lwf_editor.dll.mdb

Unityプロジェクトにセット

lwf.dll lwf_editor.dll lwf/csharp/unity/shaders をそれぞれ下記のように配置する。

Assets/
   Editor/
      lwf_editor.dll
   Plugins/
      lwf.dll
   Resources/
      shaders/*.shader

以前のバージョンでは
lwf.dll -> lwf_editor.dll の順番でimportしないとUnityがクラッシュしていたが
今は大丈夫そう。

ソースコードのまま使用する場合は下記にある unitypackage を利用するとインポートが楽。

lwf/csharp/unity/dist/lwf.unitypackage

LWFS

LWFへの変換と確認を簡単にしてくれるツール。

ダウンロード

http://code.google.com/p/lwfs/downloads/list
ここから環境にあったものを取得する

私はMacを使用しているので LWFS-osx-20131119-1217.zip を選択。

インストール

Applicationディレクトリに置くだけ。

$ unzip LWFS-osx-20131119-1217.zip
$ mv LWFS /Applications/

README に書かれていますが
OS X Marvericks を使用している場合は下記を実行する必要があるようです。

$ xattr -d -r com.apple.quarantine /Applications/LWFS

これをしないと壊れている的なメッセージが出ました。

起動

start.appをダブルクリック。もしくは下記コマンドを実行する。

open /Applications/LWFS/start.app

デスクトップに変換元と変換後の出力ディレクトリが作成される。

~/Desktop/LWFS_work         # 変換元ファイル置き場
~/Desktop/LWFS_work_output  # LWF変換後の出力先

また、起動と同時にLWF用のパブリッシュが可能な
Publish for LWFコマンドがFlashにインストールされる。

インストール先

~/Library/Application\ Support/Adobe/Flash\ CS6/ja_JP/Configuration/Commands/Publish\ for\ LWF.jsfl

アニメーションデータ作成

Flashムービー作成

下記点に気をつけながら作成する。

  • Flashのパブリッシュターゲットは Flash Player 7 にする

Publish for LWF が調整してくれるようです!

  • シェイプは使えないので画像ファイルにする

  • ムービークリップの回転はできるがムービークリップ内の画像を回転させるとLWF変換時にエラーとなる

    現在の swf2lwf.rb では改善されているようです!

  • ActionScriptは使用不可(stop,playなどの簡単なアクションは使用可能)

    • 但し mc.gotoAndStop() のようにムービークリップを指定した操作はできない

tellTarget() が使えるそうです!これで代替可能ですね。

tellTarget("mc") {
      gotoAndStop();
}
tellTarget("..") {
      gotoAndStop();
}
  • トゥイーンはクラシックトゥイーンのみ使用可能
  • マスクは使用できない
  • ビットマッププロパティの圧縮は「劣化なし」にする
    • 「劣化なし」でない場合 ERROR: Bitmap is as JPEG. Bitmap should be as 'Loss-less' となる

Publish for LWF が調整してくれるようです!

  • ムービークリップへの着色はできない。明度の設定は可能。
    • 詳細カラー設定の乗算値によって代用はできるかもしれない。但し、加算値は'0'としておくこと
      • 使用できるようにする方法はある

パブリッシュ

コマンド -> Publish for LWF

  • パブリッシュ前
 test/
 └─ test.fla
  • パブリッシュ後
 test/
 ├─ test.fla
 ├─ test.swf
 └─ test.bitmap/*.png

FlashをLWFに変換

LWFSを使用する場合

swfやbitmapが入ったディレクトリを ~/Desktop/LWFS_work に置くと
~/Desktop/LWFS_work_output/unity にLWFデータが出力される。

$ mv test ~/Desktop/LWFS_work
$ ls ~/Desktop/LWFS_work_output/unity

test

手動で行う場合

現バージョンでは ruby 1.9.3 以降が必要。
要求rubyバージョンは今後変わる可能性が高いので rbenv かなんかで
複数バージョン扱えるようにしておくと良いかも。

# LWFに変換
$ ruby lwf/tools/swf2lwf/swf2lwf.rb test.swf


# 不要なファイルを削除(情報としては有用)
$ cd test.lwfdata/
$ ls |grep -v -E "\.lwf|\.png" |xargs rm

# 拡張子変更
$ mv test.lwf test.bytes

# Publish時に作成された画像ファイルをもってくる
$ mv ../test.bitmap/*.png ./

LWFデータをUnityプロジェクトにインポートする

下記のように Resources の中に入れる。
管理しやすいように LwfData を用意したがResources直下でも可。

Assets/
   Resources/
      LwfData/
         test/

動かしてみる

Unity上で動かす

LWFObjectを継承したクラスを用意する。

LwfSampleObject.cs
using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class LwfSampleObject : LWFObject {
    void Start() {
        string dir = System.IO.Path.GetDirectoryName(lwfName);
        if (dir.Length > 0) {
            dir += "/";
        }
        if (Application.isEditor) {
            UseDrawMeshRenderer();
        }

        Load(lwfName, dir);
    }
}

空のGameObjectを作成し上記スクリプトを Add Component する。
Lwf Name パラメータにbytesファイル名 LwfData/test/test を拡張子なしでセット。

再生用のスクリプトを用意し、GameObjectに Add Component すると再生されます。

Play.cs
using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class Play : MonoBehaviour {
    public LwfSampleObject lwfObject;

    void Start() {
        lwfObject.GotoAndPlayMovie("_root", 1, true);
    }
}

Unity上での表示位置について

Flashのステージサイズを640x960とした場合、GameObjectのx,yはそれぞれ半分の-320,480とするとカメラの中心に表示される

Unity側からムービークリップを操作する

  • フレーム番号で指定
LwfSampleObject.cs
this.GotoAndPlayMovie("_root", 1, true);
  • ラベルで指定
LwfSampleObject.cs
this.GotoAndPlayMovie("_root", "label", true);

Flash側の組み方として
_root には1フレームにアニメーションの1シーンを置く形の方が扱いやすいので
下記のような呼び方をよく使用しています。

LwfSampleObject.cs
    public void PlayScene() {
        this.GotoAndPlayMovie("_root", "scene1", true);
        this.GotoAndPlayMovie("scene1", "part1", true);
    }

ムービークリップからUnityに通知する

アニメーションの特定の位置でUnity側に処理をさせたい場合
例えば指定の位置で音を鳴らす等
その場合、ムービークリップ内に fscommand() を入れることで通知できます。

// "event”は固定。第二引数にイベント通知名を入れる。
fscommand("event", "sendMessage");

Unity側でイベント通知を受けるには SetEventHandler() を使い
第一引数に受信したいイベント通知名を入れる。

LwfSampleObject.cs
    void Start() {
        // …
        Load(lwfName, dir);

        SetEventHandler("sendMessage", (movie, button) => {
            // ここにイベント通知された時に行いたい処理を書く
        });
        SetEventHandler("animationEndMessage", (movie, button) => {
            // 受信したいイベントが複数ある場合はその分定義する。
        });
    }

これらイベント通知機能とラベルによるフレーム移動があれば大抵のことは実現できると思います。

テクスチャ入れ替え

Unity側からLWFのテクスチャを入れ替えるために LwfSampleObject
ChangeTexture メソッドを追加する。

LwfSampleObject.cs
    public void ChangeTexture(Texture2D newTexture, string targetTextureName) {
        var cache = LWF.UnityRenderer.ResourceCache.SharedInstance().textureCache;
        if (cache != null) {
            if (cache.ContainsKey(targetTextureName)) {
                var cache_item = cache[targetTextureName];
                var tex_context = cache_item.Entity();
                tex_context.material.mainTexture = newTexture;
            }
        }
    }

使い方: sample.png を別のテクスチャに入れ替える場合

ChangeTexture(newTexture, "test/LwfData/test/sample");

第二引数: LWF名 + テクスチャファイルパス(拡張子なし)

テクスチャ入れ替え時の注意点

同じLWFを複数箇所で同時に再生している場合
テクスチャを入れ替えるとすべてのLWFのテクスチャが入れ替わります。
特定のLWFのテクスチャのみ入れ替えたい場合はFlash側で予めテクスチャを分けておいてあげる必要があります。

画像をTexturePackerでまとめる

1. パブリッシュ

コマンド -> Publish for LWF

2. テクスチャアトラス作成

TexturePacker で画像をまとめてjson形式で出力する。

コマンドラインでやる場合は下記

/Applications/TexturePacker.app/Contents/MacOS/TexturePacker --scale 0.93750 --format json --data test.json --sheet "texture.png" test/test.bitmap/*.png

scale については各自調整してください。

3. LWFデータ作成

jsonファイルを指定して変換処理を行う。

# LWFに変換
$ ruby lwf/tools/swf2lwf/swf2lwf.rb test.swf test.json

後の処理は以前と同じです。

複数テクスチャアトラスを使用する

1枚に収まりきらなかった場合は複数のjsonを指定することで可能。

# LWFに変換
$ ruby lwf/tools/swf2lwf/swf2lwf.rb test.swf test1.json test2.json

テクスチャアトラス使用時のテクスチャ入れ替え

テクスチャアトラスを使用すると以前のやり方でのテクスチャ入れ替えができないため
入れ替えを行うテクスチャだけアトラスとは別に個別で持たせました。

その場合特に何か処理をする必要はなく
jsonに含まれていないテクスチャは勝手に個別扱いにしてくれます。

入れ替え用テクスチャについて

そのまま使用はしないため何も描かれていない画像を使用。
さらに無駄を省くため下記もかけています。

pngquant --ext .png --force 256 ./*.png

加算合成が使いたい

アニメーションのクオリティを上げるためにやっぱり加算合成がしたい!
と言われたのでデフォルトでは使えない加算合成をできるようにしてみます。
とはいっても、LWFには元々加算合成の機能が組み込まれているのでそれを利用するだけですが!
(速度が遅くなるためデフォルトではオフになっているそうです。)

加算合成機能を有効にする

機能を有効にしたdllに作り直す。

$ cd lwf/csharp/unity/build
$ vim Rakefile
$ rake

Rakefileの変更箇所

Rakefile
 desc "build"
 task :build do
   puts "lwf.dll:"
-  system "#{MONO_BIN}/gmcs #{LIBS} #{MONO_OPTS} -out:lwf.dll #{SRCS.join(' ')}"
+  system "#{MONO_BIN}/gmcs #{LIBS} #{MONO_OPTS} -out:lwf.dll #{SRCS.join(' ')} -define:LWF_USE_ADDITIONALCOLOR"
   puts "lwf_editor.dll:"
-  system "#{MONO_BIN}/gmcs #{EDITOR_LIBS} #{MONO_OPTS} -out:lwf_editor.dll #{EDITOR_SRCS.join(' ')}"
+  system "#{MONO_BIN}/gmcs #{EDITOR_LIBS} #{MONO_OPTS} -out:lwf_editor.dll #{EDITOR_SRCS.join(' ')} -define:LWF_USE_ADDITIONALCOLOR"
 end

加算合成用にシェーダーを書き換える

既存のシェーダーでは加算値は反映されないので
LWFPreMultipliedAlpha.shader をいじります。

LWFPreMultipliedAlpha.shader
Shader "LWF/PreMultipliedAlpha" {
    Properties {
+       _AdditionalColor ("AdditionalColor", Color) = (0, 0, 0, 0)
        _Color ("Color", Color) = (1, 1, 1, 1)
        _MainTex ("Texture", 2D) = "white" {}
    }

    SubShader {
        Tags {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
        }
        Cull Off
        ZWrite Off
        Blend One OneMinusSrcAlpha
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            sampler2D _MainTex;
            uniform half4 _MainTex_ST;
            fixed4 _Color;
+           fixed4 _AdditionalColor;
            struct v2f {
                float4 pos: SV_POSITION;
                float2 uv: TEXCOORD0;
                fixed4 color: COLOR;
            };
            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.color = v.color * _Color;
                return o;
            }
            fixed4 frag(v2f i): COLOR0
            {
+               fixed4 color_result = tex2D(_MainTex, i.uv.xy) * i.color;
+               if (color_result[0] != 0) {
+                   color_result += _AdditionalColor;
+               }
+               return color_result;
-               return tex2D(_MainTex, i.uv.xy) * i.color;
            }
            ENDCG
        }
    }
}

おわりに

LWFは簡単にアニメーションを複数プラットフォームで動かすことができる良いツールだと思います。
ただ情報がまだまだ少なくて結構大変でした。
この記事が少しでもこれから使う方への参考になれば嬉しいです。

ちなみにどこかおかしい点等あればご指摘頂けると助かります!
色々試しながら使っていたので使い方が違うものもあるかもしれません。。

謝辞

@splhack さんにアドバイス頂きました。ありがとうございます!
https://gist.github.com/splhack/8006982