20200724のUnityに関する記事は8件です。

UnityのuGUIで8ドットフォントを書く

Unityで2Dの低解像度のドットがくっきり見えるようなゲームを作りたいと思いました。
そこでまず文字を書こうと思い、8x8ドットのフォントを描きましたがこれをuGUIで表示する方法がわからない。
ググるとShoeBoxを使ったビットマップフォントの使い方など出てきたのですが、どうにもカーニングしてしまって等幅で書いてくれない…
探していたらこのような サイト があったので参考にさせていただきまして、自分の覚書としてまとめたものです。

まず作ったフォントはこれです。
8x8font.png

128x48で数字とアルファベット少しの記号がアスキーコードに従って入っています。
縦64ドットになっているのはキリを良くするためです。

それでこれをCustomFontとして登録したいわけですけど、パラメータを手作業で入れるのは無理なので.fontsettingsファイルを吐き出すことにしました。

fontsetting.py
# fontsetting を作ろう
fileName = "8x8font01.fontsettings"
imageWidth = 128
imageHeight = 64
fontWidth = 8
fontHeight = 8
charid = 0x20

header = ('%YAML 1.1 \n'
'%TAG !u! tag:unity3d.com,2011:\n'
'--- !u!128 &12800000\n'
'Font:\n'
'  m_ObjectHideFlags: 0\n'
'  m_CorrespondingSourceObject: {{fileID: 0}}\n'
'  m_PrefabInstance: {{fileID: 0}}\n'
'  m_PrefabAsset: {{fileID: 0}}\n'
'  m_Name: CustomFont01\n'
'  serializedVersion: 5\n'
'  m_LineSpacing: {}\n'
'  m_DefaultMaterial: {{fileID: 0}}\n'
'  m_FontSize: 0\n'
'  m_Texture: {{fileID: 0}}\n'
'  m_AsciiStartOffset: 0\n'
'  m_Tracking: 1\n'
'  m_CharacterSpacing: 0\n'
'  m_CharacterPadding: 1\n'
'  m_ConvertCase: 0\n'
'  m_CharacterRects:\n')

part = ('  - serializedVersion: 2\n'
'    index: {}\n'
'    uv:\n'
'      serializedVersion: 2\n'
'      x: {:.5f}\n'
'      y: {:.5f}\n'
'      width: {:.5f}\n'
'      height: {:.5f}\n'
'    vert:\n'
'      serializedVersion: 2\n'
'      x: {}\n'
'      y: {}\n'
'      width: {}\n'
'      height: {}\n'
'    advance: {}\n'
'    flipped: 0\n')
footer = ('  m_KerningValues: []\n'
'  m_PixelScale: 0.1\n'
'  m_FontData: \n'
'  m_Ascent: 0\n'
'  m_Descent: 0\n'
'  m_DefaultStyle: 0\n'
'  m_FontNames: []\n'
'  m_FallbackFonts: []\n'
'  m_FontRenderingMode: 0\n'
'  m_UseLegacyBoundsCalculation: 0\n'
'  m_ShouldRoundAdvanceValue: 1\n')

f = open(fileName,"w")

f.write(header.format(fontHeight))

height = fontHeight/imageHeight
for i in range(int(imageHeight/fontHeight)):
    y = 1.0 - (i+1)*fontHeight/imageHeight
    width = fontWidth/imageWidth
    for j in range(int(imageWidth/fontWidth)):
        x = j*fontWidth/imageWidth
        f.write(part.format(charid,x,y,width,height,0,0,fontWidth,-fontHeight,fontWidth))
        charid += 1

f.write(footer)
f.close()

これで出来た.fontsettingsファイルとフォントのPNGをUnityに渡します。
テクスチャはFilterModeをPointにします。
texture.png

フォント設定はこんな感じになります。
Line Spacingを縦サイズにしておかないと改行しても重なってしまいます。
fontsettings.png

あとはマテリアルを作ります。
ShaderをUnlit/TransparentにテクスチャにフォントのPNGを指定します。
material.png

それらをTextに設定すると等幅で8x8のフォントが書けます。
text.png

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

VCIの大きさがいきなり変わる-戻らない

結論

バーチャルキャストの手による拡縮は制限範囲がある。
だから制限範囲内に収まる様にモデルを調整しよう。

背景

VR配信・SNSサービスのバーチャルキャストでは、他のVRSNSに見られない仕組みとしてVCIというものがあります。VCIはバーチャル空間で取り扱えるアイテムであり、好きな場所で好きなタイミングで取り出すことができ、その挙動はスクリプトを用いて制御することでインタラクティブな効果を奏することができます。

対象

主に初心者

症状

  • 出てきたものを拡大(縮小)しようとすると急に大きさが変わる
  • (その上)拡大(縮小)で大きさが元に戻らない
  • 出てきたものを拡大(縮小)しようとすると急に消える

など

どういうことか

バーチャルキャストでは、アイテムを両手で掴んで広げたり縮めたりすることで、アイテムの大きさを変えることができる機能があります。しかし、際限なく大きさを変えられるのではなく、どうやら元のモデルの5-0.2倍までに制限されている様です(これは確かどこにも書かれてなかったはず)。

しかしながら、初期状態のscaleはいくらでも大きな(小さな)値をとることができるので、拡大縮小した瞬間その制限が課せられてしまい、倍率がジャンプしてしまうのです。

これは作ったモデルの大きさがいい加減な時に起きやすいです。例えば、テニスボールを作ろうとした時、厳密な大きさは良き知りませんが、だいたい直径5センチくらいに収めると思います。しかし、大きさに頓着せずに作ると、1mの大きさで出来上がってしまいます。これを、モデルのscaleで調整してしまうと、たとえばscale0.05とかになってしまいます。

そのままVCIとして出力し、このボールを手に持って大きさを変えようとすると、scaleは最初は0.05ですから、手での拡大縮小範囲の外にあるので、一番近い0.2までジャンプしてしまう、つまり急に直径が20センチメートルになってしまうのです。しかも元に戻せません。(一応スクリプトからいじれば戻せるけど、そういう問題ではないですよね?)

解決策

解決策は2つあります。
一つめの方法は、愚直にモデルの大きさを治す方法です。特に説明することもありませんが、正直面倒臭いです。

そこで、微調整程度なら私はいつも次の様にします
2つめの方法は VCI消失 その5 で紹介した、読み込みのセッティングを変える方法です。
下図の「asprin」を例にとって説明します。
image.png

3dモデルを選択すると、インスペクタにモデルの情報が表示されます。ここの"Convert Units"にチェックを外してあげてください。
image.png
チェックを確認したら、
scaleの値を出力した時scale1で所望の大きさになるように適当に設定してください。わからなかったらapplyを押してトライアンドエラーした方が早いかもしれません。先のテニスボールの例だと、0.05にするといいでしょう。
image.png
下の方にスクロールして"Apply"ボタンを押します。
image.png
すると、エディター上では大きさがかわったように見えます。
で実際VCIとして出力すると、ちゃんと治っています。 

ちなみに

私は最近になってもよくやりますが、幸いblenderに戻らずに直せるのでまだ甚大度は高くはないです。
一番面倒なのは原点の位置がおかしくなっていることでしょうか、、、これはunity上ではたしか調整できなかったはずですから、、、

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

【Unity(C#)】3次元空間にオブジェクトを重なりなく生成(表示)する方法

デモ

まずはデモです。

特定の範囲内にオブジェクトがランダムかつ、
メッシュ同士が重なって表示されることなく出現します。

GunShot3.gif

生成位置(表示位置)をランダムにすることは簡単なのですが、
立体的なオブジェクトをメッシュの重なりなく表示するのは
少々入り組んだロジックを考える必要がありましたのでメモしときます。

コード

まずはコード全文です。
今回は最初からHierarchyにオブジェクトを非表示で配置しておきました。
GenerateRandom.PNG

using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using Random = UnityEngine.Random;

/// <summary>
/// ブロックをランダムな位置にランダムなタイミングで表示
/// 位置被りナシ
/// </summary>
public class ActivateBlock : MonoBehaviour
{
    [SerializeField] private GameObject _blockParent;
    [SerializeField] private BoxCollider _blockBoxCollider;

    private const float _MIN_INTERVAL_VALUE = 0.5f;
    private const float _MAX_INTERVAL_VALUE = 2.0f;
    private const float _MIN_X_VALUE = -1.0f;
    private const float _MAX_X_VALUE = 1.0f;
    private const float _MIN_Y_VALUE = 0.5f;
    private const float _MAX_Y_VALUE = 2.0f;
    private const float _MIN_Z_VALUE = -1.0f;
    private const float _MAX_Z_VALUE = 1.0f;

    private bool _isGameStart = true;

    private bool _isSetablePositionX;
    private bool _isSetablePositionY;
    private bool _isSetablePositionZ;

    private int _randomNumber;
    private float _randomInterval;
    private float _randomValueX;
    private float _randomValueY;
    private float _randomValueZ;

    private readonly List<Vector3> _usePositionList = new List<Vector3>();

    void Start()
    {
        //空同然だけどリスト作っとく
        foreach (Transform child in _blockParent.transform)
        {
            _usePositionList.Add(child.position);
        }

        DelayInitBlock();
    }

    private async UniTask DelayInitBlock()
    {
        while (_isGameStart)
        {
            //ランダムな値
                _randomNumber = Random.Range(0, _blockParent.transform.childCount);
                _randomInterval = Random.Range(_MIN_INTERVAL_VALUE, _MAX_INTERVAL_VALUE);
                _randomValueX = Random.Range(_MIN_X_VALUE, _MAX_X_VALUE);
                _randomValueY = Random.Range(_MIN_Y_VALUE, _MAX_Y_VALUE);
                _randomValueZ = Random.Range(_MIN_Z_VALUE, _MAX_Z_VALUE);

            //選ばれたブロックの位置
            Vector3 selectedBlockPosition =
                    _blockParent.transform.GetChild(_randomNumber).gameObject.transform.position;

            //選ばれたブロックの位置は比較対象から一旦削除
            _usePositionList.Remove(selectedBlockPosition);

            //現在使用中のポジションのリストから今利用検討中のポジションが利用可能か判定
            foreach (Vector3 position in _usePositionList)
            {
                //表示位置被りがないかオブジェクトの大きさでチェック
                _isSetablePositionX =
                    Mathf.Abs(position.x - _randomValueX) > _blockBoxCollider.bounds.size.x ;
                _isSetablePositionY =
                    Mathf.Abs(position.y - _randomValueY) > _blockBoxCollider.bounds.size.y;
                _isSetablePositionZ =
                    Mathf.Abs(position.z - _randomValueZ) > _blockBoxCollider.bounds.size.z ;

                //座標のうち、全ての軸で被っていたら置けないのでやり直し
                if (!_isSetablePositionX && !_isSetablePositionY && !_isSetablePositionZ)
                {
                    _usePositionList.Add(selectedBlockPosition);
                    break;
                }
            }

            //位置被りがどれか1つの軸で無ければ実行する
            if (_isSetablePositionX || _isSetablePositionY || _isSetablePositionZ)
            { 
                Vector3 randomPosition = new Vector3(_randomValueX, _randomValueY, _randomValueZ);

                //ランダムな間隔でDelay
                await UniTask.Delay(TimeSpan.FromSeconds(_randomInterval));
                _blockParent.transform.GetChild(_randomNumber).gameObject.transform.position = randomPosition;

                //新しい使用中のポジションをリストに追加
                _usePositionList.Add(randomPosition);
            }
        }
    }
}

流れとしては下記です。
⓪"オブジェクトの座標を保存しておくリスト"を作成
①ランダムな座標を作成
②ランダムにオブジェクトを選択
③選んだオブジェクトの座標を"オブジェクトの座標を保存しておくリスト"の中から削除
④XYZの3軸それぞれで位置が被っていないか比較
⑤1軸でも座標が被っていないなら重なりなく表示可能なので表示する
⑥"オブジェクトの座標を保存しておくリスト"に今回利用した座標を追加

Bounds

オブジェクトの座標同士を比較するだけでは、オブジェクト同士の重なりを防ぐことができません。
ですので、今回はBoundsと呼ばれるオブジェクトの領域を指すもの利用することにしました。

BoxCollider.bounds.sizeでオブジェクトの持つコライダーの大きさが取得できます。

このオブジェクトの大きさを利用して、
新しく配置しようとしている座標既に利用済みの座標と比べてBounds一個分離れているか
どうかを判定すれば、位置被りをなくすロジックを組むことができます。

 //表示位置被りがないかオブジェクトの大きさでチェック
 _isSetablePositionX = Mathf.Abs(現在利用中のX座標 - ランダムに生成したX座標) > _blockBoxCollider.bounds.size.x ;
 _isSetablePositionY = Mathf.Abs(現在利用中のY座標 - ランダムに生成したY座標) > _blockBoxCollider.bounds.size.y;
 _isSetablePositionZ = Mathf.Abs(現在利用中のZ座標 - ランダムに生成したZ座標) > _blockBoxCollider.bounds.size.z ;

2020/07/26 追記
取得したいBoundsを持つオブジェクトが非アクティブな時、
Boundsの取得に失敗することなく、0を返します。(要注意)

まとめ

結構必要となるロジックだと思いましたが、意外と実装録を見つけられませんでした。
もっとスマートな方法があれば教えてください。

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

【Unity】Water Ripple For Screenを使ってみた

はじめに

WaterRippleForScreenはUnityで水の波紋を表現できるJose Hernandez氏作のアセットです。無料!!
リンクはこちら

ゲームを作成しているときに「水の波紋みたいなエフェクトできたらエモくね?」となったのですが、シェーダーの知識が全く無かったために自分で作成することができなかったのでアセットに頼ろうと調べていたときに見つけました。
このアセットに関して日本語で書かれた記事を発見できなかったので備忘録を兼ねてかいていきます。

利用方法

基本

アセットのインストール方法に関しては他の方がわかりやすく説明しているため、自分のプロジェクトにインポートできている前提で話をすすめます。
インポートすると、Assetsフォルダの中にWaterRippleForScreenというフォルダが作成されます。

まずは、WaterRippleForScreen/Scripts/に存在するRippleEffectsをエフェクトを適用したいCameraに貼り付けます。
image.png

背景の画像を適当に入れて、DetectClickにチェックを入れて実行し、ゲーム画面をクリックしてみてください(下の画像は見やすいようにWaveScaleを30にしています。)
ezgif.com-video-to-gif.gif

このように水の波紋のような効果をかけられるのがこのアセットの効果です。

スクリプトから呼び出す場合は以下のようにします。
まず、忘れては行けないのが

using WaterRippleForScreens;

今回はスペースキーの入力があったら波紋を呼び出すようにしていきます。
以下のスクリプトを適当なゲームオブジェクトにアタッチしてください。

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

public class hogehoge : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Camera cam = Camera.main;
            Vector2 target = new Vector2(0, 0);//Unity上の座標
            target = cam.WorldToScreenPoint(target);//カメラ座標に変換
            target.y = Screen.height - target.y;//WRFS用に座標を変換
            cam.GetComponent<RippleEffect>().SetNewRipplePosition(target); //新しい波紋を生成
       }
    }
}

RippleEffectのSetNewRipplePositionに画面座標を上下反転させたものを渡すことで波紋を生み出せます。
(DetectClickモードでもクリックした箇所の上下反転に波紋が生み出されるので多分上下反転はバグだと思われます。)

エフェクトの調整

以下の変数はすべての波に対して適応されますのでご注意ください。波ごとに個別の設定を行うことはできませんでした。
もしかするとCameraに波の生成ごとにスクリプトからコンポーネントを追加して設定すればうまくいくかもしれません。(未検証)

DitectClick

はじめにも利用したクリックした座標(を上下反転させた座標)に波紋を生み出します。クリックを利用するプロジェクトではどこでも生み出されてしまうため、falseにしておくことをおすすめします。

WaveCount

画面に表示させる波の最大数

TimeInfinity

trueにすると画面にずっと波が表示され続けます。

WaveTime

そろぞれの波の時間が秒単位で設定できます。

WaveAnimCurve

時間経過に伴う波の挙動を決定します。0~1に収まるようにしないとおかしなことになります。

WaveScale

波の強度。ここが大きいと画面が大きく歪むようになります。

WaveScale

波の速度。

WaveFrequency

波の周波数。値が大きいほど波と波の感覚が狭まります。

CiecleXYScale

異なる値を設定することで波を楕円形にできます。

InternalRadio & ExternalRadio

image.png
image.png
画像はWaterRippleForScreenフォルダ内部に生成されるpdfよりお借りしております。
Internalの内部には波が生まれず、Internal以上Internal+External未満に波が表示され、それ以上には波が生まれません。

その他

RippleGeneratorというスクリプトも同梱されており、こちらでは自動で波を発生させられるらしい。
このエフェクトは画面に映るもの全てを歪ませてしまうため、少々使い勝手が悪そうなので今回はパスします。

参考

Asset Storeのダウンロードページ

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

Unity ML-Agents Toolkitによる機械学習

Unity MLgents Toolkitを使って機械学習を勉強していきます。

当面は、公式チュートリアルをなぞることにします。
https://github.com/Unity-Technologies/ml-agents/blob/release_3_docs/docs/Readme.md

前回は、新しい学習環境を作って動かしてみるところまでできました。
https://github.com/Unity-Technologies/ml-agents/blob/release_3_docs/docs/Learning-Environment-Create-New.md

今回は、学習環境を自分で設計していきます。
https://github.com/Unity-Technologies/ml-agents/blob/release_3_docs/docs/Learning-Environment-Design.md

(以下、公式GirHubの和訳)

学習環境の設計

このページには、シーン内のエージェントの設計ではなく、シーンとシミュレーションの設定に関連するML-Agents Unity SDKの概要のほか、学習環境の設計方法に関する一般的なアドバイスが含まれています。観察、アクション、報酬を計測する方法、マルチエージェントシナリオのチームを定義する方法、模倣学習用のエージェントのデモを記録する方法など、エージェントの設計に関する専用ページがあります。

ML-Agents Toolkitによって提供される機能セット全体のオンボードに役立つように、APIドキュメントを調べることをお勧めします。さらに、GitHubにはほぼすべてのサンプル環境の使用例があります。

シミュレーションとトレーニングプロセス

トレーニングとシミュレーションは、MLエージェントアカデミークラスによって調整された手順で進められます。アカデミーは、シーン内のエージェントオブジェクトを操作して、シミュレーションをステップ実行します。

トレーニング中、外部Pythonトレーニングプロセスは、アカデミーと通信して一連のエピソードを実行し、データを収集してニューラルネットワークモデルを最適化します。トレーニングが正常に完了したら、トレーニング済みモデルファイルをUnityプロジェクトに追加して、後で使用できます。

ML-Agents Academyクラスは、エージェントシミュレーションループを次のように編成します。

  1. アカデミーのOnEnvironmentResetを呼び出します。
  2. シーン内の各エージェントのOnEpisodeBegin()関数を呼び出します。
  3. シーンに関する情報を収集します。これは、シーン内の各エージェントのCollectObservations(VectorSensor sensor)関数を呼び出し、 センサーを更新して結果の観測を収集することによって行われます。
  4. 各エージェントのポリシーを使用して、エージェントの次のアクションを決定します。
  5. OnActionReceived()シーン内の各エージェントの関数を呼び出し、エージェントのポリシーで選択されたアクションを渡します。
  6. OnEpisodeBegin()エージェントがそのMax Stepカウントに達したか、またはそれ自体をとしてマークした場合、エージェントのEndEpisode()関数を呼び出します。

シナリオごとに必要なメソッドを、Agentクラスを拡張して実装することでトレーニング環境を作成します。

Unityシーンの整理

UnityシーンでML-Agents Toolkitをトレーニングして使用するには、シーンで必要な数のAgentサブクラスを使用します。エージェントインスタンスは、そのエージェントを表すGameObjectにアタッチする必要があります。

アカデミー

アカデミーにより、エージェントとその意思決定プロセスを調整します。一度に存在するアカデミーは1つだけです。

アカデミーのリセット

各エピソードの開始時に環境を変更するには、メソッドをアカデミーのOnEnvironmentResetアクションに追加します。

public class MySceneBehavior : MonoBehaviour
{
    public void Awake()
    {
        Academy.Instance.OnEnvironmentReset += EnvironmentReset;
    }

    void EnvironmentReset()
    {
        // Reset the scene here
    }
}

たとえば、エージェントを開始位置にリセットしたり、目標をランダムな位置に移動したりできます。PythonのUnityEnvironmentreset()メソッドが呼び出されると、環境がリセットされます。

環境をリセットするときは、変更が必要な要因を考慮して、トレーニングをさまざまな条件に一般化できるようにします。たとえば、迷路解決エージェントをトレーニングしている場合は、トレーニングエピソードごとに迷路自体を変更する必要があります。そうでなければ、エージェントはおそらく、一般的な迷路ではなく、特定の迷路を解くことを学ぶでしょう。

複数のエリア

多くのサンプル環境では、トレーニングエリアの多くのコピーがシーンにインスタンス化されます。これにより、一般的にトレーニングがスピードアップし、環境が多くの経験を並行して収集できるようになります。これは、同じ動作名で多数のエージェントをインスタンス化するだけで実現できます。可能であれば、複数の領域をサポートするようにシーンを設計することを検討してください。

複数の領域の例を確認するには、サンプル環境をご覧ください。さらに、 新しい学習環境の作成では、このオプションについて説明しています。

環境

Unityでトレーニング環境を作成する場合、外部トレーニングプロセスで制御できるようにシーンをセットアップする必要があります。考慮事項は次のとおりです。

  • Unityアプリケーションがトレーニングプロセスによって起動されると、トレーニングシーンが自動的に開始する必要があります。
  • アカデミーは、トレーニングの各エピソードについて、シーンを有効な開始点にリセットする必要があります。
  • トレーニングエピソードにはMax Stepsまたは、エピソードを手動で終了するEndEpisode()よる明確な終わりが必要です。

環境パラメーター

カリキュラムの学習と環境パラメーターのランダム化は、環境内の特定のパラメーターを制御する2つのトレーニング方法です。そのため、環境パラメーターが各ステップで正しい値に更新されていることを確認することが重要です。これを有効にするため、
EnvironmentParametersために、これらの両方の機能のトレーニング構成で定義されたパラメーターの値を取得するために使用できるC#クラスを公​​開します。

OnEpisodeBegin() 利用して、エージェントの機能から環境を変更することをお勧めしますAcademy.Instance.EnvironmentParameters。使用例については、WallJumpサンプル環境(具体的には、WallJumpAgent.cs )を参照してください 。

エージェント

Agentクラスは、観測を収集してアクションを実行するシーン内のアクターを表します。通常、Agentクラスは、他の方法ではアクターを表すシーン内のGameObjectにアタッチされます。たとえば、フットボールゲームのプレーヤーオブジェクトや車両シミュレーションの車オブジェクトなどです。すべてのエージェントには適切なが必要Behavior Parametersです。

一般に、エージェントを作成するときは、エージェントクラスを拡張し、CollectObservations(VectorSensor sensor)およびOnActionReceived()メソッドを実装する必要があります。

  • CollectObservations(VectorSensor sensor) —エージェントの環境の観察を収集します。
  • OnActionReceived() —エージェントのポリシーによって選択されたアクションを実行し、現在の状態に報酬を割り当てます。

これらの関数の実装によって、このエージェントに割り当てられた動作パラメータを設定する方法が決まります。

また、エージェントがタスクを完了する方法またはタイムアウトする方法も決定する必要があります。

OnActionReceived()関数を呼び出すことにより、エージェントがタスクを終了した(または取り返しのつかないほど失敗した)ときに、EndEpisode()関数により、エージェントエピソードを手動で終了できます。エージェントのMax Stepsプロパティを正の値に設定することもできます。エージェントは、多くの手順を実行した後、エピソードを検討します。このAgent.OnEpisodeBegin()機能を使用して、エージェントを再起動する準備をすることができます。

独自のエージェントのプログラミングの詳細については、エージェントを参照してください。

統計の記録

Unity環境内から統計を記録するメカニズムを開発者に提供します。これらの統計は、トレーニングプロセス中に集計および生成されます。統計を記録するには、C#のStatsRecorderクラスを参照してください。

使用例については、FoodCollectorサンプル環境(具体的には、FoodCollectorSettings.cs )を参照してください 。

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

Unity2020.1じゃなくても(0,0,0)の位置にCreate Emptyしたい!

Create Emptyって変な位置にGame Objectを生成するよね・・・

GameObject > Create Empty してみます。
image.png
生成されたGameObjectの Position を見てみると・・・
image.png
あああああ!(0.155,0.255,0.34)ってどこ!?変な位置に生成しないで!

ってなることがよくあります。

これは、 Create Empty をする時の Scene タブの表示領域が影響しているみたいです。

どうやらUnity2020.1だと原点にオブジェクトを生成できるらしいぞ!

昨日、こちらのツイートではじめて知ったのですが、Unity2020.1には 原点でオブジェクトを生成 という設定があるようです。これを使えば変な位置に生成されなくて便利ですね!

でも、Unity2018やUnity2019を使いたいケースもまだまだあると思います。

Unity2020.1じゃなくても、オブジェクトを原点 (0,0,0) に生成する方法がないか調べてみました!

Unity2020.1じゃなくてもできる方法見つけた

調べてみたら、まったく同じ悩みの質問を見つけました。

Is there a way to force new objects to always be created at (0,0,0,)?

こちらでは拡張エディターを作る手法がベストアンサーに選ばれてました。サンプルコードが記載されてますので、そちらを参考に拡張エディターを作ってみました。

常に (0,0,0) の位置にCreate Emptyする拡張エディターを作る

Assetsフォルダー配下に Editor フォルダーを作成し、そこに GameObjectCreation.cs を作成します。内容は以下のようにします。

using UnityEngine;
using UnityEditor;

public class GameObjectCreation : MonoBehaviour
{
    [MenuItem("GameObject/Create At 0 #&0")]
    static void createAtZero()
    {
        GameObject go = new GameObject("GameObject");

        go.transform.position = Vector3.zero;
        go.transform.rotation = Quaternion.identity;
    }
}

これで拡張エディターは完成です!
(ベストアンサーのコードはもっと長いですが、とりあえず必要なところだけ抽出しました。)

メニューに以下のように Create At 0 というのが追加されています。
image.png
試しに押してみると、
image.png
ちゃんと (0,0,0) に生成されてますね!

Shift+Alt+0 でも生成できました。

さいごに

無事に解決してよかったです。本記事の作成にあたり、以下を参考にさせていただきました。ありがとうございました。

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

UnityでHoloLens2を使う

まえがき

待望のHoloLens2が手元に届きました!!
IMG_20200723_100055.jpg
IMG_20200723_114647.jpg

初回セットアップはWindowsのPCと同じようなものでした
解説は省略します

空間認識や深度センサの精度がすごく良いです

本題

マイクロソフト公式のyoutubeチャンネルを見ていたらUnityでの開発の仕方を説明されていました
動画かつ分かりやすい説明が欲しい方はぜひそちらを参照してください
Unityの開発のやり方まで詳しく教えてくださるとは流石Microsoft様ですね!

ここでは私の環境でセットアップした過程を載せていこうと思います

機器概要

・Windows Laptop
・Unity 2019.3.2f1
・HoloLens2
・Visual Stadio 2019

導入

※Unityは導入されている前提とします
※Visual Stadioで必要なモジュールは以下の通りです
Unityのオプションはチェック外してください
image.png
image.png

Universal Windows Platformモジュール

HoloLens2のビルドに必要なモジュールをインストールしておく
やり方はUnityHubのインストールから使用するバージョンのモジュールを加える
image.png
image.png

SDKの用意

HoloLens2を扱うにはMixed Reality Tool Kit(MRTK)というSDKを利用します
GithubよりSDKをDLしてきます
必要なファイルは上から1番目,3番目の2つです
・Microsoft.MixedReality.Toolkit.Unity.Examples.2.4.0.unitypackage
・Microsoft.MixedReality.Toolkit.Unity.Foundation.2.4.0.unitypackage
image.png

手順

1.新規プロジェクト作成

新規作成から3Dで名前を設定して作成
image.png

2.HoloLens2用に設定

File/Build Settingsを開く
image.png
Universal Windows Platformをクリックして,Switch Platformする
image.png
Player Settngsを開き,Playerの一番下にあるXR SettingsからVirtual Reality Supportedにチェックする
image.png
次にVirtual Reality SDKsの+を押してWindows Mixed Realityを追加
image.png
追加した項目のEnable Depth Buffer Sharingのチェックを外す
image.png
その下のStereo Rendering Mode* の項目をSingle Pass Instancedに変更
image.png

3.MRTK AssetのImport

先ほどDLしたPackageをImportする
まずはMicrosoft.MixedReality.Toolkit.Unity.Foundation.2.4.0.unitypackageから行う
Assets/Import Package/Custom Package...から若しくはAssetsにファイルをドラッグ&ドロップ
image.png
image.png
そのままImport
image.png
Importが終わるとMRTK Project Configuratorというウィンドウが出てくるのでAppryを押す
これによってカメラの設定やHoloLensを動かすための設定を自動的に行ってくれる
image.png

次に,もう一つのPackageを同じようにImportする

4.Sampleシーンでの設定

Assets/MRTK/Exsamples/Demosに様々なデモが入っている
image.png
./Demos/HandTracking/Scenes/HandInteractionExsamplesを実行してみる
image.png
このシーンを開くとTMP Importerというウィンドウが出てくる
image.png
Import TMP Essentialsを押す
image.png
Importが終わったらウィンドウは閉じる

5.ビルド

このシーンをビルドする
File/Build Settingsを開く
Add Open Scenesを押して現在のシーンをビルドの対象とする
image.png
Buildを押して,保存先を設定する
新しいフォルダーからAPPというフォルダを作成し,選択
image.png
ビルドが完了すると出力先のフォルダにプロジェクト名と同じ名前のVisual Stadioのソリューションファイルが出来ている
image.png

6.Visual Stadioの設定

出力したソリューションファイルを開く
この時にVisual Stadioで必要なフレームワークやツールが不足している場合インストールするように指示されるので従う
image.png

USB-TypeCでHoloLens2とLaptopを接続する
※CtoCができない場合はCtoAなど別のUSBケーブルを利用してください

Visual StadioがHoloLens2にBuildするように設定を変更する
1.構成をDebugからReleaseに変更
image.png
2.ARM(Windowsx32)もしくはARM64(Windowsx64)に設定
3.ビルド先をリモートコンピュータからデバイスに変更
image.png
4.デバッグ/デバッグなしで開始をクリック
image.png
これでビルドをしてHoloLens2に配置までを自動で行う
初回のビルド時はPINコードによる認証が必要,入力を促される

7.デバイス同士のペアリング

アプリケーションのビルドを行うためにHoloLens2で設定する必要がある(私はエラーで気づかされた)
開発者モードの設定を有効にする
・HoloLens2
20200723_003335_HoloLens.jpg
20200723_002331_HoloLens.jpg
ペアリングからPINコードを表示
それをVisual Stadioで打ち込む

しかし私はここでエラーが発生
6-3にてビルド完了後,配置に失敗
image.png
再度行うもエラー
image.png
→PINによる認証が出てこない,おそらくIPアドレスが正しく認識されていない

なのでやり方を少し変更

8.リモートでビルド

USBからではなくリモートで行う
デバイス→リモートコンピュータに変更
HoloLens2のWi-Fi設定からIPアドレスを取得,プロジェクトのプロパティからデバイス名にIPアドレスを入力,デバッグなしで開始
image.png
するとPINコード入力画面が出現
image.png
開発者モードのペアリングからPINコードを取得,Visual Stadioで入力
配置正常終了と出て,HoloLens2でアプリが起動!

なんとか実行することができました.
アイトラッキングとマイクの権限に許可を与えたらデモを体験できます!!





参考

公式

What's New
【ビギナー向け】MRTK v2.2.0 がリリースされたので Examples をビルドしてみました
入門チュートリアル Unity - 紹介 (1/9 章)
マルチユーザー機能のチュートリアル - 紹介 (1/5 章)
Visual Studio を使用した配置とデバッグ
ツールのインストール

HoloLens へアプリを配置する際に「DEP0600」のエラーが出て失敗する場合の対処法
MRTK V2開発環境構築

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

Unity + Epic Online Services でオンラインゲームを作ろう ~②マルチFPS編~

概要


Github:unity_eos_fps
Unity + Epic Online Services(以下 EOS) でマルチプレイ FPS を作ってみました。
前回は「ゲームを作ろう」というタイトルなのに成果物がチャットでしたが、今回は正真正銘のゲームです。

残念:ゲーム公開ができない

ネット上の多数の方にプレイしてもらいたく開発していたのですが、
「さぁ公開だ」となったタイミングで気づきました。
Epic Online Services のゲームの公開はまだ許可されていません。
公開用のための審査提出ボタンが「COMMING SOON」となっています。
そのため、開発チーム以外のアカウントでゲームにログインするとはじかれます。
Edp37coUYAAqOrP.png
・・・

残念ですが現在はみんなでプレイができず、ビルドしてローカルでテストしかできません。
また進展があったら報告します。?

ロビー検索のバグの対処

前回と同じく 7/23 現在 EOS のロビー検索はまだバグで動きません。
バグ報告したスレッド の情報提供によると内部で通信エラーが発生しているようです。
同じロビーにいないと P2P 通信が始められないため、
対処として Glitch で簡易ロビー検索サーバーを作りました。
ロビーID を保持・配信するだけの API です
Glitch : eos-lobby

コードの工夫

SDK の呼び出しはコード量が増える一方だったので、拡張メソッドをどんどん書いて整理しました。

EOS の C# SDK は C++ SDK と書き方を統一するためか、インターフェースのメソッドは下記のようになってます。

  • 引数に直接値を書かず、データ受け渡し用クラスのインスタンスで渡す ⇒ インスタンスを new する記述が増える
  • 戻り値は処理結果(Result)の Enum ⇒ 呼び出すたびに処理が成功したか判定する必要がある
  • 処理結果はコールバックで返ってくる ⇒ ネストがどんどん深くなる

なので下記のような拡張メソッドを EOS の使用するメソッド分、追加してます。

  • 引数だけで呼び出せるように置き換え
  • 戻り値を UniTask にしてコールバックを async で受け取る

ビルド

著者環境

OS : Windows 10 Pro
Unity : Unity 2020.1.0f1

1. Github からプロジェクトチェックアウト

2. Epic Online Services デベロッパーポータルで登録

  1. 新しいプロダクト作成
  2. Epic Account Services で 3 項目を全て入力して、Configured にする image.png
  3. Product Settings の内容を Unity でプロジェクトを開いて Assets/ScriptableObjects/EOSSettings.asset に記載

3. Glitch でサーバー作成

  1. eos-lobby を開いて View Sorce -> Remix Edit で自身のアカウントにクローン
  2. .env にシークレットのキーと値を設定して
    • Variable Name:SECRET
    • Valiable Value:適当な文字列 image.png
  3. Unity プロジェクトの Assets/ScriptableObjects/EOSSettings.asset に記載
    • Api Url : https://【クローン後のプロジェクト名】.glitch.me/kvs
    • Api Securet : .env の SECRET に設定した文字列 image.png

4. Unity ビルド

Windows Standalone でビルド

終わりに

公開できないのは残念です。
EOS は正式リリースされているかのように宣伝されているので、
私のように勘違いして開発している人いそうです。
ロビー検索が動かない件も含めて、公式には早急に対応していただきたいです。

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