Aizu-Progressive xr Lab blog

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

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

Blenderのエッジで分かりずらいところ

こんにちは、VR部副部長のノジです。

今回は私がBlenderを使い初めたばかりのころ、分かりづらかったところを書こうと思います。※Blenderのバージョンはv2.77で、日本語化してあります。

  • 円柱を側面部分だけ滑らかにしたい

3Dモデリングをしていると思わぬところで思い通りにならないところがでてきます。そのひとつを円柱をつかって説明していきたいと思います。

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

まず物体を滑らかにするためにシェーディングをスムーズにし、再分割曲面のモディファイアーを下図のように追加します。

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

すると上下の面まで曲面化し、円柱にはなりません。この解決策はたくさんありますが、今回は分かりやすいものを2つ紹介します。

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

  • 解決策1

上下の辺ぎりぎりにループカットで辺を追加してあげます。ひとつ追加したら、今度は今追加した辺と立たせたい辺の間にもうひとつ辺を追加すると、角がよりはっきりします。

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

  • 解決策2

辺を追加する方法でも問題ないのですが、辺を追加することでメッシュ数が多くなり、処理の速度にも関係してきます。それを辺を分離させることで簡単に解決できます。 まず分離したい辺を選択してCtrl+Eをします。そして画像の'辺を分離`を選択するときれいに円柱になります。

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

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

  • まとめ

解決策1だと辺の丸み具合まで調節することができるが、完璧に辺を立たせることができなかったりメッシュ数が増えてしまう。

解決策2だと完璧に辺を立たせることができるが、辺が分離してしまっているため後から編集するのが面倒。

どちらも十分使えるので用途にあった方を使うのがいいと思います。

UNETに入門してみた

ども、VR部員のゼロです。

今回は今更かもしれませんがUnityにあるネットワーク機能UNET を初めて触ったので備忘録として書こうと思います。 といってもほんとに触りの部分だけです。

  • NetworkManagerの設定

まず、Scene上でCreateEmptyで空のゲームオブジェクトを作成し、名前をNetworkManagerとします。 その後AddComponetでNetworkManagerとNetworkManager HDDをアタッチ。 これでNetworkManagerの設定は終わりみたいですね。

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

  • プレイヤーを同期させる設定

今回はCubeの移動を同期させました。 CreateでCubeを作成 その後以下の移動のコードをCubeにつける

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

public class Movement : MonoBehaviour {

    [SerializeField]
    Rigidbody rig;
    [SerializeField]
    float speed = 2f;
   
    void Update () {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        this.transform.position += new Vector3(x,0,z)*Time.deltaTime * speed;    
    }
}

Add ComponetでNetwork IdenityとNetwork Transformをアタッチ Network TransformのTransformSyncModeをSync Transformに変更 Network IdentityのLocal Player Authorit にチェック

今回は操作を反映させるのは自分自身(ローカルのもの)なのでそれを判定するスクリプトをCube追加します。(自分の操作で相手のプレイヤーまで動いてしまわないように)

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

public class DisableScript : NetworkBehaviour {

    [SerializeField]
    Behaviour behaviors;

    void Start () {
        if (!isLocalPlayer) {
            behaviors.enabled = false;
        }
    }
}

isLocalPlayerで自分自身かどうかを判定しているのと今回はネットワークの機能を使うので MonoBehaiviourではなく、NetworkBehaviourを継承するのが注意点ですね。

その後InspectorでbehaviorsにCubeのMovement.csを設定します。 最後にCubeをプレハブ化してNetworkManagerのSpawn InfoのPlayerPrefabを先ほどプレハブ化した Cubeに設定して終わりとなります。

あとはエディタ側で再生しLanHost(H)ボタンを押す。 ビルドしたアプリ側でLanClient©を押してそれぞれで移動してみると Cubeが同期するはずです。

最後にすごく簡単にまとめると

  • NetworkManagerはネットワークの状態を管理するもの

  • Scriptでネットワークの機能を使いたいときにはNetworkBehaviourを継承

  • ネットワークゲームでは他のPlayerを操作できてはまずいのでその判定をisLocalPlayerで行う

といった感じでしょうか。

今回はほんの触り程度だったので、そのうち変数のやり取りやアニメーションの同期なども やってみます。

VRアカデミー 4/1, 4/8

VRプロフェッショナルアカデミー

今回は 4/1 に行われた第1回の講座と、 4/8に行われた第2回の講座について書いていこうかと思います。

4/1(第1回)

やっとはじまりました、VRプロフェッショナルアカデミー。これから私は毎週土曜日東京に通うことになりますw せっかく頑張って通うのに聞いてきたこと忘れては嫌なのでできるだけ早くここに備忘録つける癖をはやくつけたいです。(もう第1回から2週間経ってしまいましたが。)

第1回の講義では4人のゲストのお話を聞くことができました。

1人目 高橋建滋様

Ocufes知ってる人なら絶対しっているVR界では超有名な高橋様からお話を聞くことができました。現在PS4でホラゲを作っているそうです。
 高橋様はHMDを知らない人に説明する際、HMDのことを「新しいメディア」(ラジオやテレビなどと同じ、人類が120年ぶりに発明したメディア)と説明していました。またメディアというのは人間を賢く、優しくするためのもの、例えば活字というメディアは人類が感情を手に入れるためのものだとも説明してくれました。
 VRの演出方法は今はまだいろんな企業とかが研究中だそうで、それはVRだと昔ながらの演出方法が使えないからだそうです。そんな現在新しい演出方法を探している最中のことを大航海時代とも言っていましたw それに加え、「死体で谷を埋めていく」(たくさん失敗して、たくさん失敗してからその上を皆んなが歩いていく)という表現もしていました。つまり失敗を前提に作っていこうということでした。我が部も色々失敗を繰り返して成長できればいいなと思います。

2人目 待場勝利様

大学卒業後、アメリカへ映像制作を勉強。サムスン電子ジャパンでは Gear VRを担当したり株式会社ejeでVRのコンテンツに関わったりと、様々なVR制作に関わっている方です。
 現在は360度動画をメインに制作しているみたいで、今まで平面だった映像が立体にできるので、地味ではあるが深堀りして新たな表現をしていくと言っていました。
 待場様のお話しで一番印象に残ったのは、「オペレーションが重要」という話です。VRに慣れている方ならともかく、一般の方にはHMDを渡されてもそれをどのように使うかがわからないですよね。どの方が言っていたかは忘れてしまいましたが、お客さんにHMDを壊されてしまったことがあると話していた方もいましたので、特にハイエンドなHMDを使用する際にはオペレーションをしっかりしないとなあ、と感じました。

3人目 赤崎信也様

株式会社 積木製作の取締役 マネージャーをされています。機会エンジニアからCGの世界にきたそうで、現在は建築特化だそうです。
 赤崎様は「今VRを始めるメリット」について話していました。そのメリットとは、

  • 先駆者と呼ばれる

  • 今までのゲームや映画の概念を覆えせる

  • 市場を新たに創ることができる。価格も自分である程度は決めることができる(相場がまだ決まっていない)

とのことです。我らVR部部員がみな"先駆者"と呼ばれる者になれると考えると感慨深いですなあ。

4人目 古賀琢麻

株式会社アイロック 代表取締役 プロレーシングドライバーをされている方です。プロドライバーとして世界を転職してきて、そのドライビングレース経験を投入して開発をしたドライビングシュミレーターT3Rシュミレーターを開発、製造販売しています。
 古賀様は世界を見てきているので、他国と日本を比べた話をしてくれました。すごくストレートに「日本人は遅い、だって寝るもん」などとスケールのでかい意見が飛んできました。
 あと、早くやるって大事という話で、できるやつって最初にパーンッとやってあとダラダラ、最後修正って特徴があると思うとも言っていました。


このほかにも、パネルディスカッションで様々なことを聞けました。

  • 脳をどのように効率良く騙すか、脳がそれを本物だと思うエッセンスを考える

  • ものすごく妄想する(他人に自分の考えてることを事細かく説明できるようになるまで)

  • VRの最終目標は「どれだけ人の心をゆるがせるか」

  • 一般人には物語を見せないとダメ、すごい技術で盛り上がれるのは技術オタクだけ

  • 初心を忘れない!

  • 2020年にVRのキラーコンテンツが出るんじゃないか?

  • 脳科学、生理学、人文学、心理学などあらゆる分野に触れて「人間」を知ることが大事。つまりはVRってのは人間への追求

初めてHMDをかぶったときの感動を私はまだ忘れていません。初心にかえる上でも、その記憶は大事なものだと思うのでこれからも忘れずに開発をしていけたらいいなと思います。

4/8 (第2回)

2日目はあえて名前を伏せますが、Unityすごい方のお話を聞くことができました!

VR開発をしたい人には二つの道があるそうで、
「(VR開発ができる)会社に入りたい」という道と、「コンテンツを作りたい」という道です。

会社に入ってVR開発

「メリット」

  • OJT(職場で実際に実務をさせることで従業員の職業教育をすること)

  • 予算が出る

  • チーム開発としてそれなりに大きな規模の開発ができる


    「デメリット」

  • 自分のやりたいことができないかもしれない

もし、VR開発ができる会社に入りたいんだったら…?
「とにかくモノをつくる!」
今の会社でモノがなくて入れる会社はない。

VRの開発ができる会社に入社するパターン例として、

例1:
VRコンテンツ作った

ツイッターに経過を報告

VR開発者と仲良くなる

オフラインイベントで会う(VR展示会など)

就職


例2:
コンテンツ作る

VRについての技術記事を書いていく

VRイベントで登壇

SNS経由で会社からお誘い

就職


例3:
ゲーム会社でVRやりたいと申し出

却下されたので、もくもくと作った

世間がVR熱高まってきたので、手のひらクルー

アレオレ事変(あれは俺が作ったと、周りの人が言い出す)

腹が立って就職

きっかけは全部「つくる、だす!」からですね!

コンテンツを作りたい


空いている時間を使って作るしかないですね。
「メリット」
* もし利益が出るならばそれらは自分らのもの

「デメリット」
* 仲間を集めるのが大変

※講師の方も、いばらの道です、と言っていました。でも、部活であれば仲間集めというところはデメリットではないですね!!

作品について、
優れた作品には「属人性」が高い
優れた作品は一部の天才が作る

では平凡な人には?
「希少性で勝負!」
希少性は掛け算。珍しい×珍しい=めちゃくちゃ珍しい
VR×自分の分野=希少性が一つ生まれる

例: VRで福祉ってできないかな?
ある人はお年寄りを見ていて、VRで何かできないかと考えた。なかなか外に出ることができないご老人のための体験動画をある人が撮ってきて、ハコスコとかで見る!
VR×福祉×世界旅行
はどうだろうとある人は考え、彼はクラウドファンディングでお金を集めた。結果うまくいき、今では福祉領域で利用され始めている。ご老人が「ここに行きたい!」と思えばリハビリも頑張る気力につながりますよね!


自分はどんな掛け算ができるか考えてみよう。 VR×自分の分野×アイデア

まとめると、会社に入りたいんだったらとりあえず作る!!!作品作りたいんだったらVR×自分の分野×アイデア


「その他雑学」
* なぜHMDには一眼方式があるか?ーーー斜視が怖いため
* 90fps(=11ms/1フレーム)あればVR酔いしにくいと言われている
* 人間はFPS77までなら認識できるらしい(個人差はある)
* Unityアセットストアにて、欲しいものリストに多く登録されているアセットはキャンペーンで値引きされやすいらしい

written by Akiyama

この前の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部の部員が持ち回りで投稿していくブログです。特にテーマに縛りを設けずに書いていきます!