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

Oculus Questのアプリ制作やら(Unity)

概要

前回、Oculus Questのセットアップ方法について記載しました。
今回はOculus Quest用のアプリをUnityで開発するための手順と、Oculus Questでアプリを起動するまでの流れを記載します。

環境

  • Windows10
  • Unity2018
  • Android sdk 4.4(kitkat)
  • スマートフォン(ミラーリング用)

手順

Oculus QuestはAndroidOSのため、Unity側のビルド設定でAndroidにプラットフォームを変更してビルドする必要があります。

  1. Unityで新規プロジェクトを作成
  2. Asset Storeから「Oculus Integration」をダウンロード・インポート
  3. Unityで簡単なアプリ制作
  4. Android用のビルドを行うためのプラットフォームを変更
  5. ビルドしてapkファイル作成
  6. Oculus Quest側でアプリの起動

Unityで新規プロジェクトを作成

Unityを起動します。設定を3Dモードにして保存先とプロジェクト名を入力した後作成ボタンを押します。

Asset Storeから「Oculus Integration」をダウンロード・インポート

Asset Storeタブを開き、「Oculus Integration」と検索し、ダウンロード・インポートします。

unity1.png

このアセットはOculusがサポートしている公式アセットで、Oculus Questのヘッドトラッキングやコントローラーのポジトラを容易に実現することができます。
これがなくてもOculus Quest用のアプリ開発は可能ですが、コントローラーやヘッドトラッキングを使わないと、ヘッドセットを使ってVRをする意味がほとんどないように思えるため、はじめからこちらのアセットを使用します。
インポートが完了するとProjectにOculusフォルダが追加されます。
unity2.png
これで準備は整いました。

Unityで簡単なアプリ制作

まず、ProjectにあるOculus/VR/prefabs/OVRCameraRig.PrefabsをHierarchyにドラッグ&ドロップします。
unity3.png
unity4.png

このOVRCameraRigの中にカメラが付いているため、初期のSceneに入っているMain Cameraは削除します。またOculus Questで覗いた際にskyboxだけではポジトラができているかわかりづらいのでSphereを追加しておきます。
unity5.png
unity6.png

次に、OVRCameraRig ⇒ Inspector内のOVR Managerコンポーネント ⇒ Target Devices ⇒ Element0 を「Quest」に変更します。
unity8.png

次に、Hierarchyの
OVRCameraRig/TrackingSpace/LeftHandAnchor/LeftControllerAnchor
OVRCameraRig/TrackingSpace/RightHandAnchor/RightControllerAnchor
にProjectのOculus/VR/prefabs/OVRControllerPrefab.Prefabsをドラッグ&ドロップします。
unity9.png

Vtuberなどのモデルを動かす時はこのあたりにボーンの情報を入れるのかなと考えつつも次に進みます。
追加したOVRControllerPrefab ⇒ Inspector内のOVR Controller Helper ⇒ Controllerをそれぞれ「L Tracked Remote」と「R Tracked Remote」に変更します。
添付されている画像は「L Tracked Remote」に設定しているものです。「R Tracked Remote」も同様に設定してください。
unity10.png

unity11.png

よく見てみるとSceneにOculue Touchのコントローラーが浮いているのが見えますね。
これで完了です。

Android用のビルドを行うためのプラットフォーム変更

前述しましたが、Oculus QuestのOSはAndroid OSのためAndroid用にビルドできるようにプラットフォームを変更します。
メニューバーにある File ⇒ Build Settingを選択します。
左下のPlatformをAndroidに変更し、Switch Platformを選択します。
※Switch Platformには数分程度時間がかかります。
※Android SDK、Android NDK、Java JDKは設定してあるものとします。また「Edit」⇒「Unity Preferences」⇒「External Tools」のAndroidの欄から設定してあるか確認することができます。
unity12.png
unity13.png

次にPlayer Settingを開きます。ここでは3箇所変更します。

  • Other Settings ⇒ Minimum API Levelを「Android 4.4 'kitkat'」に変更する。
  • XR Settings ⇒ Virtual Reallty Supportedをチェックを入れる。
  • Virtual Reality SDK リストの+ボタンを押下し、Oculusを追加する。

ビルドしてapkファイル作成

最後に「Build and Run」ボタンを押下し、保存する場所を指定すると完了です。
unity14.png

Oculus Quest側でアプリの起動

作成したアプリはOculus Quest側のHome/ライブラリ/提供元不明のアプリの中にプロジェクト名で入っています。それをコントローラーで選択すると起動することができます。

Screenshot_20190625-160028.jpg

写真を載せるためにAndroidのスマートフォンでOculus Questの画面をミラーリングしてスクリーンショットを撮ってみましたが画質が、、、

これで以上になります。
思っていたよりも簡単に制作することができた印象でした。とりあえず1つVIVE用に作っていたアプリをOculus Quest版に作り直してみようかな(笑)

参考

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

とにかくECSを始めてみる

とにかくECSを始めてみる

Unity2018から公開されたECSですが、そのほかNativeContainerやJobSystem、Burstコンパイラと一緒に語られることが多いです。
この記事は、個人的にそれらの関係がよくわからず混乱したので、いろいろ調べつつまとめたものになります。
仕組みは置いておいて、とにかくコードを書いて理解のためのきっかけを得るというのが目標です。

準備

Unity2018以降でパッケージマネージャから以下のものをインストールしておきます。現状バージョン依存がかなり強いようなので、カッコ内に自分が試したときのバージョンを記載しておきいます。

  • Burst (1.0.4)
  • Collections (0.0.9-preview.12)
  • Entities (0.0.12-preview.24)
  • Hybrid Renderer (0.0.1-preview.4)
  • Jobs (0.0.7-preview.6)
  • Mathematics (1.0.1)

シーンにはCamera、Directional Light、コントローラをくっつけるGameObjectを配置しておきます。

とりあえずECS

なにはともあれECS。100000個のエンティティを生成して回転させるコードです。_meshや_materialには、Unityエディタのインスペクタから適当なものをアタッチしておきます。
このコードでは NativeContainer,JobSystem,Burstコンパイラは使っていませんが、ここを足がかりにしたいと思います。

Startでエンティティの作成と初期設定、Updateで回転を行っています。
描画は、RenderMeshがPositionやRotationといったコンポーネントデータを参照しながらいい感じにやってくれます。

自分のPCでは、動作はかなりガタガタです。

using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Rendering;
using Random = UnityEngine.Random;

namespace EcsOnly
{
    /// <summary>
    /// 現在の回転角 (degree)
    /// </summary>
    public struct RotDegree : IComponentData
    {
        public float3 Value;
    }

    /// <summary>
    /// 各軸の回転速度
    /// </summary>
    public struct RotSpeed : IComponentData
    {
        public float3 Value;
    }

    public class EcsController : MonoBehaviour
    {
        /// <summary>
        /// 生成するエンティティの数
        /// </summary>
        private const int NumInstances = 100000;

        /// <summary>
        /// 表示するメッシュ
        /// </summary>
        [SerializeField]
        private Mesh _mesh;

        /// <summary>
        /// メッシュに適用するマテリアル
        /// </summary>
        [SerializeField]
        private Material _material;

        /// <summary>
        /// エンティティ
        /// </summary>
        private Entity[] _entities;

        private void Start()
        {
            var em = World.Active.GetOrCreateManager<EntityManager>();

            var entityModel = em.CreateEntity(
                typeof(Position),
                typeof(Rotation),
                typeof(RotDegree),
                typeof(RotSpeed)
            );

            //
            // entityModelに共有するコンポーネントを加える
            //
            var sharedData = new RenderMesh
            {
                castShadows = ShadowCastingMode.Off,
                mesh = _mesh,
                receiveShadows = false,
                material = _material
            };

            em.AddSharedComponentData(entityModel, sharedData);

            //
            // インスタンスを生成する
            //
            _entities = new Entity[NumInstances];

            for (var idx = 0; idx < _entities.Length; idx++)
            {
                var e = em.Instantiate(entityModel);

                _entities[idx] = e;

                // 座標を設定
                var x = Random.Range(-50f, 50f);
                var y = Random.Range(-50f, 50f);
                var z = Random.Range(-50f, 50f);
                em.SetComponentData(e, new Position { Value = new float3(x, y, z)});

                // 回転速度を設定
                var rx = Random.Range(-0.1f, 0.1f);
                var ry = Random.Range(-0.1f, 0.1f);
                var rz = Random.Range(-0.1f, 0.1f);
                em.SetComponentData(e, new RotSpeed {Value = new float3(rx, ry, rz)});

                // 初期の角度
                em.SetComponentData(e, new RotDegree {Value = float3.zero});
                em.SetComponentData(e, new Rotation {Value = quaternion.identity});
            }

            em.DestroyEntity(entityModel);
        }

        private void Update()
        {
            var em = World.Active.GetOrCreateManager<EntityManager>();

            for (var idx = 0; idx < _entities.Length; idx++)
            {
                var entity = _entities[idx];

                // Entityの回転角を更新する
                var deg = em.GetComponentData<RotDegree>(entity);
                var speed = em.GetComponentData<RotSpeed>(entity);

                var newDegrees = (deg.Value + speed.Value) % 360f;

                em.SetComponentData(entity, new RotDegree {Value = newDegrees});

                var rot = em.GetComponentData<Rotation>(entity);
                rot.Value = quaternion.Euler(newDegrees);

                em.SetComponentData(entity, rot);
            }
        }
    }

}

NativeContainerを使ってみる

NativeContainerはGC対象から外れた連続したメモリを、C#から安全に使うためのものらしいです(たぶん)
最初のコードからの変更点は「インスタンスを生成する」っていうコメントから下の数行と、OnDestoryメソッドによる後片付けくらいです。

GC対象外というのがBurstコンパイラが要求する制約の1つっぽいですね。なので、この段階ではパフォーマンス的にあまり意味がないようで、動きははあまり変わらずガタガタです。

using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Rendering;
using Random = UnityEngine.Random;

namespace EcsAndNC
{
    /// <summary>
    /// 現在の回転角 (degree)
    /// </summary>
    public struct RotDegree : IComponentData
    {
        public float3 Value;
    }

    /// <summary>
    /// 各軸の回転速度
    /// </summary>
    public struct RotSpeed : IComponentData
    {
        public float3 Value;
    }

    public class EcsController : MonoBehaviour
    {
        /// <summary>
        /// 生成するエンティティの数
        /// </summary>
        private const int NumInstances = 100000;

        /// <summary>
        /// 表示するメッシュ
        /// </summary>
        [SerializeField]
        private Mesh _mesh;

        /// <summary>
        /// メッシュに適用するマテリアル
        /// </summary>
        [SerializeField]
        private Material _material;

        /// <summary>
        /// エンティティ
        /// </summary>
        private NativeArray<Entity> _entities;

        private void Start()
        {
            var em = World.Active.GetOrCreateManager<EntityManager>();

            var entityModel = em.CreateEntity(
                typeof(Position),
                typeof(Rotation),
                typeof(RotDegree),
                typeof(RotSpeed)
            );

            //
            // entityModelに共有するコンポーネントを加える
            //
            var sharedData = new RenderMesh
            {
                castShadows = ShadowCastingMode.Off,
                mesh = _mesh,
                receiveShadows = false,
                material = _material
            };

            em.AddSharedComponentData(entityModel, sharedData);

            //
            // インスタンスを生成する
            //
            _entities = new NativeArray<Entity>(NumInstances, Allocator.Persistent);
            em.Instantiate(entityModel, _entities);

            for (var idx = 0; idx < _entities.Length; idx++)
            {
                var e = _entities[idx];

                // 座標を設定
                var x = Random.Range(-50f, 50f);
                var y = Random.Range(-50f, 50f);
                var z = Random.Range(-50f, 50f);
                em.SetComponentData(e, new Position { Value = new float3(x, y, z)});

                // 回転速度を設定
                var rx = Random.Range(-0.1f, 0.1f);
                var ry = Random.Range(-0.1f, 0.1f);
                var rz = Random.Range(-0.1f, 0.1f);
                em.SetComponentData(e, new RotSpeed {Value = new float3(rx, ry, rz)});

                // 初期の角度
                em.SetComponentData(e, new RotDegree {Value = float3.zero});
                em.SetComponentData(e, new Rotation {Value = quaternion.identity});
            }

            em.DestroyEntity(entityModel);
        }

        private void Update()
        {
            var em = World.Active.GetOrCreateManager<EntityManager>();

            for (var idx = 0; idx < _entities.Length; idx++)
            {
                var entity = _entities[idx];

                // Entityの回転角を更新する
                var deg = em.GetComponentData<RotDegree>(entity);
                var speed = em.GetComponentData<RotSpeed>(entity);

                var newDegrees = (deg.Value + speed.Value) % 360f;

                em.SetComponentData(entity, new RotDegree {Value = newDegrees});

                var rot = em.GetComponentData<Rotation>(entity);
                rot.Value = quaternion.Euler(newDegrees);

                em.SetComponentData(entity, rot);
            }
        }

        private void OnDestroy()
        {
            _entities.Dispose();
        }
    }
}

JobSystemを使ってみる

制約を設けて安全にマルチスレッドを使おう、みたいなのがJobSystemのようです。
いろいろインタフェイスがあるのですが、とりあえず IJobProcessComponentDataを使ってみます。

これまでUpdateに書いていたものをEcsJobのExecuteメソッドに移動しています。引数がrefになっていて、入出力を兼ねているのでUpdateよりもすっきりした感じになりました。
EcsJobを走らせるのが、JobComponentSystemを継承したEcsJobSystemクラスです。このクラスは定義しておくだけであとは勝手にOnUpdateメソッドが呼び出されるみたいです。

動作は、マルチスレッドが効いているのか、けっこう滑らかになりました。

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Rendering;
using Random = UnityEngine.Random;

namespace EcsAndNCAndJobSystem
{
    /// <summary>
    /// 現在の回転角 (degree)
    /// </summary>
    public struct RotDegree : IComponentData
    {
        public float3 Value;
    }

    /// <summary>
    /// 各軸の回転速度
    /// </summary>
    public struct RotSpeed : IComponentData
    {
        public float3 Value;
    }

    /// <summary>
    /// Entityに対する処理
    /// </summary>
    /// <remarks>
    /// RotDegree, RotSpeed, Rotationを持つ全てのエンティティに対して処理が適用される
    /// </remarks>
    public struct EcsJob : IJobProcessComponentData<RotDegree, RotSpeed, Rotation>
    {
        public void Execute(ref RotDegree rotY, [ReadOnly] ref RotSpeed speed, ref Rotation rotation)
        {
            var rot = (rotY.Value + speed.Value) % 360f;

            rotY = new RotDegree {Value = rot};

            rotation = new Rotation {Value = quaternion.Euler(rot)};
        }
    }

    /// <summary>
    /// Jobを実行するためのコンポーネントシステム
    /// </summary>
    public class EcsJobSystem : JobComponentSystem
    {
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            var job = new EcsJob();

            return job.Schedule(this, inputDeps);
        }
    }

    public class EcsController : MonoBehaviour
    {
        /// <summary>
        /// 生成するエンティティの数
        /// </summary>
        private const int NumInstances = 100000;

        /// <summary>
        /// 表示するメッシュ
        /// </summary>
        [SerializeField]
        private Mesh _mesh;

        /// <summary>
        /// メッシュに適用するマテリアル
        /// </summary>
        [SerializeField]
        private Material _material;

        /// <summary>
        /// エンティティ
        /// </summary>
        private NativeArray<Entity> _entities;

        private void Start()
        {
            var em = World.Active.GetOrCreateManager<EntityManager>();

            var entityModel = em.CreateEntity(
                typeof(Position),
                typeof(Rotation),
                typeof(RotDegree),
                typeof(RotSpeed)
            );

            //
            // entityModelに共有するコンポーネントを加える
            //
            var sharedData = new RenderMesh
            {
                castShadows = ShadowCastingMode.Off,
                mesh = _mesh,
                receiveShadows = false,
                material = _material
            };

            em.AddSharedComponentData(entityModel, sharedData);

            //
            // インスタンスを生成する
            //
            _entities = new NativeArray<Entity>(NumInstances, Allocator.Persistent);
            em.Instantiate(entityModel, _entities);

            for (var idx = 0; idx < _entities.Length; idx++)
            {
                var e = _entities[idx];

                // 座標を設定
                var x = Random.Range(-50f, 50f);
                var y = Random.Range(-50f, 50f);
                var z = Random.Range(-50f, 50f);
                em.SetComponentData(e, new Position { Value = new float3(x, y, z)});

                // 回転速度を設定
                var rx = Random.Range(-0.1f, 0.1f);
                var ry = Random.Range(-0.1f, 0.1f);
                var rz = Random.Range(-0.1f, 0.1f);
                em.SetComponentData(e, new RotSpeed {Value = new float3(rx, ry, rz)});

                // 初期の角度
                em.SetComponentData(e, new RotDegree {Value = float3.zero});
                em.SetComponentData(e, new Rotation {Value = quaternion.identity});
            }

            em.DestroyEntity(entityModel);
        }

        private void OnDestroy()
        {
            _entities.Dispose();
        }
    }
}

Burstコンパイラを使ってみる

Burstコンパイラは特定の制約のものとでコードを最適化するものみたいです。
特定の制約というのは検索すれば簡単に見つかると思うので、ここでは割愛します。

上のコードからの変更点は、EcsJobに[BurstCompile]というアノテーションを追加しただけです。
動作はかなり滑らか!

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Rendering;
using Random = UnityEngine.Random;

namespace EcsAndNCAndJobSystemWithBurst
{
    /// <summary>
    /// 現在の回転角 (degree)
    /// </summary>
    public struct RotDegree : IComponentData
    {
        public float3 Value;
    }

    /// <summary>
    /// 各軸の回転速度
    /// </summary>
    public struct RotSpeed : IComponentData
    {
        public float3 Value;
    }

    /// <summary>
    /// Entityに対する処理
    /// </summary>
    /// <remarks>
    /// RotDegree, RotSpeed, Rotationを持つ全てのエンティティに対して処理が適用される
    /// </remarks>
    [BurstCompile]
    public struct EcsJob : IJobProcessComponentData<RotDegree, RotSpeed, Rotation>
    {
        public void Execute(ref RotDegree rotY, [ReadOnly] ref RotSpeed speed, ref Rotation rotation)
        {
            var rot = (rotY.Value + speed.Value) % 360f;

            rotY = new RotDegree {Value = rot};

            rotation = new Rotation {Value = quaternion.Euler(rot)};
        }
    }

    /// <summary>
    /// Jobを実行するためのコンポーネントシステム
    /// </summary>
    public class EcsJobSystem : JobComponentSystem
    {
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            var job = new EcsJob();

            return job.Schedule(this, inputDeps);
        }
    }

    public class EcsController : MonoBehaviour
    {
        /// <summary>
        /// 生成するエンティティの数
        /// </summary>
        private const int NumInstances = 100000;

        /// <summary>
        /// 表示するメッシュ
        /// </summary>
        [SerializeField]
        private Mesh _mesh;

        /// <summary>
        /// メッシュに適用するマテリアル
        /// </summary>
        [SerializeField]
        private Material _material;

        /// <summary>
        /// エンティティ
        /// </summary>
        private NativeArray<Entity> _entities;

        private void Start()
        {
            var em = World.Active.GetOrCreateManager<EntityManager>();

            var entityModel = em.CreateEntity(
                typeof(Position),
                typeof(Rotation),
                typeof(RotDegree),
                typeof(RotSpeed)
            );

            //
            // entityModelに共有するコンポーネントを加える
            //
            var sharedData = new RenderMesh
            {
                castShadows = ShadowCastingMode.Off,
                mesh = _mesh,
                receiveShadows = false,
                material = _material
            };

            em.AddSharedComponentData(entityModel, sharedData);

            //
            // インスタンスを生成する
            //
            _entities = new NativeArray<Entity>(NumInstances, Allocator.Persistent);
            em.Instantiate(entityModel, _entities);

            for (var idx = 0; idx < _entities.Length; idx++)
            {
                var e = _entities[idx];

                // 座標を設定
                var x = Random.Range(-50f, 50f);
                var y = Random.Range(-50f, 50f);
                var z = Random.Range(-50f, 50f);
                em.SetComponentData(e, new Position { Value = new float3(x, y, z)});

                // 回転速度を設定
                var rx = Random.Range(-0.1f, 0.1f);
                var ry = Random.Range(-0.1f, 0.1f);
                var rz = Random.Range(-0.1f, 0.1f);
                em.SetComponentData(e, new RotSpeed {Value = new float3(rx, ry, rz)});

                // 初期の角度
                em.SetComponentData(e, new RotDegree {Value = float3.zero});
                em.SetComponentData(e, new Rotation {Value = quaternion.identity});
            }

            em.DestroyEntity(entityModel);
        }

        private void OnDestroy()
        {
            _entities.Dispose();
        }
    }
}

まとめ

  • ECS、JobSystem、NativeArray、Burstコンパイラは、それぞれ単独で機能する。
  • ECSだから速いというより、動作速度に対しては JobSystemが一番効果がある気がする(ベンチマークしていないので気がするだけ)。
  • 今回は理解のために描画を取り扱ったけれど、boidやAIなど、データ処理の場面で使うのもよさそう。

最後に:コンポーネントシステムについて

今回、ECSのなかのComponentSystemにはさらっとしか触りませんでした。
特定のコンポーネントデータを含むエンティティ群に対して、一括してなにか処理をしたいというときに使うのかも?
まだ良く理解していないので、よく調べなければいけないなーと思っています。

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

UnityとFirebaseを連携してログイン機能を実装しよう

Unityに触り始めてから2週間が経過しました。
C#が全くの分からんちんで苦戦中ですが、先日UnityとFirebaseを連携する機会がありましたので、こちらで共有させて頂きたいと思います。
今回はUnityのダウンロードとFirebaseの登録は済んでいる事を前提にこちらの記事を書きました。

①【Firebase上での下準備
・FirebaseでNewProjectを作成
・SDK(FirebaseのUnityプラグインみたいなイメージ)をPCへダウンロード

②【GitHubでサンプルをダウンロードしよう】
・GitHubのfirebaseQuickstartUnityからAuthのクローンを入手
 https://github.com/firebase/quickstart-unity
・UnityHubを開いて「新しく加える」からAuth内のTest.Appを追加

③【Unity上での下準備】
・ダウンロードしたファイルを開くと沢山エラーが出ているはずですが、上のタブバーのAsset→Import Packageの中からFirebaseAuth.unitypackageを読み込むとエラーが全て消えます。
・projectからMainSceneを探して、プレイモードを実施。下記の様な表示が出たらオッケーです!
スクリーンショット 2019-06-29 13.25.16.png

④【UnityとFirebaseとの連携をする】
・Unity内からEdit→ProjectSetting→Player 使いたいデバイスのロゴを選択 IOSの場合、identification内のBundle identificationボックス内の文字列をコピー(※好きな文字に変更可能です)
・firebaseへ移動後、TOP画面のUnityのロゴをクリック。regisuterのページで先ほどUnity内でコピーした文字列を入力
・設定ファイル(Google Service-Info.slist)をダウンロード
スクリーンショット 2019-06-28 18.05.22.png
・(①でSDKをもしダウンロードしていなかったら)こちらででダウンロード。この記事に沿って連携をしている方は不要です。

・設定ファイル(Google Service-Info.slist)をUnity内のAssetへ読み込み(中身はプロジェクトネームや先ほど入力したキーなどの情報が記述されている)

⑤【Firebaseへ戻ります】
・Firebase内の右側のバーにて開発の項から「Authentication(認証)」をクリック
・ログイン方法をクリック
・メール/パスワード、匿名の項をそれぞれアクセス可能へ変更
※SNS認証も対応している様です。

⑥【ビルドをしてみよう】
・IOSあるいはアンドロイドにてビルドをし、実際に入力した事項をFirebaseのAuthenticationで確認出来たら成功です!!

⑦【Unity内でのデザイン】
ログインシーンを新しく作成し、必要に応じてテキストボックスやボタンを設定&編集することでログイン機能を実装することが出来ます。私は下記の様な形に加工してみました。
スクリーンショット 2019-06-29 17.57.53.png

おわりに
プログラミングの勉強をはじめてようやく3ヶ月が経ちました。
毎日四苦八苦の連続ですが、最近はようやく面白さを感じる時間も増えました。Unityとても楽しい!?
JSやPHPの知識を復習しつつ、新しい技術にも挑戦していきたいと思います!!

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

Oculus Questでオブジェクトを両手でつかんで拡大・縮小する

はじめに

Oculus Integrationには様々なサンプルシーンが含まれていて勉強になるのですが、最近はDistanceGrabのシーンをベースに手を加えています。
このシーンにはバグがあり物を掴んだ時に吹き飛ばされてしまうのですが、以下ページに対処法やシーンの説明があり、大変参考になりました。
【Oculus Quest開発メモ】離れた場所にある物を掴む Distance Grabber & Grabbable編【Unity】

DistanceGrabでは、片手で物をつかんで操作できるのですが、両手でつかんで操作する機能はありませんでした。
スクリプトを見たところ、結構改造しないとできなさそうな雰囲気でした。
どうしようか検討していたところ、すでにそのようなものを作成されている人がいましたので、試しに使わせていただいたところ、自分がやりたかったイメージ通りで非常に使いやすかったです。
VR 向けの自作 Grabber を作ってみた

開発環境

Unity 2019.1.7f1
Oculus Integration for Unity - 1.37
VrGrabber-v0.0.3

試したこと

ダウンロードしてきた"VrGrabber-v0.0.3.unitypackage"をOculusQuest向けに作成したプロジェクトにインポートするだけで、そのままサンプルシーンを動作させることができました。
また、DistanceGrabのシーンのオブジェクトのスクリプトを元の"DistanceGrabbable.cs"から"VrgGrabbable.cs"に差し替えて、DisatanceGrabHandLeft/RightをVrg Left/Right Grabberに差し替えることで両手で操作できるようになりました。
ただ、"DistanceGrabbable.cs"にはアウトライン・クロスヘアー対応の機能があり、外しただけではオブジェクトのアウトラインの表示が見えたままになってしまうため、表示を消すようなスクリプトを追加しました。

VrgGrabbableExtend.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace VrGrabber
{
    public class VrgGrabbableExtend : VrgGrabbable
    {
        public string m_materialColorField;

        Renderer m_renderer;
        MaterialPropertyBlock m_mpb;

        void Start()
        {
            m_renderer = gameObject.GetComponent<Renderer>();
            m_mpb = new MaterialPropertyBlock();
            m_mpb.SetColor(m_materialColorField, Color.white);
            m_renderer.SetPropertyBlock(m_mpb);

        }
    }
}

動作例

こんな感じになります。画像は離れたところから操作する例ですが、直接つかんで操作することもできます。
com.oculus.vrshell-20190701-143118_Trim_320x320_fps10.gif

これまでadbからコマンドでキャプチャしていたため2眼の画像になってしまい見にくかったのですが、メニュー画面上からの操作で録画すると普通に1眼の画像になることにいまさらですが気が付きました・・・

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

Unityゆるふわサマーアドベントカレンダー 2019

はじめに

前回: Unityゆるふわサマーアドベントカレンダー 2018

本来12月に行われるアドベントカレンダーを8月にやろうという試みです!
Unityの楽しいゆるふわな記事で令和最初の夏を盛り上げましょう?
(参考: Unity アセット真夏のアドベントカレンダー 2018 Summer! – Unity公式 Asset Portal)

問い合わせ等はこちらまで:@nkjzm

ルール

  • どなたでも参加いただけます。
  • テーマは「Unityに関すること」なら何でもアリです!
    • ゆるふわじゃないテーマでも大丈夫です。
  • 記事の形式は自由です
    • Qiita、個人ブログ、YouTubeなど
  • (できるだけ)当日までに記事を書いて登録してください。
    • 締切を過ぎた枠があれば、上書きして参加可とします。
  • 何か不明点等あればTwitterかコメントまでお願いします。

参加登録の方法

  • 編集リクエスト機能を使い、参加したい日付に以下の項目を記入して送ってください。
    • 執筆者 (名前だけでもQiitaのアカウントでもTwitterでも大丈夫です)
    • タイトル (仮でも大丈夫です)
  • 後からでも修正可能です。
  • 締切を過ぎると他の人に上書きされる可能性があるのでご了承ください。

記事の投稿後の登録方法

  • 編集リクエストで記事のタイトルとURLを送ってください。

最後に

全部埋められるように頑張りましょう!!
皆さんのご参加お待ちしております!!!!

Unityゆるふわサマーアドベントカレンダー2019

日付 執筆者 記事
8/1 @nkjzm なんか書く
8/2 @pCYSl5EDgo LINQ to NativeArrayについてなんか書く
8/3 @guru_taka 何か書く
8/4 @_
8/5 @_
8/6 @_
8/7 @_
8/8 @GONBEEE_project 音ゲー作るときの設計思想とか書くかも
8/9 @_
8/10 @_
8/11 @_
8/12 @_
8/13 @_
8/14 @_
8/15 @k7a_5 AssetBundle(Addressable, ScriptableBuildPipeline)関連で何か
8/16 @_
8/17 @_
8/18 @mao_ 最適化周りについて何か書きたい。(予定、変わる可能性有)
8/19 @pCYSl5EDgo Mono.Cecilについてなんか書く
8/20 @_
8/21 @kimika127 MVRP関連で書きます
8/22 @_
8/23 @_
8/24 @_
8/25 @_
8/26 @_
8/27 @_
8/28 @_
8/29 @_
8/30 @_
8/31 @_
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityゆるふわサマーアドベントカレンダー 2019 #ゆるふわアドカレ

はじめに

前回: Unityゆるふわサマーアドベントカレンダー 2018

本来12月に行われるアドベントカレンダーを8月にやろうという試みです!
Unityの楽しいゆるふわな記事で令和最初の夏を盛り上げましょう?
(参考: Unity アセット真夏のアドベントカレンダー 2018 Summer! – Unity公式 Asset Portal)

問い合わせ等はこちらまで:@nkjzm

ルール

  • どなたでも参加いただけます。
  • テーマは「Unityに関すること」なら何でもアリです!
    • ゆるふわじゃないテーマでも大丈夫です。
  • 記事の形式は自由です
    • Qiita、個人ブログ、YouTubeなど
  • (できるだけ)当日までに記事を書いて登録してください。
    • 締切を過ぎた枠があれば、上書きして参加可とします。
  • 何か不明点等あればTwitterかコメントまでお願いします。

参加登録の方法

  • 編集リクエスト機能を使い、参加したい日付に以下の項目を記入して送ってください。
    • 執筆者 (名前だけでもQiitaのアカウントでもTwitterでも大丈夫です)
    • タイトル (仮でも大丈夫です)
  • 後からでも修正可能です。
  • 締切を過ぎると他の人に上書きされる可能性があるのでご了承ください。

記事の投稿後の登録方法

  • 編集リクエストで記事のタイトルとURLを送ってください。

最後に

全部埋められるように頑張りましょう!!
皆さんのご参加お待ちしております!!!!

Unityゆるふわサマーアドベントカレンダー2019

日付 執筆者 記事
8/1 @nkjzm なんか書く
8/2 @pCYSl5EDgo LINQ to NativeArrayについてなんか書く
8/3 @guru_taka 何か書く
8/4 @fal_virtual VRChatでヲタ芸をできるようにするまで。
8/5 @kyusque UnityのReduxアセット色々触ってみる
8/6 @_
8/7 @taptappun Unity × Websocket 〜Unityでリアルタイム通信を実装したい人のためにテスト環境を作ったよ〜
8/8 @GONBEEE_project 音ゲー作るときの設計思想とか書くかも
8/9 @okprogramming なんかかきます
8/10 @shinyoshiaki UnityとWebVRでリモートデスクトップを実装して辛かったこと
8/11 @edo_m18 シェーダについてなんか書きます
8/12 @dfk_ohnuma 音ゲーにまつわる何か
8/13 @_
8/14 @_
8/15 @k7a_5 AssetBundle(Addressable, ScriptableBuildPipeline)関連で何か
8/16 @Raspberly 何か書く
8/17 @nanaki_pg VR関連で書く予定
8/18 @mao_ 最適化周りについて何か書きたい。(予定、変わる可能性有)
8/19 @pCYSl5EDgo Mono.Cecilについてなんか書く
8/20 @kingyo222 何かかきます
8/21 @kimika127 MVRP関連で書きます
8/22 @Sunmax0731 Unityとセンシングについて何か
8/23 @JunkiHiroi マップゲームについてなにか書きます
8/24 @reximology 未定ですがエディタ拡張まわり?
8/25 @am1tanaka Addressable Assets Systemかテストの体験記あたりを書きたい
8/26 @UnagiHuman OculusQuest + RealsenseD400について書きます
8/27 @taptappun Unityテスト CI周りの話を書こうかな(変更する可能性あり)
8/28 @tan-y 小ネタになりそうですが・・・
8/29 @monry Package Manager 関連何か書く
8/30 @lycoris102 夏の終わりに何か書きます?
8/31 @songofsaya_ Unity板ポリレイマーチング入門
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RPG作成(UE4・Unity・DirectX・DXライブラリ、、、その他、諸々)(stage:0)

はじめに

一部、自分の書いた記事があるキーワード検索で上のほうに来るようになってしまっている(非常にありがたいことであるが、ほとんど退屈しのぎで書いているものなので、責任はあまり持ちたくはないのだが、、、。なので、誤解・疑似科学的な偽物記事になってしまう可能性もあるので、そこはお許しをm(_ _)m)

「ファイゲンバウム数」「Unity マリオ アクションゲーム」「数理科学 qiita」を検索(ぺこり)。

追記(2019/07/02):いろんなキーワードで検索結果がでるようになりました。
「数学」でも出るようになったことは、大変ありがたく存じます。
「数学好き」としては,,,

RPG作成の進行の前に

結局は、個人作成において作りたいものしか作れないというのが根底にあると思う(ビジネスではない以上)。

なので、まずはRPGに限らず「作りたいものを作るには」に焦点を絞っていこう。

作りたいものを考える

結論から言ってしまうと、思いつくまで待つしかないというのが私なりの結論である(この記事も次の成果物作成のアイディアを思いつくまでの時間しのぎであるがゆえに、、、)。

しかし、人生は長い(当方、30代後半を迎え、焦りはあるがやはりそれでもこれからである。これからが勝負であるために)。

しかし、日常生活に刺激はいくらでもあるものである。

  • ひと
  • もの
  • こころ

至る所に刺激はある(心をくすぐられるものは随所にある)。人間は失敗をする生き物である。その、違和感やそれが結果オーライで成功した時の誉れは何事にも代えがたいであろう。。

何事も、まずは模倣から入るのが吉となる。
模造品にも価値がある
まずは、ソースコード丸写しでも良いので簡単なことから始めるのもよい。

もう一つのアプローチがある。

あえて難しいものに挑戦してから、挫折して簡単なものに一旦帰ってくるという方法である。

人間、甘えが生じると簡単な仕事しかさせてもらえなくなる(やはり、刺激に満ちた人生のほうが美しいものである。泥臭くとも)。

「stage:0」はここまで記載すればいいだろう。

  • 簡単なことから始める
  • あえて難しいものに挑戦してから、挫折して簡単なものに一旦帰ってくる
  • 難しいものをやり続ける【それで良いのなら、何ら問題はないが、、、

このような形で、ソフトウェア工学的な話になってしまったが、具体的なことはいくらでも後でできる。
まずは、表面をなぞることから(教えてくれる人がいればなおよい)継続していければいいよね、、、

以上

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

3D系ソフトの視点操作方法の一覧表(Unity,Blender,Sculptris,MagicaVoxel)

  • 使用している3D系ソフトによって視点操作の方法が異なるため、一覧にして思い出しやすくした。
  • Windows環境で動作確認

Blender Unity Sculptris MagicaVoxel
回転 中央ボタンDrag
テンキー2,4,6,8
Alt+左クリックDrag 右クリックDrag
左クリックDrag(*1)
右クリックDrag
平行移動 Shift+中央ボタンDrag Alt+中央ボタンDrag Alt+右クリックDrag 中央ボタンDrag
拡大縮小 マウスホイール
テンキー+/-
マウスホイール マウスホイール
Ctrl+右クリックDrag
マウスホイール
正面を向ける テンキー1(前),3(横),7(上)
(*2)
シーンギズモ Shift+回転 5
座標系 右手系 左手系 - 右手系
  • *1 オブジェクトがない場所で
  • *2 180度逆はCtrlを押しながら各数字(例:後ろはCtrl+テンキー1)

その他

  • sculptrisの9つのブラシと、キーボードのFを中心とした9つのキーが位置で対応しているため、対応を覚える必要はなない。(例:scaleは、上段の右なのでT)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む