カテゴリー別アーカイブ: program

プログラム書いてて気づいた事など。

[Unity3D][ImageEffect]Kino bloom filterを見る

高橋啓二朗(@_kzr)氏のKino Bloomフィルターの中身をみてみる。

Bloom

Bloom.csとshaderを行ったり来たりしながら見ていく。

void OnRenderImage(RenderTexture source, RenderTexture destination)

MonoBehaviour.OnRenderImage(RenderTexture,RenderTexture)

メインとなる関数。
第一引数がこれまでの結果。第二引数にこの関数で変更した内容を適用してあげなければならない。

適用はGraphics.Blitで行う。

    Graphics.Blit( source , dest );

続きを読む

[Unity3D]UPDATE()は遅いらしいし

  • UPDATE()を10000回呼ぶ
    Unityのオフィシャルブログの記事を見ていくつか気づいたこと、今後すべきことをメモしておく。

気づいたこと

  • Script Call Optimization を Fast but no Exceptions に変更 という作業で高速化できる
  • Updateは遅い

Script Call Optimization を Fast but no Exceptions に変更

Updateをまま使う場合、 Script call optimazation の項目を設定してあげる必要がある。

メニュー: Edit->Project Settings->Player

ここから設定が可能。

Updateは遅い

Updateやその他のマジックメソッドは、まずUnity側に登録されてその後GameObjectの存在チェックやNullチェック等を経て初めて呼び出される。
そのため、たとえ中身がカラだとしても void Update(){} と記述するだけで呼び出し対象にはなるし、上記のチェック等を経ているために処理の対象になり、少ないとはいえレイテンシーが発生する。

記事中では、この辺が必要無い場合、自前でManagerを作ってManagerのUpdate時に子に対して自前のUpdateを流す仕組みの方が高速であるとしている。
さらにListではなくArrayを使用したほうが効率的だとも述べられている。

自律制御のテストをしやすく子として呼ばれた時もよ動作させやすいやりかた

Manager側は一方的に呼び出すで良いとして、子側はMonobehaviour継承クラスだとしても void Update() 等を記述しない
自律テストをする場合は ChildDriver としてUpdate内で自身に着いた子用コンポーネントを自動取得して自前Updateを呼び出す仕組みにしてテストしたら良いと思われる。

具体的には

マネージャとして以下の様なコンポーネントでUpdate呼び出し。ブログまま。

    public abstract class Manager<ChildType> : MonoBehaviour
        where ChildType : IManagedMember
    {
        protected ChildType[] members;
        protected void Update(){
            int count = members.Length;
            for (var i = 0; i < count; i++) members[i].UnmmanagedUpdate();
        }
    }

呼び出される側はこんな感じでインターフェースを用意。

    public interface IManagedMember{
        void UnmmanagedUpdate();
    }
    public abstract class ManagedMember : MonoBehaviour,IManagedMember {
        public abstract void UnmmanagedUpdate();
    }

独立して子の挙動をテストしたいこ時は子にこれを追加してあげる。

    public class ManagedMemberDriver : MonoBehaviour {
        IManagedMember[] components;
        void Start () {
           this.components = GetComponents<IManagedMember>();
        }
        void Update () {
            int count = components.Length;
            for (var i = 0; i < count; i++) components[i].UnmmanagedUpdate();
        }
    }

あとは必要に応じてManager側には子作りメソッドを用意したりで色々できる。

C#のコードからメッシュを生成するチュートリアル

Polygon from s2kw on Vimeo.

  • コードからポリゴンを生成するチュートリアル。
  • 大まかな流れは以下のとおり
    • Mesh オブジェクトの生成
    • Mesh オブジェクトに頂点情報を渡す
    • Mesh オブジェクトの頂点情報に合わせた三角ポリゴン情報を渡す (この時点で画面には描画される)
    • Mesh オブジェクトにUV情報を渡す
    • Mesh オブジェクトにtangent情報を渡す
  • 書いたコード
  • チュートリアル
  • Unity::Reference::Mesh

続きを読む

[Unity][uniSWF]newしたMovieClipが突然なくなってしまう現象でハマった話

Uniswfを使用しているとプログラム上で動的にMovieClipを生成したくなることがある。
これでちょっと複雑な構造にするだけで意図した動作がなされないことが良くある。

次のコードで例を示す。

    public Vector2 v2Out;
    MovieClip linkage;
    List<MovieClip> c = new List<MovieClip>();
    private void Test(){
        var stage = MovieClipOverlayCameraBehaviour.instance.stage; 
        var a = new MovieClip();
        var im = new MovieClip();
        a.addChild(im);

        var textureA = Resources.Load("images/iconA")  as Texture2D;
        var textureB = Resources.Load("images/iconB")  as Texture2D;
        a.graphics.drawRectUV( 
            texture,
            new Rect(0, 0, 1, 1),
            new Rect(0, 0, textureA.width, textureA.height)
        );
        im.graphics.drawRectUV( // この描画は失われる。
            texture,
            new Rect(0, 0, 2, 2),
            new Rect(0, 0, textureB.width, textureB.height)
        );

        this.linkage.addChild( a );
        c.Add(a);
        a.x = cor.v2Out.x;
        a.y = cor.v2Out.y;

        MovieClipOverlayCameraBehaviour.instance.stage.addChild(this.linkage);
    }
    private void TestMcStructOut(){
        var stage = MovieClipOverlayCameraBehaviour.instance.stage; 
        Debug.Log( "ListCount : " + this.c.Count + " : linkage has :" + this.linkage.numChildren + " : stage has :" + stage.numChildren + " : a's child : " + (this.linkage.getChildAt(0) as MovieClipUtil).numChildren );
    }
    void Update(){
        if(c.Count < 1) Test();
        else{
            //c.ForEach( d => this.linkage.addChild( d ) );
            //c.ForEach( d => d.visible = true );
            c[0].x = v2Out.x;
            c[0].y = v2Out.y;
        }
        TestMcStructOut();
    }

‘Vector2’ 型のメンバ v2Out は描画させたい MovieClip の位置を変更させるためのものとして用意。
Unityを再生中でもMovieClipをぐりぐり動かせる。

Test関数内部で作成しているMovieClipの構造を改めて示すと、

    stage -> linkage -> a -> im

これを実行すると最初のフレームだけ textureA, B の両方が描画され、次のフレームでは im に描画した textureB は消滅している。

状況を整理すると
– linkage はメンバなので次のフレームでは削除される
– a はメンバではないけれども list c で参照を保持している。
– im はメンバでもないし参照を保持していない。
– 消えているのはimだけでaに描画したテクスチャは表示され続けている。

推察1 MovieClip im がメンバじゃないから失われている

im は Test() の中で創られているので関数終了後はUnity上では参照を失っている。
なので自動でガベコレ的なものがuniSWF内で動作しているのであれば参照を保持しておけば大丈夫なはずだと考え、メンバに MovieClip 型の tmpim を追加した。

しかし結果は描画されず。

メンバ変数に格納すると参照をすぐに見いだせる。当たり前だけど参照そのもは破棄はされていないことが確認できた。

    if(tmpim != null) Debug.Log("alright!"); // ここを通る事は無い。

推察2 親子関係だけ外れてしまったのでは?

前項で調べた通り、参照先は失われていなかったので描画対象ではなくなったのではと考え、子の数を調べる関数でチェックを行った。

    private void TestMcStructOut(){
        var stage = MovieClipOverlayCameraBehaviour.instance.stage; 
        Debug.Log( "ListCount : " + this.c.Count + " : linkage has :" + this.linkage.numChildren + " : stage has :" + stage.numChildren );
    }

ここに記述されている ‘numChildren’ が子の数を保持しているプロパティ。
これを回すと最初の ‘Test()’ では linkage.numChildren が 1 だけど次のフレームで記述されたログには 0 になっている。

ここで外れてしまう親子関係だけどうにかするのも手としてはありなのだけどもう一歩踏み込んでみた。

親子関係は破壊されるけれども参照先として’MovieClip’が保持される事が分かったのでこれをもうちょっと掘り進めたら以下のようになる実装になっているということが分かった。

uniSWF_couldnotStoreMovieClip by Kunihiro OHGAKI, on Flickr

その場で ‘new’ した ‘MovieClip’ に ‘addChild’ した孫 ‘MovieClip’ は次のフレームでは親子関係が破棄されている。

まとめ

  • MovieClip をその場で生成する場合はメンバに格納すべき。
  • メンバに格納済の MovieClip でも、さらにその子の MovieClip に描画した場合は親子関係が破棄される。
  • その場で ‘new’ した MovieClip に直接 graphics を記述した場合は問題なく保持される。

対策

List形式とかで生成したやつは全部格納しておき、そこからアクセスするとか。

けっこう色んなパターンを調べてやっとこの結論に至ったのだけれども間違いがあったらご指摘いただきたい。

Unityによる2Dゲーム開発入門 ~プログラミング初心者がゲームを公開する最短コース

おまけ

uniSWFの問題点

  • uniSWFはswf化してからunityに取り込むので何かするにもFlaファイルを開かなければならないのでアプリケーション常に2つ立ち上げっぱなし。
  • さらにflaの素材編集となるとphotoshopも立ち上げなければならない。
  • さらにphotoshopのデータで曲線使ってたりするとillustratorも…
  • ちょっとしたレイアウト調整がGameObjectのInspectorでできない。やれるけど標準的ではない。
  • ソフトウェアレンダリングなので最初の1フレームはデバイスの画面によって拡大縮小された表示が見える。
  • 描画コストが高い。ドローコール減らせない。
  • unityのアップグレードにどこまでついて来れるのやら心配。
  • ドキュメントが完成してない。実は実装済みでドキュメントに記載が無いって事も多々ある。
  • swf作成のお約束が多い。
  • フォントが不自由。
  • フォントサイズも不自由。

uniSWFの使いどころ

  • アニメーション作業がしやすいのでガチャみたいな画面全域で表示しつつ演出過剰にしたい場所では作業を完全に切り分けられるのでオススメ。
  • monoDevelopでソースが見れるのでswfがどういう構造になってるのか勉強になるかも。

演出だけは突出した真価を発揮する。uniSWFをコレからも宜しくお願いします。間違ってもUI全部にuniSWFを使っては行けない!マジで!(涙目)

[JS]GoogleDocsの画像をgithubに貼付けるための直リンク生成bookmarkletを作った

githubにはwikiを記述できるのだけど、wikiに記述する画像はuploadできない。
dropbox等のローカルにファイルが占有されることがないかたちで共有するにはどうしたらいいか調べ所、google drive上のimageから直リンクが取れるという事がわかった。
Permalinks for Google Drive Images

手順

  1. google drive に共有用フォルダを作成する。
  2. 画像をup
  3. google drive 上にある画像を右クリックで 開く->ドライブビューワ で開く。
  4. URLを先のリンクに従って変更する
  5. ねんがんの 直リンクURI をてにいれたぞ

ここで4のURLを毎度変更するのが面倒だったのでブックマークレットを作成した。
続きを読む

[Unity3D][C#]MenuItemの第二引数は何?

UnityEdtorの出題1とMenuItemのまとめ

CodeIQにも出題されているのでやってみると面白いと思います。
日本Androidの会 秋葉原支部 Unity部 安藤 圭吾さんの問題に挑戦中!

[wp_ad_camp_1]

Q 1

  • お題:MenuItem
    • メニューに項目追加してください。

実装方法

よく使う難易度の低い出題。
メタデータを埋め込まなければならない。
メタデータはC#以外では聞き慣れなかったのでわからないひとにとってはけっこうしんどいのではと今更ながら思った。
– 参考:C#::属性

[MenuItem("directory/like/this")]
static void OnChoseMenu(){}

Q 1 Pratical

  • 追加:メニューアイテムから項目を実行することで、洗濯中のGameObjectに子オブジェクトを追加しなさい。
    解答例

肝になるのはValidate()関数。
ここの関数はBoolを返すのだけど、その返り値に応じて二つ目の関数が実行されるか否かが決定するというところ。
どういうながれでそうなってるのか、ドキュメントを見てみる。

Documentより

// Validated menu item.
// Add a menu item named “Log Selected Transform Name” to MyMenu in the menu bar.
// We use a second function to validate the menu item
// so it will only be enabled if we have a transform selected.
[MenuItem ("MyMenu/Log Selected Transform Name")]
static void LogSelectedTransformName ()
{
Debug.Log ("Selected Transform is on " + Selection.activeTransform.gameObject.name + ".");
}

この前半部分が本来実行させたい内容を記述している。
後半に実行させるにあたっての条件を記述している。
ここでTrueが返らないとメニューアイテムの項目がアクティブにならず、グレーアウト表示がなされる。

// Validate the menu item defined by the function above.
// The menu item will be disabled if this function returns false.

[MenuItem ("MyMenu/Log Selected Transform Name", true)]
static bool ValidateLogSelectedTransformName () {
// Return false if no transform is selected.
return Selection.activeTransform != null;
}

falseにすると挙動は変わらない。どういった処理の流れになるのか、色々ためしてみた。

2つ以上の項目名が同じでショートカットの文字列が違う

  • このとき、両方とも併存させることができるのでValidateにあたる関数はそれぞれ作成することができる。
  • ショートカット部分も含めて同じ文字列にしておかないと、Validate用の関数として認められない。

Validate用関数はいつ呼ばれているか

return する前にDebug.Log()を仕掛けたら、メニューが閉じられる瞬間にDebug.Logの記述がなされた。

内部的な処理そのものはメニューを開いたタイミングで走り、メニューを閉じると各UIにOnGUIが呼び出されてコンソールの記述が変更される、という流れなのだろう。

つまり、代に引数はあらかじめ実行するか否かの指定として機能していると仮定できる。

実処理用の関数でもtrueを指定するとメニューを開くだけで実行される

試しにvalidate後に実行される関数の第二引数をtrueにしたところ、メニューが開かれるだけで実行されてしまった。

デフォルトの値

パラメータを省略するとfalseになるようだ。

試しに同じ階層に返り値voidの同族性の関数を2つならべたところ、競合し、記述が後の方が採択された。
エラーは出なかった。

翻ってちゃんとした実装について

というわけで間違った使い方をいくつか書いてみた。

英語があまり堪能ではないので上述のような記述を見つける事が出来なかったけれども、やってみた結果、そういった理由のようなので、答えはそういうことなんだろう。

せっかくなので試した時に使ったコードも載せておく。

Unity4入門   最新開発環境による簡単3Dゲーム製作
浅野 祐一 荒川 巧也 森 信虎
ソフトバンククリエイティブ
売り上げランキング: 19,094

[C#]enumをint/stringにしたりint/stringからenumにしたり

[wp_ad_camp_1]

できました。

audio-technica ダイナミックヘッドホン ATH-W1000X

参考

[RubyMotion][iOS]UITableViewControllerのおさらいとpresentModalViewControllerが非推奨されてたのを初めて知った事

Rubyの勉強を始めたのでせっかくならば、とRubyMotionを導入してiOSの仕様もおさらいしながら進めている。
相変わらずの揮発性記憶力なので再学習に近く、非効率的な自認はあるが…。
[wp_ad_camp_1]

RubyMotion

RubyMotionでは動的言語を使っている事も合って実行時の動作がとても多いのでコンパイラによる記述ミスを発見するのが遅れがち。
また、ログも自動で吐き出されるものはシンボルやアドレスだけ表示されるので追いにくいのはXcodeのそれを継承している。
またiOSフレームワークの記述方法が冗長なためにRubyMotionでも同様に記述は冗長になりやすい。

Obj-cに慣れているのであれば、あえてRubyMotionを使わずともXcodeの強力な補完機能を使う等でも良いと思う。
しかし、UIの位置調整や実行時のデータ内容確認をREPLという機能でターミナル上からリアルタイムで確認することができる。
これはとてつもなく便利で、これだけでも十分に利用価値がある。

しばらくはこれで遊んでみようと思う。

基本的な作り方はターミナル上のコマンドでテンプレートを生成したら、app_delegate.rbを編集し、必要なViewControllerを追加して行くような感じになる。
この辺はチュートリアルが良く出来ていてすぐに理解できると思う。

RELP

よく使う流れ

“`
delegate = UIApplication.sharedApplication.delegate

delegate とれたよー

blue_view = delegate.instance_variable_get(‘@blue_view’)

blue_viewに@blue_viewてメンバの参照を格納したよー

blue_view.frame = [[10,30],[200,100]]

blue_viewのframeの値を変更したよー

“`
この時点でsimulatorにはblue_viewの矩形位置が変更されているのが確認できる。

blue_view.frame = [[10,30],[200,75]]
もう一度代入することで変更が再度適用されているのが確認できる。
このような感じでRELPはターミナル上から記述を変更することで変更をリアルタイムで確認できてしまう。
アニメーション用のパラメータなども同様なので、Xib使わずに数値で調整している人にとってはオススメできるのではなかろうか。

UITableViewControllerとmodal呼び出し

たのしいRuby 第4版