UniRxでUpdateを好きな場所に書いて使おう
学部2年のユムルです。
今回はAizuVR部で使っていく可能性のあるUniRxについて話します。
UniRxとは
C#にはRx(Reactive Extensions)という標準ライブラリが存在します。
元々Unityでは使えなかったのですが、neueccさんがUnityでもRxを使える様に開発したものがUniRxです。
UniRxが得意なものは、「何か処理が起こった時に別の処理をする」という処理です。
別名をイベントハンドラーと言います。
イベントとは、プログラムにおけるあらゆる動作のことを指します。
このイベント処理を、自分の好きな場所にわかりやすく書くことができるのがUniRxの利点です。
UniRxのイベント処理について具体的にどう便利なのかは下のサイトを参照して欲しいです。
今回は深く触れないので。
UniRxを導入するメリット ~こういう時にUniRxは使えるよ~
また、UniRxを使うことで別の大きな利点があります。
Updateを好きなところに書いたり、数秒後に特定の処理をするとか、数フレーム毎に処理をするという様な処理が好きな場所に簡単に書けることです。
僕は普段からUniRxを利用しますが、その理由としてはこの側面がとても強いです。
他の機能は理解して利用するのが難しいですが、今回はその内容には深く触れず、UniRx初心者でもすぐに使いこなせる機能を紹介します。
UniRxの導入
UniRxはAssetとして公開されています。
使うときは以下のページからインポート
assetstore.unity.com
そして、コード上ではUniRxとUniRx.Triggersをusingしてください。
using UniRx; using UniRx.Triggers;
Updateを操る
UniRx初心者が真っ先に使いこなせる様になるであろうUpdateに関する機能について話します。
まずお試しにcsファイルを作成。namespaceのusingをしっかりと書いてください。Updateメソッドはいりません。消してしまいましょう。
Startメソッドの中にUpdate処理を書きます。
プリミティブのキューブを作成して、右に移動させます。
void Start() { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = new Vector3(-4f, 0f, 0f); this.UpdateAsObservable() .Subscribe(_ => { cube.transform.Translate(Vector3.right * Time.deltaTime); }); }
StartメソッドだけでCubeを動かすスクリプトが書けました。
見やすさの為、Lightingの設定を変えています。
さて、UniRxでは、この様なメソッドを繋げた書き方をします。
このメソッドの流れの中を、 イベントの情報が流れると思ってください。
そして、UpdateAsObservableは空のイベントを毎フレーム発生させるということです(厳密には発行すると言います)
thisから始まるのは、これを書いたクラスを元にUpdate処理をさせているということです。処理はGameObject依存です。
Subscribeでは、イベントが到達した時に行われる処理を登録しています。
Subscribe(=購読)という名前の意味はRxのイベントの取り扱い方から来ています。
イベントを「発行と購読」と、雑誌の様な取り扱いをしていますね。
Subscribeで処理を渡すと言いましたが、C#には関数をオブジェクトとして扱う「デリゲート」というものと、=>
の記号から、左辺を引数、右辺を処理(と返り値)という様に関数を生成する「ラムダ式」という書き方があります。
デリゲートでは変数名は指定せずに、引数や返り値の型を指定して関数をオブジェクトとして扱います。
ラムダ式では、左辺に変数名を指定しつつ、右辺に処理を書きます
今回は左辺には一つ空のイベントを表す引数(Unit型)が入って来ますが、変数名は基本_
をつけときます。
取り敢えずは_ => 処理
という書き方で処理を渡せるということがわかればOKです。
上の例では、=>
の右辺に毎フレーム実行させる処理を書きました。
この様に、UniRxを使うとUpdate処理を好きな場所に書くことができます。
上の例でも既にやっていることですが、ローカル変数をまるでクラス変数を扱うかのごとく、使えます。
もっとわかりやすく、実用的な例としては、時間を扱う処理でしょう。
var sTime = Time.time; this.UpdateAsObservable() .Subscribe(_ => { var time = Time.time - sTime; cube.transform.localScale = Vector3.one * time; if (time >= 3f) { sTime = Time.time; } });
この処理は3秒毎に基準となる時間を設定し、そのタイミングからの経過時間をCubeの大きさに反映させたものです。
この映像はgifでループされていますが、実際にもこの様に見えます。
この様にUniRxメソッドの中で宣言した変数に状態を持たせてUpdate処理を行うことができるということが確認できました。
従って、ちょっとした処理でクラス変数に変数名を迷いながらつけたり、処理がほとんどない小さなクラスを作らなくても良くなったでしょう。
Updateの書き方はもう一つありまして、
Observable.EveryUpdate() .Subscribe(_ => { }).AddTo(gameObject);
で書くことができます。
前の書き方ではそのままで自身のgameObjectに依存していましたが、
こちらではAddToを書く必要があり、gameObjectを引数に渡すことで、そのGameObjectが存在している間だけUpdateが働きます。
AddToを書き忘れると、GameObjectが消えても動き続けます。
こちらの書き方が優れているのは、先ほどの書き方に比べてパフォーマンスがいいということです。
大量の個別のUpdate処理を回す場合はこちらを使うといいでしょう。
また、UniRxでのUpdateは一定時間処理を回すとか、特定の条件を満たすまで処理を回すとか、コントロールが良く効きます。
次はそれらを見てみましょう。
一定時間だけ処理をする例です。
cube.transform.position = Vector3.down * 3f; this.UpdateAsObservable() .Take(System.TimeSpan.FromSeconds(3f)) .Subscribe(_ => { cube.transform.Translate(Vector3.up * 2f * Time.deltaTime); });
実際に使う場合は、Systemをusingするとタイプ数が減ります。
Takeは、SystemのTimeSpanで設定された時間だけイベント情報を通します。
TimeSpanにはFromSecondsの他にも、FromMilliseconds、FromMinutes等があります。
int型の数値を入れるとフレーム数指定になります
Takeを使うときは、終了時に別の処理を走らせることができます。
this.UpdateAsObservable() .Take(TimeSpan.FromSeconds(時間)) .Subscribe(_ => { // Update処理を入れる }, () => { // 終了時の処理を入れる });
特定の条件を満たすまで処理を回したい場合は、
先ほどのTakeをTakeWhileに変えてやり、中に真偽を返すラムダ式を入れます。
.Take(System.TimeSpan.FromSeconds(3f))
これを
.TakeWhile(_ => {
return !Input.GetKeyDown(KeyCode.Space))
})
これでスペースキーが押されるまで処理を回す様にできました。
ラムダ式の右辺は1文なら括弧はいりません。
.TakeWhile(_ => !Input.GetKeyDown(KeyCode.Space))
さて、UniRxではUpdateを好きなところに書くことができると言いましたが、その利点は処理がわかりやすくなるだけではありません。
普段、Update内でGetKeyDownなどをトリガーに処理をすることがあると思いますが、そこから新たなUpdate処理も走らせることができるということです。
var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); this.UpdateAsObservable() .Where(_ => Input.GetKeyDown(KeyCode.R)) .Subscribe(_ => { var sTime = Time.time; var maxTime = 0.5f; var stop = false; this.UpdateAsObservable() .TakeWhile(_2 => !stop) .Subscribe(_2 => { var t = (Time.time - sTime) / maxTime; if (t >= 1) { t = 1; stop = true; } var rad = t * Mathf.PI * 2f; sphere.transform.position = new Vector3( -Mathf.Sin(rad), -Mathf.Cos(rad), 0f); }); });
Where句はラムダ式の右辺の真偽値が真の時のみイベント情報を流します。
Rキーが押された時に一度Subscribeで登録された処理が走ります。
このタイミングで別のUpdate処理を走らせて、0.5秒間球を回しています。
一定時間後に処理&一定時間の繰り返し
一定時間後に処理をしたい場合は、Timerというものが使えます。
var renderer = cube.GetComponent<Renderer>();
Observable
.Timer(TimeSpan.FromSeconds(3f))
.Subscribe(_ => {
renderer.material.color = Color.blue;
});
3秒後に色が青に変わります。
処理を繰り返したい場合は、Timerの
引数1に最初に実行するまでの時間
引数2に間隔
を入れることで、処理を繰り返すことができます。
Observable .Timer(TimeSpan.FromSeconds(1f), TimeSpan.FromSeconds(1f)) .Subscribe(_ => { // ここでusing Systemしていると、Randomが短く打てません。 renderer.material.color = new Color( UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value); }):
もしくは、Intervalを使うことでも、処理を繰り返すことができます。
.Interval(TimeSpan.FromSeconds(1f))
これで1秒毎にランダムに色が変わります。
UniRxの勉強として
ます最初に、これからUniRxを勉強する人のために少し補足をします。
今回の記事では、イベント情報という単語を用いて説明していましたが、
イベント情報の発行から購読(=Subscribe)までの流れを「ストリーム」と呼びます。
また、メソッドを繋げて書く書き方は、「メソッドチェーン」と言います。
WhereとかTakeとか、イベント処理をするメソッドを「オペレータ」と言います。
次に、僕がUniRxを勉強するのに使ったサイトを紹介します
UniRxについて書いた記事をまとめてみた
まあ、UniRxと検索して一番上にでてくるページの人のところなのですが
あと逆引き便利
UniRx オペレータ逆引き
最後に、僕がUniRxを勉強するときにはまった点を紹介します。
今回は毎フレーム流れてた空のイベントを利用していましたが、UniRxでは自分で自由にストリームを流すことが出来ます。
僕がはまったのは、その流し方を間違えてしまった所です。
UpdateAsObservableを元に、条件を満たしている間ストリームを発行するようにしたところ、逆に条件を満たしていない時の動作を設定できなくなってしまいました。
そもそも、ストリームを使う必要がありませんでした。
bool型で保持しておけば良かったのです。
ストリームを発行するのは、トリガー的(ある動作を起こしたい状態になった等)なタイミングで使うのがやりやすいかと思います。
最後
今回、UniRxの機能の一部を取り上げました。
Updateをうまく操れる様になったでしょうか。
なっていたら幸いです
ここまで読んでくださってありがとうございました。
Blenderを使ってみた
こんにちは、VR部2年の町田です。
去年はあまり活動に参加できなかったので今年は何かやってみようと思い、まずはblenderを使ってみることにしました。
今回は、初心者に易しいサイトがあったので、それを参考に転がるサイコロを作ってみました。 とても分かりやすいので、短時間で完成させることができました! ↓
ざっくりとした手順は以下の通りです。
①サイコロのモデルを作る
②色々なポーズを保存する
③アニメーションにする
1枚目の画像は、静止画のサイコロです。 2枚目は、サイコロを回転させようとした時に、スピンで物体が回転すると勘違いしていた時の様子です←
スピンは回転体を作るものであり、サイコロ自体を回転させるときはオブジェクトを選択した状態でRキーを押して回転させキーフレームを登録するということを理解しました。
そして最終的に回転するサイコロが出来上がったのでよかったです。
まとめ
今回blenderを使ってみてモデリングの楽しさを実感することができたので、今後この機能を使ってもっと本格的なモデルを作ってみたいと思いました。また、他のソフトも勉強してみたいと感じる良いきっかけとなりました。
この勉強意欲を忘れずに、来週からのテストに向けての勉強も頑張れるといいですね。
Unite Tokyo 2018に行って来ました!!
こんにちは。VR部2年の白嶋です。私たちの部活ではUnityをふんだんに使っているのですが、Unityスキルを磨き上げるべくUnite Tokyo 2018に行って来ました。Uniteは3日間に渡って講演が行われました。
1日目
今日の講演は基調講演のみでした。Unityの方針とUnityの現状について仰っていました。Unityの方針は、「開発の民主化」「ハードウェアー問題の解決」「開発者の成功を手助け」です。「開発の民主化」、これはUnityが最初から目指している事で無料で開発が出来、無料でプラットフォームにビルド出来るようにするです。「ハードウェアー問題の解決」はデベロッパーにビルド時の面倒くさいデバイス依存のプログラムを書かずにすませて、Unityがほぼデバイス依存のプログラムを書いてくれます。「開発者の成功を手助け」はリソースが英語しかない、そもそもネットに情報がない。という事を防ぐために積極的にコミュニティを作り、開発者同しの情報交換を出来るようしています。次にUnityの現状は色々な企業が目をつけていてゲーム以外の場面で活用されている様です。例えば、建築系の企業ですと、マイクロソフトのホロレンズで建築予定のモデルを現実世界と合わせて見る事によって実際に見て気づいた改善点などが分かったりします。他には、車の企業ですと、クライアントが何色がいいのかなど実際に見て細かい所をオーダーするという事が出来ます。VTuberのキズナアイさんが出て来ました。驚きました!!
2・3日目
さて、Uniteの本番は2、3日からです!頑張って話を聞いてきました。色々な講演でProBuilder推していました。Unityエディター内でモデルの編集が出来ますので色々と便利そうですよね。また、最新バージョンで追加されたJobSystemなど個人的に気になっているので試してみたいと思っております。オーディオ系の講演もあり、今まで簡単に実装出来たオーディオはきちんとした設定にしないと実はメモリを無駄に消費していたら無駄なコンバートでCPUに負荷がかかる様ですので気をつけないとと思いました。他にも色々と復習しようと思いますので、公開スライドと動画を合わせて見ます!! →無料でスライド・講演動画がありますので、ぜひご覧あれ!! Unite Tokyo 2018 講演タイムテーブル
個人的GW振り返り
こんにちは。VR部2年の森口です。今回は個人的なGWについて振り返りたいと思います。今年のGWは例年以上にVRに触れたGWとなりましたのでそれについて話していきたいと思います。
ニコニコ超会議2018
ニコニコ超会議2018とは
ニコニコ超会議とはドワンゴが運営する「ニコニコのコンテンツを(だいたい)すべて地上に再現する」をコンセプトに千葉県の幕張メッセで行われたイベントで2日間で約160000人ほどの来場者を記録しました。
超歌舞伎VR
私はこのニコニコ超会議(以下超会議)にて超歌舞伎VRというコンテンツを体験してきました。超歌舞伎とはこの超会議で展示されたメインブースのひとつで、歌舞伎作品にプロの歌舞伎役者の方とともにVOCALOIDの初音ミクや鏡音リンが出演するという日本の伝統文化と現代の文化が合わさったコンテンツになっています。その作中に登場する初音ミクの舞をVR空間内にて間近に見ることができるのが超歌舞伎VRとなっています。
HMDはPlayStationVRを使い、ユーザ側の操作は見る視点の変更のみといったゲームなどとは違い鑑賞のみのコンテンツでした。当日は参加希望者が殺到し長蛇の列になっていて指定された一つのムービーしか見ることができませんでしたが時間に余裕があれば複数のムービーから選択して様々なものを見ることができたようでした。
また、こちらのコンテンツは自前のPlayStationVRでも無料で体験することができるようなので機会があれば体験してみるのはいかがでしょうか。
VRムービー作成
我々の部が行っている活動の一つとしてVRキャラバンというものがあります。この活動についてはこちらの記事を参考にしてください。
前回の活動の反省点として、ご年配の方々などあまりVRについてよく知らない方々がとっつきにくいコンテンツばかりを展示してしまったというのがありました。ゲームのような複雑なコンテンツだとこのような問題が発生しがちなので我々は操作を必要としないスマホVRでのムービーコンテンツを作成し次回以降のVRキャラバンにて展示することにしました。そのコンテンツのテーマは「VR内で電車に乗り四季を旅する」です。私はコンテンツの作成に携わっていてGWも実家に帰省しつつ作成を行っていました。
※画像は開発中の夏のシーンのものです
私自身Unityはまだまだ勉強中の身でVRムービーも初めて作るのであの手この手で試行錯誤しつつ作業していました(笑)
多くの皆さんに楽しんでいただけるコンテンツを目指して作成していきますので公開まで今しばらくお待ち頂ければと思います。
Blenderでモデリング
2月に行われました部内ハッカソンにて3DモデリングソフトのBlenderを触る機会があり、その時にモデリングの面白さを知って以来モデリングを勉強しています。UnityのAsset Storeにも多くの素晴らしい3Dモデルがありますがどうも自分の欲しいモデルが見当たらないとなったときにモデルを自作する能力があれば万事解決です。私の今年の目標の一つとして「なるべく自作したモデルのみで一つVRコンテンツを作る」というものがあるので早くBlenderをマスターしたいと思います。 こちらは私が所属しているKチームのコンテンツで使用するためのガスバーナーのモデルです。
まとめ
大学2年になり昨年よりは知識・技術共についてきたとは思いますがまだまだ多くの面で勉強しなければならないことがたくさんあります。そう考えると今年のGWは私にとって視野を広げたり、技術習得のためになる良いGWになったかなと思います。
本記事内で少し触れましたVRムービー含め会津大学VR部の今後の活動に期待と応援をよろしくお願いします!
Timelineを使ってみる
こんにちは、VR部2年の森川です。私は訳あって映像を制作することになったので、Unityにある「Timeline」という機能の基本の機能を調査しました。ですので、今回はTimelineの使い方を簡単に整理していきます。
Timelineとは
AnimationClip、AudioClip、Camera等を配置して、これらの実行させたい処理を経過時間ごとに操作することができる機能です。
Timelineを扱う事によって生まれるメリットは、
- GameObject毎の処理を一々コードを書かなくて済む。
- ウィンドウを見るだけで、どのような処理が行われてるか分かりやすい。
- 複雑な処理を行いやすくなる。
です。それでは早速使っていきたいと思います。
準備・主な機能
準備
まずは、空GameObjectを生成します。名前は適当にRootとしておきます。
次にTimelineエディタを開きます。Window->Timelineから開くことができます。
開いたら先ほど作った空GameObjectを選択し、Timelineエディタに"Create"と出るのでそれをクリック。
すると拡張子がplayableのファイルが生成されます。その後、空GameObjectにPlayable DirectorとAnimetorコンポーネントが追加されている事を確認しましょう。
これにより、RootというGameObjectを基準にタイムライン制御を行う事ができるようになりました。
主な機能
Timelineには"Track"というものがあり、Timelineエディタの行に相当するものです。TrackはエディタのAddをクリックすると追加できます。また、Trackの右側に表示されるグラフのようなものをアセットと言います。ここでどのタイミングで処理を行うかをフレーム毎、または時間毎に操作する事ができます。
今回は代表的な5つのTrackの説明をします。
1. Activation Track
指定したGameObjectのActiveを切り替えるTrackです。
2. Animation Track
指定したGameObjectのアニメーションを操作できるTrackです。
ここでのクリップはAnimation Clipなので、GameObjectにClipが付いているならば、それを再生する事ができます。また、エディタ内でClipを作る事ができます。作成方法はAnimationウィンドウでの操作と同様です。
3. Audio Track
指定した音楽ファイルを再生、停止する事ができるTrackです。
4. Control Track
指定したPrefabを表示、非表示にできるTrackです。
アセットを右クリックし、クリップをAddすることにより使う事ができます。このクリップのInspectorから、親オブジェクトと生成するPrefabを指定できます。
パーティクルでの演出をするときに使えそうな感じですね。
5. Playable Track
スクリプト制御を行うTrackです。私が今回調べていて行き詰まったのはここのTrackです。
ここではPlayableBehaviorクラスとPlayableAssetクラスのサブクラスを用いて実装します。
簡単にこの2つの関係を説明すると、PlayableAssetクラスは処理を行うGameObjectの参照を保持させておくもの、PlayableBehaviorクラスは参照したオブジェクトにどのような処理を行うのか命令をするものです。
これらのスクリプトのデフォルトはAssets->Create->Playablesより生成できます。
ここにサンプルコードを載せておきます。カメラがLookAt関数で対象物を見続けるものです。
コードは主に他サイトを模倣して書いたものなので、私の理解した範囲のみ説明します。その以外に関しては、後ほど参考サイトのリンクを貼るのでそちらで確認してください。
TimelinePlayableAsset.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
[System.Serializable]
public class TimelinePlayableAsset : PlayableAsset
{
public ExposedReference<GameObject> charaObj;
public ExposedReference<GameObject> target;
public override Playable CreatePlayable(PlayableGraph graph, GameObject go) {
var behaviour = new TimelinePlayableBehaviour();
behaviour.charaObject = charaObj.Resolve(graph.GetResolver());
behaviour.target = target.Resolve(graph.GetResolver());
return ScriptPlayable<TimelinePlayableBehaviour>.Create(graph, behaviour);
}
}
- public ExposedReference<GameObject> charaObj;
ここではシーン上にある参照するオブジェクトを格納してます。また、Project内に存在するオブジェクトを参照する場合は通常通り以下のように書けます。
public GameObject charaObj;
- public override Playable CreatePlayable(PlayableGraph graph, GameObject go){ }
私はここに関してはおまじないと思って書いてます(笑)。
TimelinePlayableBehavior.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class TimelinePlayableBehaviour : PlayableBehaviour
{
public GameObject charaObject;
public GameObject target;
public override void OnGraphStart(Playable playable) {
}
public override void OnGraphStop(Playable playable) {
}
public override void OnBehaviourPlay(Playable playable, FrameData info) {
}
public override void OnBehaviourPause(Playable playable, FrameData info) {
}
public override void PrepareFrame(Playable playable, FrameData info) {
charaObject.transform.LookAt (target.transform);
}
}
- OnGraphStartクラス
タイムライン開始時実行される。 - OnGraphStopクラス
タイムライン停止時実行される。 - OnBehaviourPlayクラス
PlayableTrack再生時実行される。 - OnBehaviourPauseクラス
PlayableTrack停止時実行される。 - PrepareFrameクラス
PlayableTrack再生時毎フレーム実行される。
これを実装すると、ちゃんとカメラが追尾してる事が確認できますね。
まとめ
使って見て感じたことは、細かい設定(実行したいタイミングをいじる等)を容易にする事ができて便利だと感じる事ができました。また他にも調べて見て"Cinemachine"というものと組み合わせて使うと、カメラによる演出の幅が広がり躍動感のある映像が作りやすくなると思いました。今後はCinemachineを使ってTimelineで動かせるように調査を続けて行きたいと思います。
- 参考サイト
Timelimeの使い方
そろそろUnity2017のTimelineの基礎を押さえておこう - 渋谷ほととぎす通信
【Unity2017.2.0f3版】Unityタイムラインの5つの基本機能の使い方と、Cinema Directorとの違いを整理しました - Cross Road
Timeline×Clinechineについて
【Unity】Timelineに動的に生成したオブジェクトをバインドする - テラシュールブログ