AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

SkinnedMeshRendererのTextureを動的に書き換える

Textureをスクリプトから編集してみる - のしメモ アプリ開発ブログ
こちらを参考に適用先をSkinnedMeshに変更してみた。

リボンを青くする

対象Humanoidでは、
U_Char_0のSkinnedMeshには、マテリアルが7つ登録されているが、materialは先頭をとれるらしい
配列で取れば7つ取れるでしょう。
先頭は「0.mt_ribbon_01.png」でリボンのマテリアルが登録されている。
手始めにこれを書き換えてみる。
readできません的なエラーが出る。importSettingで変更可能とあるので、リボンのテクスチャ画像のInspectorを見ると
read/writeフラグがOFFになっているのでOnにする

f:id:yasu9780:20170124145248p:plain

おー青くなった!
SetPixelとGetPixelは遅いので禁じ手らしいが、出血時のみ服に赤いシミを作るぐらいは一瞬だしなんとかなるんではないか?
この方法で、武器で攻撃された瞬間に、服や顔に赤いシミをランダムに適当につければ返り血表現ができるんでは。

実行時間を検証

pixelサイズを調べてみると
pixels.Length = 65536 となっている。
256x256だら64K個のpixel数となっていた。
一回当たりの実行時間を調べてみる


精密実行時間を3回調べてみると
25 33 27
ミリ秒だった。
1ミリ秒は1/1000秒=0.001秒のこと。

UpdateのTime.deltaTimeは、だいたい1/60秒なので、0.01666秒
ちなみにFixedUpdateはデフォルトで0.02秒ごとに呼ばれる(物理演算の実行間隔)

この処理は30ミリ秒ぐらいだから、0.03秒ぐらいかかっている。ということは2fpsぐらいかかってる。
べつに移動処理じゃないんだから、呼び出して表示されるまでに2/60秒かかるってだけだな。

テクスチャを読みだして、なにもセットしないで書き込んだら、2ミリ秒しかかかってなかった。
10倍速くなった。
やはりchange_pixelsの読み出しと、SetValue()を6万回で30ミリ秒程度かかっているってことか。
なにもセットしないとchange_pixels配列は0で埋まってるからリボンは黒くなる。

書き換えピクセル数を減らして実行時間を見る

書き換える回数減らせば速くなるってことか?

実際に半分だけ書き換えると8ミリ秒で終わった。
1000回にすると2ミリ秒。だいたい0.1fpsで終わる

これなら1000個程度の赤い点を打つだけならupdateの中で余裕できるはず。
f:id:yasu9780:20170124153254p:plain

服を赤くする

実際のpixel数はtexuteによりますね。
256x256なら64K個ですが、1024x1024なら1024x1024個なので相当増えます。


服のテクスチャにランダムに100000個赤い点。
服は1024x1024テクスチャだったので、10万個打ったので、さすがに65ミリ秒かかりました。
3fpsかかってる。512x512にすればもっと点減らせるでしょうけど。
でも、一回だけ呼ぶなら時間は気にしないでいいはずなんで、返り血に見える打ち方を研究しましょう。
f:id:yasu9780:20170124161204p:plain

デカールで血しぶき貼り付けた方が良かった

プロ生ちゃんのTシャツにデカール貼る記事を思い出したので、
プロ生ちゃんのTシャツに絵を重ねてみよう - Onoty3D
同様にニコニココモンズの返り血画像を張ってみた

f:id:yasu9780:20170124172404p:plain

こっちの方が全然いいじゃん orz

toon shaderでどうやるか分かりませんが、setPixelでやる話はお蔵入りの予感

        GameObject obj = FindDeep(this.gameObject, "U_Char_0");
        SkinnedMeshRenderer meshRenderer = obj.GetComponent<SkinnedMeshRenderer>();
        Texture2D mainTexture = (Texture2D)meshRenderer.material.mainTexture;
        Color[] pixels = mainTexture.GetPixels();

        // 書き換え用テクスチャ用配列の作成
        Color[] change_pixels = new Color[pixels.Length];
        for (int i = 0; i < pixels.Length; i++)
        {
            Color pixel = pixels[i];

            // 書き換え用テクスチャのピクセル色を指定
            Color change_pixel = new Color(pixel.r, pixel.g, 1, pixel.a);
            change_pixels.SetValue(change_pixel, i);
        }

        // 書き換え用テクスチャの生成
        Texture2D change_texture = new Texture2D(mainTexture.width, mainTexture.height, TextureFormat.RGBA32, false);
        change_texture.filterMode = FilterMode.Point;
        change_texture.SetPixels(change_pixels);
        change_texture.Apply();

        // テクスチャを貼り替える
        meshRenderer.material.mainTexture = change_texture;