20200524のUnityに関する記事は3件です。

模倣学習を使って人らしい動作を獲得できるか? - 1. Unityで強化学習を試す -

目指すゴール

まずはキャラクターに頭をなでてもらいたい。
頭の位置を目標点としたIKと周期的な頭位置の変更などでも実現出来ると思いますが、
模表学習による人の獲得をゴールとして進めていきます。

まずは強化学習で人らしい動きを獲得できないことの確認、
その後、模倣学習により、人の教示により人らしい動きを教えることをします。

本記事では、サンプルの実行までをします。

強化学習と模倣学習の事例

敵と戦うようなゲームで模倣学習と強化学習を使った事例では、強化学習(学習手法が何かは不明)では岩に隠れながら敵と戦うような動作を獲得できなかったのに比べ、模倣学習ではできたとのことです。
他にも強化学習でうまくかなかった例として、CoastRunner7が挙げられていました。

Unityで気軽に強化学習

Unityでは、ml-agentsというライブラリを使って、Unityで自分で作った環境内で、自分で設計したエージェントの動作を学習させることができます。
ここに必要な概念がまとまっています。Unityの知識が少しあれば、強化学習の知識などなくても理解できるはずです。

サンプルを動かす

このチュートリアルがシンプルでわかりやすくて、自分でエージェント作るのに必要な基礎も習得できるのでおすすめです。

エージェントを作る場合、次のコードを書きます。

  • (エピソードの初期状態)エピソードの初期化処理、エピソード終了定義、エピソード終了時の再初期化処理
  • (観測値を作る) 観測値をベクトルなどの形式に変換する
  • (アクションを受け取り報酬を返す)受け取ったアクションを環境に反映する。例えば、制御信号を、物理世界の力にする。環境の値を元に報酬を計算する
  • (optional:テスト用コード) コントローラーやキーボード入力をアクションの値に変換

観測値を作る際のTipsとして、Analytical Solutionを書く場合に(つまり、自分でアルゴリズムを考えたりする場合に)計算に使いそうな要素を観測値として入れるのが目安らしいです。

(一点注意点ですが、PolicyGradientの改良版アルゴリズムでボールをゴールまで動かすというプログラムになっています。最後に作成する学習パラメータの設定ファイルのみ、PolicyGradientのパラメータの設定が不足していてエラーが出るので、それだけ修正しました。)

Unityで実行してみた結果がこれです。

結果を見てみる

Tensorboardで実行結果のログを見れます。
このサンプルだと、50000エピソードの繰り返し(6分程度で学習完了)で、
ほぼ100%はタスクを完了出来るようになっています。
他にも内部的なメトリックを見ることができ、モデルの改善とか比較とかにも使えそうです。

Screenshot from 2020-05-24 14-52-14.png

エピソードの並列化

このサンプルのようにTrainingArea GameObjectを作り、
その子としてゲームオブジェクトを入れておくことで、エピソードの並列化が容易であるとのことです。
Game ObjectをAssetsにD&DするとPrefabが生成されて、
PrefabをSceneにD&Dすると、TrainingArea GameObjectと同等のGameObjectが作られる。
その上でPythonのmlagents-learnコマンドを実行、Editor上でUnityを実行することで、エピソードが並列実行される。

Editor上での実行について

PythonとUnityはソケットかなにかで繋がっているようですが、
なぜか、Editor上での実行ではなく、アプリとして実行した場合、同じローカル上でUnityアプリを実行したとしても、トレーニングが開始されません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

unity1weekに参加してみて

unity1weekに参加してみて公開するまで

unity1weekとは

Unityを使って1週間でゲームを作るイベントです。
以下、本家サイト
Unity1週間ゲームジャム

ゲームのテーマを確認

が今回のテーマになります。

ゲームの内容と目的を考える

今回の個人的大目標は "unity1roomで何か最低限の状態をだす"でした。

密は、ほとんど思いつかなかったのでサーバーとクライアントが密につながっている
クイズゲームということにしています。

作ったゲーム

タイトルはカメQです

タイトル画面
f3333ba636910b808cc787ac05117173.png

クイズ解答画面
54449c9994d6fe83dac84d97ec1561fe.png

4択のクイズで正解を選んだらスコアが増えるゲームとして作りました
*クイズの中身は現在作成中になります

公開手続き

今回は、躓いたこともいくつかあったので作業手順も一緒に残していきます。

WebGlでビルド

unity1weekでは、unityroomに投稿する必要があるので、WebGlでビルドをしていました。
*実際のビルドには、30分前後もかかったりしたので注意が必要です

ファイルのアップロードを選択

ゲームの概要を入力

067c94a70c62f96c6659f166dc56f635.png

WebGlの設定を入力

WebGl_Config.png

WebGlのアップロード作業

画面に出てくる拡張子とあっているものを選択してアップロードしていくだけ

ここで設定完了なので確認をしてみる

動かない....,,,,

エラーとしては、サーバー側がUnityroom側からのリクエストを受け付けないようになっていた

azure側のcsrfにunityroomを追加してみる

設定変更.png

通信イメージ

unityroomの場合、外部にリクエストを送信するサーバーは別になっているので以下のような図形になります(2020年5月現在)
quizSystemDocument.png

最後に

今回は、unityroomへのアップロード以外に、通信処理を入れた場合の設定値等についても知見を得られることが多くあり良かったです。

今回は参加できてよかったです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity]動画にshaderを使って簡単なエフェクトをかけてみる

はじめに

自分が手伝っているイベントのVRizeでちょっとshader使いたいねとなったので、一時期ちょっと勉強していた知識を頼りにshaderを書いてみました。ちなみに凄いこと出来るわけではないので凄い人は期待しないでください。

対象者

shaderの基本的な事を理解している人
やることはUVスクロールなのでそれが理解できれば大丈夫です。

完成物

こんな感じのテストでを作りました。

まずは画像をスクロールさせてみる

完成物だけ作りたい人はスルーしてください。
適当なplane(Cubeとかでも可)を用意して、以下のshaderコードと共にマテリアルをオブジェクトにアタッチしてください。
_MainTexに適当な画像を指定すればplane上で画像が表示され、スクロールするはずです。

Shader "Unlit/scroll"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _ScrollSpeed ("ScrollSpeed", float) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _ScrollSpeed;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                if(i.uv.y > 0.7){
                    i.uv.x = i.uv.x + _Time *_ScrollSpeed * -2;
                }
                else if(i.uv.y > 0.4000){
                    i.uv.x = i.uv.x + _Time *_ScrollSpeed * 2.5;
                    //.uv.y = i.uv.y + _Time *_ScrollSpeed * -0.5;
                }
                else{
                    i.uv.x = i.uv.x + _Time *_ScrollSpeed;
                    //i.uv.y = i.uv.y + _Time * _ScrollSpeed;
                }

                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

仕組みは簡単で、fragmentシェーダ内でuv.xに時間経過を取得できる_Timeを乗算することでTextureをuvのx方向にスクロールさせています。また、インスペクタから自由に速度を調節できるようにするために_ScrollSpeed変数を宣言して使用しています。
更に、if文でuv.yの値に応じて* -2* 2.5などとしてやることで、部分的にスクロール速度が変化するようになっています。

動画で同じことをする

動画でやる方法ですが、まずは動画を流す対象としてRenderTextureをプロジェクトタブから用意します。
次に動画を流したいplaneにVideo Playerコンポーネントをアタッチします。
そうしたら、Video PlayerコンポーネントからVideo Clipに流したい動画を指定し、Render Mode > RenderTextureに変更し、Target Textureに先ほど作成したRenderTextureを指定します。(すべてVideo Playerの設定です)
後はRenderTextureを先ほどのshaderに...と思うと思いますがそのまま持っていくと映像が破綻しはじめます。
原因は調べていませんが、恐らくVideo PlayerからRenderTextureに映像を書き込む際にShaderで行った変更が適用されてしまっているのではないかなと考えたので、回避策としてRenderTextureからTextureに変換することでワンクッション置くことを考えました。
変換方法は調べたらすぐにでてきました。参考
参考を頼りに実装したスクリプトがこちらです。
作成したスクリプトは映像を流したいオブジェクト(今回であればplane)にアタッチしてください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class movie : MonoBehaviour
{
    public RenderTexture tex;
    private Material material;
    // Start is called before the first frame update
    void Start()
    {
        this.material = GetComponent<Renderer>().material;
    }

    // Update is called once per frame
    void Update()
    {
        Texture myTexture = toTexture2D(tex);
        this.material.SetTexture("_MainTex", myTexture);
    }

    Texture2D toTexture2D(RenderTexture rTex){
        Texture2D tex = new Texture2D(512, 512, TextureFormat.RGB24, false);
        RenderTexture.active = rTex;
        tex.ReadPixels(new Rect(0,0, rTex.width, rTex.height), 0,0);
        tex.Apply();
        return tex;
    }
}

RenderTextureからTextureに変換する部分は、参考ままにtoTexture2Dメソッドとして定義しています。
後は、Updateで毎フレームRenderTextureTextureに変換し、material.SetTextureでshaderにテクスチャを渡すことで、
好きなように先ほど作ったshaderや、オリジナルのshaderでエフェクトをかけれるようになります。

終わりに

久々にshaderを書いたのでとても楽しかったです。(ほんの数行だけど)
何かあったら、コメントで教えていただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む