Unityで2Dボーンアニメーション

 Unityで2Dのボーンアニメーション(スキンメッシュアニメーション)を試してみた。

標準の"Animation"でも一応アニメーションは可能だが、多関節を動かすのはかなり気合が必要なので、以下のようなツールを使う方が現実的みたい。
  ・SmoothMoves:$75
  ・EasyMotion2D:$55
  ・OPTPiX SpriteStudio:99,750円

SpriteStudioは独立したWindowsアプリで、日本語化されているし実績もあり使い勝手が良さそう。cocos2dなどにも使える。ただ、アトラス化の機能が無い(既存のアトラス画像を読み込んで手作業でパーツ分けする必要がある)ことと、とても高価なことがネックだ。
それに比べてSmoothMovesとEasyMotion2DはどちらもUnityのAssetStoreで購入できて、比較的安価。このうち評価が良かったSmoothMovesを使うことにした。

大まかな手順は、
  1.パーツ画像をまとめたアトラス画像を作成
  2.アニメーションを作成
  3.シーンへ配置
という流れ。

まずはアトラス作成。
メニュー"SmoothMoves"→"Create Asset"→"Texture Atlas Data"で、Projectウインドウ内にアトラスデータを作成する。そのデータを選択してInspectorに表示されている"Open Atlas Editor"をクリックすると、エディタが起動する。そこに事前にUnityに取り込んで置いたpngなどのパーツ画像をまとめてドロップ。それぞれのパーツの関節の位置を指定する。

"Rebuild Atlas"をクリックするとアトラスのテクスチャとマテリアルが作成される。画像が汚くなる場合は、テクスチャのFormatを"Compressed"から変更すると良い。


次にアニメーション作成。
メニュー"SmoothMoves"→"Create Asset"→"Bone Animation Data"で、Projectウインドウ内にアニメーションデータを作成する。そのデータを選択してInspectorに表示されている"Open Animation Editor"をクリックすると、エディタが起動する。同時に開かれるWelcomeウインドウはすぐ閉じていい。

最初は何をやるのか全く分からないけど、慣れると簡単。
まず左下のボーンヒエラルキーでボーンの空データを作成する。次に右下のAnimation Clipsで新規クリップを作成する。ここで初めてタイムラインが表示され、0フレーム目に空のキーフレームが作成される。
このキーフレームをクリックすると上にボーンの情報が表示される。まだテクスチャと紐付けされていない。左上で、Typeを"Transform Only"から"Image"に変更して、Atlasに先ほど作成したアトラスを指定すると、すぐ右側にテクスチャリストが表示されるので選択する。そして右側で大きさ、位置、回転、前後関係(Depth)などを調整する。この作業をボーン数分行う。

ここからアニメーション付け作業。今回は、0フレーム:棒立ち、10フレーム:バンザイ、20フレーム:棒立ち、というシンプルなアニメーションを作る。
0フレームは既に出来ているので、10フレーム目の縦一列を選択して、右クリックで表示される"Duplicate First Keyframes"を実行。すると0フレームがコピーされるので、各ボーンの位置や回転などを操作して動きを付ける。20フレームにも0フレームをコピーする。

Animation Clipsの"Once"を"Loop"に変更して、画面上の三角の再生ボタンで動きを確認する。問題なければ画面を閉じて終了。

最後にシーンへの配置。
サンプルアプリを見ると凄く複雑な構成で悩むけど、実はすごく簡単。
メニュー"SmoothMoves"→"Create GameObject"→"Bone Animation"でHierarchyウインドウ内にアニメーションを配置する。InspectorのAnimation Dataに先ほど作成したアニメーションをドロップする。そして"Open Control Panel"を押して一回SmoothMovesのコントロールパネルを開いてすぐ閉じる。なんかこれをやっておかないと駄目みたい。

この状態ではまだ空のGameObjectだけど、最初の実行時に自動的に何かの処理が走って配下に色々なオブジェクトやコンポーネントが作成される。これで完了。アニメーションが大きすぎる場合は、スケールを変えるかカメラの位置やサイズを調整する。

ちなみにこのGameObjectは標準のAnimationコンポーネントを持っているので、以下のようなコードで任意のタイミングで再生したりアニメーションを変更できる。
    gameObject.animation.Play("Walk");

動作するWebサンプルはこちら

問題点。
全て同じマテリアルなのに何故かDrawCallがキャラクタ数分になっている。どうやらスキンメッシュはDynamicバッチが効かないらしい。1つのアニメーションで複数のアトラスを使用する場合はさらに増大することになるので、注意が必要だ。


Unity4のアップグレード

 4へのアップグレード料金が期間限定で20%オフってことで早速チェック。
確かに安くなっている。新規ライセンスが10万以上なので、もう麻痺してしまって5万が安く感じる。3.5で様子見ようと思っていたけど・・。


Unityがメジャーバージョンアップ

 Unity4が発表された。

まさか3.5の後にいきなり4とは。。モバイルでのシャドウは魅力的だけど、3.Xとは別のライセンスがいるみたいだしな。。

Unityで作ったAndroidプログラムを実機で動かす

 ◆手順その1・・・ Android端末を用意する
    この時まで寝かせておいたsim無しIS04とケーブルを引っ張り出した。
    調べるとどうも伝説的な機種だったようだ。(悪い意味で)

◆手順その2・・・AndroidSDKをインストール
    インストール後、いくつかpackageを入れてtoolsにパスを通した。

◆手順その3・・・UnityのAndroidライセンスを購入
    Basicが34,000円、Proが127,500円。相変わらず購入方法が分かりづらい。

◆手順その4・・・Unityでビルド
    Androidライセンスのシリアルを設定すると、Android用にビルドできる。
    とりあえず細かい設定は無しでビルド。xxx.apkというファイルが出来た。

◆手順その5・・・USBケーブルで接続して実機にインストール
    ターミナルでコマンドを実行。
    XXX--MacBook-Pro:Desktop xxxx$ adb install -r xxx.apk 
    2129 KB/s (9530962 bytes in 4.370s)
     pkg: /data/local/tmp/xxx.apk
    Success
    おお!動いた!

keystoreの設定とか全くしてないのに、問題なく動いた。初めてiPhone実機で動かしたときの苦労と比べると、拍子抜けするほど簡単だった。何故かエミュレータにインストール出来ないが、今は置いておこう。

Unityでポストエフェクト

 AppStoreやUnityのAssetStoreから無料でダウンロードできる「AngryBots」という無料サンプルゲームが参考になる。実装されているポストエフェクトは、4つ。

【全てのエフェクトが有効の状態】
全部入り。

【被写界深度:オフ】
手前のオブジェクトのぼかしが無くなる。

【ブルーム:オフ】
光の滲みが無くなって、色味も変わる。

【反射:オフ】
床に映り込んだ光の反射が無くなる。

【ノイズ:オフ】
ザラザラとしたノイズが無くなる。

【全てオフ】
全て有効な状態と比べると、かなりスッキリというかグラフィックのインパクトが無い。

サポートされる端末が限られるし負荷も高いけど、ここまで印象が変わるなら、是非とも自分のアプリで実装を検討したい。

Infinity Blade2

 値下げをしていたiOSアプリ「Infinity Blade2」を買った。
1にかなりハマったので2を買ってしまうと仕事が手につかなくなりそうで我慢していたが、欲望に負けた。「アンリアルエンジン」で開発されたそのグラフィックはさすがの一言。でもこのゲームの凄いところは、グラフィックだけではなく、タッチパネルを活かしたゲーム性や、飽きるまで永遠に遊べるゲームシステム。売れて当然だ。


ついでに「Unity」で開発されたiOSゲームの代表作「shadowgun」を起動して画面を見比べてみた。かなり地味なものの、改めて見るとこっちもよくできてる。コンシューマでも広く使われている分、アンリアルエンジンの方がグラフィックが良い印象があるけど、明確な優劣はあるんだろうか。



Unity開発メモ:実行時エラー

 Unityでシーンを実行すると、ある場所で以下の様なエラーが表示されるようになった。
InvalidProgramException: Invalid IL code in XXXX:YYYY: IL_0343: ldarg.0
エラーの場所は別のスクリプトのメソッドを呼び出しているところで、ビルドは正常だし動作も今まで全く問題無かった。ググってみても、原因が様々で手がかりが見つからない。

メソッド名を変えたり、部分的にコメントアウトしたりして、やっと気がついた。
ビット演算をしている箇所で、本来 0x3FF とすべきところを2進と16進を混同して 0x1111111111 としていた。ただのバカなうっかりミスだった。

Unity開発メモ:時刻の保存

 現在時刻を保存するメモ。
DateTime.Now.Ticksで"12:00:00 01/01/0001"からの経過秒をlong型で取得できる。PlayerPrefs.SetIntだと桁溢れするため、これをStringで保存する。
復元はConvert.ToInt64でlong型に戻してDateTimeのコンストラクタに渡す。

【保存】
var ticks : long = DateTime.Now.Ticks;
PlayerPrefs.SetString("datetime", ticks.ToString());
PlayerPrefs.Save();

【復元】
var dateString : String = PlayerPrefs.GetString("datetime");
var ticks : long = Convert.ToInt64(dateString);
print(new DateTime(ticks));

なお、日付型のSystem.DateTimeはデフォルトでは使えないので、コードの先頭に
import System; が必要。

また、時刻の差分(秒)は、このように求める。
var diff : long = (newTicks - oldTicks) / (1000 * 1000 * 10);
(Ticksは100ナノ秒)

Unity開発メモ:iPhone解像度

 iPhoneでの性能調査のため、とあるシーン(3000ポリゴン程度、物理演算を使用)のフレームレートを測ってみた。

iPhone3GS (fog有)60 fps
iPhone4 (fog有、retina)38 fps
iPhone4 (fog無、retina)48 fps
iPhone4S (fog有、retina)60 fps
iPad (fog有)33 fps
iPad (fog有)42 fps
iPad2 (fog有、AAx2)60 fps
new iPad (fog有、retina)60 fps

iPhone4とiPadがやけに遅い。iPadはともかく、iPhone4は何とか60fpsを実現したい。
一番手っ取り早い方法はレンダリング解像度を320x480に下げること。

まずは、Unityの標準クラス Screen のメソッドを使ってみた。
Screen.SetResolution (320, 480, true);
これは表示がおかしくなってうまくいかなかった。

次に iOS PlayerSetting の Target Resolution の設定。
・Native(Default Device Resolution)
・Standard(Medium or Low Resolution)
・HD(Highest available resolution)
"Standard"にすると解像度が下がるが、iPhone4やnew iPadも影響を受けるようだ。

ネットで調べるとやっと解決策が見つかった。
Unityから生成されるiOSコードを以下のような感じで変更すれば、端末ごとにRetinaかSDの制御が可能になるようだ。さらに、scaleFactor を 0.5 とかに設定することでもっと解像度を下げることも可能なので、iPadの高速化も見込めそうだ。

AppController.mm
bool CreateSurface(EAGLView *view, EAGLSurfaceDesc* surface)
{
CAEAGLLayer* eaglLayer = (CAEAGLLayer*)surface->eaglLayer;
assert(eaglLayer == [view layer]);

CGSize newSize = [eaglLayer bounds].size;
newSize.width  = roundf(newSize.width);
newSize.height = roundf(newSize.height);

#ifdef __IPHONE_4_0
    int resolution = UnityGetTargetResolution();

    if (    (resolution == kTargetResolutionNative || resolution == kTargetResolutionHD)
    && [view respondsToSelector:@selector(setContentScaleFactor:)]
    && [[UIScreen mainScreen] respondsToSelector:@selector(scale)]
       )
    {
CGFloat scaleFactor = [UIScreen mainScreen].scale;
struct utsname u;
uname(&u);
NSString* machine = [[[NSString alloc] initWithUTF8String:u.machine] autorelease];
if ([machine isEqualToString:@"iPhone3,1"] ||
[machine isEqualToString:@"iPod4,1"]) {
scaleFactor = 1.0f;
}
[view setContentScaleFactor:scaleFactor];
newSize.width = roundf(newSize.width * scaleFactor);
newSize.height = roundf(newSize.height * scaleFactor);
UnitySetInputScaleFactor(scaleFactor);
    }
#endif

surface->w = newSize.width;
surface->h = newSize.height;

UNITY_DBG_LOG ("CreateWindowSurface: FBO¥n");
CreateSurfaceGLES(surface);
GLES_CHK( glBindRenderbufferOES(GL_RENDERBUFFER_OES, surface->renderbuffer) );

return true;
}

結果として、iPhone4でも 60fps を実現することが出来た。
iPhone4 (fog有、AAx2)60 fps

Retina表示より質は劣るが、AAをかけても高いfpsを維持できるので、アプリの方向性によっては十分良い方法だと思う。

Unity開発メモ:GemShader

 宝石のようなレンダリングができるフリーのAsset「GemShader」。
cubemapが何たらとかで、そのままではiPhoneで動作しないようだ。
PCでは動作するのにiPhoneで動かなくてガックリ、というパターンがきつい。


calendar
    123
45678910
11121314151617
18192021222324
252627282930 
<< June 2017 >>
selected entries
categories
archives
recent comment
others
mobile
qrcode