RectNativeでARアプリ開発
はじめに
現在は増井俊之研究室でNFCを用いたARのキャリブレーションとスマホARにおける表示インターフェースの研究をしています。 最初はSFCのAdvent Calendarだし「情報基礎の先の今どきJS入門」みたいな感じで書こうかなとも思っていたのですが、どうやら自分の前後の人がARについて書くとのこと。 自分の今の研究もスマホARだし、この流れに乗らずにはいられまい!ということで「ReactNativeでARアプリ開発」と称してReactNativeのAR/VRのライブラリであるViroReactの使い方を書いていこうと思います。 TL;DR
つらつら書いてたら長すぎたので....
簡単なチュートリアル(文字画像の表示およびそのアニメーション)を示します。
MacOS→iOS実機ビルドです(saji.iconが試せるAndroid実機を持ってないのでAndorid編は次回....) 「コードだけ見れればいいんじゃ」という人はGitHubをご覧ください.... 想定読者
以下のような読者を想定しています。
JS/TSの最低限の文法は知っている
気合を入れないと生のJSをかけない身体になってしまったのでサンプルコードは全てTypeScriptで書きます。 もちろんJSでも動きます。
Macで開発している
今回はMac→iOS実機ビルドまでをやります
Androidでも動くと思う!(未確認/多分追記します)
なんでReactNativeなの?
なんでReactNative?
マルチプラットフォームでネイティブアプリが作れちゃう!
宣言的にARのオブジェクトを配置できちゃう
Reactだからね
webフロントエンドの技術を使って作れてしまう
saji.iconがインターンでいつも触っている(個人的な理由) 注意
今回はMacOSで開発→iOS実機ビルドまでをやります。 Androidの場合は
また下記の環境構築では このページの「For Andorid」を7の後に進めてください。 開発環境
一応書いた時点でのsaji.iconの環境を載せておきます
OS : macOS Catalina
環境の構築
1. まずはwatchmanを入れます
brew install watchman
2. CocoaPodsが入っていない場合は入れてください
sudo gem install cocoapods
3. プロジェクトを作りたいところに移動してください
4. RNのプロジェクトを作成します。
npx react-native init ReactNativeArSample --version 0.60.6
現状0.59代はiOS13でビルド時にエラーとなるため0.60.6に引き上げています。
特別な理由のない場合は0.60.6の利用をお勧めします
5. プロジェクト内に移動します
cd ReactNativeArSample
以下のようなファイル構成になっているはずです
https://gyazo.com/cfa380184d1218a45e57e5a29f8afd89
6. ただのJSでの開発は辛いので(主観です)TypeScript用の環境を整えましょう(ReactNativeはtsファイルも読んでくれるので大仰な設定は入りません) 以下のようなtsconfigファイルをルートディレクトリにおきます
code:tsconfing.json
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"jsx": "react",
"strict": true,
"baseUrl": "./",
"paths": {
},
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true
},
}
型定義ファイルを追加します
yarn add -D @types/react @types/react-native
7. ViroReactを追加します。
まずは install
yarn add react-viro
次に./ios直下にあるPodfileを以下のように追記してください
code:Podfile
....略.....
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
# 以下の2行を追記
pod 'ViroReact', :path => '../node_modules/react-viro/ios/'
pod 'ViroKit_static_lib', :path => '../node_modules/react-viro/ios/dist/ViroRenderer/static_lib'
target 'ReactNativeArSampleTests' do
....略.....
さらに同じく./ios直下にあるPodfileのplatform :ios, '9.0'の部分のバージョンを上げてください
11では動きます。
platform :ios, '11.0'
さらに./ios直下に以下のようなshellスクリプトを書きます(いらないかも 2020/05/29)
code:fix.sh
cd ./Pods/GVRSDK/Libraries/
lipo -info libGVRSDK.a
architectures="armv7 i386 x86_64 arm64"
for arch in $architectures
do
echo Create thin archive libGVRSDK_$arch
lipo -thin $arch libGVRSDK.a -output libGVRSDK_$arch
chmod 777 libGVRSDK_$arch
remove=""
for object in $(ar -t libGVRSDK_$arch)
do
if ${object} == vlog_is_on_*
then
echo $object
remove=$object
fi
done
then
echo removing $remove from $arch
ar -dv libGVRSDK_$arch $remove
else
echo No symbol matching "vlog_is_on_*" found for $arch
fi
done
echo Rebuild libGVRSDK.a
lipo -create libGVRSDK_armv7 libGVRSDK_i386 libGVRSDK_x86_64 libGVRSDK_arm64 -output libGVRSDK.a
for arch in $architectures
do
rm libGVRSDK_$arch
echo Delete thin archive libGVRSDK_$arch
done
cd ../../../
このshellスクリプトはCocoaPodsでpod installした後、必ず実行するようにしてください
毎回やるのは面倒なのでpackage.jsonのscriptsに以下のように書いてしまい、pod installする時ははnpmのscript経由で行うと楽かなと思います。
code:nodescripts
"scripts": {
"start": "react-native start",
"test": "jest",
"lint": "eslint .",
"pod-install": "cd ./ios && pod install && ./fix.sh && cd ../"
},
8. ViroReactの型情報を入れてしまいましょう
ルートディレクトリに ./typings/react-viroというディレクトリを作り、index.d.tsを作成し、内容を以下から持ってきて貼り付けます。
9. info.plistに権限を追記します
./ios/ReactNativeArSample/Info.plistに以下のように追記します。
code:info.plist
...略
<key>NSCameraUsageDescription</key>
<string>Used for AR/VR</string>
...略
10. ./ios配下のReactNativeArSample.xcworkspaceをxcodeで開きます。
左のメニューからReactNativeSampleの方をクリックします
Settings & Capabilities タブで SignInしておきましょう
Build Settingsタブを開き、
EnableBitcode をNoにしてください
https://gyazo.com/bca1da2e55f41e50ca0dca74e119177a
左のメニューからPodsの方をクリックします
上と同じようにBuild Settingsタブを開き、EnableBitcode をNoにしてください
ARのViewを作っていく
環境構築お疲れ様でした。これでやっと開発に入れます。 まずはViroReactでのコンポーネントの構造を知っておきましょう。(と言っても単純です)
ViroReactのコンポーネントたちはざっくり以下のような関係になっています
ViroARSceneNavigator/ViroVRSceneNavigator
大元です
ViroARSceneやViroVRScene自体の表示・切り替えする役目
ここで表示するViroARScene/ViroVRSceneを指定する
webで言えばルーティング用のコンポーネントみたいなイメージです
ViroARScene/ViroVRScene
一つのAR/VRのビューの単位(その世界一つ分)
この中にAR/VR用の部品を配置していき、AR/VRの世界を構築できます。
webで言えば一つのpageコンポーネントみたいなイメージです
ViroText/ViroImage/.....etc
部品
webで言えば各部品コンポーネントみたいなイメージです
これらをざっくりコードで書くとこんな感じになります(propsとかを省略しているので動かないですが)
code:ViroStructure.tsx
const ARView = () => (
<ViroARScene>
<ViroText />
<ViroImage />
{....etc}
</ViroARScene>
)
const App = () => (
<View>
<ViroARSceneNavigator
initialScene={{scene: ARView}} //ここで描きたいARSceneを指定
viroAppProps={{}}
/>
</View>
)
なんとなくイメージがつかめたでしょうか?それでは実際に書いて動かしてみましょう!
とりあえずrootディレクトリにコンポーネント置いていくのはアレなので./srcディレクトリを作り、以下のような構成にしてみましょう。
code:srcDir
src/
├── ARScenes/
│ └── HelloWorldScene.tsx
└── App.tsx
HelloWorldScene.tsxは以下のように書いてみましょう。
code:HelloWorldScene.tsx
import React from 'react';
import {ViroARScene, ViroText} from 'react-viro';
export default function HelloWorldScene() {
const _onInitialized = (state: any, reason: any) => {};
return (
<ViroARScene onTrackingUpdated={_onInitialized} onClick={() => {}}>
<ViroText
text={'Hello! AR World!!'}
style={{
fontSize: 80,
color: '#103059',
textAlignVertical: 'center',
textAlign: 'center',
fontWeight: '900',
}}
width={9}
height={2}
/>
</ViroARScene>
);
}
App.tsxもこんな感じで...
code:App.tsx
import React from 'react';
import {ViroARSceneNavigator} from 'react-viro';
import HelloWorldScene from './ARScenes/HelloWorldScene';
export default function App() {
return (
<ViroARSceneNavigator
apiKey={''}
initialScene={{scene: HelloWorldScene}}
viroAppProps={{}}
autofocus={true}
/>
);
}
rootディレクトリに戻り、index.jsでAppをインポートしている部分を以下のように書き換えましょう
code:index.js
/**
* @format
*/
import {AppRegistry} from 'react-native';
import App from './src/App'; //ここを変更した。
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
とりあえず実行
とりあえずこれで動かしてみましょう!
まずは./iosにあるReactNativeArSample.xcworkspaceをXcodeで開きます。
https://gyazo.com/fb70e40a3ddf27aab54b302377d2642c
(注意:nodebrewなどのnodeバージョンマネージャーを使っている方へ)
Build Phases > Bundle React Native code and imagesと進み
export NODE_BINARY=nodeとなっているところを正しいnodeのパスに書き換えてください
例(nodebrewの場合):export NODE_BINARY=$HOME/.nodebrew/current/bin/node
iPhoneをPCに繋ぎ(ロックを解除しておきます)、左上のBuild先をクリックすると繋いだiPhoneがDeviceに出てくると思うのでそれを指定します.
https://gyazo.com/9690b0d33f841d4424c82d9df14e789a
あとは左上のRunボタン(▶︎)をポチッと押すだけです。
うまくいくとアプリが起動し以下のように同意を求められるはずです
https://gyazo.com/0f2ed53c3782640e9188ffbdb1bf9e19
OKを押します
すると.....
https://gyazo.com/cbe6c089fec12154e7927fa1a5a5d18d
やったね!
説明
動いただけではアレなので軽く説明を。
まずはHelloWorldScene.tsxですね。
code:HelloWorldScene.tsx
import React from 'react';
import {ViroARScene, ViroText} from 'react-viro';
export default function HelloWorldScene() {
const _onInitialized = (state: any, reason: any) => {};
return (
<ViroARScene onTrackingUpdated={_onInitialized} onClick={() => {}}>
<ViroText
text={'Hello! AR World!!'}
style={{
fontSize: 80,
color: '#103059',
textAlignVertical: 'center',
textAlign: 'center',
fontWeight: '900',
}}
width={9}
height={2}
/>
</ViroARScene>
);
}
おそらくReact書いている方には違和感ゼロだと思います onTrackingUpdatedは名前の通りTrackingの状態が更新されると呼ばれます。初期化などで使う場合は利用しましょう。
positionは[x,y,z]という形で表示する三次元座標になっています
https://files.readme.io/b891975-viro_camera_diagram.png
起動した地点から座標系が設定されます。
今回だとposition={[0, 0, -4]}なので正面の奥に配置しているのが分かります。
styleは割と自由に指定できます。
width と heighはちゃんと指定しないとはみだした分が描画されなかったりします。
余裕を持って指定しましょう。
今回は指定していませんがrotationも重要です
文字や画像デフォルトではz軸の正の向きに向いているので、場所によっては自分側に向くように回転させなくてはなりません。
指定の仕方は rotation={[x軸回転,y軸回転,z軸回転]}で、単位は度、時計回りが正です。
次にApp.tsxも解説します。
code:App.tsx
import React from 'react';
import {ViroARSceneNavigator} from 'react-viro';
import HelloWorldScene from './ARScenes/HelloWorldScene';
export default function App() {
return (
<ViroARSceneNavigator
apiKey={''}
initialScene={{scene: HelloWorldScene}}
viroAppProps={{}}
autofocus={true}
/>
);
}
ViroARSceneNavigatorには多くのPropsを指定できます
よく使いそうなところだけ
まずはこれがないと始まらないSceneの指定です
initialScene={{scene: HelloWorldScene}}の部分で描きたいARScenenのコンポーネントを指定します。
React使いとしては気になるのがPropsの受け渡しだと思います。もちろんできます。(少し複雑ですが)
渡す際はviroAppProps={{hoge:"huga"}}のようにすることで描くARScenenのコンポーネントにPropsを渡せます。
受け取る際はARScenenのコンポーネント側でprops.sceneNavigator?.viroAppProps?.hogeのようにすると受け取れます。
ちょっと応用
イメージも描きたい!
<ViroImage />で表示できます。
code:ImageSample.tsx
import React from 'react';
import {ViroARScene, ViroImage} from 'react-viro';
import 'react-native';
export default function HelloWorldScene() {
const _onInitialized = (state: any, reason: any) => {};
return (
<ViroARScene onTrackingUpdated={_onInitialized} onClick={() => {}}>
<ViroImage
height={1}
width={2}
placeholderSource={require('../assets/images/test.png')}
source={{uri: '../assets/images/test.png'}}
/>
</ViroARScene>
);
}
src/assets/images/test.pngに好きな画像を配置してください。
https://gyazo.com/35974a1e4f3f53c5d4348422a024f2f1
アニメーションつけたい
ViroAnimationsでつけられます
code:AnimationSample.tsx
import React from 'react';
import {ViroARScene, ViroImage, ViroAnimations} from 'react-viro';
import 'react-native';
ViroAnimations.registerAnimations({
rotate: {
properties: {
rotateZ: '+=60',
},
duration: 500,
easing: 'Linear',
},
});
export default function HelloWorldScene() {
const _onInitialized = (state: any, reason: any) => {};
return (
<ViroARScene onTrackingUpdated={_onInitialized} onClick={() => {}}>
<ViroImage
height={1}
width={2}
placeholderSource={require('../assets/images/test.png')}
source={{uri: '../assets/images/test.png'}}
animation={{
name: 'rotate',
run: true,
loop: true,
}}
/>
</ViroARScene>
);
}
まずViroAnimations.registerAnimationで使いたいアニメーションを登録します。
この例だと画像を60度/500msでz軸で回してます。
https://gyazo.com/3d324e99e1337ece313cdc91614ec442
その後Component内でanimationPropsを利用し名前と実行,loopなどの指定をします。
これも↑のDocsに書いてあります。
うまく組み合わせると複雑なアニメーションができたり、アニメーション同期したりします。
クリックイベント取りたい!
<ViroImage />や<ViroText />のはOnclickなどが生えています。
code:ClickSample.tsx
import React, {useState} from 'react';
import {ViroARScene, ViroText} from 'react-viro';
export default function HelloWorldScene() {
const _onInitialized = (state: any, reason: any) => {};
return (
<ViroARScene onTrackingUpdated={_onInitialized} onClick={() => {}}>
<ViroText
text={text}
style={{
fontSize: 80,
color: '#103059',
textAlignVertical: 'center',
textAlign: 'center',
fontWeight: '900',
}}
onClick={() => {
setText('Clicked');
}}
width={9}
height={2}
/>
</ViroARScene>
);
}
このような感じでイベントに応じで文字や表示内容を変えることも出来ます。
さらにその先へ
出来るみたいです(まだ試せてません)。
出来たらまた記事書くかもです。
マーカーは?
出来るみたいです(まだ試せてません)。
最後に
ここまで読んでいただきありがとうございます。(長いのに....)
サンプルコードはgithub で公開してますので是非試してみてください。 ViroReactを使うと思ったよりいろいろなことができることを知っていただけたのではないでしょうか? ARのアプリ作りたいけど、Webはまだ自由度低いし、Unityはちょっと....というWebエンジニアの皆さんは是非試してもらえればなと思います。
もちろん既存のReactNativeアプリに追加できるので、AR機能を持ったマルチプラットフォームなアプリケーションを作りたい方にもおすすめです。 Andorid向けの構築の話は今回手が回らなかった(まだ試せるデバイスを保有していないのもあります)ので動作確認でき次第書きたいと思います。
参考