- 投稿日:2020-02-12T21:24:37+09:00
角丸四角とか円を綺麗に描けるシェーダー作った
BasicShapeSprite
https://github.com/kyubuns/BasicShapeSprite
出来ること
基本的な使い方
- SquareComponent, Mesh Filter, Mesh Rendererを貼り付けたGameObjectを作る
- Mesh Rendererのマテリアルを、BasicShapeSprite/Materials/以下に入っているものにする
- おしまい
直接シェーダーを呼び出す
- 以下の情報を渡してメッシュを描画する
- uv1(float4)
- [0] : x (0.0f - w)
- [1] : y (0.0f - h)
- [2] : w
- [3] : h
- uv2(float2)
- [0] : 角丸のR
- [1] : 枠の幅
- uv3(float4)
- 各角を角丸にするかどうか(1.0f or 0.0f)
- [0] : 左下
- [1] : 左上
- [2] : 右下
- [3] : 右上
- 投稿日:2020-02-12T21:01:42+09:00
UnityでROS#のチュートリアルを動かしてみた
はじめに
UnityでROSを動かすためのアセットROS#のチュートリアルをOculusQuest上で動かしてみたところ、
色々躓いたところがありましたので書いておきます。
今回ROSは初めて触ったので、基本的なところがわかっていない状態で進めています。
VirtualBoxの設定で治るとの情報を見つけて、試してみたところ治った!!
— 高浜 (@SatoshiTakahama) February 11, 2020
この後はGazebo=>Unity側の受信処理まで動いて、ロボットが動くようになりました pic.twitter.com/J2cMIVMWBbROS# wiki
ROS#のページです。ここに記載のある1. Installation and Configuration ~ 2.3 Gazebo Simulation Example
を今回動かしています。アセットストア
ROS#のアセットストアのページです。
試行中、アセットストアからダウンロードしたものからリポジトリの最新版(更新はいくつか入っているようでした)に切り替えたのですが、自分が遭遇した問題とは関係なかったようです。VirtualBox上にROSの開発環境を作る
VirtualBoxの環境設定時に参考にさせていただきました。ROS講座
ROSの環境設定時と、ROSの基礎知識の確認に参考にさせていただきました。ROS入門から各種応用まで非常に幅広い内容を丁寧に解説されています。開発環境
Unity 2019.3.0f5
ROS# 当初1.6 => リポジトリから2020/2/8にダウンロードに切り替え
Oculus Integration for Unity - 12.0
VirtualBox 6.1.2
ホストOS Windows10 Home バージョン1909
ゲストOS 当初Ubuntu 18.04 LTS => Ubuntu 16.04 LTS
ROS kinetic躓いたところ
ゲストOS
最初、UbuntuのLTS最新版でよいかと思い18.04 LTSを入れたのですが、ROSのバージョンkineticを使う場合は16.04 LTSが必要でした。
ROSのバージョンMelodicであれば18.04 LTSでよいのですが、TurtleBot2をみるとkineticを使っている前提のようにも見えたのでkineticを選択しました。ROS#自体はMelodicで動作するようですので、Melodic+18.04 LTSでもよかったのかもしれません(未確認です)。VirtualBoxの設定
当初、ディスプレイ->スクリーン->3Dアクセラレーションを有効化:有効化の設定で使用していたのですが、これが原因で、後でGazeboを起動するときにSegmentation Faultが発生しており、解決に非常に時間がかかりました。設定は後で変更できるので、現象が発生するようであれば無効化に切り替えてもよいと思います。Guest Additionsのインストール
画面サイズの追従やクリップボードの共有のために必須の設定なのですが、Ubuntuのインストール直後にそのまま設定すると失敗します。必要なパッケージを設定してから実行する必要があります。VirtualBox Guest Additionsのインストールを参考に設定しました。ROSで謎のエラーが発生する
チュートリアルの2.1 Transfer a URDF from ROS to Unityを実行したところ、ROS側で以下のようなエラーが発生しました。
これについては、
catkin_make
のあとに
source ~/.bashrc
を実行することで解決しました(どうやらcatkin_makeの後は毎回必要なようです)。自分の.bashrcには、ROSのインストールのスクリプトで設定された内容が追加されています。RVIZ起動でエラーが発生する。
チュートリアルの2.2 Transfer a URDF from Unity to ROSを実行したところ、ROS側で以下のようなエラーが発生しました。
これについては、catkin_ws/srcフォルダで、
git clone https://github.com/ros/joint_state_publisher.git
cd ..
catkin_make
source ~/.bashrc
を実行することで解決しました。OculusQuestで実行するとエラーが発生する
チュートリアルの2.3 Gazebo Simulation Exampleを実行したところ、PC(Unityのエディタ)では問題なかったのですが、OculusQuest上で実行すると、大量のNullReferenceExceptionが発生しました。発生していた場所はJoyPublisher.csだったのですが、調査のためにあちこちDebug.Logを入れていたところ、なぜかStartにDebug.Logを追加すると現象が発生しなくなりました。原因は不明なのですが、とりあえずはこれで動かしています。ROS側で2回目以降の受信ができない。
前項と同じチュートリアルで、1回目の受信ログは残るのですが、2回目以降の受信ログが残らない現象が発生していました。
rostopic echo /joy
で確認してみると、Unity側からのメッセージは送られているように見えました。
受信のスクリプトjoy_to_twist.pyで、受信処理の最後のrate.sleep()をコメントアウトしたら動くようになりました(メッセージを受信するごとに動かすところなので、ここでウェイトを入れる必要はないはず)。
追記1
OculusQuestで実行する部分は、元のチュートリアルから追加した部分になります。OculusQuestでジョイスティックを使用するために、RosConnectorに付加されたコンポーネントJoy Axis Reader(2か所)の設定を以下のように変更しています。
Horizontal => Oculus_CrossPlatform_PrimaryThumbstickHorizontal
Vertical => Oculus_CrossPlatform_PrimaryThumbstickVertical
- 投稿日:2020-02-12T18:00:20+09:00
「UnityのARFoundationでAR空間に豆腐を召喚する」をやって、ARFoundationをフレームワークとして使う上で困らないレベルに理解してみた
はじめに
ARFoundationを利用したオリジナルARアプリを作成するにあたり、@shun-shun123さんのQiita記事にあった「UnityのARFoundationでAR空間に豆腐を召喚する」を練習でやってみた。
元記事URL:https://qiita.com/shun-shun123/items/1aa646049474d0e244be今回は、上記記事を通じて「ARFoundationをフレームワークとして使う上で困らないレベルに理解してみた」内容を書いていこうと思う。(ほぼ公式サイトを和訳しただけ)
※ARFoundationで提供されるスクリプトのコード理解も後でやりたい
Unity公式サイト ARFoundationページ:https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@3.0/manual/index.html#basic-setup環境
Unity 2019.3.0f6
ARFoundation 3.0.1
AR Subsystems 3.0.0
ARKit XR Plugin 3.0.1
XR Legacy Input Helpers 1.3.8
Xcode 11.3.1
macOS Catalina 10.15.2
iOS 13.2.3基本設定
まずはじめにSceneに「AR Session」と「AR Session Origin」をGameObjectとして追加する。
※画像はUnity公式サイトよりこの2つのObjectはAR機能を実装する上で必須らしい。
それぞれが果たしている役割が公式サイトに書いてあったので読んでみた。AR Session
・一連のAR体験をコントロールする(セッション機能)
・ターゲットのプラットフォーム(実機等)でAR機能を利用可能/不能にするAR Session Origin
・検知したObjectの特徴(位置・向き・大きさ)を確定させる
AR体験においては、「現実世界で検知したものをデジタルなGameObjectとして認識」or「現実世界にデジタルなGameObjectを生成」のように、カメラ越しにリアルとデジタルが重畳表示される。
その際に、例えばカメラが移動してもセッション開始時の原点を覚えておくことで、現実世界で適切にGameObjectの位置・向き・大きさを表示することができる。このAR Session Originが果たす役割上(現実世界で適切にGameObjectの位置・向き・大きさを表示)、「現実世界を認識するCamera Object」&「現実世界に生成させるGame Object」は、AR Session Originの子Objectでなければならない。
※AR CameraがAR Session Originの子Objectになっている。
※今回「現実世界に生成させるGameObject」である豆腐は、豆腐PrefabのジェネレータスクリプトをAR Session Originのコンポーネントにしている。AR Camera
初期設定から自分で変更した点があったので、ついでにAR Cameraについても書いておく。
上述の通り、AR Session Originの子Objectに配置されるAR Cameraだが、下記3つのコンポーネントを有している。① AR Camera Manager
・実機カメラのAuto Focusモードのオン/オフ
・現実世界の光量計算機能のオン/オフ(パフォーマンスに大きく影響するので基本はオフに設定)
※画像はUnity公式サイトより② AR Camera Background
・実機カメラの映像を背景として表示させる(自分で背景映像をカスタム可能だが、ARアプリなら基本的にはこのまま使う)
※画像はUnity公式サイトより③Tracked Pose Driver
・実機カメラの位置と向きを認識する(実機から位置・向き情報を読み出す)
※画像はUnity公式サイトより公式サイトには、「AR Cameraには上記3つのコンポーネントがある」と書いてあったのだが、私がAR Session OriginをSceneに追加したときには、Tracked Pose Driverではなく、AR Pose Driverとなっていた。
後々、不具合が発生してもめんどくさいので、公式サイトに則ることにし、AR Pose DriverをDelete、Tracked Pose DriverをAddしておいた。
※AR Pose DriverとTracked Pose Driverの違いは、後ほどコードを紐解きつつ理解したい。平面検知 & 検知した平面に豆腐召喚
豆腐を召喚させる方法として、元記事ではまず平面検知をしていた。
平面検知の実装方法としては、AR Plane Managerを、GameObjectのAR Session Originにコンポーネントとして追加するだけで完了。
(厳密には、AR Plane Managerを、ScriptのAR Session Originと同様のGameObjectに追加していればOK)また「画面タップしてRay(光線)を飛ばし、その光線と検知した平面が衝突した点に豆腐を召喚」という機能を実装するため、AR Raycast ManagerをAR Session Originにコンポーネントとして追加。
最後にPlace On Plane(これは自分で1から書くScript)もAR Session Originにコンポーネントとして追加。
※この辺の実装方法・コードは元記事を見ていただきたい。
※元記事URL:ちなみにAR Session OriginのInspectorは最終的にこんな感じになった。
これで実装完了なのだが、最後の最後に戸惑った部分があったので共有しておく。
実際に実機(iPhone11 Pro)で動かしてみたときに、検知した平面をタップしても、豆腐が召喚されないという現象が起きた。エラーは何も見当たらないのに。
原因は、召喚した豆腐がデカすぎてカメラが豆腐の内側に入ってしまったため、召喚されていないように見えていただけだった。
TofuPrefabのScaleをX・Y・Zすべて 1→0.1 に変更して解決。Trackable Manager
AR Plane Managerは、ARFoundationで提供されるTrackable Managersのひとつで、Trackable ManagersはScriptのAR Session Originと同様のGameObjectに追加される必要がある。
理由は、前述した通り、AR Session Originが果たす役割である(現実世界で適切にGameObjectの位置・向き・大きさを表示)。
※画像はUnity公式サイトより
※ちなみにTrackable Managersは上記表の種類がある。
今回、平面検知に使用したAR Plane Manager だけでなく、例えばAR Tracked Image Managerを使用すれば人体検知ができたりする。Trackable Managersは、各々が検知可能な現実世界の物体が定められており(あるいは自ら定義することも可能っぽい)、その物体検知に基づき、GameObjectの生成・削除を常にupdateしている。
最後に
ARFoundationをフレームワークとして使える状態になるために、この記事を書いてみたが、人に説明できるまで理解するのはやっぱり難しい、、(まだコードの紐解きはできていないし、、、泣)
用語の使い方がおかしかったり、公式サイトの英語をニュアンスで理解してしまっている部分もあるので、間違っている部分があればご指摘いただけると幸いです。
あと、これまで新しいフレームワークを勉強するときは日本語のサイト・記事でどうにかしようとしてばかりいたけど、ARFoundationに関しては公式サイトが一番体系的で分かりやすかった。
英語から逃げてたらダメだ、、!!Unity公式サイト AR Foundationページ:https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@3.0/manual/index.html
初めて知った用語たち
offset
https://wa3.i-3-i.info/word11923.html
→位置を基準点からの距離で表すことsession
https://it-trend.jp/words/session
→接続を確立してから切断するまでの一連の通信のこと。
- 投稿日:2020-02-12T15:53:25+09:00
Unity + Aseprite でドット絵ゲーム開発に快適な環境を目指す
想定環境
Windows10Pro(64bit)
Unity2018.4f
Aseprite v1.2.1
作ったもの
スプライトシート内のそれぞれのスプライトにそれぞれの Pivot やサイズを保持したままAnimation Importer でインポートできるよう、Animation Importer を改修してみました
https://github.com/john95206/AnimationImporter/tree/add-applying-slice-parameter-option
Unityでドット絵ゲームを作る
Unityでドット絵ゲームを作るために、まず必要なのは、スプライトシートです。
まずはこんなのを用意して、適宜設定をし、スライスし、アニメーションさせるという流れになると思います。
やることが…やることが多い…!!
はい。やってみると意外と大変です。Unity標準の Animation/Animator はそれなりに癖がありますし、アニメーション機能を自作するのもかなり骨が折れます。
そこまでするならGameMakerでよくね?Asepriteの強み
そこでおすすめなのがAsepriteです。
https://www.aseprite.org/スプライトシートを作るまでならEDGEだろうがフォトショだろうがペイントだろうがなんだっていいのですが、Asepriteは、json出力や、コマンドラインによる操作にも柔軟に対応していて、非常に拡張のしがいがあるという点で強みがあります。(言ってる意味がよくわからなくても大丈夫です)
上記の機能をうまく活かしてくれた素晴らしいツールの一例としてAnimation Importerがあります。
https://github.com/john95206/AnimationImporterこれを Aseprite と組み合わせると、Asepriteの編集ファイル(.ase)をUnityのプロジェクト下に置き、専用のWindowにドラッグアンドドロップするだけで、スプライトシート・Animation・Animatorを自動で生成してくれます。
https://blog.redbluegames.com/unity-tutorial-animate-pixel-art-using-aseprite-and-animation-importer-5c4fe1e06985最強ですね。
Animation Importer の欠点
最強の拡張ツール Animation Importer ですが、使ってみるとところどころかゆいところに手が届かなかったりします。(自分のために作られたものではないので当たり前ですが)
例えば、次のような場合にもんやりします。
- スプライトシート内の各Sprite のサイズやPivotがまちまちな場合
- Animation内でスクリプトの呼び出しやコライダーなどのプロパティを変更してる場合
まず、Animation Importer で絵を更新する場合、スプライトシート・すべてのAnimation・Animatorは一度削除され、新たなアセットとして生成しなおされます。
そのため、Animation Importerでそれらを生成した後に行った変更(スプライトシートならばSliceのやりなおし・Pivotの手動変更、Animationならばイベントの追加やプロパティの変更)はすべて消えてしまいます。
そういうことならばそうなっても困らないようにルールを決めて絵を作ればいいじゃんと言えばその通りなのですが、せめて一点目のPivotやサイズに関しては何も気にせず作りたいなと思って頑張ってみました。
Costom Pivot や Sprite のサイズを自由に設定したまま開発したい!
現行の Animation Importer でも Pivot の設定項目はあるんですが、これはあくまで一律の設定なので、各Sprite毎の設定は今のところできないようです。
また、Unityの仕様上、前述のようにアセットを削除して新規作成しなおすというフローは致し方ないものがあります。
ではどうするか。Aseprite1.2beta 以降に実装された、Sliceを使います。
Aseprite の Slice 機能
Sliceとは、雑に説明すると、UnityのSpriteEditorをAsepiriteでも使えるみたいなものです。
わたしもまだこの機能を把握しきっていないのですが、本稿では上記の機能として扱います。(もしかしたら結構イレギュラーな使い方かも)Aseprite上で Shit + C を押すと、Sliceモードになります。この状態で選択した矩形は、Slice Property として登録されます。おあつらえ向きにPivotのプロパティもあるので、SpriteEditorと同じようにPivotも登録します。
上図だと、矩形の下に小さな1ドットの四角が Pivot になります。
Slice プロパティをAnimation Importerに反映させる
冒頭でもリンクを貼りましたが、この度、このSliceプロパティをそのままスプライトシートのSliceの設定としてスプライトシートを作れるよう、Animation Importerを拡張しました。(プルリク済み)
https://github.com/john95206/AnimationImporter/tree/add-applying-slice-parameter-option
使い方は以下の通りになります。
- 上記リンクから、改修版 Animation Importer をダウンロードして自分のプロジェクトに適用します。
- (Aseprite側)すべてのコマに、Slice設定を一つずつだけ登録する。Sliceを一つ登録したらそのたびにSaveします。この時、直前のコマと同じプロパティの場合、新たなSliceと認識されないので、少しずらしてSave→戻してまたSaveといった手順が必要になります。(もっといい手があるかもです)
- (Unity側)Anim Importer のウィンドウを開き、新たな項目 Apply Slice Parameter にチェックを入れます。(この時Pivotの項目が消えますが、仕様です。チェックを外すと戻ります。)
以上です。後は今まで通りAnim Importerで.aseファイルを読み込ませるだけです。
最後に
ドット絵の新作ゲームはここ数年で、もはや珍しいものではなくなってきています。
わたしも、そして数えきれないほどたくさんの開発者が、ドット絵ゲームを新規開発しています。しかし、いざ作るぞ!となった時、ドット絵の描き方や描きやすいツールは調べれば簡単に見つかるのですが、その開発環境についてはあまり語られてきていないと思います。
今後は、本稿だけでなく、いかにして楽してドット絵ゲームを作っていくか、よりよいドット絵ゲーム開発環境とはどんなものかを議論する機会が増えればいいなあと思っています。
- 投稿日:2020-02-12T15:16:32+09:00
Unityでアニメーションさせたらコライダーがずれる解決方法
blender2.8 でダメージを受けたら後ろに飛ばされるアニメーションを作って
unityで使用しようとしたところコライダーだけがその場に残ってキャラクターのアニメーションについてこない現象が起こりました。
解決方法
unityでアニメーションを動かして座標が動いているボーンを(数字が動く)探して
その子要素に空のゲームオブジェクトを作成。コライダーと当たり判定のスクリプトをアタッチする。
あたりのtagづけなどの設定も忘れずにする。
- 投稿日:2020-02-12T14:23:18+09:00
UnityでWheel Colliderを付けた車両が荒ぶるのを落ち着かせる方法
- 投稿日:2020-02-12T13:17:36+09:00
Unity 2019.3のHDRP (DXR使用)でLightmapと併用 (Tier1)
Unity 2019.3のHDRP(DXR使用)の説明です。
プロジェクトの設定については「Unity 2019.3のHDRP (DXR使用)のプロジェクトを作成」もご参照くださいませ。木造の建築物を読み込み、これを使ってフォトリアルなシーンにしていきます。
ここでは「Tier1」を使用し、間接照明はLightmap + Reflection Probe + Light Probeを併用しました。なお、この木造建築のシーンはGitHubの「Unity2019_3_HDRP_DXR_RoomTest」にプロジェクトを公開していますので、こちらもご確認くださいませ。
ここで行うことは以下になります。
- Iter1を使用する
- Ambient Occlusion/Screen Space Reflectionでレイトレーシングを使用
- Global Illuminationのレイトレーシングは「使用しない」
- 間接照明(GI計算)部はLightmapのベイク処理に置き換える
DXRの効果として、Ambient Occlusion/Screen Space Reflectionでレイトレーシングする、ということになります。
それ以外は普通のHDRPと変わりません。Tier2での表現 (参考)
リファレンスとして「Tier2」の「Path Tracing」使用と比較します。
この段階では、まだLightmapのベイクやReflection Probeの配置は行っていません。
「Ambient Occlusion」「Screen Space Reflection」「Global Illimination」をすべてOffにして、
レイトレーシングを使用しないようにすると以下のようになりました。
「Path Tracing」を有効にする (Tier2)
Tier2で「Path Tracing」を有効にし、「Maximum Samples」を512、「Maximum Depth」を5にしました。
Path Tracing未使用時のままのIBLの場合は明るすぎるため、「Sky and Fog Volume」の「HDRI Sky」の「Exposure」を10から2に変更しました。
以下のようにレンダリングされました。
「Post Process Volume」の「Exposure」の「Fixed Exposure」を8.7から6.0に変更し、全体的に明るくして室内を表示しました。
室外から室内に移動する場合、そのままの露出だと全体が暗いままになるため、露出調整は必要になります。
Tier2の場合は、特にLightmap/Reflection Probeを使用しなくてもフォトリアルな表現になっています。
ただし、Fogは効いていません。「Path Tracing」を無効にする (Tier2)
「Path Tracing」を無効にし、「Ambient Occlusion」「Screen Space Reflection」「Global Illimination」をOnにします。
「Screen Space Reflection」「Global Illimination」の「Bounce Count」を指定していますが、
「Path Tracing」を使った場合と比較してリアルさは薄れています。Tier1での表現
速度面と表現面の両方を確保した状態で表現力を上げたいため、Tier1を使用して以下のような手順を取りました。
- Lightmap用のベイク光源をArea Lightで配置
- 直接照明の光源は、Realtime光源として配置
- 間接照明の大部分は、Lightmapに頼る (レイトレーシングのGlobal Illuminationを使わない)
- 映り込みは Reflection Probeも使用 (レイトレーシングのSSRも併用)
- Staticでない形状の光源の間接照明の補間として、Light Probeを使用
リファレンスとして、Tier2時の「Path Tracing」の結果を目指す、とします。
直接照明や一次反射でレイトレーシングを使用することでフォトリアルに近づけます。Tier1に変更
メインメニューの「Edit」-「Project Settings」を選択し、「Graphics」を選択します。
「Scriptable Render Pipeline Settings」に割り当てられている「HDRenderPipelineAsset」を選択すると、Project上の実ファイルがハイライトされます。
このAssetを選択し、Inspectorで「Raytracine Tier」を「Tier 1」に変更します。
以下のように、ぬるい感じになりました。
上記は、レイトレーシングとして「Ambient Occlusion」「Screen Space Reflection」「Global Illumination」を使用しています。
「Path Tracing」は無効にしています。Tier1の場合は、Screen Space ReflectionやGlobal Illuminationで複数回の再帰的な反射は行われないのと、いくつか精度を犠牲にしているようで(Reflectionの解像度など)、Tier2よりは品質が下がります。
これより、パラメータの調整とLightmap/Reflection Probeの使用で補っていきます。
Lightmapの指定
Lightmapを行う手順は、以下の流れになります。
これはHDRPやDXRに限らず、Unityでは共通の作業になります。
- 建物の形状で「Gegnerate Lightmap UVs」を有効にする
- シーンの建物を「Static」にする
- Lightingウィンドウでベイクを実行
Projectウィンドウでインポートした形状を選択し、Inspactorの「Model」の「Gegnerate Lightmap UVs」をOnにしてApplyボタンを押して確定します。
これは形状のすべての面が重ならないようなUVを作成します。Lightmapをベイクする際に利用されます。
この指定がない場合は、一番最後のUVレイヤがLightmap用として参照されます。Hierarchyウィンドウで、Lightmapのベイク対象の形状を選択します。
ここでは木造の建物と地面に同じ処理を行いました。
対象形状のInspectorで右上の「Static」をOnにします。
子形状がある場合は、それもStaticにするか聞いてきます。子もStaticにしました。
こうすることで、Lightmapのベイク対象になります。Lightingウィンドウを開き、Sceneタブを選択します。
室内シーンなので「Lightmapping Settings」の「Lightmapper」で「Prograssive CPU」が選択されていることを確認します。
「Prograssive GPU」を選択したほうが計算速度が速いのですが、複雑なシーンだとGPU計算の場合に失敗する場合があるため、CPUで計算します。
また、「Bounces」を2から4に変更しました。
こうすることにより、Lightmapのベイク計算の時間はかかりますがより間接照明が回り込むことになります。
「Generate Lighting」ボタンを押すとLightmapのベイク計算が開始されます。
この計算は、シーンの規模が大きくなれば時間がかかります。
数十分から数時間かかる場合もあります。以下は、Lightmapを使用しない場合+各レイトレーシングの要素を使用したときの結果です。
要素 有効/無効 その他 Lightmap 未使用 - Reflection Probe 未使用 - Light Probe 未使用 - Ambient Occlusion 有効 Ray Tracing On Screen Space Reflection 有効 Ray Tracing On Global Illumination 有効 Ray Tracing On Lightmapのベイクを適用しました。
「Global Illumination」のレイトレーシングを使っている場合は結果はほぼ変わらなかったです。
要素 有効/無効 その他 Lightmap 有効 - Reflection Probe 未使用 - Light Probe 未使用 - Ambient Occlusion 有効 Ray Tracing On Screen Space Reflection 有効 Ray Tracing On Global Illumination 有効 Ray Tracing On Lightmapを使用した場合+「Global Illumination」を無効にした場合は、部屋の奥が暗くなりました。
このほうが結果として正しそうです。
要素 有効/無効 その他 Lightmap 有効 - Reflection Probe 未使用 - Light Probe 未使用 - Ambient Occlusion 有効 Ray Tracing On Screen Space Reflection 有効 Ray Tracing On Global Illumination 無効 - ただし、この場合はStaticではない形状に対してベイクの効果が適用されないため浮いたようになります。
これを解決するには、映り込みについてはReflection Probeを使用、
Staticでない形状での光の当たり具合はLight Probeを使用する必要があります。Reflection ProbeとLight Probeを使用しない場合は、室内に移動すると以下のようになりました。
要素 有効/無効 その他 Lightmap 有効 - Reflection Probe 未使用 - Light Probe 未使用 - Ambient Occlusion 有効 Ray Tracing On Screen Space Reflection 有効 Ray Tracing On Global Illumination 無効 - 机や椅子、奥のタンスなどのライティングが正しくありません。
廊下の映り込みも明るくなっています。Reflection Probeの配置
部屋の角や光の変化がある部分に、Reflection Probeを配置しました。
この後、再びLightmapのベイクを行いました。
要素 有効/無効 その他 Lightmap 有効 - Reflection Probe 有効 - Light Probe 未使用 - Ambient Occlusion 有効 Ray Tracing On Screen Space Reflection 有効 Ray Tracing On Global Illumination 無効 - 床部分の映り込みが変化しています。
Light Probeの配置
壁の境目などの光の変化が激しくなりそうなところに、Light Probeを配置しました。
等間隔にLight Probeを並べるようにしています。
なお、Light ProbeやReflection Probeのアイコン類は、Scene Viewの上の「Gizmos」をOnすることで表示されます。
この後、再びLightmapのベイクを行いました。
要素 有効/無効 その他 Lightmap 有効 - Reflection Probe 有効 - Light Probe 有効 - Ambient Occlusion 有効 Ray Tracing On Screen Space Reflection 有効 Ray Tracing On Global Illumination 無効 - 机や椅子、奥のタンスなどのライティングが正しくなりました。
以上で、「Ambient Occlusion」「Screen Space Reflection」でレイトレーシングを使用、
Global Illuminationを未使用とし、Lightmapで置き換えました。
Lightmapを使用しないときよりも明暗のメリハリがつきましたが、廊下と机や椅子との接地感が弱い、全体的なフォトリアル感がない、など気になる点があります。
次にこれらを改善していきます。Area Lightの配置
間接照明は、Area Lightを使用して間接照明をわずかに補助します。
この光源は、Lightmap用としてBakedを指定しました。
「Baked Shadows」もEnableを指定しました。「Intensity」は2000 Lumen、「Range」を20として、ほんのわずかに照らすようにしています。
Area Lightを配置後、LightingよりBakeを実行します。Directional LightをOffにして、背景のIBLとArea Lightだけにすると以下のようになりました。
Directional Light(Realtime)をOnにすると以下のようになりました。
Ambient Occlusionの調整
接地感が弱い箇所を補間するために、Ambient Occlusionを調整します。
「Ray Tracing Settings」を選択してInspectorを開きます。
「Ambient Occlusion」の「Intensity」を0.72から3.5と強くしました。
「Denoise Radius」を0.5から0.2に変更しました。
これは、Denoise時に収集する半径になりますが、これが大きいとAOの効果が飽和したようになって見えにくくなるため、小さくすることでより影響が出るようにしています。
Directional Lightの影の品質を上げる
Directional LightのInspectorを開き、Shadowsの「Resolution」を「Ultra」にすると2048解像度のシャドウマップになります。
また、「Screen Space Shadows」をOnにすると品質が少し上がります。
Screen Space Reflectionの品質を上げる
「Ray Tracing Settings」を選択してInspectorを開きます。
「Screen Space Reflection」の「Minimun Smoothness」の値を下げると、
個々のマテリアルでSmoothness値がそれ以上の場合はレイトレースが行われます(それ以下の値の場合はSSR)。
これにより、GPUリソースを消費しますが1次レイの映り込みの品質が上がることになります。
「Minimun Smoothness」を0.7から0.3に下げました。
天井や奥の壁の照り返しが少し増しました。
以上で、Lightmap/Reflection Probe/Light Probeとレイトレーシング周りの調整が一通り完了したので、
あとはPost Processingの調整を行います。Post Processingの調整
Vignetteで「Intensity」を0.3として、少しだけ強めにしました。
Exposureで「Mode」を「Automatic」として、自動露出にしました。
こうすることで、室内と室外に移動してもその都度Exposureを調整する必要がなくなります。
また、「Limit Max」を8としました。
White Balanceで「Temperature」を10としました。
少しだけ暖色になるようにしています。
Chromatic Aberrationで「Intensity」を0.095としました。
Tonemappingで「Mode」をNeuralとしました。
Color Adjustmentsで「Post Exposure」を0.7にしました。
これにより、少しだけ明るくします。
「Saturation」を-10にしました。
これにより、少しだけグレイスケールの要素を入れて全体を落ち着かせています。
Depth Of Fieldで「Focus Mode」を「Manual」とし、Near Blur/Far Blurの値を指定してボカシを与えました。
なお、DOF効果はGame Viewで表現されます。Scene Viewでは表示されません。
Post Processingの調整の結果、以下のようになりました。
光沢用の光源を配置
上記画像では床の映り込みの光沢が薄いです。
光沢に関しては、Point LightをRealtime光源として配置するとしました。
Point Lightの影(Shadow Map)は無効にしています。
以下のようになりました。
床の光沢感が増しました。
これは本来はないニセ光源ではあるのですが、光沢を出す場合は特に有効です。HDRIとフォグの確認
HDRIとフォグについては確認のみです。
「Sky and Fog Volume」では以下のように指定しています。
背景を暗くする場合は「Exposure」の値を下げるようにします。フォグはわずかにかけるようにしていますが、もし、強めに与える場合は距離値を調整します。
「Fog Attenuation Distance」を20000から100に変更、「Maximum Height」を5000から1000に変更、「Max Fog Distance」を5000から1000に変更してみました。
以下のようになります。
光が入りにくくなったため、「Directional Light」のEmissionの「Intensity」を10000(Lux)から100000に変更しました。
Spot Lightで強めの光を設けた場合など、フォグがある空間ではボリュームライト表現が行えます。
以下は、Spot LightのEmissionで「Intensity」を5000000(Lumen)と極端に大きな値を与えてます。
以上で、Tier2のパストレーシングを使用しなくても、Tier1でそれなりに詰めることができるのを確認できました。
フォグ効果や速度面を考えると、Tier1を使い、間接照明は従来のLightmapを使う、というのは今のところ有効かもしれません。以上のプロジェクトは、
GitHubの「Unity2019_3_HDRP_DXR_RoomTest」に公開しています。
- 投稿日:2020-02-12T13:07:46+09:00
【VSCode】ちゃんと拡張機能を入れたのに、MonoBehaviourだけ怒られる(動作には支障がない)
- 投稿日:2020-02-12T12:41:47+09:00
【Unity】イメージエフェクトを使用しない簡易GlowShader
なるべく軽量にするため、イメージエフェクトを使用せずに光の玉を表現させる一例です。
一枚の板で、円をぼかし拡大縮小して
光っている風に見せかけてます。vertex
どこから見ても同じように見せるようにビルボードにします。
Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" } ・・・ struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; ・・・ v2f vert (appdata v) { v2f o; o.vertex = mul(UNITY_MATRIX_P, mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0)) + float4(v.vertex.x, v.vertex.y, 0.0, 0.0) * float4(0.5, 0.5, 1.0, 1.0)); // XYのスケーリング }ビルボードについての詳細はこちらの記事が詳しいです。
常にカメラを向くオブジェクトをGPUで実装fragment
四角形からはみ出ない程度に円を描いて良い感じにぼかし、アニメーションさせています。
形状によってはテクスチャのほうがきれいに表現できるかと思います。fixed4 frag (v2f i) : SV_Target { float4 col = _Color; float dist= length(i.uv - 0.5) * 2; // 外に行くほど薄くなるようぼかす col *= saturate(1 - dist); // 中心の光具合を強調・拡縮アニメーション col *= (1 - dist) * lerp(1, 3, sin(_Time.z) * 0.5 + 0.5); col = saturate(col); clip(col.a - 0.0001); return col; }アルファブレンド
背景と馴染むようこれもよい感じに調整。
サンプルの場合はBlend SrcAlpha DstAlphaちなみに確認時は以下のようにしておくとmaterialで調整ができるので便利です。
Properties { [Enum(UnityEngine.Rendering.BlendMode)]_BlendSrc("Blend Src", Float) = 0 [Enum(UnityEngine.Rendering.BlendMode)]_BlendDst("Blend Dst", Float) = 0 } ・・・ Blend [_BlendSrc][_BlendDst]利用できる場面
結局板なので、角度によって他のオブジェクトに板が遮られたりすると
切れ目が不自然に見えたりしまいます。
近距離のオブジェクトとの兼ね合いでどのくらい許容できるか次第かと思います。
- 投稿日:2020-02-12T12:40:22+09:00
VRで飛行移動の開発で調べた酔い対策
はじめに
Unityで一人称視点のVRアプリに飛行移動の機能を開発するに当たって、
主に移動・旋回機能での酔いに関して調べたことと、個人的な感想となります。確認したデバイスは
Oculus Rift s/Oculus Quest/HTC VIVEまた基本的な対策に関しては以下を参考にさせていただいたので、
詳細は参照ください。
- VR等のコンテンツ制作技術活用ガイドライン2018
- VR酔い防止のための真のルール
- ◆VR酔いを防ぐにはどうすればいい!?~エンジニア視点で考える原因と対策~
- 『エースコンバット7』のVR酔いや違和感を排除する戦いの数々!重要な“没入ライン”を越えるためのヒントは『ギャラクシアン3』にあった!?【CEDEC 2019】
- 日本列島VRとHoleLenz
移動方法
元々アプリの移動方式は地上移動のみでテレポート型だったが
飛行移動に関してはスティックの前後操作で前進/後退する仕組み。(空間移動型)
ただやはりこの方式になると酔いに強い/弱い人で結構差が出てくる。対策
脳と体の同期ズレの軽減。見ているものと身体の動きが違うと感じると酔う。
速度は遅く等速直線運動であるほうが酔いにくいとのことだが、移動範囲もあるのでそこそこの速度が必要。
ということで加速度を加えて、後退速度は前進時より低速で移動するように調整。
この辺りは特に日本列島VRを参考にさせていただいた。次の動きを「予測」させて酔いを軽減
進行方向については、HMDで向いてる方向に移動という手法もあるが、
今回は既存の仕組みでVRレーザーポインターを装備していたため、上下前後ポインタの向きに合わせて進むようにした。
向きの指針として認識もしやすいため、進む方向の「予測」の役割を果たせているかと思う。旋回
スティック左右操作での自分の向きを回転
対策
これに関しては常にスナップターン方式(スティックの左右操作一回ごとに30度ずつ回転)
停止・低速状態でスムーズ回転はかなりきつい。
速度がでている状態であればかなり軽減される。(ただ本当にそこそこな速度が出てる状態でないときつめ。)
機能としては旋回できた方が楽しい体験になるが、今回一番酔い影響が強いと感じたところでもあった。その他の対策等
今回は基本的に上記のような対策を行ったが、
さらに酔いを軽減させる方法としては
- 手前に固定のパネル・UIなどを表示。(効果高そう)
- 向きをさらに意識しやすいよう矢印を表示。
- 移動中は速度に応じて視野を狭める類のエフェクトを追加。
- 移動停止時の減速。(未検証)
など。
また当アプリは特にアクション性も低く、周りの動きも激しくないため、
アプリの特性にもよるのかとも思います。
- 投稿日:2020-02-12T00:24:27+09:00
[Unity]ML-Agents「Hide / Escape - Avoidance of Pursuing Enemies」を動かす
かくれんぼのやつが動かない
Unityの機械学習「ML-Agents」を使ったサンプル「Hide」これがエラーするわ動かないわで大変だった
これが動くようになったので、そこまでの記録を残します
ダウンロード
データセット
このサイトの下の方にあるGitHub
Hide
この「いいね!」マークの上にあるリンクからダウンロードします↑このページに飛びます↓
んでダウウンロード↓
「Clone or download」
このセットの中に色々入ってますので
ドキュメントなり普段unityプロジェクトを保存している場所なりに解凍してくださいJson.net
JSON.net
Newtonsoft.json(JSON使うためのもの)をダウンロードしていない人はこちらも後で必要になるので
↓一番上の「Json120r3.zip」だけで大丈夫です
適当にダウンロードして適当に解凍してください
後で必要になりますUnity
UnityHubを起動し、「リストに追加」
先ほど解凍した
hide-escape-master の中の unity-environment を選択
これで↓「フォルダの選択」
こうなる
噂によるとバージョンは2018.4以上がいいそうなので
2018.4.16をインストールこんな感じで↓バージョン変更して開く
ウィンドウ出ますが「確認」押してGO
例のブツをみてみよう
↑の「Hide」というシーンを開く
これですよこれ 見たかったのは~ライティングをOFFにしておく~
本編に特別関係ないけど、何かあるたび光の当たり方を計算されるのはストレスなので、機能をオフにする
開いたウィンドウ↓の一番下にある「Auto Generate」のチェックを外し
「Genaerate Lighting」ボタンを押す
とりあえずエラー
下2つはBlenderインストールしてれば何か違うのかもしれませんが、入ってないのでパス
左上の「Clear」押しても消えないエラーに対処していきます
Json.netをプラグインに入れる
ダウンロードした「Json120r3」の
Json120r3 → Bin → net20 → Newtonsoft.Json.dll を以下の場所にコピペ
参考文献Unityでセットアップ
参考文献
Project Settingの
Playerの
other Settingを開き
ちょっと下の方この
「ENABLE_TENSORFLOW;UNITY_POST_PROCESSING_STACK_V1」
を
「ENABLE_TENSORFLOW」
に変更↓
しかしエラーは減らない
んんんんんんんんんんんん
まあ必要な項目ではあったはずなので、エラーが消えるための設定ではなかっただけでしょうパッケージを入れませう
なんか言ってた
適当なところにダウンロードし、「Import package」でダウンロードしたファイルを指定する
そしたらウインドウでるから、右下の「Import」ボタンをクリック
驚きの白さなんだか様子が変です
「HideBrain」を選択すると
なんか言ってる ファイルがねぇ とこれで動くぜ ヒャッハー!
赤おっっっっせぇぇぇぇ
なんじゃあの移動速度はぁぁぁ一生追いつけんわぁぁぁ赤を早くさせる
「Academy」を選択
「Value」の値を「3」とかにします(お好みで)
こんだけ早ければいいだr…いまUターンしなかった?
これで
盲目の追跡者
が完成しましたね✨(コナン君の映画のタイトルにありそう)
次は赤に視界を設けます
※Blenderが入っていないために、視界のモデル(扇形↓)が生成できなかったと思われ
プログラム的には、
視線上にいる
→扇の当たり判定作動
→青を追いかける
ってなってるので、
扇の代わりを作ればおkつまり、シーンにいる各9人に視界を設けるだけ!!
こんな時のためのプレハブ機能!!視界を作る
仕方ないので方法は2通り
・先を見越して「Chaser」をプレハブに置き換える
・9人の「Chaser」に当たり判定を設ける選ばれたのは後者でした
やり方は簡単
1. 全ての「fov-shape」を同時選択
2. 位置調整
3. メッシュとコライダーを設定1.全ての「fov-shape」を同時選択
2. 位置調整
3. メッシュとコライダーを設定
Mesh Filter の「Mesh」に「Cube」を選択
Mesh Collider の「Mesh」に「Cube」を選択
できた
仁王立ちの追跡者
赤の横を青がスルッと通りすぎると以下のように、到達点で停止するバグが判明
プログラムに工夫が必要
「HideChaser」を開き
グローバル変数を宣言HideChaser.csfloat timer = 0; Vector3 pos;Update()の中に以下を追加
HideChaser.csif(transform.position == pos) { timer += Time.deltaTime; if(timer > 5) { timer = 0; Debug.LogWarning("Stopped"); agentInFOV = false; agentInLOS = false; chasingAgent = false; PickNextRoom(); } } else { timer = 0; } pos = transform.position;応急処置ですがこれでなんとかなります
一応全文載せておきます↓HideChaser.csusing System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class HideChaser : MonoBehaviour { public GameObject myAgent; public GameObject chaserHead; [HideInInspector] public HideAgent hideAgent; public GameObject[] seekLocations; private float positionDoneThreshold = 0.15f; public GameObject[] chaserInitialPositions; [HideInInspector] public NavMeshAgent navAgent; [HideInInspector] public GameObject currentTarget; public GameObject targetLocationIndicator; [HideInInspector] public bool agentInLOS = false; [HideInInspector] public bool agentInFOV = false; [HideInInspector] public bool chasingAgent = false; public bool showDebug = false; [HideInInspector] public Vector3 lastKnownAgentLocation; private Rigidbody chaserRigidbody; public HideAcademy hideAcademy; public GameObject winZone; float timer = 0; Vector3 pos; void Start () { this.navAgent = this.GetComponent<NavMeshAgent>(); this.chaserRigidbody = this.GetComponent<Rigidbody>(); this.hideAgent = myAgent.GetComponent<HideAgent>(); currentTarget = seekLocations[Random.Range(0, seekLocations.Length)]; navAgent.SetDestination(currentTarget.transform.position); this.targetLocationIndicator.transform.parent = null; lastKnownAgentLocation = Vector3.zero; pos = transform.position; } void Update () { PlaceTargetIndicator(); MoveChaser(); if(transform.position == pos) { timer += Time.deltaTime; if(timer > 5) { timer = 0; Debug.LogWarning("Stopped"); agentInFOV = false; agentInLOS = false; chasingAgent = false; PickNextRoom(); } } else { timer = 0; } pos = transform.position; } void MoveChaser() { // If Agent Has Not Been Seen // Pick next room upon reaching destination if (Mathf.Abs((currentTarget.transform.position - this.transform.position).magnitude) < positionDoneThreshold && (chasingAgent == false)) { //Debug.Log("Chaser Arrived At Location: " + currentTarget); PickNextRoom(); } // If Agent Has Been Seen // Pick next room upon reaching last known location if ((Mathf.Abs((lastKnownAgentLocation - this.transform.position).magnitude) < positionDoneThreshold) && (chasingAgent == true) && (agentInLOS == false)) { //Debug.Log("Chaser Arrived At LastKnownAgentLocation"); chasingAgent = false; PickNextRoom(); } // If Agent is currently seen, chase if (chasingAgent == true) { //Debug.Log("Chase Agent"); ChaseAgent(); } } public void InLOS() { if (agentInFOV) { agentInLOS = true; chasingAgent = true; lastKnownAgentLocation = myAgent.transform.position; } } private void OnCollisionEnter(Collision collision) { if (collision.gameObject == myAgent.transform.gameObject) { HideAgent agent = myAgent.GetComponent<HideAgent>(); agent.done = true; agent.reward -= 10f; agent.losses += 1; } } void PlaceTargetIndicator() { if (chasingAgent == false) { targetLocationIndicator.transform.position = currentTarget.transform.position; } else { targetLocationIndicator.transform.position = lastKnownAgentLocation; } } public void PickNextRoom() { GameObject tempCurrentTarget = seekLocations[Random.Range(0, seekLocations.Length)]; while(tempCurrentTarget == currentTarget) { tempCurrentTarget = seekLocations[Random.Range(0, seekLocations.Length)]; } if(tempCurrentTarget != currentTarget) { //Debug.Log("New target chosen: " + tempCurrentTarget + " Old target was: " + currentTarget); currentTarget = tempCurrentTarget; navAgent.SetDestination(currentTarget.transform.position); targetLocationIndicator.transform.position = currentTarget.transform.position; } } public void ChaseAgent() { currentTarget = myAgent; navAgent.SetDestination(lastKnownAgentLocation); } public void Reset() { // Get curriculum variables from academy float chaserSpeed = hideAcademy.GetComponent<HideAcademy>().chaserSpeed; // Set curriculum variables navAgent.speed = chaserSpeed; this.chaserRigidbody.isKinematic = true; GameObject chaserInitialPosition = chaserInitialPositions[Random.Range(0, chaserInitialPositions.Length)]; this.transform.position = new Vector3(chaserInitialPosition.transform.position.x, this.transform.position.y, chaserInitialPosition.transform.position.z); this.transform.rotation = chaserInitialPosition.transform.rotation; if (hideAcademy.mode == HideAcademy.Mode.Escape) { if (winZone != null) { winZone.transform.position = new Vector3(chaserInitialPosition.transform.position.x, winZone.transform.position.y, chaserInitialPosition.transform.position.z); } } agentInLOS = false; chasingAgent = false; currentTarget = null; //lastKnownAgentLocation = Vector3.zero; this.chaserRigidbody.isKinematic = false; PickNextRoom(); } }モード変更
「Academy」オブジェクトの「Mode」を「Escape」にすると脱出口が現れるようになります
黄色の四角いやつあとはがんばって
動いたはいいけど、果たして機械学習しているのか まだわかってない