React VR (WebVR)を試してみる
黒田 大介(Dycoon)です。先日React VR 1.0.0がリリースされたので実験プログラムを作り使い勝手を確認してみました。
React VRはブラウザ上で動作するVRアプリケーション(WebVR)を作るためのフレームワークです。 以下の実験プログラムのDemoでは以下のようなものを確認できます。
- マウスクリックかVR用コントローラーのボタンを押すことで指示しているボタンの色が変わる
- Oculus Touchでは左のコントローラーのスティックを押す
- 部屋のモデルファイルを表示しそれを眺めたり少し移動したり
テクスチャー画像などは重めなので読み込みに時間がかかると思います。ご注意ください。
動作確認環境
- Windows10
- Oculusでの表示
- Chromium 56.0.2910.0 (Developer Build) (64 ビット)
- Oculus Touchでの入力
- Chromeのブラウザ表示とマウス入力
- Oculusでの表示
- Android
- Chrome Canary
- https://webvr.rocks/chrome_for_android
- 現在の一般向けのChromeだとWebVRの設定をしてもまだ動作しないようです。
- CardboardでVRモードにした場合クリック入力の方法が無いです。
- Chrome Canary
ReactVRでの表示の記述
以下のようなコマンドでプロジェクトを生成してみました。
react-vr init ReactVrExperimental
すると以下のようなコードが生成されました。
export default class ReactVrExperimental extends React.Component {
render() {
return (
<View>
<Pano source={asset('chess-world.jpg')}/>
<Text
style={{
backgroundColor: '#777879',
fontSize: 0.8,
fontWeight: '400',
layoutOrigin: [0.5, 0.5],
paddingLeft: 0.2,
paddingRight: 0.2,
textAlign: 'center',
textAlignVertical: 'center',
transform: [{translate: [0, 0, -3]}],
}}>
hello
</Text>
</View>
);
}
};
なんとなく、ReactNativeの書き方に似ています。 実際にReactVRのパッケージにはReactNativeが含まれています。 ReactNativeはweb用の出力のパッケージ1もあるなどより抽象的なアプリケーション記述用のフレームワークになりつつあるのかもしれません。
ボタンを並べてみているところは以下のような感じです。
render() {
var buttons = [];
for(var i = 0 ; i < 3 ; i++) {
((i) => {
buttons.push(
<VrButton style={{
backgroundColor: this.state.clicked[i]
? "#aa2211"
: "#1122aa",
height: 0.29,
margin: 0.01
}} onClick={() => {
var clicked = this.state.clicked;
clicked[i] = !clicked[i];
this.setState({
clicked: clicked
});
}} key={`button${i}`}>
<Text>Test Button</Text>
</VrButton>
);
})(i);
}
return (
<View>
<Pano source={asset('chess-world.jpg')}/>
<View style={{
position: "absolute",
layoutOrigin: [
0.5, 0.5
],
flexDirection: 'column',
width: 1,
padding: 0.2,
transform: [
{
translate: [0, 0, -3]
}
]
}}>
{buttons}
</View>
</View>
)
}
styleのtransformで土台となるボタンを持つViewの位置を決めてその中にFlexboxでレイアウトを指定しています。
次に部屋の表示をする部分を見てみます。
render() {
var buttons = [];
...
return (
<View>
...
<Animated.View
style={{
position: 'absolute',
transform: [
{
rotateY: 90,
},
{
translateX: this.state.roomPosition[0]
},
{
translateY: this.state.roomPosition[1]
},
{
translateZ: this.state.roomPosition[2]
},
],
}}
>
<Model
source={{
obj:asset("room/room.obj"),
mtl:asset("room/room.mtl"),
}}
lit={false}
>
</Model>
</Animated.View>
</View>
);
}
Modelのところで部屋のwavefront objファイルを読み込んで表示します。 今回部屋のモデルはこちらを使いました。 SketchfabにはCC BYくらいのライセンスであつかえるデータが結構あったりします。 ただ、ReactVRで読み込めないobjファイルだったようなので、一旦blenerにimportしてからexportしなおしました。
Modelの上の階層にあるAnimated.Viewは部屋の中を移動するように見せるために部屋を移動させるために追加しました。 本当はSceneという表示する場所をワールド座標で設定する方法が用意されているのでそれを使うべきだと思います。 しかし現在のバージョンだとUIのクリック判定の位置がずれるようなのでこのような対策をしました。
床をクリックしたらその場所に移動のような仕組みにしようと思いましたが、現状のReactVRだとクリックイベントでクリックした場所のワールド座標を得ることができないようです。 簡単にはできなさそうだと思ったので今回はそうした機能は見送りました。
まとめ
レイアウトルールを決めてComponentを配置できる場合はReactの記述方法は良いと思います。 パノラマ画像ビューワーなどならば簡単に作れそうです。
しかし、3D Modelを雑多に配置したい場合やモデルデータの構造に合わせてComponentを組み立てたいというシナリオも考えられます。 たとえば、家のモデルがあって扉のモデルが別にあるとします。 家のどこに扉があるかという配置はtransformで座標を指定するのは大変そうです。 UnityなどにあるようなGUIのツールがほしくなるかもしれません。
GUIのツールの場合ReactのComponentを出力させたとしてうまく扱う方法があるかなどイメージがつかめていません。 また、家のモデルの中にすでに扉が含まれている場合に、扉に動きを割り当てたいときどうするかという問題も考えられます。 ReactのComponentで扱いにくい部分は別の仕組みで解決したほうが良いかもしれません。
発展途上の段階だと思いますが興味深いところもあり楽しみです。