20200922のUnityに関する記事は9件です。

Unity ML-agents で実行条件を変えて学習時間を比較してみた

CPU/GPU、UnityEditor/ビルド、ビルドの複数実行、Agentの複数実行と、
実行条件を変えて学習時間を比較してみました。
プログラムはRollerBallを参考につくっていて、こちらに挙げてあります。

環境

  • Windows10
  • Python 3.7.9
  • TensorFlow 2.3.0
  • Unity 2019.4.10f1
  • ML-Agent Release6

学習の高速化

  • GPU で計算する(判断基準は下に記載)
  • ビルドした exe で学習させる
    • --env
  • --no-graphics オプション : 画面表示なし
  • 複数同時起動、CPUのマルチコア(スレッド)が最大
    • --num-envs
  • Agent を複製して実行する

Behavior ParameterのInterface DeviceにGPUを設定する判断基準

単純な推論であればCPUのほうが早い。GPUを選択する基準は以下の通り。
1. Visual Observation
2. エージェント数 * Observation > 1024
3. エージェント数 * 隠れ層の数 > 1024

学習時間の計測結果

手法 学習時間(秒) CPU使用率 補足
UnityEditor 68 25 CPU
GPU 71 25 Behavior Parameter に GPU を設定、※1
ビルド 86 13 ※2
複数同時起動 55 35 --num-envs=4
Agent 複製 21 25 複製4つ、UnityEditor

※1 それぞれ1回の測定なので、数秒は誤差の範囲
※2 ビルド版が UnityEditor より遅くなっているのは、Python とビルドアプリがCPUを食い合っているためだと思われる

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

Could not establish connection with unity package manager

open terminal type in
setx UNITY_NOPROXY localhost

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

5 Czekotolada による 質問 · 2019年02月25日 17:18 · c#package Could not establish connection with unity package manager

open terminal

setx UNITY_NOPROXY localhost

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

【webGL】ブラウザだとカクついて動かなかったお話【chrome】

この記事でできること

  • unityroomで作品を公開した際、もしカクついて全く動かないなぁ、というときに、chromeの設定で解決できるかもしれない。
  • キーワード…「ハードウェア アクセラレーション」

経緯と問題

FieldWalkingをunity1weekGAMEJAMで公開後、評価期間が終了したのでアップデートを繰り返していました。

その途中、演出としてボリュームを上げたところ、ブラウザ上ではかくついて確認できなくなりました。

スクリーンショット 2020-09-22 9.02.42.png

あれこれと
Unityの描画クオリティであったり、
カメラのカリング設定もしましたが、
ブラウザ上では動作確認が難しい状態が続きました。

chromeの設定を見てみると、
「ハードウェア アクセラレーションが使用可能な場合は使用する」の項があったので
google先生に確認したところ、推奨としてはオンのようでした。(調査時点ではオフでした)
スクリーンショット 2020-09-22 9.10.57.png


結果

chromeの「ハードウェア アクセラレーションが使用可能な場合は使用する」をオンをしたら、
ブラウザ上でも確認することができました。


宣伝

unityroomの1weekGAMEJAMで公開した2作品は、評価期間終了後もアップデートしています。
ぜひプレイしていってください。

FW11ss01.png

SS_AddBalance101.png

また、AddBalanceについては、cluster版も試作としてリリースしました。
こちらもみなさまアバターで遊びに来てくださいませ!!

AddBalanceForCluster2.png

AddBalanceForCLusterAnim.gif

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

【webGL】Uncaught RangeError: Maximum cal stack size exceeded【このエラーなに?】

この記事でできること

  • unityroomなど、webGL形式のものをブラウザで起動した際に起こる特定のエラーを解決することができます。

こんなエラーが出たことありませんか?

  • スクショはこんな感じ
    スクリーンショット 2020-09-22 8.39.09.png

  • テキストで書くとこんな感じ

An error occurred running the Unity content on this page.
See your browser JavaScript console for more info.
The error was:
Uncaught RangeError: Maximum cal stack size exceeded

解決策

  • chromeの場合は、キャッシュを削除したら解決しました。

スクリーンショット 2020-09-22 8.39.20.png

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

MagicLeapで床にオブジェクトを配置する方法

開発環境

Unity : 2019.3.7f1
LuminOS : 0.98.11, APILevel 8
MagicLeap : UnitySDK 0.24.1
MagicLeap : ToolKit 特にバージョン表記等はないので現時点(2020/09/22)での最新

MagicLeapToolKitのDLはこちらから

今回開発したアプリのリポジトリはこちらになります

完成するもの

下準備

ProjectSettings > MagicLeap > ManifestSettingsにて以下の項目にチェックを入れました

  • ControllerPose
  • LowLatencyLightwear
  • WorldReconstruction

Manifest.png

スクリプト等

今回のスクリプトはMagicLeap ToolKitのPlaceOnFloorを改造したものです

PlaceOnFloor.png

素のPlaceOnFloorのままだと初回の床判定以降は床判定を行わないので何度でも床判定を行えるようにしました。

改造したFloorChecker.cs

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

#if PLATFORM_LUMIN
using UnityEngine.XR.MagicLeap;
#endif


namespace FloorCheck
{
    /// <summary>
    /// MagicLeapToolsのFloorOnPlaceを改造したクラス.
    /// 床検知を何度もにできるようにする.
    /// </summary>
    public class FloorChecker : MonoBehaviour
    {
        readonly float HeadLocationIdleThreshold = 0.003f;
        readonly float HeadRotationIdleThreshold = .3f;
        readonly int HistoryCount = 5;
        readonly float HeadIdleRequiredDuration = .2f;

        // Public Properties:
        public Vector3 Location
        {
            get;
            private set;
        }


        [Tooltip("Does content's content match it's transform forward?")]
        [SerializeField] bool flippedForward;


        List<Vector3> headLocationHistory;
        List<Quaternion> headRotationHistory;
        float headLocationVelocity;
        float headRotationVelocity;
        Transform mainCamera;
        bool headLocationIdle;
        bool headRotationIdle;
        bool headTemporarilyIdle;
        bool headIdle;
        bool placementValid;


        //Init:
        void Awake()
        {
            //refs:
            mainCamera = Camera.main.transform;

            //requirements:
            if (FindObjectOfType<MLSpatialMapper>() == null)
            {
                Debug.LogError("PlaceOnFloor requires and instance of the MLSpatialMapper in your scene.");
            }
        }


        //Flow:
        void OnEnable()
        {
            //sets:
            headLocationHistory = new List<Vector3>();
            headRotationHistory = new List<Quaternion>();
        }


        //Loops:
        void Update()
        {
            //let headpose warmup a little:
            if (Time.frameCount < 3)
            {
                return;
            }

            HeadActivityDetermination(); 
        }


        //Coroutines:
        IEnumerator HeadIdleTimeout()
        {
            yield return new WaitForSeconds(HeadIdleRequiredDuration);
            headIdle = true;
        }


        void HeadActivityDetermination()
        {
            //history:
            headLocationHistory.Add(mainCamera.position);
            if (HistoryCount < headLocationHistory.Count)
                headLocationHistory.RemoveAt(0);

            headRotationHistory.Add(mainCamera.rotation);
            if (HistoryCount < headRotationHistory.Count)
                headRotationHistory.RemoveAt(0);

            //location velocity:
            if (headLocationHistory.Count == HistoryCount)
            {
                headLocationVelocity = 0;
                for (int i = 1; i < headLocationHistory.Count; i++)
                {
                    headLocationVelocity += Vector3.Distance(headLocationHistory[i], headLocationHistory[i - 1]);
                }
                headLocationVelocity /= headLocationHistory.Count;

                //idle detection:
                if (headLocationVelocity <= HeadLocationIdleThreshold)
                {
                    if (!headLocationIdle)
                    {
                        headLocationIdle = true;
                    }
                }
                else
                {
                    if (headLocationIdle)
                    {
                        headLocationIdle = false;
                    }
                }
            }

            //rotation velocity:
            if (headRotationHistory.Count == HistoryCount)
            {
                headRotationVelocity = 0;
                for (int i = 1; i < headRotationHistory.Count; i++)
                {
                    headRotationVelocity += Quaternion.Angle(headRotationHistory[i], headRotationHistory[i - 1]);
                }
                headRotationVelocity /= headRotationHistory.Count;

                //idle detection:
                if (headRotationVelocity <= HeadRotationIdleThreshold)
                {
                    if (!headRotationIdle)
                    {
                        headRotationIdle = true;
                    }
                }
                else
                {
                    if (headRotationIdle)
                    {
                        headRotationIdle = false;
                    }
                }
            }

            //absolute idle head determination:
            if (headLocationIdle && headRotationIdle)
            {
                if (!headTemporarilyIdle)
                {
                    headTemporarilyIdle = true;
                    StartCoroutine(HeadIdleTimeout());
                }
            }
            else
            {
                if (headTemporarilyIdle)
                {
                    headIdle = false;
                    headTemporarilyIdle = false;
                    StopCoroutine(HeadIdleTimeout());
                }
            }
        }


        /// <summary>
        /// 指定したRayの位置に床があるか否か、ある場合はその座標も返す.
        /// </summary>
        /// <param name="ray"></param>
        /// <returns></returns>
        public (bool, Vector3) LookingAtFloorDetermination(
            Ray ray)
        {
            //cast to see if we are looking at the floor:
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                MagicLeapTools.SurfaceType surface = MagicLeapTools.SurfaceDetails.Analyze(hit);

                if (surface == MagicLeapTools.SurfaceType.Floor)
                {
                    Location = hit.point;
                    placementValid = true;
                    return (true, Location);
                }
                else
                {
                    placementValid = false;
                    return (false, Vector3.zero);
                }
            }
            else
            {
                placementValid = false;
                return (false, Vector3.zero);
            }
        }


    }
}

FloorCheckerを利用するFloorCheckOnPlaceContent.cs

using System;
using MagicLeapTools;
using UnityEngine;

namespace FloorCheck
{

    /// <summary>
    /// トリガを入力したときに床を判定し、床の場合はオブジェクトを配置するサンプル.
    /// </summary>
    [RequireComponent(typeof(FloorChecker),typeof(AudioSource))]
    public class FloorCheckOnPlaceContent : MonoBehaviour
    {

        [SerializeField] AudioClip pressClip;
        [SerializeField] AudioClip successClip;
        [SerializeField] AudioClip failedClip;
        [SerializeField] GameObject content;
        [SerializeField] Pointer pointer;
        FloorChecker floorChecker;
        AudioSource audio;


        void Start()
        {
            floorChecker = GetComponent<FloorChecker>();
            audio = GetComponent<AudioSource>();
        }


        public void OnTriggerDown()
        {
            audio.PlayOneShot(pressClip);
            (bool onFloor, Vector3 pos ) result = floorChecker.LookingAtFloorDetermination(new Ray(pointer.Origin, pointer.Direction));
            if (result.onFloor)
            {
                audio.PlayOneShot(successClip);
                content.transform.position = result.pos;
            }
            else
            {
                audio.PlayOneShot(failedClip);
            }
        }



    }
}

シーンの構成

シーンの構成は以下の画像の通りになっています

Scene.png


MainCameraは Assets > MagicLeap > Core > Assets > Prefabs にある物を使いました

MainCamera.png


ControlPointerは Assets > MagicLeap-Tools > Prefabs > Input から

ControllerPointer.png


今回はSpatialMapperを表示してどのメッシュの判定が通っているかをわかりやすくするので Assets > MagicLeap > Core > Assets > Prefabs のMLSpatialMapperも利用します

MLSpatialMapper.png

MLSpatialMapperにはメッシュを生成するルートとなるオブジェクトが必要なのでシーン上にMeshRootオブジェクトを作成しそれをあてがっています

SpatialMapper.png


FloorCheckerを利用するクラス等はこのような構成になります
効果音は魔王魂さんから拝借

FloorChecker.png

トリガ入力に対応して床判定を行うためにControlPointerのイベントにFloorCheckOnPlaceContentのOnTriggerDownを登録しています

Attack.png

完成

実機にビルド or ZeroIterationで動作確認をすれば

これで床を判定し、床だけに配置したいオブジェクトとかの実装ができるようになります

感想

この判定を使えば床判定の入ってるメッシュだけAgentのNavMeshを晴れたりできるかも?

まだやってない、出来たら記事にするかもしれません

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

UVScrollシェーダーの書き方

はじめに

この記事は以下のサイトの記事を参考にさせていただいてます
https://qiita.com/Nekomasu/items/d50a4409e48ad77bc7f2
https://amagamina.jp/unity-shader/

制作背景的な

そもそもUVスクロールをなぜ作ろうとしたの?
->インターンの実装で少しでも画面をにぎやかしたかったから。
以上!!!

仕様的なもの

UnlitShaderで作成
必要プロパティ
+ テクスチャを入れるためのMainTex
+ X軸のスクロールスピードを制御する_ScrollX
+ Y軸のスクロールスピードを制御する
ScrollY

時間が進むごとにスクロールさせたいので定義済みの値である_Timeをスクロールの処理に追加

実際のコード

UVScroll.shader
Shader "Unlit/UVScroll"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _ScrollX("X ScrollSpeed",Range(0.0,1.0))=0.1
        _ScrollY("Y ScrollSpeed",Range(0.0,1.0))=0.2
    }
    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 _ScrollX;
            float _ScrollY;

            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
            {
                i.uv.x += _ScrollX * _Time;
                i.uv.y += _ScrollY * _Time;
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityPlugin/Android/基本

[環境]

OS: windows10 pro
IDE:Android Studio4.0.1
Unity 2019.4.5f1
確認した実機: Galaxys8

[参考]

[Android用Plugin(java[aar])の作成(https://qiita.com/fukaken5050/items/c9ac144344c5f6ff9f57)
https://dream-target.jp/2019/01/04/unity_android/
https://qiita.com/okuhiiro/items/1aaec487d1ab8b086095
https://ghoul-life.hatenablog.com/entry/2019/01/26/030622
https://note.com/attomicgm/n/ncb22f460e8b6

https://baba-s.hatenablog.com/entry/2018/09/18/170000 確認済

本文

UnityでAndroidProjectを出力する

・適当にCUBE等を配置する。
・Unityでプロジェクトを作成する(例:TestAndroidPlugin)
・「ExportProject」「DevelopmentBuild」にチェックします。
image.png

・AndroidにスイッチしバンドルIDを設定する。
・com.ore.TestAndroidPlugin) → Javaでは重要なので意識してください。com.ore.TestAndroidPluginとなってる華胥ありますが私はここでつまづきました
・MinimumAPILevelを設定する(例:Android4.4 APILevel19) デフォルト
image.png

・Unityプロジェクトと同じフォルダにExport用フォルダを作成し、フォルダに移動してから「フォルダの選択」を押す(例:TestAndroidPlugin\Android)
 ・AndroidStudio用プロジェクトが生成される

AndroidStudioで読み込む

UnitySDKかAndroidStudioのSDKを使うか指定する。
image.png

プロジェクト解析にすこし時間がかかります。
・ビルドエラーは出ず問題なく実行できます。

image.png

Unityの機能をAndroidから使うため、classes.jar/android.jarを配置します。

今回の環境では以下に存在しました。
C:\Program Files\Unity\Hub\Editor\2019.4.5f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes

C:\Users\user\AppData\Local\Android\Sdk\platforms\android-30\
C:\Android\SDK\platforms\android-30

プラグインモジュールの追加

・メニューの「File」>「New」>「NewModule」を押す
 ・「AndroidLibrary」を選択し、「Next」を押す
image.png

 ・「Application/Library name」を設定する(例:UnityPlugin)
 ・「Package name」を右側の「edit」を押し、設定し、「done」を押す(例:com.ore.unityplugin)
 ・「MinimumSDK」をUnityに設定したものと同じか、小さいものに設定する(例:API23)
image.png

 ・「Finish」を押す

■「build.gradle」の編集

Unityライブラリファイル"unity-classes.jar"(またはclasses.jar)を、出力されるaarファイルに含めないようにします。

//classes.jarファイルは、コンパイルのときのみ使用する
//Android Studio 3系では、「implementation fileTree」と記述すると
//classes.jarも含まれてしまうため「compileOnly」と記載して
//jarファイルはコンパイルのみ使用するようにします。

dependencies {
    //implementation fileTree(dir: "libs", include: ["*.jar"])  NG
    compileOnly fileTree(dir: 'libs', include: 'unity-classes.jar')

    implementation 'androidx.appcompat:appcompat:1.2.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

 ・右上に出ている「SyncNow」を押す

プラグイン用javaクラスの追加

・プロジェクトツリーから「プラグイン名」>「Java」>「パッケージ名」を選択(例:unityplugin>Java>com.ore.unityplugin)
 ・(AndroidTest)や(Test)と書かれていないもの(一番上)
・メニューの「File」>「New」>「JavaClass」を押す
・「Name」を設定(例:TestPlugin)
・「OK」を押す
・以下はトースト表示する簡単なサンプル

image.png

package com.ore.unityplugin;

import android.app.Activity;
import android.widget.Toast;

import com.unity3d.player.UnityPlayer;

public class TestPlugin
{

    public static void showToast(final String message) {
        final Activity activity = UnityPlayer.currentActivity;
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

UnityPlayerでビルドエラーがでるので、unityLibrary-libsの[unity-classes.jar]を UnityPlugin-libsにコピーする。IDE右上の[SyncProject with Gradle]を押すとビルド成功します。
image.png
 ・aarのサイズは16K程度です。100kくらいある場合はunity-classes.jarも含んでおり、プラグイン利用時にUnityが持つJarと衝突します。

作成したPluginを使う

UnityProject/Asset/Plugins/Androidに作成したプラグイン *.aar を配置する。

スクリプト

TestPlugin を作成して適当なGameObjectに配置する。UnityでButtonとTextを生成してTestPlugin と接続する。
最後にAndroid実機で動作確認をする。

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

public class TestPlugin : MonoBehaviour
{
    [SerializeField] private Button _button = null;
    public Text m_text = null;

    private void Start()
    {
        _button.onClick.AddListener(() => OnButtonClick(_button));
        m_text.text = "start";
    }

    private void OnButtonClick(Button button)
    {
        m_text.text = "OnButtonClick_1";

        using (AndroidJavaClass javaClass = new AndroidJavaClass("com.ore.unityplugin.TestPlugin"))
        {
            Debug.Log("OnButtonClick");
            m_text.text = "OnButtonClick_2";

            javaClass.CallStatic("showToast", "Test");
        }
    }
}

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

UnityでHTTP(GET)通信によるJSONデータ取得

たまに使うことあって、
その都度「どうだったけー?」って悩むので自分用備忘録。

UNityアセットストアから
JSON Object
というアセット をダウンロード

Image from Gyazo

プログラム中、GET通信したいタイミングに

StartCoroutine(connect("https://URL"));

を記述。




こんな感じ

update.cs
void Update() {
    //通信したいURLを代入
    StartCoroutine(connect("https://URL"));
}

IEnumerator connect(string url){
    WWW www = new WWW(url);
    yield return www;
    print(www.text);
    JSONObject json = new JSONObject(www.text);
    //powerというkeyのvalueを取得
    JSONObject power = json.GetField("power");
    print("power is " + power.n); ;
}

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