Help us understand the problem. What is going on with this article?

【iOS13】新しくなったWebVRの使い方 [PlayCanvas]

はじめに

iOS13でWebVRをやる方法が変わりました。今まで(iOS 12)は、Safariの設定から加速度の許可をする方法だったのですが、iOS13から許可の方法が変わり、ブラウザ上から許可を求めるようになりました。
PlayCanvasを使用した対応方法がなかったため公開いたしました。

iOS 12のWebVRを使用するための権限を取得する方法

  1. iOSの設定を開く
  2. モーションと画面の向きのアクセスを許可する
  3. ブラウザ上でデバイスの動作と方向を取得できるようになる

iOS 13から変わった"動作と方向へのアクセス"

  1. ブラウザからアラートを出す
  2. 許可または拒否のどちらかが選択される
  3. 許可された場合ブラウザ上でデバイスの動作と方向を取得できるようになる

PlayCanvasでWebVRを使用する

  • JavaScriptでゲームを作れるエンジンのPlayCanvasを使用してiOS13に対応をさせます。

このプロジェクトのFork元のStarter Kit: VRを参考にして作成します。

1. PlayCanvasでWebVRのスターターキットを使用して作成をする

スターターキットを使用してiOS13のWebVRに対応をする方法を紹介します。

one

2. シーンの選択をする

two

Rootのweb-vr-ui.jsを書き換える

three

変更後のweb-vr-ui.js

web-vr-ui.js
/*jshint esversion: 6, asi: true, laxbreak: true*/
const WebVrUi = pc.createScript('webVrUi');

WebVrUi.attributes.add("camera", {type: "entity", title: "Camera"});
WebVrUi.attributes.add("enterVrWhite", {type: "asset", title: "Enter VR White Asset"});
WebVrUi.attributes.add("enterVrOrange", {type: "asset", title: "Enter VR Orange Asset"});
WebVrUi.attributes.add("infoBoxLifeSpan", {type: "number", default: 3, title: "Info Box Life Span",});

WebVrUi.prototype.initialize = function() {    
    if (this.app.vr && this.app.vr.display) {
        this.app.vr.display.on("presentchange", this.onVrPresentChange, this);
    }

    this.app.assets.load(this.enterVrWhite);
    this.app.assets.load(this.enterVrOrange);

    // HTML UI setup
    const css = '#vr-button {position: absolute;right: 0px;bottom: 0px;background-image: url("'+ this.enterVrWhite.getFileUrl() +'");width: 146px;height: 104px;display: block;'+
        'background-position: 0px 0px;background-size: 146px 104px; cursor: pointer;}' +        
        '#vr-button:hover {background-image: url("' + this.enterVrOrange.getFileUrl() + '");}' +
        '#info-box {position: absolute; right: 140px;bottom: 26px;display: block;background-color: rgba(0,0,0, 168);color: rgb(218, 218, 218);padding: 5px 10px 5px 10px;max-width: 220px;}' +
        '#info-box a, #info-box a:hover, #info-box a:visited, #info-box a:active {text-decoration: underline;color: rgb(218, 218, 218);}';

    const style = pc.createStyle(css);
    document.head.appendChild(style);

    this.vrButtonDiv = document.createElement("div");
    this.vrButtonDiv.id = "vr-button";
    this.vrButtonDiv.innerHTML = "&nbsp"; 

    document.body.appendChild(this.vrButtonDiv);

    this.infoBoxDiv = document.createElement("div");
    this.infoBoxDiv.id = "info-box";    

    this.infoBoxLifeTime = 0;
    this.infoBoxShowing = false;

    this.vrEntered = false;

    const self = this;

    const onEnterVrPressedEvent = function() {  
        // If WebVR is available and a VrDisplay is attached
        if (self.app.vr && self.app.vr.display) {
            if(self.vrEntered) {
                // Exit vr (needed for non-mobile)
                self.camera.camera.exitVr(function (err) {
                    if (err) {
                        console.warn(err);
                    } 
                });
            }
            else {
                // Enter vr
                self.camera.camera.enterVr(function (err) {
                    if (err) {
                        console.warn(err);
                    } 
                });
            }
        } 
        else {
            if (!self.infoBoxShowing) {
                if (self.app.vr.isSupported) {
                    self.infoBoxDiv.innerHTML = "No VR display or headset is detected.";
                }
                else {
                    self.infoBoxDiv.innerHTML = "Sorry, your browser does not support WebVR :(. Please go <a href='https://webvr.info/' target='_blank'>here</a> for more information.";
                }   

                self.infoBoxLifeTime = self.infoBoxLifeSpan;
                document.body.appendChild(self.infoBoxDiv);
                self.infoBoxShowing = true;
            }
        }
    };


    const onEnterVrPressedEventIOS13 = function(){

        if ( DeviceMotionEvent && DeviceMotionEvent.requestPermission && typeof DeviceMotionEvent.requestPermission === 'function') {
            DeviceMotionEvent.requestPermission();
          }

          if ( DeviceOrientationEvent && DeviceOrientationEvent.requestPermission && typeof DeviceOrientationEvent.requestPermission === 'function') {
            DeviceOrientationEvent.requestPermission().then((state) => {
                if(state === "granted"){
                    self.camera.camera.enterVr(function (err) {
                        if (err) {
                            console.warn(err);
                        } 
                });
                }else if(state === "denied"){
                    alert("Permission is denied !")
                }

            })
          }

    }

    if(window.navigator.userAgent.includes("OS 13")){
        this.vrButtonDiv.addEventListener('click', onEnterVrPressedEventIOS13, false);

    }else{
        this.vrButtonDiv.addEventListener('click', onEnterVrPressedEvent, false);
        onEnterVrPressedEvent();
    }

};

// update code called every frame
WebVrUi.prototype.update = function(dt) {
    if (this.infoBoxShowing) {
        this.infoBoxLifeTime -= dt;
        if (this.infoBoxLifeTime <= 0) {
            document.body.removeChild(this.infoBoxDiv);
            this.infoBoxShowing = false;
        }
    }
};

WebVrUi.prototype.onVrPresentChange = function(display) {
    if (display.presenting) {
        // Only remove the VR button if we are on mobile
        if (pc.platform.mobile) {
            document.body.removeChild(this.vrButtonDiv);
        }
        this.vrEntered = true;
    }
    else {
        if (pc.platform.mobile) {
            document.body.appendChild(this.vrButtonDiv);
        }
        this.vrEntered = false;
    }
};

WebVrUi.prototype.scaleInfoPanel = function(scale) {
};

変更点について

変更点はGistに差分があります。
既存のパソコンなどの動作はそのまま使用できるので、userAgentを見てiOS13のときのみに許可を求めるスクリプトを追加します。
https://gist.github.com/yushimatenjin/ce6e0dfe346510c94d65ff7e4afde14a#file-web-vr-ui-js-L80-L111

  • 1. DeviceOrientationEvent.requestPermission()こちらの関数を実行することでデバイスから動作と方向の許可を求めるアラートを出すことができます
  • 2. DeviceOrientationEvent.requestPermission()の返り値は現在の権限の状態deneidgrantedが非同期で渡されます。
    1. 権限を持っている状態grantedだった場合にPlayCanvasのenterVr関数でVRの状態(画面が2分割になり、回転などを取得している)にします。
  • デバイスの取得の方方はこちらを参考にいたしました
    iOS13でWebARとWebVRにおけるデバイスモーション設定が改善しました!

web-vr-ui.js
    const onEnterVrPressedEventIOS13 = function(){

          if ( DeviceOrientationEvent && DeviceOrientationEvent.requestPermission && typeof DeviceOrientationEvent.requestPermission === 'function') {
            DeviceOrientationEvent.requestPermission().then((state) => {
                if(state === "granted"){
                    self.camera.camera.enterVr(function (err) {
                        if (err) {
                            console.warn(err);
                        } 
                });
                }else if(state === "denied"){
                    alert("Permission is denied !")
                }

            })
          }

    }

    if(window.navigator.userAgent.includes("OS 13")){
        this.vrButtonDiv.addEventListener('click', onEnterVrPressedEventIOS13, false);

    }else{
        this.vrButtonDiv.addEventListener('click', onEnterVrPressedEvent, false);
        onEnterVrPressedEvent();
    }

};

表示できました

この一連の動作を見てみるとこのような表示になります。

※Gif

実際に使っている端末で動かす

このツイートまたはQRから飛ぶことができます。


yushimatenjin
インターネットに無限の可能性を感じています。
https://twitter.com/Mxcn3
playcanvas
"PlayCanvasは、ブラウザ向けに作られたWebGL/HTML5ゲームエンジンです。PlayCanvas運営事務局は日本国内でのPlayCanvasの普及を目的に活動しています"
https://playcanvas.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした