うどんゲームメモ

ゲームの技術メモをまったりと

EasyMotionRecorderを応用したモーキャプデータのモバイル共有

現在、ある案件にてUnityでモーションキャプチャを行い、そのモーションをなんとかしてスマホで共有したいという要求があり、それを現実化するために空いた時間で少しずつ開発を行っていました
その際にとあるモーションの再生録画機構のおかげで作業工程を減らすことができたためメモ

EasyMotionRecorder

github.com

EasyMotionRecorderは某Vtuberで有名なDuoがシンプルなモーションの再生及び録画機構として公開しているライブラリです
元々はAnimationClipを共有しようとか考えていたのですが、モバイルでのランタイム共有においてUnityAssetの共有がかなりネックになってしまったため独自のモーション機構から共有を試みようと思ったのがきっかけでした
基本的にはモーションのあるフレームに必要なボーン情報などをシリアル化可能な状態でまとめ、配列化して共有すればいいのですがそのまとめる工数をあまり取りたくなかったのです
ざっと実装を見た感じ、シリアル化とランタイム実行を考慮したすごく都合のいい状態でまとめてくれていたこれを採用しました

システム

f:id:myudon:20180715224748p:plain

システムは上図のようになっています、とりあえず共有ができればよかったためクライアント以外の部分はかなり簡易的な作りになっています

  1. モーキャプサイドが専用のシーンをエディタで叩いて、モーションキャプチャからモーションデータを生成(別にランタイムでもいいです)

  2. サーバーに転送しユーザー情報やモーション情報と紐づけて保存

  3. スマホ側がサーバーにリクエストして指定のモーションをダウンロード

  4. ローカルに保存しておいて任意で再生

ざっくり言うと上記のフローです
クライアントサイドとしてUnityでモーションキャプチャやモーションのダウンロードを行い、AWS上にサーバーとクラウドストレージ、RDBを用意してモーションデータや関連情報の管理をしています

実装

それでは本題であるUnityとEasyMotionRecorderでのモーションデータの共有に入ります
使用ケースで実装形式が変わるため共有のために行っている処理を抜粋して簡単に説明します
まずモーションデータの生成です、今回はモーションキャプチャーの機器としてPerception Neuronを使用しました
EasyMotionRecorderを使用することでかなり簡単にGUIをいじって生成することができます、詳しくは公式ドキュメントを読んでいただくのが早いのでここでは説明を省略します

f:id:myudon:20180716014034p:plain

Recordを終了させると_posesにHumanoidのモーションデータが記録されるため、このデータを使っていきます


次にモーションデータをシリアル化します、ここではDuoのモーションデータ形式をほぼそのまま使用しています
EasyMotionRecorderではHumanPosesという形式のデータで保存しており、中身はアニメーションフレーム単位でのモーション情報です
Vector3とQuaternionだけシリアル化の関係でfloatに分解しています、最近ではcsv吐き出しの機構をduoが追加したっぽいのでそちらを使うのでもよいでしょう
また、シリアライズに関してはシンプルな方法で記述しています、使用する開発環境やコストに合わせてシリアライズ形式は好きなものを選択してください

[System.Serializable]
public class SerializableMotionData
{
    // DB管理しない付随するモーション情報があればつける
    public string hoge;

    // duoのHumanPosesに含まれるモーション情報
    public List<HumanoidPoses.SerializeHumanoidPose> poses;

    public SerializableMotionData(string hoge, List<HumanoidPoses.SerializeHumanoidPose> poses)
    {
        this.hoge = hoge;
        this.poses = poses;
    }
}
// シリアライズの簡易例

    /// <summary>
    /// バイナリシリアライズ
    /// </summary>
    public static byte[] SerializeMotionData(SerializableMotionData obj)
    {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();

        bf.Serialize(stream, obj);
        return stream.ToArray();
    }

    /// <summary>
    /// バイナリデシリアライズ
    /// </summary>
    public static SerializableMotionData DeserializeMotionData(byte[] bytes)
    {
        MemoryStream stream = new MemoryStream(bytes);
        BinaryFormatter bf = new BinaryFormatter();
        var obj = bf.Deserialize(stream) as SerializableMotionData;
        return obj;
    }

そして投稿です、UnityWebRequestでいいんですが、今回は都合でObservableWWWを使用しています

// 任意のレスポンスを定義してやり取り
    public static async Task<TResponse> PostMotionData(byte[] poses)
    {
        var endpoint = "";
        var form = new WWWForm();

        // ここで送信するモーション情報を定義

        // モーションデータのバイナリ
        form.AddBinaryData("poses", poses);

        // using UniRx
        var www = await ObservableWWW.Post(endpoint, form);
        var response = JsonUtility.FromJson<TResponse>(www);

        return response;
    }

次に共有するモバイル側の実装です、今回使用したケースでは一回モーションの関連情報をサーバーに問い合わせてモーションをダウンロードするんですが、そこは省略し直接モーションデータをURLからダウンロードする部分を記述します
投稿同様にObservableWWWでシンプルに記述しています

// URL指定してDL
    public static async Task<SerializableMotionData> GetMotionData(string url)
    {
        // using UniRx
        var www = await ObservableWWW.GetAndGetBytes(url);
        var motion = DeserializeMotionData(www);

        return motion;
    }

モーションデータをデシリアライズし、モーションプレイヤーに流し込みます
MotionDataPlayerという再生機構は用意されているので、適当にデータを紐づけておいてそこに代入する方式をとりました

f:id:myudon:20180716024006p:plain

   // HumanPosesに対して追加
  public void SetPoses(List<SerializeHumanoidPose> poses)
    {
        Poses = poses;
    }
    // MotionDataPlayerに対して追加
    public void SetMotion(List<HumanoidPoses.SerializeHumanoidPose> poses)
    {
        _recordedMotionData.SetPoses(poses);
    }

後はMotionDataPlayerで再生してやればモバイルのランタイムでモーションを見ることができます
フレーム単位でポーズをいじってるだけなのでその辺をいじる機構を作れば色々再生周りの機構も作れるでしょう


AR100Projects

最後に自分が行ってる活動の宣伝をば
この機構の開発の発端は、イワケンこと同期の岩崎謙太(@tanaka_lit)とともに行っている「AR100-Projects」という施策の下で開発中のプロダクトです
このプロジェクトはイワケンとともにARで世界にインパクトを与える、プロダクトを量産するという思想の下に、時代がAR本格化する数年後に向けてARプロダクトを100個作ろうというとてもクリエイティブなものです
ARやVRについて圧倒的な熱意を持っているイワケンやプロダクトに協力してくれる様々な人たちとともに、ARでできることを考えつつ形にしていっています
まだまだ発展途中ですが、自分も技術者としてというよりも、クリエイターとして自分を高めていくためにこのプロジェクトを盛り上げて成功させようと考えています
開発したプロダクトは勿論、ここで得た技術知見の共有などもブログで積極的に行っていく予定なので応援していただけると幸いです

Unity開発における継承とコンポジション

開発を進めていくうえでクラスの関係性をどのように設計するかを画策することは多々あると思います。
最近ではUnity2018でECSといったUnityでの開発アーキテクチャも話題になり、Unityでそれらをどう管理するのが正解か?という議論もちょこちょこ見られるようになりました。(自分だけかも)
そんな今回はUnityの開発思想に則して、少し基礎的な部分になりますがクラス設計の小話をしたいと思います。ECSの理解に対して必須の見識だと感じているので参考になれば幸いです。(変な解釈の部分があればご指摘ください)

継承とコンポジション

まず、プログラミングにおいて基礎的な要項ですが、継承とコンポジションの相違性について洗い出します。
継承もコンポジションも複数クラスの共有化という点では同じです、簡単に言ってしまうと違いはその共有する際のクラス間の関係性です。
継承の関係をざっくり言うと「is-a」です。継承ではスーパークラスの性質をサブクラスが全て引き継ぎ、全て我が物として使用します。
コンポジションの関係をざっくり言うと「has-a」です。共有するクラスをメンバとして管理し、依存したい部分にアクションを起こします。
継承はスーパークラスそのものでありそのサブタイプとなりますが、コンポジションではあくまでも共有する機能を持った拡張クラスでしかありません。

Unityとコンポーネント指向

それでは継承とコンポジションの相違点を踏まえ、Unityで開発する際のクラス関係を考えましょう。

Unityはコンポーネント指向をベースとしており、ある実装の枠組みに対してコンポーネントという機能単位で実装を図っていくことがベターです。
例えばある3Dキャラクターの敵を実装するとして、描画を行うコンポーネント、座標を管理するコンポーネント、敵キャラとしてアクションを起こすコンポーネント...等と作用ごとに分割し実装していきます。
それに対してクラスを共有するような物が出てきたらどうでしょう。

上の例から、様々な敵クラスに派生していくことを考えます。当然、敵毎のユニークなアクションを行うものは別途で実装を行いますが、3Dキャラクターとしての共通処理、敵としての共通処理は共有化を図ることになります。
その時、正解なのは「is-a」ベースの継承クラスを用意することでしょうか、それとも「has-a」ベースの共有コンポーネントを用意することでしょうか。
上記でも述べた継承の特性をもう一度考えます、継承という関係性はサブクラスがスーパークラスに対して大きく依存をすることになります。スーパークラス内で敵クラスについて共通処理の改修が行われた際にその派生した敵キャラクターについては保証されません。設計者がそれについて担保した設計にしているのならば別ですが、リリース毎に改修作業が増える可能性は十分にあります。

コンポーネント指向において、完全な「is-a」関係を要するものはそう多くはないと考えています。共有化すべき処理をCommonなりなんなり共有コンポーネントとして与え、それについてアクセス側がアクションを起こすという形が無難であり、そういった「has-a」の関係性で構成されるべきです。
継承が必要な関係性の場合は良いのですが、コンポーネント指向である以上、実装において共有化を要する際には機能単位でのコンポジションベースで考えることを徹底したほうがいいですね。


Unity2018のECSはコンポーネント指向を理解し、コンポーネント単位での振る舞いを考えることで理解が深まるものだと感じています。
コンポジション等の設計指向の基礎を再確認し、ECSを学ぶことで最善な設計を追求していきたいです。
自分もまだこの部分の解釈については検討途中であるため、感想や意見、指摘などがあればお願いします。

Rxで条件付きの能力を設計する

バトルゲームを作成していて頻繁に出てくるのが「Aの時Bを発動する」と言った条件付きの能力です 例えばパズドラのゼウスというキャラクターは「HPが満タンの時、味方全体の攻撃力が3倍になる」という能力を持っています

f:id:myudon:20180329003932j:plain

またスプラトゥーンのギアの中にも、「対戦開始から30秒までの時、速度が上昇する」「復活した時、相手の位置が遠くから見える」等といった条件付きの能力を含んだものが存在します

f:id:myudon:20180329004718p:plain

勿論これらの他にもこれらのような条件をトリガーとして発動する能力は多く、バトルをデザインする上でかなりメジャーな材料と言えるでしょう

ですが、それらを安直にゲームシステム内にどんどん実装していくと、ゲーム開発が進むにつれ見るに堪えない構造になりがちです。これは時間を条件としたり、キャラクターのパラメーターを条件としたり、取り巻く環境の状況を条件としたりと様々な箇所にトリガーが考えられるからです
また、これらの能力はゲームを運用して、バトル環境をサイクルしていくにつれても増えていきます、Aという条件でB、Aという条件でC、AとDという条件でC等、組み合わせ的にも増えていくことが考えられるため、変更や振る舞いの追加に強い設計が求められます

そこで今回はUniRxを使って、この課題に対してゲームのシステムロジックに依存せず稼働し、かつ変更などに柔軟に対応できる設計を考えていきます

設計と実装例

まずはベースとなる形を考えます、条件付きの能力をレベルデザインの点から見た時、条件と効果は別々で考えていき、そこから組み合わせ的に一つの物を作りだすということが多くなります
つまり、デザインする上で条件と効果がそれぞれ単独で動く作りであると、個々にテストを行い、調整を行うことが出来ます

条件と効果

条件側は、単一の担当している条件を監視して達成したかどうかだけを通知し、効果側は単一の担当している効果の発動や有効無効の切り替えを行うようにします
それぞれ条件と効果の基盤をスーパークラス化し、それを元に実装していきます

using System;
using UnityEngine;
using UniRx;

public abstract class ConditionBase : IDisposable
{
    protected Component _dependencyComponent;

    public ConditionBase(Component component)
    {
        _dependencyComponent = component;
    }

    //条件達成通知
    public Subject<bool> OnAchieve = new Subject<bool>();

    public void Dispose()
    {
        OnAchieve.Dispose();
    }

    public static ConditionBase GetCondition(ConditionType type, Component dependency)
    {
        // 具体的な条件の取得
    }

    public enum ConditionType
    {

    }
}
using System;
using UnityEngine;

public abstract class EffectBase
{
    protected Component _dependencyComponent;

    public EffectBase(Component component)
    {
        _dependencyComponent = component;
    }
    
    //効果の有効化/無効化
    public abstract void SwitchEffect(bool invoke);

    public static EffectBase GetEffect(EffectType type, Component dependency)
    {
        //具体的な効果の取得
    }

    public enum EffectType
    {

    }
}

Binder

条件と効果を元に、この2つをBindする大本の能力の基盤クラスを設計します、能力自身はあくまでも条件と効果の中身に干渉せず、ただBindするだけです
ここで汎用的な能力設計を行うために、RxでどのようにBindをするかを考えていきます
能力が持つ条件については、例えば上記で上げた例では単一条件で単一効果を担保していましたが、例えば複合条件、また複数条件の内1つでも満たしていたら発動など、条件をAND的に、OR的に考えることも考慮したほうが汎用性が高いと言えます
そこで、複数の条件からくる通知を束ねて考えて、その束からAND,OR的に導出をすることで様々な条件発動に対する回答を試みます、ここで役に立つのがRxです
条件達成をイベントストリーム的に捉え、それらを並列に監査します、イメージは下図です

f:id:myudon:20180408111705p:plain

これをUniRxを用いて実装していきます、肝になるのがCombineLatestです
CombineLatestは複数のストリームを統一して監視するものです、対象とする複数ストリームよりいずれかのストリームから値が発行された時に全てのストリームが保持している値を流します
これを応用し、条件の達成通知を統合して購読します
f:id:myudon:20180401224826p:plain
Binderに条件と効果の識別子、そしてその処理に必要となる依存性を外部から流し込みます、そしてBinderを立ち上げて条件と効果の結びつきをCombineLatestによって実現します

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UniRx;

public class Binder : IDisposable
{

    private List<ConditionBase> _conditions;

    private List<EffectBase> _effects;

    private IDisposable _andDisposable;
    private IDisposable _orDisposable;

    // 能力の干渉対象
    private GameObject _dependencyObject;

 public Binder(Component dependency, List<ConditionBase.ConditionType> conditionTypes, List<EffectBase.EffectType> effectTypes)
    {
        _dependencyObject = dependency.gameObject;

        _conditions = conditionTypes.Select(type => ConditionBase.GetCondition(type, dependency)).ToList();
        _effects = effectTypes.Select(type => EffectBase.GetEffect(type, dependency)).ToList();
    }
  
    //初期化でそれぞれの通知をCombineLatestで束ねて処理
    public void Initialize()
    {
        _andDisposable =
            _conditions.Select(x => (IObservable<bool>)x.OnAchieve)
            .CombineLatest()
            .Subscribe(_ => _effects.All(x => true))//andで条件を束ねる
            .AddTo(_dependencyObject);

       _orDisposable =
            _conditions.Select(x => (IObservable<bool>)x.OnAchieve)
            .CombineLatest()
            .Subscribe(_ => _effects.Any(x => true))//orで条件を束ねる
            .AddTo(_dependencyObject);
    }

    public void Dispose()
    {
        _conditions.ForEach(condition => condition.Dispose());

        _andDisposable.Dispose();
        _orDisposable.Dispose();
    }
}

今回はもっとも単純な形としてEnumから具体的なサブクラスを呼び出し、共通処理からポリモーフィズム的な条件と効果の呼び出しを行っています
条件についても 基本型としてBindを設計しましたが、条件の性質によっては束ね方が変わってくるかと思います

メリット

まず1番のメリットは先述にもあったように、条件と効果が疎に連結され、組み合わせを柔軟に組むことができることです
能力の追加や仕様変更に対しても強く、また条件についてはストリームで監視を行う以上条件の処理の重さに合わせて監視の粒度を調整することも可能です
何より効果毎の調整といったデバッグ機能などのテストコードの実装が容易であり、細かい変更にコストを割くことが無くなるでしょう

デメリット

一つはRxそのものがゲームロジックにクリティカルに介入するという事そのものです
自分はRxが確かに好きなのですが、好きであるからこそしっかりと使い所は見極めるべきだと考えています
特定のゲームロジックに対し監視を仕掛ける以上、Rxは処理コストを要します、ゲーム内容によってはここの処理コストがボトルネックとなってしまう可能性もあり、簡単に導入を決定できるものではないと言えます
もう一つはイベント処理の通知化にとらわれてしまう事です
依存性を持つコンポーネントに対して監視し、条件が処理を取り行う為、条件側からイベントを何かしらの形で購読できる形が必要になってきます
その為に多数のSubjectの発生やReactive化が必要となるという懸念があります、無論それによる処理負荷の肥大の可能性も考えられるでしょう


今回、設計の一例としてRxを用いた汎用化を紹介しましたが、あくまでも形の1つであり、内部の既存構造によって最善形は変わってくるかと思います
ですが、瞬間的に完結しないゲームロジックの汎用的設計の1つの解決案として、Rxを頭の片隅に置いておくことは良いことですし、道具として知ってだけでもロジックの捉え方が広くなるのでおすすめです

全天球カメラを用いた没入型コンテンツとその発展性

最近全天球カメラ使って遊んでおり(研究)、HMDを用いたコンテンツの可能性が広がらないかなと思い記事にしました
今回は少し趣の違う記事ですが、少しでも参考になれば幸いです。

全天球カメラを用いた没入型コンテンツ

皆さんは全天球カメラって知ってますか?一時期パノラマ写真とか流行ったかと思います。パノラマ写真を撮るときに使うのは全天球カメラですね。
普通のカメラのように前方だけを写すのではなく、自分を中心として360度全方位が取れるカメラです。RICOH社から出ているThetaが有名な例で、自分も研究で使用しています。
f:id:myudon:20171205203731j:plain
Thetaを例として話すと前方と後方に魚眼レンズが付いていて、自分を中心とした天球の前方と後方の映像が別々に出力されます。それを繋ぐと360度映像の完成というわけです。
じゃあこの全天球カメラ使って何するの?何に使われるの?と、まぁ一番はHMDと併用した没入型コンテンツでしょう。
適当に天球作って法線裏返してThetaの映像をシームレスにマッピングすればThetaを中心とした全天球映像が簡単に出来るので、その中央にカメラを置き、ヘッドトラッキングしたHMDに出力してやればあっという間に360度映像を楽しめちゃいます。最近だとUnityなどの無料ゲームエンジンが進化を遂げており、HMDを使った開発が容易なので比較的技術的なハードルも低いです。
Thetaはライブ映像を出力できるので繋いでやれば動画にもできます、例えばThetaを海に放り投げて繋げば海の中を覗いて魚が泳いでいるのを見れますし、ライブ会場に持っていけばライブ体験だって可能です。また、Wi-Fi接続も出来るのでFPSは落ちますが無線での映像提供も可能です。
このように、全天球カメラを使うと360度映像を使って簡単に没入型コンテンツのベースを作ることが可能です。まだまだコンテンツへの応用は少ないですが期待できる分野です。


視野合成とコンテンツの発展性

次に視野合成について話します、視野合成と言うと難しそうに聞こえますが言ってしまえば画像をいい感じにくっつける技術です。
例えばOculusRiftでは立体視を単一映像情報で実現するために、映像を投影する際にシェーダー側で処理し理論的な歪みを左右の画像に付与することで、左右の視差を作っています。
f:id:myudon:20171205203725j:plain
360度映像から視野となる映像を作成すると考えた時、この映像情報を合成することで様々な試みが出来ます。
例えば普段は視界にとらえられていない真横や後ろの情報を正面に投影されるように合成することでカメラなどの物理的な挙動なしで、それらの見えない部分の映像を見ることが出来ますし、高さなどに焦点を当てて合成すれば普段よりも高い視点だったり低い視点だったりが楽しめます。
OculusRift等の視野角が狭いという点をこれらの合成でカバーすることももちろん検討できます、複数台の全天球カメラで360度映像を取得しそれらを合成すれば、理論上どのような位置からどのような角度で見ているか汎用的に表現できるでしょう。
勿論カメラの位置を移動させたりすれば表現はできますが、物理的な制約は付き纏います。映像を合成するというアプローチでカバーすることでコンテンツの表現がより自由になると思います。
現状HMDを用いた没入型コンテンツというのは基本的に1人称視点が多いですが、今とは違う一風変わったコンテンツの進化が求められてきたときに、こういった技術がアプローチ出来ると感じています。(現実空間でTPSとかやってみたいです)


HMDを使ったコンテンツというのは確実に増えてきていて、ちょっとやそっとの内容ではあまり驚かれなくなってきました。
少しでも新しい、面白いコンテンツを提供したい、その心を持ち続けてこういったコンテンツに活かせる技術を学んでいきたいですね  

エンジニアインターン体験記(ITベンチャー多め)

この記事はNITMic Advent Calendar 20日目の記事になります
お前何回書くんだよみたいな感じですが、自分の担当する最後の記事なので温かい目で見てください
去年何社かお邪魔させてもらった短期のインターンについて話していきたいと思います
エンジニアを目指す方や、インターン行こうか迷ってる方にとって少しでも参考になれば幸いです


会社ごとの感想

自分は短期インターンとして伺った会社は4社です、この4社ごとの簡単な内容の説明と学んだことなどを書いていきます

1.サイバーエージェント

1社目はITベンチャー大手であるサイバーエージェントさんです
サイバーエージェントさんについては2回短期インターンにお邪魔させてもらいました
1つ目はTechnical Creator Challengeというインターンです
内容としては5日間の短期開発インターンで、テレビアプリの開発をしました
中でも特徴的なのは企画、デザイン、実装までを全て一人でやるということで、デザインからエンジニアリングまで様々な技術を持つ学生が集まる非常に勉強することが多いインターンでした
自分が参加したのが栄えある第一回で、最終審査には社長である藤田晋さんがいらっしゃったのも印象に残っています
同じインターンに参加した学生が紹介インタビューを受けているので良ければ参考にしてみてください

developers.cyberagent.co.jp

2つ目は京都ハックというインターンです
内容としてはこちらも5日間の短期開発インターンです、京都という地域に結び付けたサービスの開発をしました
こちらはチーム開発で1チーム3人程度で作成をしました、Webアプリやスマホ用アプリからドローンを応用したアプリまで様々でした(自分はARのサービスを作りました)
実際に京都の町に繰り出しながら開発案を練ったりなど、普段の個人開発では学べないようなことも多くいい機会になりました

2.エイチーム

2社目は地元名古屋で活躍するエイチームさんです
エイチームさんではWebサービスとゲーム開発の2つの1dayインターンを実施しており、自分はゲーム開発インターンに参加させていただきました
内容としては1日のUnityを用いたゲーム開発で、最終的に工夫をコンペ形式で競うものでした(チーム開発ではなく個人開発)
地元開催ということもあり、自分の学校やゲーム開発で交流のある専門学校の生徒が多く、とても和気あいあいとしたインターンでした(東京と大阪でも開催されます)
コンペ上位者には1か月のコンテスト型インターンへの参加が認められ、そこからさらにチーム開発を行うことになります

3.カプコン

3社目はコンシューマーゲームでおなじみのカプコンさんです
開催場所は大阪のカプコン本社近くにある研究開発ビルで、関西圏から多くの学生が参加していました
内容としては2日間に渡るチームでのゲーム開発コンペでした、俗にいうゲームジャムですね
審査をする方々も有名なゲームに携わっているクリエイターの方々ばかりで、フィードバックを直にいただけるだけでもいい経験になりました
足りないところをしっかりと指摘していただけるため、自分の強いところや弱いところがはっきりしていい機会になりました

4.アカツキ

最後の紹介になるのは成長に勢いのあるアカツキさんです
内容としては1日のゲームジャムだったのですが、それだけのために2泊分のホテルと交通費を出していただけたのはびっくりしました
VRのゲームを1日で開発することになり、結構ぎりぎりのスケジュールの戦いでしたが学ぶものも多かったです
開発の前に参加者全体でアイデアソンのようなものも行われ、ゲームの企画を考えるいい機会にもなりました
結果的にチームにも恵まれ、優勝できたので個人的には印象深いインターンですね
VRのゲームを作成し、それを実際に会社で開発しているような人にプレイしていただきフィードバックをいただけたのもかなり貴重な体験でした


短期インターンを経験して

短期インターンを通して得たものですが、まず確実なのは開発力ですね
短期インターンは短期という性質上ハッカソン形式をとるものが多く、いかに少ない時間で機能を実装していくかの訓練になります
また色々な技術者との交流や共同開発も行うため、多様な角度からの実装アプローチが身に付きます
それに連ねて、ギークな人脈も増えていきました
学生vs学生といった形式が多いため参加するたびにこんな学生もいるのかという発見ができます、インターンを機に一緒に開発をする仲間が増えアウトプット形式の幅が広がりました
また審査は会社で実際に開発を行っているような方々がされるため、会社について話を伺う事も出来ます
ですが、会社でどのような雰囲気で開発がされていて技術選定はどうなっているかを見定めたい場合は長期インターンの方が多くのことを知れて適しているかと思います


インターンを受けるには

インターンを受けたい!という学生さんの技術力にもよりますが、インターンは全部が全部行きたいところに行けるわけではないです
所によっては倍率が100倍などのインターンもあり、正直落ちることも多々あります
自分の行きたいインターンをしっかりと見定めて、自分の技術をしっかりとアピールすることが重要になってきます
特にエンジニアインターンだと何かしら見せることのできる成果物やソースコードがあると良いですね
インターンは学生の内しか行けない貴重な機会なので是非トライしてみてほしいです

Blenderでゲームのコストカットしたりタイトル画面作ったりしてみた

この記事はNITMic Advent Calendar 18日目の記事になります
今回はBlenderを用いたちょっとしたテクニックを紹介します
Blenderの自体の操作説明に関しましては省略しますので、ご了承ください


ゲームとレンダリングコスト

最近ではハイエンドなグラフィックを売りにしたゲームが増えてきました
中でも本当にこれはCGなのか?と疑ってしまうようなものもあります
しかし、ハイエンドなグラフィックほど裏では莫大な計算処理が施されています
リアルタイムレンダリングでそういったリッチな表現をこなし続けるというのは、不可能ではありませんがそれ相応のグラフィック性能を要求されることになります
特に流体シミュレーションや、サブサーフェス・スキャタリング、透過処理といった重めの処理はリアルタイムレンダリングだとそれっぽい表現でぼかすということも少なくありません
でもリッチな表現を使いたい!という人のために、今回はBlenderを使ってその表現をプリレンダリングし、テクスチャに起こしてしまうことで比較的低コストでリアルな表現を取る方法を紹介します

Blenderでプリレンダリング

リアルタイムに計算するのが難しいならあらかじめ計算してしまえ!ということでBlenderを使ったプリレンダリング技法の紹介をしていきます
今回使用するのはBlenderに標準で搭載されているCyclesレンダーというレンダリングエンジンです
後、今回レンダリングをより快適に行うためGPUレンダリングを採用しています、Blenderはこういう切り替えもお手軽にできるのでお勧めです
f:id:myudon:20171217222351p:plain
今回題材にするのはこの何の変哲もない宝石の入った宝箱です、これにCyclesレンダーを用いてまずそれっぽいリッチな加工をしていきます
今回はBlenderを使ってリッチな表現をするという趣旨ではないため、そこの過程については省略します
f:id:myudon:20171217222716p:plain
分かりやすくコテコテに表現を盛ってみました
金属光沢やIBL(Image Based Lighting)、透明処理や屈折光など重い処理が盛り盛りです
f:id:myudon:20171217224445p:plain
このレンダリング結果をテクスチャに焼いていきます、右下のメニューにBakeという項目が存在するので、そこで焼く表現の設定や実際に焼くコマンドを行います
また、この時Samplingの項目を設定してあげることで精密度を上げることができます、もちろん細かいほうが綺麗ですがその分レンダリングにも時間がかかるのでそこは注意です
(あまりにも設定を上げ過ぎるとBakeに数時間かかっちゃったりします)
また、Bake先のテクスチャについてはマテリアル内で何にもつながってないテクスチャが必要となります、ここ割とつまづきやすいので注意しましょう
f:id:myudon:20171217235158p:plain
またBakeするからには、UV展開がされていることも必須なのでその辺の手順もしっかりと踏みましょう
f:id:myudon:20171217230824p:plainf:id:myudon:20171217230827p:plain
宝箱の外部のテクスチャを結果の例として焼いてみました
映り込みまでもがしっかりとテクスチャに反映されているのがわかると思います、リアルタイムで計算せずにテクスチャにあらかじめレンダリング結果を焼くことでリッチな表現を残しつつコストカットができるというわけです
勿論、リアルタイムレンダリングとは違って、動かしたり違う視点から見た際に違和感が出てしまうというデメリットがあります
なので使いどころをしっかりと見極めて、使えそうなところはコストカットを図っていくといいでしょう

プチ応用例(タイトル画面の作成)

一般的には上記のような3Dモデルのレンダリングコスト削減に用いる技術ですが、使い方によってはこんなこともできちゃいますという例です
f:id:myudon:20171217231952p:plain
これは自分が過去に制作したゲームのタイトル画面です
個人制作であったため、タイトル画面などのデザインリソースが間に合わずどうしようか画策していた時にある方法を思いつきました
それは、Blender内でタイトル用の1シーンを作り、テクスチャとして焼いてしまおうという方法です
f:id:myudon:20171217233025p:plain
制作風景です、カメラの前にゲーム内で使用するキャラクターやオブジェクトを配置していきます
タイトル用なので解像度あげあげでリッチに仕上げていきます、それでも焼くのにかかった時間はせいぜい1時間ほどでした
f:id:myudon:20171217233322p:plain
これがオブジェクトの配置が終わり、環境光も含めてベイクしたものです
3Dモデルを配置していくだけなので、どんな構図でも大丈夫なわけです
後はこの作業が撮影監督になった気分で楽しいですね!
f:id:myudon:20171217233849p:plain
後はこの画像を元にPhotoShop等のデザインツールで仕上げを行います(自分はGIMPでやりました)
ここにタイトルロゴなどを加えて完成となりました、制作期間もそんなにかからなかったです
このように、ちょっとしたワンシーンを画像にしたい時などにもBlenderは活用できるので試してみてはいかがでしょうか

Unity開発で使うライブラリ(アセット)備忘録

この記事はNitmic Advent Calendar 13日目の記事になります
いい加減UnityじゃなくてCGの話しようと思ったんですけどとりあえずそれは来週にでも回そうかと・・・
今回は自分がゲーム開発する際によく使うライブラリだったりアセットだったりをまとめようかなと思い、書きました
早い話が前回のデバイス紹介のライブラリ編です
またお前かよみたいな感じですけどお暇な人は読んでみてください


1.UniRx

1つ目は自分のもっとも使っているライブラリ、UniRxです
Rx(Reactive Extensions)というのは所謂リアクティブプログラミングをObserverパターンを用いて実現させるためのライブラリを指します
それをUnity向けに作ったのがUniRxというわけです
イベントストリームという、イベントを時系列の流れとして捉える処理が特徴的であり、非同期処理などに長けています
ゲームで言えば何秒後かに処理するといったタイマー処理だったり、一連の動作が行われたかどうかを待機する処理などが書きやすいですね


2.Vuforia

2つ目はARライブラリ、Vuforiaです
主に短期インターンハッカソンでお世話になりました、簡単なARコンテンツを作る際に重宝しています
マーカーベースのARコンテンツを作る際に、ほとんどの工程を担ってくれます(マーカーベースというのは任意の画像をかざすことでコンテンツを提供するもののことです)
画像をかざして3Dモデルを出すという基本工程ならばコーディングが要らないほどに簡単なので試してみてはいかがでしょうか


3.SocialWorker

3つ目はSNS連携を行うSocialWorkerです
Unityといえばアプリ開発であり、アプリといえばSNS連携が欠かせなくなってきています
SocialWorkerは特に難しい記述も必要なく、アプリ内でのSNS投稿がサクッと出来ちゃいます
サポートしているのはiOS/AndroidでのTwitterFacebook、Line、Instagram、メールです
もちろん連携してデータを色々と使ったりなど柔軟なことをする場合には自分でAPIを叩いてやるべきだと思いますので、簡易的な投稿機能などがほしいときに使ってみるといいでしょう


4.DOTween

4つ目はアニメーションライブラリ、DOTweenです
イラストが変化しつつ遷移していくようなアニメーションのことを一般的にTweenアニメーションと呼びます(フェードしてきたり、拡大縮小したりなど)
そのTweenアニメーションをUnityで実現するためのライブラリで、自分がTweenアニメーションを実装する際に一番使うものです
特徴的なのがアニメーションをシーケンスという連続した流れで捉えることができることですね
複数のアニメーションを動的に結合したり、同時に処理したりなど、多様な使い方をすることができます
初心者の方でも扱いやすく、表現の幅がぐんと広がるのでおすすめです


5.Julius

5つ目は音声認識ライブラリ、Juliusです
その名の通り、音声を認識してそれを文字列に起こしたりすることができます
単純な音声認識なら割とすぐ出来てしまうので、ちょっとしたアプリを作るときに役立ちます
ただ、会話などをするには精度など様々な点で難しいところがあるので、ピンポイントなワード認識用って感じです


6.Zenject

6つ目はDIフレームワークであるZenjectです
自分が秋ごろに書いた記事でも説明した、Unityの設計においてDIコンテナを採用する際に用いるものです(詳しい説明はその記事を読んでいただければ!)
Unityでシングルトンを用いて設計を行うと割と密結合になってしまったり、肥大化したシステムでサイクルがとっ散らかったりしまったりして自分はあまり好きではないです
Zenjectを用いて必要なパーツを提供する機構を導入してあげるとそういった点がかなりスッキリするので自分は積極的に使いたいなと思っています


7.NGUI

7つ目はUIライブラリであるnGUIです
Unityには標準でuGUIというUIを実装するためのサポートシステムが存在しますが、それよりもより自由度と難易度を上げたのがnGUIになります
少し癖が強いですが、3D空間上のUIやテキストと画像混合のアニメーションなど、使いこなすと広い表現が可能になります
ただnGUIでしか出来ないということが割と限られていたり、uGUIと処理の細部が違っていたり(イベント処理がraycastじゃなくてcolliderだったり)するので積極的な採用をするよりは使いどころを見極めるべきものだと思います


いかがでしたでしょうか、所謂コンテンツの表現を伸ばすものと、そもそものコーディングをアシストするものを紹介しました
後者に関しては、ライブラリ一つで構造がすっきりするというのは割とよくある話なのでまずは試してみてはいかがでしょう
導入しただけで開発期間が大きく短縮されるのはよいことですし、あるものはどんどん活用していきましょう(勿論それなりの理解をした上でですが)
また機会があればこれらのライブラリの活用例であったり簡単な解説を記事にしようかなと思います