Aizu-Progressive xr Lab blog

会津大学のVR部であるA-PxLの部員が持ち回りで投稿していくブログです。部員がそれぞれVRに関する出来事やVRにちなんだことについて学んだことを書いていきます。

連絡はサークルTwitterのDMへお願いします。
「面白法人カヤックVR分室」としても活動しています。詳細はこちら

この前のVRアカデミーで気になったところ 〜その1〜

この前のVRアカデミーで使ったプロジェクトデータで、初めから書いてあったコードで気になったところがあったので自分なりに色々してみた。

レイヤーとビット演算

当たったら呼ばれる OnCollisionEnter() 関数の中に

public class Arrow : MonoBehaviour {

    public LayerMask _hitableLayer;
    ・・・

    void OnCollisionEnter ( Collision collision ) {

        if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) {
            /*
             * 衝突したオブジェクトが _hitableLayerに含まれるとき。
             * LayerMaskは複数のレイヤーを指定できてInspector上では扱いやすいが、
             * データ上はビット演算になっていて、直感的でない。
             * 指定のレイヤーにだけ反応するようにするには、上記の書き方をすると効率的。
            */

            「指定したレイヤーとぶち当たったレイヤーが同じだったときの処理」

        } else {
	   「それ以外のレイヤーにぶち当たったときの処理」
        }

    }

と書いてった。

if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { }

これなんだろう、、、見たことない書き方だなあ。<< を使ってるからビット関連かな、、、

ログに出して見た

Sample

    void OnCollisionEnter ( Collision collision ) {

	Debug.Log ("shift operation : " + ((1 << collision.gameObject.layer)));
	Debug.Log ("_hitableLayer : " + _hitableLayer.value);
	Debug.Log ("bit operation : " + ((1 << collision.gameObject.layer) & _hitableLayer));

        if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) {
           ・・・
        } else {
           ・・・
        }
      ・・・
    }


「if文の条件が成り立ったときのログ」
f:id:aizu-vr:20170306202511p:plain:w200

「if文の条件が成り立たず else文のときのログ
f:id:aizu-vr:20170306202510p:plain:w200


_hitableLayer は public な変数で、Unityエディタから "Target" というレイヤーが選択されている。Tags & Layer からUnityに設定されているLayer一覧をみてみると、
f:id:aizu-vr:20170306204049p:plain:w300
となっていて、Target は8個目(0を入れると9個目)に設定されていた。

Debug.Log ("_hitableLayer : " + _hitableLayer.value);

のログでは 256 とでている。なんで "Target" から 256 が?きっと2進数からきてるのではないだろうか。

256 は 2の8乗。Target は8個目にあった。ここが関係してるのかと。


8 7 6 5 4 3 2 1 0 (桁)
1 0 0 0 0 0 0 0 0 (2進数) = 256(10進数)

1 << collision.gameObject.layer

というところはシフト演算なので、collision.gameObject.layer の値だけ 1 をシフトさせる。
Target レイヤー以外は Default レイヤー(0番目)で設定されているので 1 のままでシフトしない。よってログでも 1 が出力されている。

Target レイヤー(8番目)にあたったときは、8回シフトするので、
1 (0回目)
10 (1回目)
100 (2回目)
1000 (3回目)
10000 (4回目)
100000 (5回目)
1000000 (6回目)
10000000 (7回目)
100000000 (8回目) = 256(10進数)

よってログで 256 と出力されている。


この 1 か 256 の値と、_hitableLayer (256) を & でビット演算すると、

「1のとき」
000000001
100000000 &
ーーーーーー
000000000 = 0(10進数)

よって、if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { } が成り立たなくなる。

「256のとき」
100000000
100000000 &
ーーーーーー
100000000 = 256(10進数)

よって、if (((1 << collision.gameObject.layer) & _hitableLayer) != 0) { } が成り立つ。

こんなやり方があったなんて...。ビット演算シフト演算なので効率は良さそうですね。これはいいこと知ったっ!


ちょっと文章で書くのきつかったです。。。わかりにくくてごめんなさい。

あぁ〜、大学で2進数とかビット演算とか習うけどこーゆーところで使うんだなあ。と大学の勉強のモチベにもつながりました。またなんか気になるところ解決できたら投稿します。



written by Akiyama

VR Academy 〜3/4 プレ講座〜

3/4にVRプロフェッショナルアカデミーのプレ講座(3回目)が行われました。第2回目には私は参加できていないので、4月入って講座がはじまったときに第2回目に参加された方にどのようなことをやったのか聞いてみたいですね。第3回はVRの知識がついたというよりかは、Unityの知識がつきました。見たことはあるけど使ったことのない機能が色々でてきたので、ここに備忘録として記録しておこうと思います。


UnityEvent

public or SerializeField 属性の UnityEventを使うことによってコールバック関数をUnity側から設定することができます。
e-words.jp

例えば、

using UnityEngine;
using UnityEngine.Events;

public class TestEvent : MonoBehaviour {

	public UnityEvent publicEventTest;
	[SerializeField] private UnityEvent serializeFieldEventTest;

}

このようなコードをかいて空オブジェクトに付け加えてみると、
f:id:aizu-vr:20170305222436p:plain
のようにUnity側に先ほど作った UnityEvent がエディタにでてきます。こっからコールバック関数を指定できます。


〜 Sample 〜

先ほどのファイルを以下に書き換えました↓

using UnityEngine;
using UnityEngine.Events;

public class TestEvent : MonoBehaviour {

	public UnityEvent publicEventTest;
	[SerializeField] private UnityEvent serializeFieldEventTest;

	void Update() {

		if (Input.GetKeyDown (KeyCode.Space)) {
			publicEventTest.Invoke ();
		}

		if (Input.GetMouseButtonDown (0)) {
			serializeFieldEventTest.Invoke ();
		}

	}

}

UnityEvent名.Invoke() でUnityエディタから指定した関数を実行させることができます。今回は新しく DebugTest.cs というファイルを先ほどと同じように空オブジェクトに付け加えて以下のコードを書きました。

using UnityEngine;

public class DebugTest : MonoBehaviour {

	public void PrintDebug() {
		Debug.Log ("Debug test");
	}

	public void PrintInt(int num) {
		Debug.Log (num);
	}

}

PrintDebug()関数は引数を取らない関数で、PrintInt()関数はint型の引数を1つとる関数です。
この2つの関数をUnityエディタから UnityEvent に指定します。ドラッグ&ドロップで先ほどの空オブジェクトだったものをいれてあげます。
f:id:aizu-vr:20170305230431p:plain
そしたら、No Function とかいてあるボタンを押して関数が書いてあるファイル名から関数名を探して選択します。
f:id:aizu-vr:20170305230705p:plain
関数のアクセス修飾子が public でないと候補欄に関数がでてきませんので注意してください。
f:id:aizu-vr:20170305225935p:plain
2個目の関数の引数もUnityエディタから指定できますね(ここでは1996と入力しているところです)。

実行して、Spaceキーと左クリックを押すと、
f:id:aizu-vr:20170305231456p:plain
とログにでてきました!




シングルトン

シングルトン自体についてはWikiなどで調べてください。
シングルトンは私は今まで名前しか聞いたことありませんでした。こんなふうに実装するんだなあ、としみじみ思いました。

新しく SingletonTest.cs というファイルを作り、以下をかきました。

using UnityEngine;

public class SingletonTest : MonoBehaviour {

	private int num = 0;

	private static SingletonTest instance;

	private void Awake () {
		if (instance == null) {
			instance = this;
		} else if (instance != null) {
			Destroy(this.gameObject);
		}
	}

	public static SingletonTest GetInstance() {
		return instance;
	}

	public void Print() {
		Debug.Log ("Test" + num);
		num++;
	}

}

これを他のファイルから使います。

using UnityEngine;

public class UsingSingleton : MonoBehaviour {

	// Update is called once per frame
	void Update () {
		if (Input.GetMouseButtonDown (1)) {
			SingletonTest.GetInstance().Print();
		}
	}
}

これで右クリックをするとログに、
f:id:aizu-vr:20170305235643p:plain
こんな感じでながれてきました。


シングルトンについてはまだ私自身使い勝手がイマイチ理解できてないので、これから実践で使ってみて慣れていこうと思います。
あとクエストのオブジェクトループがよくまだわかってないのでわかったら追記しようかと。

written by Akiyama

VR Academy 〜プレ講座〜

1/28、VRプロフェッショナルアカデミーのプレ講座が行われました。
来年度の4月から本格的に始まる講座のために、VRがどのようなものか、ビジネスではどのように使われているか、VRコンテンツのジャンルはどのようなものがあるか、制作にはどのような知識・技術が必要かなどを約5時間で教えていただきました。

「VRの価値の3要素」

1、体験

映像をあたかも目の前の現実として経験している

2、時間、場所の超越

時間や場所の制約がない

3、超現実

そもそも現実では不可能な視点で見れる

これこそがVRの価値だと。これから作る作品にはこれらがふくまれているかに気をつけて開発していこうと思いました。

あと、このVRアカデミー4月からはじまって3ヶ月間毎週あるのですが、最後にいままで習ったものを使って作品を作り、その作ったものを企業の方々に来てもらって発表するらしいんです。いやあ、知らなかたです。すごく緊張しますが、普通の学生じゃ経験できないようなことだと思うので頑張ってみようと思います。

 その日学んだことを忘れないように、このブログを備忘録として記録していこうかと思います。っということで1/28の分書いていきます。


「カメラを2分割する」

f:id:aizu-vr:20170305132337p:plain

スマホのVRでは画面を2分割しますよね、まずその2分割の方法を書いていきます。

まず、Hierarchy に Camera を2つ用意します。(Hierarchy で右クリック -> Camera)
両方とも同じ座標に設置します。(Transform コンポーネントを同じにする)
その2つのカメラを空オブジェクトにいれておきましょう。(Hierarchy で右クリック -> Create Empty。その空オブジェクトを違うわかりやすい名前に変えておきましょう)
f:id:aizu-vr:20170305132654p:plain

Right/LeftCamera には最初から、

  • Transform
  • Camera
  • Flare Layer
  • Audio Listener

の Component がついています。同じシーンに ”Audio Listener” が2つ以上あるとUnity側から怒られるので片方消しておきましょう。

LeftCamera の Camera コンポーネントViewport Rect プロパティーの値をいじって2分割します。

Viewport Rect は X, Y, W, H の要素を持っており、X, Y はカメラビューを2次元の平面上のどこに表示するかを設定でき、W, H はカメラビューの表示の幅と高さを設定できます。すべて0~1の値です。

カメラビューの左上を軸として考え、左側のカメラのXを0、Wを0.5にします。2分割なので半分の0.5です。同じように右側のカメラのXを0.5、Wを0.5にすることによって2分割にできます。左右同じビューになっていればOKです。


「プラットフォームによってコードを分岐させる」

Unity上だとこのコード実行してほしいけど、スマホ上だとこっちのコードを実行してほしい...というときには、プラットフォームごとに処理を分けます。#if#elif をつかって分岐させます。

↓プラットフォームごとの書き方はこちらの公式のマニュアルを見てください
docs.unity3d.com

sample code

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

public class CameraController : MonoBehaviour {

	public float speed;
	Quaternion _attitude;

	// Use this for initialization
	void Start () {
		#if UNITY_EDITOR
		#elif UNITY_IOS || UNITY_ANDROID

		Input.gyro.enabled = true;

		#endif
	}

	// Update is called once per frame
	void Update () {

		#if UNITY_EDITOR

		if (Input.GetKey (KeyCode.LeftArrow)) {
			this.transform.Rotate (Vector3.up * -Time.deltaTime * speed, Space.World);
		}
		if (Input.GetKey (KeyCode.RightArrow)) {
			this.transform.Rotate (Vector3.up * Time.deltaTime * speed, Space.World);
		}
		if (Input.GetKey (KeyCode.UpArrow)) {
			this.transform.Rotate (Vector3.left * Time.deltaTime * speed);
		}
		if (Input.GetKey (KeyCode.DownArrow)) {
			this.transform.Rotate (Vector3.left * Time.deltaTime * -speed);
		}

		#elif UNITY_IOS || UNITY_ANDROID

		_attitude = Input.gyro.attitude;
		_attitude.x *= -1; _attitude.y *= -1;
		this.transform.rotation = Quaternion.AngleAxis(90f, Vector3.right) * _attitude;

		#endif
	}
}

これを書いたファイルを Cameras に付け加えると、iPhoneまたはAndroidだったら内臓されているジャイロセンサーをONにして、デバイスの向きをとりそれをカメラの向きに代入してくれます。


第1回はこんな感じでした。来年度から本格的に始まる前にやっとくことをおすすめされたところをやっておき万全の状態で挑みたいですね

written by Akiyama

VR部 ブログ開設

これから学んでいくことを忘れないための備忘録や、これから入部してくれる部員たちのために学んだ知識を書き残していきましょう!
VR部のブログではありますが、もちろんVRに関係ないことも投稿してくれても大丈夫です。(例えば大学の講義で習ったこととか...)

何か記事を書き込むときには、

  • カテゴリーを選択
  • 名前

をお願いします!

それでは、これからみんなで頑張っていきましょーっ!

written by Akiyama

会津大学VR部の部員が持ち回りで投稿していくブログです。特にテーマに縛りを設けずに書いていきます!