WebXR(React-XR)に関するアレコレ
React Three Fiberの関連ライブラリであるReact-XRを利用して制作物を作り始めたので、備忘録や知見、その他雑記等諸々書いていきます。
そもそもなぜWebXR?
先日、AppleからVision ProというMRヘッドセットの発表がありました。
今後のVRMRコンテンツの発展を考える上でApple製MRデバイスは避けられない選択肢の一つと考えるべきです。
しかし、過去のAppleの動向から見るに、AppleがOpenXRのようなネイティブアプリケーション開発のための標準APIを実装しない可能性があり、そうなった場合には開発者は多かれ少なかれ、複数プラットフォームに対応するための作業にタスクを割かなくてはならなくなります。
それだけの価値のあるものならともかく、そこまでのタスクを割く労力が厳しいと感じたアプリケーションはAppleデバイスへの対応を諦めなくてはいけません。
まして、これまでのAppleデバイスのように開発にMacや高額なヘッドセットが必要になることを考えると、個人開発をやっているXR開発者には厳しいと感じることもあるでしょう…。
要は全部Appleのせいなのですが、そんなAppleにも実装を避けられないものがあります。
それがWebXRなのです。
WebXRはW3CというWebの標準規格を策定する団体が策定したものになりますが、W3Cの会員の中にはAppleも含まれており、実際にiOSのWebXRは機能こそしないものの、項目としては存在しており、いつになるかは不透明ですが、今後の対応の可能性があると思われます。
詳しくはこちらを参照ください。
つまり、WebXRならば、たとえそれが囲い込みの激しいAppleのデバイスであろうと、特別な対応なく使用できる可能性が高いということです。
なので、今後WebXRにも挑戦してみると、何かといいことがあるかもしれませんね。
WebXR(React-XR)を触って感じた課題
これはReact-XRの問題なのかもしれないのですが、インタラクティブな要素が基本的にはコントローラーから伸びる光線での制御、もしくはハンドトラッキングによるオブジェクトに触れることでの制御がメインで、ネイティブアプリケーションによくあるGrabで物を掴むなどの動作を実装するのが大変な印象を受けました。
実際にはそういった問題も解決する方法があるのかもしれないのですが、この辺はReact-XRでの複雑なゲームなどのアプリケーションを作る上で障壁になりそうな感じはありました。
また、当たり前ですがアニメーションは基本的にアニメーションファイルを読み込むか、アニメーションライブラリ頼りなので、WebページライクなWebXRアプリケーションを作るのには苦労しないと思うのですが、Unityのような複雑なアニメーションを組み合わせて作るアプリケーションはかなりしんどいかもしれないですね。
React-XRのXRビューはHTTPS接続でないと動かない
実際にアプリをGithub pagesやVerselにデプロイする上ではそこまで問題にならないかもしれないですが、開発を進める上でHTTPでのデバッグを行おうとすると「VR unsupported」と表示が出て動かない問題に直面するはずです。
理由はわかりませんが、XRビュー上ではHTTPSのみでしか動作しないことに注意してください。
XRビューではrequestAnimationFrameが動作せず、多くのアニメーションライブラリでデフォルトの状態では動作しない
useFrameなどを使用して手動更新をすることでこの問題は解決することが出来ます。
React Three FiberとReact-XRのフックはJSXのCanvas、XR内で読み込ませないといけない
これはReact Three Fiberを使っている人なら当然の情報かもしれませんが、React Three FiberやReact-XRで使用するフックはJSX内のCanvas、XR内で読み込ませる必要があります。
その際に、新たに関数を作ってコンポーネントとして呼び出す必要があり、またコンポーネントなので返り値に何らかの要素がないといけません。
実装例はこちらです。
function Frame(){//React Three FiberのフックであるuseFrameを呼び出すための関数
const timeRef = useRef(0);
useFrame((state, delta) => {
timeRef.current += delta
gsap.updateRoot(timeRef.current);
})
return(
<></>{/*コンポーネントなので返り値が必要、空でもOK*/}
)
}
function Interaction(){//React-XRのフックであるuseInteractionを呼び出すための関数
useInteraction(box,"onSelect",(e:XRInteractionEvent)=>{
console.log(e);
select();
})
return(
<></>
)
}
return (
<div>
<XRButton mode="AR"/>
<Canvas>
<Frame/>{/*React Three Fiberで呼び出すフックを有したコンポーネントは<Canvas>下にないといけない*/}
<XR>
<Controllers />
<Hands />
<directionalLight/>
<mesh
ref={box}
position={new THREE.Vector3(0,1,-2)}>
<boxGeometry
args={[1,1,1]}/>
<meshBasicMaterial
color="blue" />
</mesh>
<mesh
ref={box2}
position={new THREE.Vector3(100,100,100)}>
<boxGeometry
args={[1,1,1]}/>
<meshBasicMaterial
color="red" />
</mesh>
<Interaction/>{/*React-XRで呼び出すフックを有したコンポーネントは<XR>下にないといけない*/}
</XR>
...