鿍奍;: ãã®æ©è½ã¯éæ¨å¥¨ã«ãªãã¾ãããã¾ã 対å¿ãã¦ãããã©ã¦ã¶ã¼ãããããããã¾ãããããã§ã«é¢é£ããã¦ã§ãæ¨æºããåé¤ããã¦ããããåé¤ã®æç¶ãä¸ã§ããããäºææ§ã®ããã ãã«æ®ããã¦ããå¯è½æ§ãããã¾ãã使ç¨ãé¿ããã§ããã°æ¢åã®ã³ã¼ãã¯æ´æ°ãã¦ãã ããããã®ãã¼ã¸ã®ä¸é¨ã«ããäºææ§ä¸è¦§è¡¨ãè¦ã¦å¤æãã¦ãã ããããã®æ©è½ã¯çªç¶åä½ããªããªãå¯è½æ§ããããã¨ã«æ³¨æãã¦ãã ããã
ã¡ã¢: WebVR API 㯠WebXR API ã«ç½®ãæãããã¾ããã WebVR ã¯æ¨æºã¨ãã¦æ¹åããããã¨ã¯ãªããããå°æ°ã®ãã©ã¦ã¶ã¼ã§ããæ¢å®ã§å®è£ ã»æå¹åããããå°æ°ã®ç«¯æ«ãã対å¿ãã¦ãã¾ããã§ããã
WebVR API ã¯ã¦ã§ãéçºè ã®ãã¼ã«ãããã¸ã®ãã°ãããè¿½å æ©è½ã§ã Oculus Rift ã®ãããªãã¼ãã£ã«ãªã¢ãªãã£ãã¼ãã¦ã§ã¢ã¸ã®ã¢ã¯ã»ã¹ãå¯è½ã¨ãªãã¾ããããã¦åºåãããåããåãã¯ã¦ã§ãã¢ããªã®æç»æ´æ°ã«å¤æããã¾ããããã VR ã¢ããªãéçºã¯ã©ã®ããã«ããã°ããã®ã§ããããï¼ ãã®è¨äºã§ã¯ãããã«é¢ããåºç¤çãªè§£èª¬ãè¡ãã¾ãã
å§ãã¾ãããå§ããã«ã¯ã次ã®ãã®ãå¿ è¦ã§ãã
対å¿ãã¦ãã VR ãã¼ãã¦ã§ã¢
使ç¨ããå ´åã VR å°ç¨ãã¼ãã¦ã§ã¢ã使ç¨ã㦠VR ã·ã¼ã³ã®ã¬ã³ããªã³ã°/表示ãå¦çããã®ã«ååãªæ§è½ã®ã³ã³ãã¥ã¼ã¿ã¼ãè³¼å ¥ãã VR ã®é¢é£ã¬ã¤ãï¼ä¾ï¼ VIVE READY ã³ã³ãã¥ã¼ã¿ã¼ï¼ãè¦ã¦ããã ãã¨ãå¿ è¦ãªãã®ããããã¨æãã¾ãã
対å¿ãã¦ãããã©ã¦ã¶ã¼ãã¤ã³ã¹ãã¼ã«ããã¦ããã㨠- ææ°ã®Firefox Nightly ã¾ã㯠Chrome ãããã¹ã¯ãããã§ãã¢ãã¤ã«ã§ããæ£ãã鏿ã¨ãªãã¾ãã
ãã¹ã¦ã®çµã¿ç«ã¦ãå®äºãããã simple A-Frame demo ã«ã¢ã¯ã»ã¹ããã¨ãã·ã¼ã³ãã¬ã³ããªã³ã°ãããããå³ä¸ã®ãã¿ã³ãæ¼ã㦠VR 表示ã¢ã¼ãã«å ¥ããã¨ãã§ãããã©ããã§ãã»ããã¢ããã«ãã£ã¦ WebVR ãæ£ããåä½ãããã©ããããã¹ããããã¨ãã§ãã¾ãã
æ°ãã JavaScript ã³ã¼ãã®æãçè§£ããå¿ è¦ãªããWebVR äºæã® 3D ã·ã¼ã³ããã°ãã使ãããå ´åã¯ãA-Frame ãæç¶æé©ãªãªãã·ã§ã³ã¨è¨ãã¾ããããããããã¯çã® WebVR API ãã©ã®ããã«åä½ããã®ããæãã¦ã¯ããã¾ããã®ã§ã次ã«åããããã®ã¯ãã®ç¹ã§ãã
ç°¡åãªãã¢WebVR API ãã©ã®ããã«åä½ããã®ãã説æããããã«ã次ã®ãã㪠raw-webgl-example ãåå¼·ãã¦ã¿ã¾ãããã
ã¡ã¢: ãã®ãã¢ã®ã½ã¼ã¹ã³ã¼ã 㯠GitHub ã§ãã©ã¤ãã§è¦ããã¨ãã§ãã¾ã also.
ã¡ã¢: ãã©ã¦ã¶ã¼ã§ WebVR ãåä½ããªãå ´åãã°ã©ãã£ãã¯ã«ã¼ããéãã¦å®è¡ãã¦ãããã©ããã確èªããå¿ è¦ãããå ´åãããã¾ããä¾ãã° NVIDIA ã®ã«ã¼ãã®å ´åã NVIDIA ã³ã³ããã¼ã«ããã«ãæ£å¸¸ã«è¨å®ããã¦ããã°ãå©ç¨ã§ããã³ã³ããã¹ãã¡ãã¥ã¼ãªãã·ã§ã³ãããã¾ã - Firefox ãå³ã¯ãªãã¯ãã Run with graphics processor > High-performance NVIDIA processor ãé¸ãã§ãã ããã
ãã®ãã¢ã§ã¯ãWebGL ã®ãã¢ã®èæ¯ã§ãããå転ãã 3D ç«æ¹ä½ãæ±ã£ã¦ãã¾ããç§ãã¡ã¯ãããçã® WebGL API ã³ã¼ãã使ç¨ãã¦å®è£ ãã¦ãã¾ããåºæ¬ç㪠JavaScript ã WebGL ã¯ä¸åæãããWebVR ã®é¨åã®ã¿ãæããäºå®ã§ãã
ãã®ãã¢ã§ã¯ã次ã®ãããªæ©è½ãåãã¦ãã¾ãã
ãã®ãã¢ã®ã¡ã¤ã³ã® JavaScript ãã¡ã¤ã«ã®ã½ã¼ã¹ã³ã¼ããè¦ã¦ããã¨ãå è¡ããã³ã¡ã³ãã§ "WebVR" ã¨ããæååãæ¢ãã°ãç°¡åã« WebVR ã«ç¹åããé¨åãè¦ã¤ãããã¨ãã§ãã¾ãã
ã¡ã¢: åºæ¬ç㪠JavaScript 㨠WebGL ã«ã¤ãã¦ã¯ã JavaScript å¦ç¿ç´ æãWebGL ãã¥ã¼ããªã¢ã«ãåç §ãã¦ãã ããã
ã¢ããªã¯ã©ãåãããã®ç¹ã§ãã³ã¼ãã® WebVR é¨åãã©ã®ããã«åä½ããã®ããè¦ã¦ããã¾ãããã
å ¸åçãªï¼åç´ãªï¼ WebVR ã¢ããªã¯ãã®ããã«ä½æ¥ãã¾ãã
Navigator.getVRDisplays()
ã使ç¨ãã¦ã VRãã£ã¹ãã¬ã¤ã¸ã®åç
§ãåå¾ãã¾ããVRDisplay.requestPresent()
ã使ç¨ã㦠VR ãã£ã¹ãã¬ã¤ã¸ã®è¡¨ç¤ºãéå§ãã¾ããVRDisplay.requestAnimationFrame()
ã¡ã½ããã使ç¨ãã¦ããã£ã¹ãã¬ã¤ã®æ£ãããªãã¬ãã·ã¥ã¬ã¼ãã§ã¢ããªã®ã¬ã³ããªã³ã°ã«ã¼ããå®è¡ããã¾ããVRDisplay.getFrameData()
ï¼ã表示ã·ã¼ã³ã両ç¼ã§ 2 åæç»ããã¬ã³ããªã³ã°ãããã¥ã¼ããã£ã¹ãã¬ã¤ã«éä¿¡ãã¦ã¦ã¼ã¶ã«è¡¨ç¤ºãã¾ã (VRDisplay.submitFrame()
)ãä¸è¨ã®ç¯ã§ã¯ããã® raw-webgl-demo ã詳ããè¦ã¦ãããä¸è¨ã®æ©è½ãå ·ä½çã«ã©ãã§ä½¿ç¨ãããããè¦ã¦ããã¾ãã
ããã¤ãã®å¤æ°ã§å§ããæåã«åºä¼ã WebVR é¢é£ã®ã³ã¼ãã¯ã以ä¸ã®ãããã¯ã§ãã
// WebVR 夿°
const frameData = new VRFrameData();
let vrDisplay;
const btn = document.querySelector(".stop-start");
let normalSceneFrame;
let vrSceneFrame;
const poseStatsBtn = document.querySelector(".pose-stats");
const poseStatsSection = document.querySelector("section");
poseStatsSection.style.visibility = "hidden"; // hide it initially
const posStats = document.querySelector(".pos");
const orientStats = document.querySelector(".orient");
const linVelStats = document.querySelector(".lin-vel");
const linAccStats = document.querySelector(".lin-acc");
const angVelStats = document.querySelector(".ang-vel");
const angAccStats = document.querySelector(".ang-acc");
let poseStatsDisplayed = false;
ãããã«ã¤ãã¦ç°¡åã«èª¬æãã¾ãã
frameData
ã«ã¯ VRFrameData
ãªãã¸ã§ã¯ããå
¥ãããã㯠VRFrameData()
ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ä½æãã¾ããããã¯åæç¶æ
ã§ã¯ç©ºã§ãããå¾ã« VR ãã£ã¹ãã¬ã¤ã«è¡¨ç¤ºããåãã¬ã¼ã ã®ã¬ã³ããªã³ã°ã«å¿
è¦ãªãã¼ã¿ãæ ¼ç´ããã¬ã³ããªã³ã°ã«ã¼ãã®å®è¡ã«åããã¦å¸¸ã«æ´æ°ããã¾ããvrDisplay
ã¯åæåããã¦ãã¾ããããå¾ã« VR ãããã»ããï¼VRDisplay
â API ã®ä¸å¿çãªå¶å¾¡ãªãã¸ã§ã¯ãï¼ã¸ã®åç
§ãä¿æããããã«ãªãã¾ããbtn
㨠poseStatsBtn
ã«ã¯ãã¢ããªãå¶å¾¡ããããã«ä½¿ç¨ãã 2 ã¤ã®ãã¿ã³ã¸ã®åç
§ãæ ¼ç´ããã¦ãã¾ããnormalSceneFrame
㨠vrSceneFrame
ã¯åæåãããã«å§ã¾ãã¾ãããå¾ã§ Window.requestAnimationFrame()
㨠VRDisplay.requestAnimationFrame()
ã®å¼ã³åºãã¸ã®åç
§ãæ ¼ç´ãã¾ãããããã¯é常ã®ã¬ã³ããªã³ã°ã«ã¼ãã¨ç¹å¥ãª WebVR ã¬ã³ããªã³ã°ã«ã¼ããå®è¡ããããã«ãªãã¾ãããå¾ã§ãã® 2 ã¤ã®éãã説æãããã¨ã«ãªãã¾ããã³ã¼ãå
ã®ä¸»è¦ãªé¢æ°ã®ä¸ã¤ã¯ start()
ã§ãæ¬ä½ã®èªã¿è¾¼ã¿ãå®äºããã¨ãã«ãã®é¢æ°ãå®è¡ãã¦ãã¾ãã
// start
//
// æ¬ä½ãèªã¿è¾¼ã¾ããã¨ãã«å¼ã³åºããããã¼ã«ãåå¾ããããã«ä½æããã¾ãã
document.body.onload = start;
ã¾ãå§ãã«ãstart()
㯠WebGL ã³ã³ããã¹ããåå¾ãã¦ã3D ã°ã©ãã£ãã¯ã HTML ã® <canvas>
è¦ç´ ã«ã¬ã³ããªã³ã°ããããã«ä½¿ç¨ãã¾ããæ¬¡ã«ãgl
ã³ã³ããã¹ããå©ç¨ã§ãããã©ããã調ã¹ã¾ããå©ç¨ã§ããå ´åã¯ã表示ããã·ã¼ã³ãè¨å®ããããã«ããã¤ãã®é¢æ°ãå®è¡ãã¾ãã
function start() {
canvas = document.getElementById("glcanvas");
initWebGL(canvas); // Initialize the GL context
// WebGL setup code here
次ã«ããã£ã³ãã¹ããã©ã¦ã¶ã¼ã®ãã¥ã¼ãã¼ããã£ã±ãã«è¨å®ããã¬ã³ããªã³ã°ã«ã¼ã (drawScene()
) ãæåã«å®è¡ãã¦ãã·ã¼ã³ããã£ã³ãã¹ã«å®éã«ã¬ã³ããªã³ã°ããå¦çãå§ãã¾ãããã㯠WebVR ã§ã¯ãªããé常ã®ã¬ã³ããªã³ã°ã«ã¼ãã§ãã
// draw the scene normally, without WebVR - for those who don't have it and want to see the scene in their browser
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
drawScene();
ããã§æåã® WebVR åºæã®ã³ã¼ãã«å
¥ãã¾ããã¾ãæåã«ã Navigator.getVRDisplays
ãåå¨ãããã©ããã調ã¹ã¾ã - ãã㯠API ã¸ã®ã¨ã³ããªã¼ãã¤ã³ãã§ããããããã£ã¦ WebVR ã®åºæ¬çãªæ©è½ãé©åã«æ¤åºãããã¨ãã§ãã¾ãããããã¯ã®æå¾ï¼else
å¥ã®ä¸ï¼ã«ããããåå¨ããªãå ´åã WebVR 1.1 ããã©ã¦ã¶ã¼ã§å¯¾å¿ãã¦ããªããã¨ã示ãã¡ãã»ã¼ã¸ããã°åºåãã¦ãããã¨ããããã¾ãã
// WebVR: Check to see if WebVR is supported
if (navigator.getVRDisplays) {
console.log('WebVR 1.1 supported');
if () { }
ãããã¯ã®ä¸ã§ã Navigator.getVRDisplays()
ã¨ãã颿°ãå®è¡ãã¦ãã¾ãããã®é¢æ°ã¯ãã³ã³ãã¥ã¼ã¿ã¼ã«æ¥ç¶ããã¦ãããã¹ã¦ã® VR ãã£ã¹ãã¬ã¤æ©å¨ãæ ¼ç´ããé
åã§å±¥è¡ããããããã¹ãè¿ãã¾ãã 1 å°ãæ¥ç¶ããã¦ããªãå ´åã¯ãé
åã¯ç©ºã«ãªãã¾ãã
// Then get the displays attached to the computer
navigator.getVRDisplays().then((displays) => {
ãããã¹ã® then()
ãããã¯ã®ä¸ã§ãé
åã®é·ãã 0 以ä¸ãã©ããã調ã¹ã¾ãã0 以ä¸ã§ããã°ã夿° vrDisplay
ã®å¤ãé
åã® 0 çªç®ã®ã¤ã³ããã¯ã¹ã«éåããã¾ããããã§ vrDisplay
ã«ã¯ãæ¥ç¶ããããã£ã¹ãã¬ã¤ã表ã VRDisplay
ãªãã¸ã§ã¯ããæ ¼ç´ããã¾ããã
// If a display is available, use it to present the scene
if (displays.length > 0) {
vrDisplay = displays[0];
console.log('Display found');
ã¡ã¢: ã³ã³ãã¥ã¼ã¿ã¼ã«è¤æ°ã® VR ãã£ã¹ãã¬ã¤ãä¿æãããã¨ã¯ã¾ããªãã§ããããããã®ãã¢ã§ã¯åç´ãªãã®ãªã®ã§ãã¨ããããã¯ããã§å¤§ä¸å¤«ã§ãããã
VR 表示ã®éå§ã¨åæ¢ããã§ VRDisplay
ãªãã¸ã§ã¯ããåå¾ãããã®ãªãã¸ã§ã¯ãã使ç¨ãã¦ãã¾ãã¾ãªãã¨ãè¡ããã¨ãã§ãã¾ããæ¬¡ã«è¡ããã¨ã¯ããã£ã¹ãã¬ã¤ã¸ã® WebGL ã³ã³ãã³ãã®è¡¨ç¤ºãå§ããããæ¢ãããããããã®æ©è½ãè¨å®ãããã¨ã§ãã
åã®ã³ã¼ããããã¯ã«å¼ãç¶ããä»åº¦ã¯éå§/忢ãã¿ã³ (btn
) ã«ã¤ãã³ããªã¹ãã¼ã追å ãã¾ãããã®ãã¿ã³ãã¯ãªãã¯ãããã¨ãã«ããã£ã¹ãã¬ã¤ã«ãã§ã«è¡¨ç¤ºããã¦ãããã©ããã確èªãã¾ãï¼ããã¯ããªãéæããªæ¹æ³ã§ããã¿ã³ textContent
ãä½ãæ ¼ç´ãã¦ãããã調ã¹ããã¨ã«ãã£ã¦è¡ããã¾ãï¼ã
ãã£ã¹ãã¬ã¤ãã¾ã 表示ããã¦ããªãå ´åã VRDisplay.requestPresent()
ã¡ã½ããã使ç¨ãã¦ããã©ã¦ã¶ã¼ããã£ã¹ãã¬ã¤ã¸ã®ã³ã³ãã³ãã®è¡¨ç¤ºãå§ããããã«ãªã¯ã¨ã¹ããã¾ããããã¯ã弿°ã¨ãã¦ããã£ã¹ãã¬ã¤ã«è¡¨ç¤ºãããã¬ã¤ã¤ã¼ã表ã VRLayerInit
ãªãã¸ã§ã¯ãã®é
åãåãã¾ãã
ç¾å¨ã表示ã§ããã¬ã¤ã¤ã¼ã®æå¤§æ°ã¯ 1 ã§ãå¿
è¦ãªãªãã¸ã§ã¯ãã®ã¡ã³ãã¼ã¯ VRLayerInit.source
ããããã£(ããã¯ããã®ã¬ã¤ã¤ã¼ã§è¡¨ç¤ºããã <canvas>
ã¸ã®åç
§ã§ããä»ã®å¼æ°ã¯ãæè¦çãªæ¢å®å¤ã¨ãã¦ä¸ãããã¦ãã¾ã - leftBounds
ããã³ rightBounds
)) ã§ã弿°ã¯ [{ source: canvas }] ã«ãªã£ã¦ãã¾ããï¼½
requestPresent()
ã¯è¡¨ç¤ºãæ£å¸¸ã«å§ã¾ã£ãã¨ãã«å±¥è¡ããããããã¹ãè¿ãã¾ãã
// Starting the presentation when the button is clicked: It can only be called in response to a user gesture
btn.addEventListener('click', () => {
if (btn.textContent === 'Start VR display') {
vrDisplay.requestPresent([{ source: canvas }]).then(() => {
console.log('Presenting to WebVR display');
表示ãªã¯ã¨ã¹ããæåããã®ã§ãä»åº¦ã¯ VRDisplay ã«è¡¨ç¤ºãã¦ããã³ã³ãã³ããã¬ã³ããªã³ã°ããããã®è¨å®ãå§ãããã¨æãã¾ããæåã®è¨å®ã¨ãã¦ããã£ã³ãã¹ã§ VR ãã£ã¹ãã¬ã¤ã¨åã大ããã«è¨å®ãã¾ããããã¯ãVRDisplay.getEyeParameters()
ã使ç¨ãã¦ä¸¡ç®ã® VREyeParameters
ãåå¾ãããã¨ã«ãã£ã¦è¡ããã¾ãã
次ã«ãåç´ãªè¨ç®ãè¡ã£ã¦ãç®ã® VREyeParameters.renderWidth
㨠VREyeParameters.renderHeight
ã«åºã¥ã㦠VRDisplay æç»é åã®åè¨å¹
ãè¨ç®ãã¾ãã
// Set the canvas size to the size of the vrDisplay viewport
const leftEye = vrDisplay.getEyeParameters("left");
const rightEye = vrDisplay.getEyeParameters("right");
canvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2;
canvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight);
次ã«ãåå drawScene()
颿°å
ã® Window.requestAnimationFrame()
å¼ã³åºãã«ãã£ã¦è¨å®ãããã¢ãã¡ã¼ã·ã§ã³ã®ã«ã¼ãããã£ã³ã»ã«ãã代ããã« drawVRScene()
ãå¼ã³åºããã¨ã«ãã¾ãããã®é¢æ°ã¯åã¨åãã·ã¼ã³ãã¬ã³ããªã³ã°ãã¾ãããWebVR ã®ç¹å¥ãªãã¸ãã¯ãè¡ããã¾ããããã§ã®ã«ã¼ã㯠WebVR ã®ç¹å¥ãª VRDisplay.requestAnimationFrame
ã¡ã½ããã«ãã£ã¦ç¶æããã¦ãã¾ãã
// stop the normal presentation, and start the vr presentation
window.cancelAnimationFrame(normalSceneFrame);
drawVRScene();
æå¾ã«ããã¿ã³ããã¹ããæ´æ°ããæ¬¡ã«ãã¿ã³ãæ¼ãããæå»ã« VR ãã£ã¹ãã¬ã¤ã¸ã®è¡¨ç¤ºã忢ããããã«ãã¾ãã
btn.textContent = 'Exit VR display';
});
ç¶ãã¦ãã¿ã³ãæ¼ãããã¨ãã« VR 表示ã忢ããããã«ã VRDisplay.exitPresent()
ãå¼ã³åºãã¦ãã¾ããã¾ãããã¿ã³ã®ããã¹ãã³ã³ãã³ããå転ããã requestAnimationFrame
ã®å¼ã³åºããå
¥ãæ¿ãã¾ãããããã§ã VRDisplay.cancelAnimationFrame
ã使ç¨ã㦠VR ã¬ã³ããªã³ã°ã®ã«ã¼ãã忢ãã drawScene()
ã使ç¨ãã¦é常ã®ã¬ã³ããªã³ã°ã«ã¼ããåã³éå§ãã¦ãããã¨ãåããã¾ãã
} else {
vrDisplay.exitPresent();
console.log('Stopped presenting to WebVR display');
btn.textContent = 'Start VR display';
// Stop the VR presentation, and start the normal presentation
vrDisplay.cancelAnimationFrame(vrSceneFrame);
drawScene();
}
});
}
});
} else {
console.log('WebVR API not supported by this browser.');
}
}
ãã¬ã¼ã³ãã¼ã·ã§ã³ãå§ããã«ã¯ããã©ã¦ã¶ã¼ã«è¡¨ç¤ºãããç«ä½è¦ã確èªãã¾ãã
å®éã«ã©ã®ããã«ç«ä½è¦ãè¡ããããã¯ä¸è¨ãã覧ãã ããã
ãªã WebVR ã¯ç¬èªã® requestAnimationFrame() ãæã¤ã®ãããã¯è¯ã質åã§ãããªããªãã VR ãã£ã¹ãã¬ã¤å ã§ã¹ã ã¼ãºãªã¬ã³ããªã³ã°ãè¡ãã«ã¯ãã³ã³ãã¥ã¼ã¿ã¼ã®ãªãã¬ãã·ã¥ã¬ã¼ãã§ã¯ãªãããã£ã¹ãã¬ã¤ã®ãã¤ãã£ããªãã¬ãã·ã¥ã¬ã¼ãã§ã³ã³ãã³ããã¬ã³ããªã³ã°ããå¿ è¦ãããããã§ãã VR ãã£ã¹ãã¬ã¤ã®ãªãã¬ãã·ã¥ã¬ã¼ã㯠PC ã®ãªãã¬ãã·ã¥ã¬ã¼ãããã大ãããéå¸¸ã¯æå¤§ã§ 90fps ã§ãããã®ã¬ã¼ãã¯ãã³ã³ãã¥ã¼ã¿ã¼ã®ã³ã¢ãªãã¬ãã·ã¥ã¬ã¼ãã¨ã¯ç°ãªãå½¢ã«ãªãã¾ãã
VR ãã£ã¹ãã¬ã¤ã表示ããã¦ããªãã¨ãã¯ãVRDisplay.requestAnimationFrame
㯠Window.requestAnimationFrame
ã¨åãããã«åä½ããã®ã§ãå¿
è¦ã«å¿ãã¦ããã®ã¢ããªã§ä½¿ç¨ãã¦ãã 2 ã¤ã®ã¬ã³ããªã³ã° ã«ã¼ãã§ã¯ãªãã1 ã¤ã®ã¬ã³ããªã³ã° ã«ã¼ãã ãã使ç¨ã§ãããã¨ã«çæãã¦ãã ããã2 ã¤ä½¿ç¨ããã®ã¯ãVR ãã£ã¹ãã¬ã¤ãåå¨ãããã©ããã«å¿ãã¦ç°ãªããã¨ãè¡ããçè§£ããããããã«ç©äºãå¥åã®ãã®ã«ãããã£ãããã§ãã
ãã®ç¹ã§ã VR ãã¼ãã¦ã§ã¢ã«ã¢ã¯ã»ã¹ãããã¼ãã¦ã§ã¢ã«ã·ã¼ã³ã表示ãããããªã¯ã¨ã¹ãããã¬ã³ããªã³ã° ã«ã¼ããå®è¡ãå§ããããã«å¿ è¦ãªãã¹ã¦ã®ã³ã¼ããè¦ã¦ãã¾ãããããã§ãã¬ã³ããªã³ã° ã«ã¼ãã®ã³ã¼ããè¦ã¦ã WebVR åºæã®é¨åãã©ã®ããã«åä½ããã®ãã説æãã¾ãã
ã¾ããã¹ã¦ãã¬ã³ããªã³ã°ã«ã¼ã颿°ã§ãã drawVRScene()
ã®å®ç¾©ããå§ãã¾ãããã®å
é¨ã§æåã«è¡ããã¨ã¯ VRDisplay.requestAnimationFrame()
ãå¼ã³åºãã¦ãã«ã¼ããä¸åº¦å¼ã°ããå¾ï¼ããã¯ã³ã¼ãã®ååã§ VR ãã£ã¹ãã¬ã¤ã«è¡¨ç¤ºãéå§ããã¨ãã«çºçãã¾ãï¼ãã«ã¼ããå®è¡ãç¶ããããã«ãããã¨ã§ãããã®å¼ã³åºããã°ãã¼ãã«å¤æ° vrSceneFrame
ã®å¤ã¨ãã¦è¨å®ããVR ãã¬ã¼ã³ãã¼ã·ã§ã³ãçµäºããã VRDisplay.cancelAnimationFrame()
ã®å¼ã³åºãã§ã«ã¼ãããã£ã³ã»ã«ã§ããããã«ãã¦ãã¾ãã
function drawVRScene() {
// WebVR: Request the next frame of the animation
vrSceneFrame = vrDisplay.requestAnimationFrame(drawVRScene);
次㫠VRDisplay.getFrameData()
ãå¼ã³åºãã¦ããã¬ã¼ã ãã¼ã¿ãæ ¼ç´ããããã«ä½¿ç¨ããã夿°åãæ¸¡ãã¾ããå
ã»ã©ãframeData
ã¨ãã夿°ã§åæåãã¾ãããå¼ã³åºãããå¾ããã®å¤æ°ã«ã¯æ¬¡ã®ãã¬ã¼ã ã VR æ©å¨ã«ã¬ã³ããªã³ã°ããããã«å¿
è¦ãªãã¼ã¿ã VRFrameData
ãªãã¸ã§ã¯ãã¨ãã¦ããã±ã¼ã¸ã³ã°ããã¦æ ¼ç´ããã¾ããããã«ã¯ãå·¦ç®ç¨ã¨å³ç®ç¨ã®ã·ã¼ã³ãæ£ããã¬ã³ããªã³ã°ããããã®æå½±ããã³ãã¥ã¼ãããªãã¯ã¹ãããã¦æ¹åãä½ç½®ãªã©VRãã£ã¹ãã¬ã¤ã®ãã¼ã¿ãæ ¼ç´ããç¾å¨ã® VRPose
ãªãã¸ã§ã¯ãã¨ãã£ããã®ãå«ã¾ãã¦ãã¾ãã
ããã¯ãã¬ã³ããªã³ã°ããããã¥ã¼ãå¸¸ã«ææ°ã®ç¶æ ã«ãªãããã«ããã¬ã¼ã ãã¨ã«å¼ã³åºãããå¿ è¦ãããã¾ãã
// Populate frameData with the data of the next frame to display
vrDisplay.getFrameData(frameData);
ããã§ãVRPose
ããããã£ããç¾å¨ã® VRFrameData.pose
ãåå¾ããå¾ã§ä½¿ç¨ããããã«ä½ç½®ã¨æ¹åãæ ¼ç´ãã夿° poseStatsDisplayed
ã true ã®å ´åã¯ç¾å¨ã® pose ã pose stats ããã¯ã¹ã«éã£ã¦è¡¨ç¤ºãããã¨ãã§ãã¾ããã
// You can get the position, orientation, etc. of the display from the current frame's pose
const curFramePose = frameData.pose;
const curPos = curFramePose.position;
const curOrient = curFramePose.orientation;
if (poseStatsDisplayed) {
displayPoseStats(curFramePose);
}
ããã§ããã£ã³ãã¹ã«ã¯æç»ãå§ããåã«ã¯ãªã¢ãããæ¬¡ã®ãã¬ã¼ã ãã¯ã£ããã¨è¦ããããã«ãªããååã®ã¬ã³ããªã³ã°ãã¬ã¼ã ãè¦ããªããªãã¾ããã
// Clear the canvas before we start drawing on it.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
ããã§ãå·¦ç®ã¨å³ç®ã®ä¸¡æ¹ã®ãã¥ã¼ãã¬ã³ããªã³ã°ãããã¨ãã§ãã¾ããæåã«ãã¬ã³ããªã³ã°ã«ä½¿ç¨ããæå½±ä½ç½®ã¨è¡¨ç¤ºä½ç½®ã使ããå¿
è¦ãããã¾ããããã㯠WebGLUniformLocation
ãªãã¸ã§ã¯ãã§ã WebGLRenderingContext.getUniformLocation()
ã¡ã½ããã使ç¨ãã¦ä½æãã弿°ã¨ãã¦ã·ã§ã¼ãã¼ããã°ã©ã ã®èå¥åã¨èå¥å ãæ¸¡ãã¾ãã
// WebVR: Create the required projection and view matrix locations needed
// for passing into the uniformMatrix4fv methods below
const projectionMatrixLocation = gl.getUniformLocation(
shaderProgram,
"projMatrix",
);
const viewMatrixLocation = gl.getUniformLocation(shaderProgram, "viewMatrix");
次ã®ã¬ã³ããªã³ã°æé ã§ã¯ã次ã®ãã¨ãè¡ãã¾ãã
WebGLRenderingContext.viewport
ã§æå®ãã¾ã - ããã¯è«ççã«ã¯ãã£ã³ãã¹å¹
ã®æåã®ååã¨ããã£ã³ãã¹é«ããã£ã±ãã«ãªãã¾ããWebGLRenderingContext.uniformMatrix4fv
ã¡ã½ããã§è¡ãã¾ãããã®ã¡ã½ããã«ã¯ãä¸ã§åå¾ããä½ç½®æ
å ±ã¨ VRFrameData
ãªãã¸ã§ã¯ãã§å¾ãå·¦è¡åã®å¤ã渡ããã使ç¨ãã¾ããdrawGeometry()
颿°ãå®è¡ãã¾ããååã®2ã¤ã®æé ã§æå®ããå
容ãããå·¦ç®ç¨ã«ã®ã¿ã¬ã³ããªã³ã°ãããã¨ã«ãªãã¾ãã// WebVR: Render the left eye's view to the left half of the canvas
gl.viewport(0, 0, canvas.width * 0.5, canvas.height);
gl.uniformMatrix4fv(
projectionMatrixLocation,
false,
frameData.leftProjectionMatrix,
);
gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.leftViewMatrix);
drawGeometry();
ããã§ãã¾ã£ããåããã¨ãå³ç®ã§è¡ãã¾ãã
// WebVR: Render the right eye's view to the right half of the canvas
gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height);
gl.uniformMatrix4fv(
projectionMatrixLocation,
false,
frameData.rightProjectionMatrix,
);
gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.rightViewMatrix);
drawGeometry();
次ã«ã drawGeometry()
颿°ãå®ç¾©ãã¾ãããã®é¢æ°ã®ã»ã¨ãã©ã¯ã 3D ç«æ¹ä½ãæç»ããããã«å¿
è¦ãªä¸è¬ç㪠WebGL ã³ã¼ãã§ãã mvTranslate()
㨠mvRotate()
颿°å¼ã³åºãã« WebVR åºæã®é¨åãããã¾ãããããã¯ãç¾å¨ã®ãã¬ã¼ã ã«ãããç«æ¹ä½ã®ç§»åã¨å転ãå®ç¾©ããè¡åã WebGL ããã°ã©ã ã«æ¸¡ããã®ã§ãã
ãããã®å¤ã VRPose
ãªãã¸ã§ã¯ãããåå¾ãã VR ãã£ã¹ãã¬ã¤ã®ä½ç½® (curPos
) ã¨æ¹å (curOrient
) ã«ãã£ã¦å¤æ´ãã¦ãããã¨ããããã¨æãã¾ãããã®çµæãä¾ãã°é ãå·¦ã«åããããå転ããããããã¨ãx ä½ç½®å¤ (curPos[0]
) 㨠y åè»¢å¤ ([curOrient[1]
) ã x ç§»åå¤ã«è¿½å ããã¾ããã¤ã¾ããä½ããè¦ã¦ããã¨ãã«é ãå·¦ã«ç§»å/å転ãããã¨ããã¥ã¼ãã¯å³ã«ç§»åãããã¨ãæå³ãã¾ãã
ããã¯ãVR ãã¼ãºãã¼ã¿ã使ç¨ããããã®ãã°ããæ±ãæ¹æ³ã§ãããåºæ¬çãªåçã説æãã¦ãã¾ãã
function drawGeometry() {
// Establish the perspective with which we want to view the
// scene. Our field of view is 45 degrees, with a width/height
// ratio of 640:480, and we only want to see objects between 0.1 units
// and 100 units away from the camera.
perspectiveMatrix = makePerspective(45, 640.0 / 480.0, 0.1, 100.0);
// Set the drawing position to the "identity" point, which is
// the center of the scene.
loadIdentity();
// Now move the drawing position a bit to where we want to start
// drawing the cube.
mvTranslate([
0.0 - curPos[0] * 25 + curOrient[1] * 25,
5.0 - curPos[1] * 25 - curOrient[0] * 25,
-15.0 - curPos[2] * 25,
]);
// Save the current matrix, then rotate before we draw.
mvPushMatrix();
mvRotate(cubeRotation, [0.25, 0, 0.25 - curOrient[2] * 0.5]);
// Draw the cube by binding the array buffer to the cube's vertices
// array, setting attributes, and pushing it to GL.
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
// Set the texture coordinates attribute for the vertices.
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
// Specify the texture to map onto the faces.
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
// Draw the cube.
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
// Restore the original matrix
mvPopMatrix();
}
次ã®ã³ã¼ã㯠WebVR ã¨ã¯ä½ã®é¢ä¿ããªããåãã¬ã¼ã ã§ç«æ¹ä½ã®åè»¢ãæ´æ°ããã ãã§ãã
// Update the rotation for the next draw, if it's time to do so.
let currentTime = new Date().getTime();
if (lastCubeUpdateTime) {
const delta = currentTime - lastCubeUpdateTime;
cubeRotation += (30 * delta) / 1000.0;
}
lastCubeUpdateTime = currentTime;
ã¬ã³ããªã³ã°ã«ã¼ãã®æå¾ã®é¨åã§ VRDisplay.submitFrame()
ãå¼ã³åºãã¾ãããã®ã¡ã½ããã§ã¯ããã¹ã¦ã®ä½æ¥ãå®äºãã <canvas>
ã«è¡¨ç¤ºãã¬ã³ããªã³ã°ãããã¨ããã¬ã¼ã ã VR ãã£ã¹ãã¬ã¤ã«éä¿¡ãã¦ãããã«è¡¨ç¤ºãããã¨ãã§ãã¾ãã
// WebVR: Indicate that we are ready to present the rendered frame to the VR display
vrDisplay.submitFrame();
}
ãã¼ãºï¼ä½ç½®ãåããªã©ï¼ãã¼ã¿ã®è¡¨ç¤º
ãã®ç¯ã§ã¯ãåãã¬ã¼ã ã§æ´æ°ããããã¼ãºãã¼ã¿ã表示ãã displayPoseStats()
颿°ã«ã¤ãã¦èª¬æãã¾ãããã®é¢æ°ã¯ããªãåç´ã§ãã
ãã¹ã¦ VRPose
ãªãã¸ã§ã¯ãããå¾ããã 6 ã¤ã®ç°ãªãå½¢ã®ããããã£å¤ãèªåèªèº«ã§å¤æ°ã«æ ¼ç´ãã¾ãããããã Float32Array
ã¨ãã¾ãã
function displayPoseStats(pose) {
const pos = pose.position;
const orient = pose.orientation;
const linVel = pose.linearVelocity;
const linAcc = pose.linearAcceleration;
const angVel = pose.angularVelocity;
const angAcc = pose.angularAcceleration;
ããã¦ããã®ãã¼ã¿ãæ
å ±ããã¯ã¹ã«æ¸ãåºãããã¬ã¼ã ãã¨ã«æ´æ°ãã¦ãã¾ããããããªãã¨å¤ãèªã¿ã«ããã®ã§ã toFixed()
ã§åå¤ãå°æ°ç¹ä»¥ä¸ 3 æ¡ã«åºå®ãã¦ãã¾ãã
ãã¼ã¿ã表示ããåã«ãç·å½¢å é度ã¨è§å é度ã®é
åãæ£å¸¸ã«è¿ããããã©ãããæ¤åºããããã«ãæ¡ä»¶å¼ã使ç¨ãã¦ãããã¨ã«ã¡ã¢ãã¦ããã¦ãã ããããããã®å¤ã¯ã¾ã ã»ã¨ãã©ã® VR ãã¼ãã¦ã§ã¢ã§å ±åãããªãã®ã§ããããè¡ããªãã¨ã³ã¼ããã¨ã©ã¼ãçºçãã¾ãï¼é
åã¯æ£å¸¸ã«å ±åãããªã㨠null
ãè¿ãã¾ãï¼ã
posStats.textContent = `Position: ` +
`x ${pos[0].toFixed(3)}, ` +
`y ${pos[1].toFixed(3)}, ` +
`z ${pos[2].toFixed(3)}`;
orientStats.textContent = `Orientation: ` +
`x ${orient[0].toFixed(3)}, ` +
`y ${orient[1].toFixed(3)}, ` +
`z ${orient[2].toFixed(3)}`;
linVelStats.textContent = `Linear velocity: ` +
`x ${linVel[0].toFixed(3)}, ` +
`y ${linVel[1].toFixed(3)}, ` +
`z ${linVel[2].toFixed(3)}`;
angVelStats.textContent = `Angular velocity: ` +
`x ${angVel[0].toFixed(3)}, ` +
`y ${angVel[1].toFixed(3)}, ` +
`z ${angVel[2].toFixed(3)}`;
if (linAcc) {
linAccStats.textContent = `Linear acceleration: ` +
`x ${linAcc[0].toFixed(3)}, ` +
`y ${linAcc[1].toFixed(3)}, ` +
`z ${linAcc[2].toFixed(3)}`;
} else {
linAccStats.textContent = 'Linear acceleration not reported';
}
if (angAcc) {
angAccStats.textContent = `Angular acceleration: ` +
`x ${angAcc[0].toFixed(3)}, ` +
`y ${angAcc[1].toFixed(3)}, ` +
`z ${angAcc[2].toFixed(3)}`;
} else {
angAccStats.textContent = 'Angular acceleration not reported';
}
}
WebVR ã¤ãã³ã
WebVR ã®ä»æ§ã§ã¯ã VR ãã£ã¹ãã¬ã¤ã®ç¶æ ã®å¤åã«ã¢ããªã®ã³ã¼ããåå¿ã§ããããã«ãããã¤ãã®ã¤ãã³ããçºè¡ãããæ©è½ãããã¾ã (Window ã¤ãã³ã ãåç §ãã¦ãã ãã)ãä¾ã¨ãã¦ã
vrdisplaypresentchange
- VR ãã£ã¹ãã¬ã¤ã®è¡¨ç¤ºç¶æ
ãå¤åããã¨ããã¤ã¾ã表示ããé表示ãã¾ãã¯é表示ãã表示ã¸ã¨å¤åããã¨ãã«çºè¡ããã¾ ããvrdisplayconnect
- 対å¿ãã VR ãã£ã¹ãã¬ã¤ãã³ã³ãã¥ã¼ã¿ã¼ã«æ¥ç¶ãããã¨ãã«çºè¡ããã¾ããvrdisplaydisconnect
- 対å¿ãã VR ãã£ã¹ãã¬ã¤ãã³ã³ãã¥ã¼ã¿ããåæãããã¨ãã«çºè¡ããã¾ããããããã©ã®ããã«åä½ããã®ãã示ãããã«ããã®åç´ãªãã¢ã§ã¯ä»¥ä¸ã®ãããªä¾ãè¨è¼ãã¦ãã¾ãã
window.addEventListener("vrdisplaypresentchange", (e) => {
console.log(
`Display ${e.display.displayId} presentation has changed. Reason given: ${e.reason}.`,
);
});
ãã®ããããã£ã«ã¯ãã¤ãã³ããçºè¡ããã VRDisplay
ã¸ã®åç
§ãæ ¼ç´ãããã¤ãã³ããçºçããçç±ã人éãèªã¿åãå¯è½ãªå¤ã§ç¤ºãã¾ãã
ããã¯ã¨ã¦ãæçãªã¤ãã³ãã§ãããã£ã¹ãã¬ã¤ãäºæããåæãããå ´åãå¦çããããã«ä½¿ç¨ãããã¨ãã§ããã¨ã©ã¼ãçºçããã®ã黿¢ããã¦ã¼ã¶ã¼ã«ç¶æ³ãèªèããããã¨ãã§ãã¾ãã Google ã® Webvr.info ãã¬ã¼ã³ãã¼ã·ã§ã³ã®ãã¢ã§ã¯ããã®ã¤ãã³ãã使ç¨ã㦠onVRPresentChange()
function ãå®è¡ãããUI ã³ã³ããã¼ã«ãé©å®æ´æ°ããã¦ãã£ã³ãã¹ã®ãµã¤ãºã夿´ããã¾ãã
ãã®è¨äºã§ã¯ãåç´ãª WebVR 1.1 ã¢ããªã使ããæ¹æ³ã«ã¤ãã¦ãåå¾ããã®ã«å½¹ç«ã¤ãããåºæ¬çãªãã¨ã説æãã¾ããã
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4