ãã®è¨äºã§ã¯ãWebXR ãã¥ã¼ããªã¢ã«ã·ãªã¼ãºã®ä»¥åã®è¨äºã§ç´¹ä»ããæ å ±ãå©ç¨ãã¦ãã¦ã¼ã¶ã¼ã VR ãããã»ããããã¼ãã¼ãããã¦ã¹ã使ç¨ãã¦èªç±ã«ç§»åã§ããåè»¢ç«æ¹ä½ãã¢ãã¡ã¼ã·ã§ã³åããä¾ã使ãã¾ãã ããã¯ã3D ã°ã©ãã£ãã¯ã¹ã¨ VR ã®å¹¾ä½å¦ãã©ã®ããã«æ©è½ãããã«ã¤ãã¦ã®çè§£ãæ·±ããã®ã«å½¹ç«ã¤ã ãã§ãªããXR ã¬ã³ããªã³ã°ä¸ã«ä½¿ç¨ããã颿°ã¨ãã¼ã¿ãã©ã®ããã«é£æºãããã確å®ã«çè§£ããã®ã«å½¹ç«ã¡ã¾ãã
ãã®ä¾ã®å®éã®ã¹ã¯ãªã¼ã³ã·ã§ãã
ãã®ä¾ã®ã³ã¢ã§ãããå転ãããã¯ã¹ãã£ã¼ä»ãã§ç §æä»ãã®ç«æ¹ä½ã¯ãWebGL ãã¥ã¼ããªã¢ã«ã·ãªã¼ãºããæç²ãããã®ã§ãã ã¤ã¾ããã·ãªã¼ãºã®æå¾ãã 2 çªç®ã®è¨äºã® WebGL ã§ã®ã©ã¤ãã£ã³ã°ãã«ãã¼ãã¾ãã
ãã®è¨äºã¨ä»éããã½ã¼ã¹ã³ã¼ããèªãã¨ãã¯ã3D ãããã»ããã®ãã£ã¹ãã¬ã¤ãååã«åå²ãããåä¸ã®ç»é¢ã§ãããã¨ãè¦ãã¦ããã¨å½¹ã«ç«ã¡ã¾ãã ç»é¢ã®å·¦ååã¯å·¦ç®ã§ã®ã¿è¡¨ç¤ºãããå³ååã¯å³ç®ã§ã®ã¿è¡¨ç¤ºããã¾ãã æ²¡å ¥åãã¬ã¼ã³ãã¼ã·ã§ã³ã®ããã«ã·ã¼ã³ãã¬ã³ããªã³ã°ããã«ã¯ãåç®ã®è¦ç¹ãã 1 åãã¤ãã·ã¼ã³ãè¤æ°åã¬ã³ããªã³ã°ããå¿ è¦ãããã¾ãã
å·¦ç®ãã¬ã³ããªã³ã°ããå ´åãXRWebGLLayer
ã® viewport
ã¯ãæç»ãæç»é¢ã®å·¦ååã«å¶éããããã«æ§æããã¦ãã¾ãã éã«ãå³ç®ãã¬ã³ããªã³ã°ããå ´åããã¥ã¼ãã¼ãã¯æç»ãæç»é¢ã®å³ååã«å¶éããããã«è¨å®ããã¾ãã
ãã®ä¾ã§ã¯ãXR ããã¤ã¹ã使ç¨ãã¦æ²¡å ¥åãã£ã¹ãã¬ã¤ã¨ãã¦ã·ã¼ã³ãæç¤ºããå ´åã§ããç»é¢ä¸ã®ãã£ã³ãã¹ã«è¡¨ç¤ºãããã¨ã§ããã示ãã¦ãã¾ãã
ä¾åé¢ä¿ãã®ä¾ã§ã¯ãthree.js
ãªã©ã® 3D ã°ã©ãã£ãã¯ãã¬ã¼ã ã¯ã¼ã¯ã«ä¾åãã¾ããããè¡åæ¼ç®ã«ã¯éå»ã«ä»ã®ä¾ã§ä½¿ç¨ãã¦ãã glMatrix
ã©ã¤ãã©ãªã¼ã使ç¨ãã¾ãã ãã®ä¾ã§ã¯ãWebXR API ã®ä»æ§ãæ
å½ãããã¼ã ã§ãã Immersive Web Working Group ã«ãã£ã¦ç®¡çããã¦ãã WebXR ããªãã£ã«ãã¤ã³ãã¼ããã¾ãã ãã®ããªãã£ã«ãã¤ã³ãã¼ããããã¨ã§ãWebXR ãã¾ã å®è£
ããã¦ããªãå¤ãã®ãã©ã¦ã¶ã¼ã§ãã®ä¾ãæ©è½ããããã¨ãã§ããWebXR 仿§ã®ã¾ã å®é¨çãªæ¥ã
ã®éã«çºçãã仿§ããã®ä¸æçãªé¸è±ãæ»ããã«ãã¾ãã
ãã®ä¾ã«ã¯ããã©ã¦ã¶ã¼ã«ãã¼ãããåã«å®æ°ã®å¤ã調æ´ãããã¨ã§æ§æã§ããããã¤ãã®ãªãã·ã§ã³ãããã¾ãã ã³ã¼ãã¯æ¬¡ã®ããã«ãªãã¾ãã
const xRotationDegreesPerSecond = 25;
const yRotationDegreesPerSecond = 15;
const zRotationDegreesPerSecond = 35;
const enableRotation = true;
const allowMouseRotation = true;
const allowKeyboardMotion = true;
const enableForcePolyfill = false;
//const SESSION_TYPE = "immersive-vr";
const SESSION_TYPE = "inline";
const MOUSE_SPEED = 0.003;
xRotationDegreesPerSecond
X 軸ãä¸å¿ã«å転ããã 1 ç§ãããã®åº¦æ°ã
yRotationDegreesPerSecond
Y 軸ãä¸å¿ã«å転ããã 1 ç§ãããã®åº¦æ°ã
zRotationDegreesPerSecond
Z 軸ãä¸å¿ã«å転ããã 1 ç§ãããã®åº¦æ°ã
enableRotation
ç«æ¹ä½ã®å転ãæå¹ã«ãããã©ããã示ããã¼ã«å¤ã
allowMouseRotation
true
ã®å ´åããã¦ã¹ã使ç¨ãã¦è¦éè§ããããï¼ä¸ä¸ï¼ãããã¨ã¼ï¼å·¦å³ï¼ãããã§ãã¾ãã
allowKeyboardMotion
true
ã®å ´åãWãAãSãD ãã¼ã¯ãã¥ã¼ã¢ã¼ãä¸ãå·¦ãä¸ãå³ã«ç§»åããä¸ä¸ã®ç¢å°ãã¼ã¯åå¾ã«ç§»åãã¾ãã false
ã®å ´åããã¥ã¼ã¸ã® XR ããã¤ã¹ã®å¤æ´ã®ã¿ã許å¯ãã¾ãã
enableForcePolyfill
ãã®ãã¼ã«å¤ã true
ã®å ´åããã©ã¦ã¶ã¼ãå®éã« WebXR ããµãã¼ããã¦ããå ´åã§ãããã®ä¾ã§ã¯ WebXR ããªãã£ã«ã®ä½¿ç¨ã試ã¿ã¾ãã false
ã®å ´åããã©ã¦ã¶ã¼ã navigator.xr
ãå®è£
ãã¦ããªãå ´åã«ã®ã¿ããªãã£ã«ã使ç¨ãã¾ãã
SESSION_TYPE
使ãã XR ã»ãã·ã§ã³ã®ã¿ã¤ã: ããã¥ã¡ã³ãã®ã³ã³ããã¹ãã§æç¤ºããã¤ã³ã©ã¤ã³ã»ãã·ã§ã³ã® inline
ã¨ãã·ã¼ã³ã没å
¥å VR ãããã»ããã«æç¤ºãã immersive-vr
ã
MOUSE_SPEED
ãããã¨ã¨ã¼ã®å¶å¾¡ã«ä½¿ç¨ãããã¦ã¹ããã®å ¥åãã¹ã±ã¼ãªã³ã°ããããã«ä½¿ç¨ããã乿°ã
MOVE_DISTANCE
ã·ã¼ã³å ã§ãã¥ã¼ã¢ã¼ãç§»åããããã«ä½¿ç¨ãããã¼ã®ããããã«å¿çãã¦ç§»åããè·é¢ã
ã¡ã¢: ãã®ä¾ã§ã¯ãimmersive-vr
ã¢ã¼ãã使ç¨ãã¦ããå ´åã§ãã常ã«ç»é¢ã«ã¬ã³ããªã³ã°ãããå
容ã表示ããã¾ãã ããã«ããã2 ã¤ã®ã¢ã¼ãéã®ã¬ã³ããªã³ã°ã®éããæ¯è¼ã§ãããããã»ããããªãå ´åã§ã没å
¥åã¢ã¼ãããã®åºåã確èªã§ãã¾ãã
次ã«ãWebGL ããã³ WebXR åºæã®æ å ±ãæ ¼ç´ããããã«ä½¿ç¨ããããã®ããå§ãã¦ãã¢ããªã±ã¼ã·ã§ã³å ¨ä½ã§ä½¿ç¨ããã夿°ã¨å®æ°ã宣è¨ãã¾ãã
let polyfill = null;
let xrSession = null;
let xrInputSources = null;
let xrReferenceSpace = null;
let xrButton = null;
let gl = null;
let animationFrameRequestID = 0;
let shaderProgram = null;
let programInfo = null;
let buffers = null;
let texture = null;
let mouseYaw = 0;
let mousePitch = 0;
ãã®å¾ã«ä¸é£ã®å®æ°ãç¶ãã¾ãã ããã«ã¯ä¸»ã«ãã·ã¼ã³ã®ã¬ã³ããªã³ã°ä¸ã«ä½¿ç¨ããããã¾ãã¾ãªãã¯ãã«ã¨è¡åãå«ã¾ãã¾ãã
const viewerStartPosition = vec3.fromValues(0, 0, -10);
const viewerStartOrientation = vec3.fromValues(0, 0, 1.0);
const cubeOrientation = vec3.create();
const cubeMatrix = mat4.create();
const mouseMatrix = mat4.create();
const inverseOrientation = quat.create();
const RADIANS_PER_DEGREE = Math.PI / 180.0;
æåã® 2 ã¤ï¼viewerStartPosition
㨠viewerStartOrientation
ï¼ã¯ã空éã®ä¸å¿ã«å¯¾ãã¦ãã¥ã¼ã¢ã¼ãé
ç½®ãããå ´æã¨ãæåã«è¦ãæ¹åã示ãã¾ãã cubeOrientation
ã¯ç«æ¹ä½ã®ç¾å¨ã®æ¹åãæ ¼ç´ããcubeMatrix
㨠mouseMatrix
ã¯ã·ã¼ã³ã®ã¬ã³ããªã³ã°ä¸ã«ä½¿ç¨ãããè¡åã®ã¹ãã¬ã¼ã¸ã§ãã inverseOrientation
ã¯ãã¬ã³ããªã³ã°ããããã¬ã¼ã å
ã®ãªãã¸ã§ã¯ãã®åç
§ç©ºéã«é©ç¨ããå転ã表ãããã«ä½¿ç¨ãããã¯ã©ã¼ã¿ããªã³ã§ãã
RADIANS_PER_DEGREEE
ã¯ãè§åº¦ãã©ã¸ã¢ã³ã«å¤æããããã«åº¦åä½ã®è§åº¦ãä¹ç®ããå¤ã§ãã
宣è¨ãããæå¾ã® 4 ã¤ã®å¤æ°ã¯ãã¦ã¼ã¶ã¼ã«è¡åãè¦ããããã®åºåå
ã® <div>
è¦ç´ ãåç
§ããããã®ã¹ãã¬ã¼ã¸ã§ãã
LogGLError()
ã¨å¼ã°ãã颿°ã¯ãWebGL 颿°ã®å®è¡ä¸ã«çºçããã¨ã©ã¼ã®ãã°æ
å ±ãåºåããããã®ç°¡åã«ã«ã¹ã¿ãã¤ãºãããæ¹æ³ãæä¾ããããã«å®è£
ããã¦ãã¾ãã
function LogGLError(where) {
let err = gl.getError();
if (err) {
console.error(`WebGL error returned by ${where}: ${err}`);
}
}
ããã¯ãããã°ã©ã ã®ã©ã®é¨åãã¨ã©ã¼ãçæãããã示ãããã«ä½¿ç¨ãããæåå where
ãå¯ä¸ã®å
¥åã¨ãã¦åãåãã¾ãã ããã¯ãåæ§ã®ã¨ã©ã¼ãè¤æ°ã®ç¶æ³ã§çºçããå¯è½æ§ãããããã§ãã
é ç¹ã·ã§ã¼ãã¼ã¨ãã©ã°ã¡ã³ãã·ã§ã¼ãã¼ã¯ã©ã¡ãããWebGL ã§ã®ã©ã¤ãã£ã³ã°ã®è¨äºã®ä¾ã§ä½¿ç¨ããã¦ãããã®ã¨ã¾ã£ããåãã§ãã ããã§ä½¿ç¨ããã¦ããåºæ¬çãªã·ã§ã¼ãã¼ã® GLSL ã½ã¼ã¹ã³ã¼ãã«èå³ãããå ´åã¯ããããåç §ãã¦ãã ããã
é ç¹ã·ã§ã¼ãã¼ã¯ãåé ç¹ã®åæä½ç½®ã¨ããã¥ã¼ã¢ã¼ã®ç¾å¨ã®ä½ç½®ã¨æ¹åãã·ãã¥ã¬ã¼ãããããã«ãããã夿ããããã«é©ç¨ããå¿ è¦ã®ãã夿ãæå®ãã¦ãåé ç¹ã®ä½ç½®ãè¨ç®ããã¨ã ãè¨ã£ã¦ããã¾ãããã ãã©ã°ã¡ã³ãã·ã§ã¼ãã¼ã¯ããã¯ã¹ãã£ã¼ã§è¦ã¤ãã£ãå¤ããå¿ è¦ã«å¿ãã¦è£éããç §æå¹æãé©ç¨ãã¦åé ç¹ã®è²ãè¿ãã¾ãã
WebXR ã®èµ·åã¨åæ¢ã¹ã¯ãªãããæåã«ãã¼ãããã¨ãã«ãload
ã¤ãã³ãã®ãã³ãã©ã¼ãã¤ã³ã¹ãã¼ã«ãã¦ãåæåãå®è¡ã§ããããã«ãã¾ãã
window.addEventListener("load", onLoad);
function onLoad() {
xrButton = document.querySelector("#enter-xr");
xrButton.addEventListener("click", onXRButtonClick);
projectionMatrixOut = document.querySelector("#projection-matrix div");
modelMatrixOut = document.querySelector("#model-view-matrix div");
cameraMatrixOut = document.querySelector("#camera-matrix div");
mouseMatrixOut = document.querySelector("#mouse-matrix div");
if (!navigator.xr || enableForcePolyfill) {
console.log("Using the polyfill");
polyfill = new WebXRPolyfill();
}
setupXRButton();
}
load
ã¤ãã³ããã³ãã©ã¼ã¯ãWebXR ã®ãªã³ã¨ãªããåãæ¿ãããã¿ã³ã¸ã®åç
§ã xrButton
ã«åå¾ããclick
ã¤ãã³ãã®ãã³ãã©ã¼ã追å ãã¾ãã æ¬¡ã«ã4 ã¤ã® <div>
ãããã¯ã¸ã®åç
§ãåå¾ãã¾ãã ãã®ãããã¯ã«ã¯ãã·ã¼ã³ã®å®è¡ä¸ã«æ
å ±æä¾ã®ç®çã§ãæãããã¨ãªãè¡åããããã®ç¾å¨ã®å
容ãåºåããã¾ãã
次ã«ãnavigator.xr
ãå®ç¾©ããã¦ãããã©ããã確èªãã¾ãã ããã§ãªãå ´åãããã³/ã¾ã㯠enableForcePolyfill
æ§æå®æ°ã true
ã«è¨å®ããã¦ããå ´åã¯ãWebXRPolyfill
ã¯ã©ã¹ãã¤ã³ã¹ã¿ã³ã¹åã㦠WebXR ããªãã£ã«ãã¤ã³ã¹ãã¼ã«ãã¾ãã
次ã«ãsetupXRButton()
颿°ãå¼ã³åºãã¾ãã ãã®é¢æ°ã¯ãSESSION_TYPE
宿°ã§æå®ãããã»ãã·ã§ã³ã¿ã¤ãã«å¯¾ãã WebXR ãµãã¼ãã®æç¡ã«ãããå¿
è¦ã«å¿ã㦠"Enter/Exit WebXR" ãã¿ã³ãæå¹ã¾ãã¯ç¡å¹ã«ããããã®æ§æãå¦çãã¾ãã
function setupXRButton() {
if (navigator.xr.isSessionSupported) {
navigator.xr.isSessionSupported(SESSION_TYPE).then((supported) => {
xrButton.disabled = !supported;
});
} else {
navigator.xr
.supportsSession(SESSION_TYPE)
.then(() => {
xrButton.disabled = false;
})
.catch(() => {
xrButton.disabled = true;
});
}
}
ãã¿ã³ã®ã©ãã«ã¯ãå®éã« WebXR ã»ãã·ã§ã³ã®éå§ã¨åæ¢ãå¦çããã³ã¼ãã§èª¿æ´ããã¾ãã 以ä¸ã«ããã示ãã¾ãã
WebXR ã»ãã·ã§ã³ã¯ããã¿ã³ã® click
ã¤ãã³ãã®ãã³ãã©ã¼ã«ãã£ã¦ãªã³ã¨ãªããåãæ¿ãããããã¿ã³ã®ã©ãã«ã¯ã"Enter WebXR" ã¾ã㯠"Exit WebXR" ã«é©åã«è¨å®ããã¾ãã ããã¯ãonXRButtonClick()
ã¤ãã³ããã³ãã©ã¼ã«ãã£ã¦è¡ããã¾ãã
async function onXRButtonClick(event) {
if (!xrSession) {
navigator.xr.requestSession(SESSION_TYPE).then(sessionStarted);
} else {
await xrSession.end();
if (xrSession) {
sessionEnded();
}
}
}
ããã¯ãxrSession
ã®å¤ã調ã¹ã¦ãé²è¡ä¸ã® WebXR ã»ãã·ã§ã³ã表ã XRSession
ãªãã¸ã§ã¯ãããã§ã«ãããã©ããã確èªãããã¨ããå§ã¾ãã¾ãã ãªãå ´åã¯ãã¯ãªãã¯ã¯ WebXR ã¢ã¼ããæå¹ã«ããè¦æ±ã表ãã¦ããã®ã§ãrequestSession()
ãå¼ã³åºãã¦ãç®çã® WebXR ã»ãã·ã§ã³ã¿ã¤ãã® WebXR ã»ãã·ã§ã³ãè¦æ±ããæ¬¡ã« sessionStarted()
ãå¼ã³åºãã¦ããã® WebXR ã»ãã·ã§ã³ã§ã·ã¼ã³ã®å®è¡ãéå§ãã¾ãã
䏿¹ãé²è¡ä¸ã®ã»ãã·ã§ã³ããã§ã«ããå ´åã¯ããã® end()
ã¡ã½ãããå¼ã³åºãã¦ã»ãã·ã§ã³ã忢ãã¾ãã
ãã®ã³ã¼ãã§æå¾ã«è¡ããã¨ã¯ãxrSession
ãã¾ã é NULL
ãã©ããã確èªãããã¨ã§ãã ããã§ããå ´åã¯ãend
ã¤ãã³ãã®ãã³ãã©ã¼ã§ãã sessionEnded()
ãå¼ã³åºãã¾ãã ãã®ã³ã¼ãã¯å¿
è¦ãªãã¯ãã§ãããå°ãªãã¨ãä¸é¨ã®ãã©ã¦ã¶ã¼ã end
ã¤ãã³ããæ£ããçºç«ããªãã¨ããåé¡ãããããã§ãã ã¤ãã³ããã³ãã©ã¼ãç´æ¥å®è¡ãããã¨ã«ããããã®ç¶æ³ã§çµäºããã»ã¹ãæåã§å®äºãã¾ãã
sessionStarted()
颿°ã¯ãã¤ãã³ããã³ãã©ã¼ãè¨å®ããé ç¹ã·ã§ã¼ãã¼ã¨ãã©ã°ã¡ã³ãã·ã§ã¼ãã¼ã® GLSL ã³ã¼ããã³ã³ãã¤ã«ãã¦ã¤ã³ã¹ãã¼ã«ããã¬ã³ããªã³ã°ã«ã¼ããéå§ããåã« WebGL ã¬ã¤ã¤ã¼ã WebXR ã»ãã·ã§ã³ã«ã¢ã¿ãããããã¨ã«ãããå®éã®ã»ãã·ã§ã³ã®è¨å®ã¨éå§ãå¦çãã¾ãã ããã¯ãrequestSession()
ã«ãã£ã¦è¿ããã promise ã®ãã³ãã©ã¼ã¨ãã¦å¼ã³åºããã¾ãã
function sessionStarted(session) {
let refSpaceType;
xrSession = session;
xrButton.innerText = "Exit WebXR";
xrSession.addEventListener("end", sessionEnded);
let canvas = document.querySelector("canvas");
gl = canvas.getContext("webgl", { xrCompatible: true });
if (allowMouseRotation) {
canvas.addEventListener("pointermove", handlePointerMove);
canvas.addEventListener("contextmenu", (event) => {
event.preventDefault();
});
}
if (allowKeyboardMotion) {
document.addEventListener("keydown", handleKeyDown);
}
shaderProgram = initShaderProgram(gl, vsSource, fsSource);
programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
vertexNormal: gl.getAttribLocation(shaderProgram, "aVertexNormal"),
textureCoord: gl.getAttribLocation(shaderProgram, "aTextureCoord"),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(
shaderProgram,
"uProjectionMatrix",
),
modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
normalMatrix: gl.getUniformLocation(shaderProgram, "uNormalMatrix"),
uSampler: gl.getUniformLocation(shaderProgram, "uSampler"),
},
};
buffers = initBuffers(gl);
texture = loadTexture(
gl,
"https://cdn.glitch.com/a9381af1-18a9-495e-ad01-afddfd15d000%2Ffirefox-logo-solid.png?v=1575659351244",
);
xrSession.updateRenderState({
baseLayer: new XRWebGLLayer(xrSession, gl),
});
if (SESSION_TYPE == "immersive-vr") {
refSpaceType = "local";
} else {
refSpaceType = "viewer";
}
mat4.fromTranslation(cubeMatrix, viewerStartPosition);
vec3.copy(cubeOrientation, viewerStartOrientation);
xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
xrReferenceSpace = refSpace.getOffsetReferenceSpace(
new XRRigidTransform(viewerStartPosition, cubeOrientation),
);
animationFrameRequestID = xrSession.requestAnimationFrame(drawFrame);
});
return xrSession;
}
æ°ãã使ãã XRSession
ãªãã¸ã§ã¯ãã xrSession
ã«ä¿åããå¾ããã¿ã³ã®ã©ãã«ã "Exit WebXR" ã«è¨å®ãã¦ãã·ã¼ã³ã®éå§å¾ã®æ°ããæ©è½ã示ãã¾ãã ã¾ããend
ã¤ãã³ãã®ãã³ãã©ã¼ãã¤ã³ã¹ãã¼ã«ãã¦ãããããXRSession
ã®çµäºãéç¥ããã¾ãã
次ã«ãHTML ã«ãã <canvas>
ã¸ã®åç
§ã¨ãã® WebGL ã¬ã³ããªã³ã°ã³ã³ããã¹ããåå¾ãã¾ãã ããã¯ãã·ã¼ã³ã®æç»é¢ã¨ãã¦ä½¿ç¨ããã¾ãã xrCompatible
ããããã£ã¯ãè¦ç´ ã§ getContext()
ãå¼ã³åºãã¦ããã£ã³ãã¹ã® WebGL ã¬ã³ããªã³ã°ã³ã³ããã¹ãã«ã¢ã¯ã»ã¹ããã¨ãã«è¦æ±ããã¾ãã ããã«ãããã³ã³ããã¹ãã WebXR ã¬ã³ããªã³ã°ã®ã½ã¼ã¹ã¨ãã¦ä½¿ç¨ã§ããããã«æ§æããã¾ãã
次ã«ãmousemove
㨠contextmenu
ã®ã¤ãã³ããã³ãã©ã¼ã追å ãã¾ãããallowMouseRotation
宿°ã true
ã®å ´åã«éãã¾ãã mousemove
ãã³ãã©ã¼ã¯ããã¦ã¹ã®åãã«åºã¥ãã¦ãã¥ã¼ã®ãããã¨ã¨ã¼ãå¦çãã¾ãã ããã¦ã¹ã«ãã¯ãæ©è½ã¯ãã¦ã¹ã®å³ãã¿ã³ãæ¼ãã¦ããéã®ã¿æ©è½ãããã¦ã¹ã®å³ã¯ãªãã¯ã§ã³ã³ããã¹ãã¡ãã¥ã¼ãããªã¬ã¼ããããããcontextmenu
ã¤ãã³ãã®ãã³ãã©ã¼ããã£ã³ãã¹ã«è¿½å ãã¦ãã¦ã¼ã¶ã¼ãæåã«ãã¦ã¹ã®ãã©ãã°ãéå§ããã¨ãã«ã³ã³ããã¹ãã¡ãã¥ã¼ã表示ãããªãããã«ãã¾ãã
次ã«ãã·ã§ã¼ãã¼ããã°ã©ã ãã³ã³ãã¤ã«ãããã®å¤æ°ã¸ã®åç
§ãåå¾ããåä½ç½®ã®é
åãæ ¼ç´ãããããã¡ã¼ãåæåããåé ç¹ã®ä½ç½®ãã¼ãã«ã¸ã®ã¤ã³ããã¯ã¹ãé ç¹æ³ç·ãåé ç¹ã®ãã¯ã¹ãã£ã¼åº§æ¨ãæ ¼ç´ãã¾ãã ããã¯ãã¹ã¦ WebGL ãµã³ãã«ã³ã¼ãããç´æ¥åå¾ããã¦ãããããWebGL ã§ã®ã©ã¤ãã£ã³ã°ã¨ãã®åã®è¨äºã® WebGL ãç¨ãã 3D ãªãã¸ã§ã¯ãã®ä½æããã³ WebGL ã§ã®ãã¯ã¹ãã£ã¼ã®ä½¿ç¨ãåç
§ãã¦ãã ããã æ¬¡ã«ãloadTexture()
颿°ãå¼ã³åºãã¦ããã¯ã¹ãã£ã¼ãã¡ã¤ã«ããã¼ããã¾ãã
ã¬ã³ããªã³ã°æ§é ã¨ãã¼ã¿ããã¼ããããã®ã§ãXRSession
ãå®è¡ããæºåãéå§ãã¾ãã baseLayer
ãæ°ãã XRWebGLLayer
ã«è¨å®ã㦠XRSession.updateRenderState()
ãå¼ã³åºããã¨ã«ãããã»ãã·ã§ã³ã WebGL ã¬ã¤ã¤ã¼ã«æ¥ç¶ãã¦ãã¬ã³ããªã³ã°é¢ã¨ãã¦ä½ã使ç¨ããããèªèãã¾ãã
次ã«ãSESSION_TYPE
宿°ã®å¤ã調ã¹ã¦ãWebXR ã³ã³ããã¹ããæ²¡å
¥åã«ãããã¤ã³ã©ã¤ã³ã«ãããã確èªãã¾ãã æ²¡å
¥åã»ãã·ã§ã³ã¯ local
åç
§ç©ºéã使ç¨ããã¤ã³ã©ã¤ã³ã»ãã·ã§ã³ã¯ viewer
åç
§ç©ºéã使ç¨ãã¾ãã
glMatrix
ã©ã¤ãã©ãªã¼ã® 4x4 è¡åç¨ã® fromTranslation()
颿°ã¯ãviewerStartPosition
宿°ã§æå®ããããã¥ã¼ã¢ã¼ã®éå§ä½ç½®ã夿è¡å cubeMatrix
ã«å¤æããããã«ä½¿ç¨ãã¾ãã ãã¥ã¼ã¢ã¼ã®éå§æ¹åã§ãã viewerStartOrientation
宿°ã¯ãcubeOrientation
ã«ã³ãã¼ãã¦ãæéã®çµéã«ä¼´ãç«æ¹ä½ã®å転ã追跡ããããã«ä½¿ç¨ãã¾ãã
sessionStarted()
ã¯ãã»ãã·ã§ã³ã® requestReferenceSpace()
ã¡ã½ãããå¼ã³åºãã¦ããªãã¸ã§ã¯ãã使ãã空éãè¨è¿°ããåç
§ç©ºéãªãã¸ã§ã¯ããåå¾ãããã¨ã§ä»ä¸ãã¾ãã è¿ããã promise ã XRReferenceSpace
ãªãã¸ã§ã¯ãã«è§£æ±ºãããã¨ããã® getOffsetReferenceSpace
ã¡ã½ãããå¼ã³åºãã¦ããªãã¸ã§ã¯ãã®åº§æ¨ç³»ã表ãåç
§ç©ºéãªãã¸ã§ã¯ããåå¾ãã¾ãã æ°ãã空éã®åç¹ã¯ãviewerStartPosition
ã§æå®ãããä¸ç座æ¨ã«ããããã®æ¹å㯠cubeOrientation
ã«è¨å®ããã¦ãã¾ãã æ¬¡ã«ãrequestAnimationFrame()
ã¡ã½ãããå¼ã³åºãã¦ããã¬ã¼ã ãæç»ããæºåãã§ãããã¨ãã»ãã·ã§ã³ã«éç¥ãã¾ãã å¾ã§ãªã¯ã¨ã¹ãããã£ã³ã»ã«ããå¿
è¦ãããå ´åã«åãã¦ãè¿ããããªã¯ã¨ã¹ã ID ãè¨é²ãã¾ãã
æå¾ã«ãsessionStarted()
ã¯ãã¦ã¼ã¶ã¼ã® WebXR ã»ãã·ã§ã³ã表ã XRSession
ãè¿ãã¾ãã
ï¼ã¦ã¼ã¶ã¼ã«ããçµäºããXRSession.end()
ã®å¼ã³åºãã§ï¼WebXR ã»ãã·ã§ã³ãçµäºããã¨ãend
ã¤ãã³ããéä¿¡ããã¾ãã ããããsessionEnded()
ã¨ãã颿°ãå¼ã³åºãããã«è¨å®ãã¾ããã
function sessionEnded() {
xrButton.innerText = "Enter WebXR";
if (animationFrameRequestID) {
xrSession.cancelAnimationFrame(animationFrameRequestID);
animationFrameRequestID = 0;
}
xrSession = null;
}
ããã°ã©ã ã§ WebXR ã»ãã·ã§ã³ãçµäºãããå ´åã¯ãsessionEnded()
ãç´æ¥å¼ã³åºããã¨ãã§ãã¾ãã ãããã®å ´åãããã¿ã³ã®ã©ãã«ãæ´æ°ãã¦ãã¯ãªãã¯ã«ãã£ã¦ã»ãã·ã§ã³ãéå§ããããã¨ã示ãã¾ãã ãã®å¾ãã¢ãã¡ã¼ã·ã§ã³ãã¬ã¼ã ã«å¯¾ããä¿çä¸ã®ãªã¯ã¨ã¹ããããå ´åã¯ãcancelAnimationFrame
ãå¼ã³åºãã¦ãã£ã³ã»ã«ãã¾ãã
ãããå®äºããã¨ãxrSession
ã®å¤ã NULL
ã«å¤æ´ãã¦ãã»ãã·ã§ã³ãçµäºãããã¨ã示ãã¾ãã
ããã§ã¯ããã¼ãã¼ãã¨ãã¦ã¹ã®ã¤ãã³ãã WebXR ã·ããªãªã§ã¢ãã¿ã¼ãå¶å¾¡ããããã«ä½¿ç¨ã§ãããã®ã«å¤æããã³ã¼ããè¦ã¦ã¿ã¾ãããã
ãã¼ãã¼ãã使ç¨ããç§»å空éãç§»åããããã®å
¥åãåãã WebXR ããã¤ã¹ããªãã¦ããã¦ã¼ã¶ã¼ã 3D ä¸çãç§»åã§ããããã«ããããã«ãkeydown
ã®ãã³ãã©ã¼ã§ãã handleKeyDown()
ã¯ãæ¼ããããã¼ã«åºã¥ãã¦ãªãã¸ã§ã¯ãã®åç¹ããã®ãªãã»ãããæ´æ°ãããã¨ã§å¿çãã¾ãã
function handleKeyDown(event) {
switch (event.key) {
case "w":
case "W":
verticalDistance -= MOVE_DISTANCE;
break;
case "s":
case "S":
verticalDistance += MOVE_DISTANCE;
break;
case "a":
case "A":
transverseDistance += MOVE_DISTANCE;
break;
case "d":
case "D":
transverseDistance -= MOVE_DISTANCE;
break;
case "ArrowUp":
axialDistance += MOVE_DISTANCE;
break;
case "ArrowDown":
axialDistance -= MOVE_DISTANCE;
break;
case "r":
case "R":
transverseDistance = axialDistance = verticalDistance = 0;
mouseYaw = mousePitch = 0;
break;
default:
break;
}
}
ãã¼ã¨ãã®å¹æã¯æ¬¡ã®ã¨ããã§ãã
W
ãã¼ã¯ããã¥ã¼ã¢ã¼ã MOVE_DISTANCE
ã ãä¸ã«ç§»åãã¾ãã
S
ãã¼ã¯ããã¥ã¼ã¢ã¼ã MOVE_DISTANCE
ã ãä¸ã«ç§»åãã¾ãã
A
ãã¼ã¯ããã¥ã¼ã¢ã¼ã MOVE_DISTANCE
ã ãå·¦ã«ã¹ã©ã¤ãããã¾ãã
D
ãã¼ã¯ããã¥ã¼ã¢ã¼ã MOVE_DISTANCE
ã ãå³ã«ã¹ã©ã¤ãããã¾ãã
ä¸ç¢å°ãã¼
â
ã¯ããã¥ã¼ã¢ã¼ã MOVE_DISTANCE
ã ãåæ¹ã«ã¹ã©ã¤ãããã¾ãã
ä¸ç¢å°ãã¼
â
ã¯ããã¥ã¼ã¢ã¼ã MOVE_DISTANCE
ã ã徿¹ã«ã¹ã©ã¤ãããã¾ãã
R
ãã¼ã¯ãå ¥åãªãã»ããããã¹ã¦ 0 ã«ãªã»ãããããã¨ã«ããããã¥ã¼ã¢ã¼ãéå§ä½ç½®ã¨æ¹åã«ãªã»ãããã¾ãã
ãããã®ãªãã»ããã¯ã次ã®ãã¬ã¼ã ã®æç»ããã¬ã³ãã©ã¼ã«ãã£ã¦é©ç¨ããã¾ãã
ãã¦ã¹ã«ãããããã¨ã¨ã¼ã¾ãããã¦ã¹ã®å³ãã¿ã³ãæ¼ããã¦ãããã©ããã確èªãã mousemove
ã¤ãã³ããã³ãã©ã¼ããããæ¼ããã¦ããå ´åã¯ããã®æ¬¡ã«å®ç¾©ããã¦ãã rotateViewBy()
颿°ãå¼ã³åºãã¦ãæ°ãããããï¼ä¸ä¸ãè¦ãï¼ã¨ã¨ã¼ï¼å·¦å³ãè¦ãï¼ã®å¤ãè¨ç®ãã¦ä¿åãã¾ãã
function handlePointerMove(event) {
if (event.buttons & 2) {
rotateViewBy(event.movementX, event.movementY);
}
}
æ°ãããããã¨ã¨ã¼ã®å¤ã®è¨ç®ã¯ã次㮠rotateViewBy()
颿°ã§å¦çãã¾ãã
function rotateViewBy(dx, dy) {
mouseYaw -= dx * MOUSE_SPEED;
mousePitch -= dy * MOUSE_SPEED;
if (mousePitch < -Math.PI * 0.5) {
mousePitch = -Math.PI * 0.5;
} else if (mousePitch > Math.PI * 0.5) {
mousePitch = Math.PI * 0.5;
}
}
å
¥åã¨ãã¦ãã¦ã¹ç§»åéã® dx
㨠dy
ãä¸ããããã¨ãæ°ããã¨ã¼å¤ã¯ãmouseYaw
ã®ç¾å¨ã®å¤ãã dx
㨠MOUSE_SPEED
ã¹ã±ã¼ãªã³ã°å®æ°ã®ç©ãå¼ããã¨ã§è¨ç®ãã¾ãã ããã¦ãMOUSE_SPEED
ã®å¤ãå¢ãããã¨ã§ããã¦ã¹ã®å¿çæ§ãå¶å¾¡ã§ãã¾ãã
XRSession.requestAnimationFrame()
ã®ã³ã¼ã«ããã¯ã¯ã以ä¸ã«ç¤ºã drawFrame()
颿°ã«å®è£
ããã¦ãã¾ãã ãã®ä»äºã¯ããã¥ã¼ã¢ã¼ã®åç
§ç©ºéãåå¾ããæå¾ã®ãã¬ã¼ã ããã®çµéæéãèæ
®ãã¦ãã¢ãã¡ã¼ã·ã§ã³åããããªãã¸ã§ã¯ãã«é©ç¨ããå¿
è¦ã®ããåãã®éãè¨ç®ãããã¥ã¼ã¢ã¼ã® XRPose
ã«ãã£ã¦æå®ãããåãã¥ã¼ãã¬ã³ããªã³ã°ãããã¨ã§ãã
let lastFrameTime = 0;
function drawFrame(time, frame) {
let session = frame.session;
let adjustedRefSpace = xrReferenceSpace;
let pose = null;
animationFrameRequestID = session.requestAnimationFrame(drawFrame);
adjustedRefSpace = applyViewerControls(xrReferenceSpace);
pose = frame.getViewerPose(adjustedRefSpace);
if (pose) {
let glLayer = session.renderState.baseLayer;
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
LogGLError("bindFrameBuffer");
gl.clearColor(0, 0, 0, 1.0);
gl.clearDepth(1.0); // Clear everything
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
LogGLError("glClear");
const deltaTime = (time - lastFrameTime) * 0.001; // Convert to seconds
lastFrameTime = time;
for (let view of pose.views) {
let viewport = glLayer.getViewport(view);
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
LogGLError(`Setting viewport for eye: ${view.eye}`);
gl.canvas.width = viewport.width * pose.views.length;
gl.canvas.height = viewport.height;
renderScene(gl, view, programInfo, buffers, texture, deltaTime);
}
}
}
æåã«è¡ããã¨ã¯ãrequestAnimationFrame()
ãå¼ã³åºãã¦ã次ã®ãã¬ã¼ã ãã¬ã³ããªã³ã°ããããã« drawFrame()
ãå度å¼ã³åºãããã«è¦æ±ãããã¨ã§ãã æ¬¡ã«ããªãã¸ã§ã¯ãã®åç
§ç©ºéã applyViewerControls()
颿°ã«æ¸¡ãã¾ãã ãã®é¢æ°ã¯ããã¼ãã¼ãã¨ãã¦ã¹ã使ç¨ãã¦ã¦ã¼ã¶ã¼ãé©ç¨ããç§»åãããããã¨ã¼ãèæ
®ãã¦ãªãã¸ã§ã¯ãã®ä½ç½®ã¨æ¹åã夿ãããæ¹è¨ããã XRReferenceSpace
ãè¿ãã¾ãã ãã¤ãã®ããã«ããã¥ã¼ã¢ã¼ã§ã¯ãªããä¸çã®ãªãã¸ã§ã¯ãããç§»åããæ¹åã夿´ãããã¨ãå¿ããªãã§ãã ããã è¿ãããåç
§ç©ºéã«ããããããç°¡åã«è¡ããã¨ãã§ãã¾ãã
æ°ããåç
§ç©ºéãæå
ã«ããã¨ããã¥ã¼ã¢ã¼ã®ä¸¡ç®ã®è¦ç¹ã表ã XRViewerPose
ãå¾ããã¾ãã ãããæåããå ´åã¯ãã»ãã·ã§ã³ã§ä½¿ç¨ããã¦ãã XRWebGLLayer
ãåå¾ãããã®ãã¬ã¼ã ãããã¡ã¼ã WebGL ãã¬ã¼ã ãããã¡ã¼ã¨ãã¦ä½¿ç¨ããããã«ãã¤ã³ããããã¨ã§ã¬ã³ããªã³ã°ã®æºåãéå§ãã¾ãï¼WebGL ã®ã¬ã³ããªã³ã°ã¯ã¬ã¤ã¤ã¼ã«æç»ãããã¨ã§ãXR ããã¤ã¹ã®ãã£ã¹ãã¬ã¤ã«æç»ããã¾ãï¼ã XR ããã¤ã¹ã«ã¬ã³ããªã³ã°ããããã« WebGL ãæ§æãããã®ã§ããã¬ã¼ã ãé»ã«ã¯ãªã¢ãã¦ãã¬ã³ããªã³ã°ãéå§ããæºåãæ´ãã¾ããã
æå¾ã®ãã¬ã¼ã ãã¬ã³ããªã³ã°ããã¦ããã®çµéæéï¼ç§åä½ï¼ã¯ãtime
ãã©ã¡ã¼ã¿ã¼ã§æå®ãããç¾å¨ã®æå»ããåã®ãã¬ã¼ã ã®ã¿ã¤ã ã¹ã¿ã³ã lastFrameTime
ãæ¸ç®ãã0.001 ãæãã¦ããªç§ãç§ã«å¤æãããã¨ã§è¨ç®ãã¾ãã æ¬¡ã«ãç¾å¨ã®æå»ã lastFrameTime
ã«ä¿åãã¾ãã
drawFrame()
颿°ã¯ãXRViewerPose
ã§è¦ã¤ãã£ããã¹ã¦ã®ãã¥ã¼ãå復å¦çãããã¥ã¼ã®ãã¥ã¼ãã¼ããè¨å®ããrenderScene()
ãå¼ã³åºãã¦ãã¬ã¼ã ãã¬ã³ããªã³ã°ãããã¨ã§çµäºãã¾ãã åãã¥ã¼ã®ãã¥ã¼ãã¼ããè¨å®ãããã¨ã«ãããåç®ã®ãã¥ã¼ããããã WebGL ãã¬ã¼ã ã®ååã«ã¬ã³ããªã³ã°ãããå
¸åçãªã·ããªãªãå¦çãã¾ãã æ¬¡ã«ãXR ãã¼ãã¦ã§ã¢ã¯ãåç®ããã®ç®åãã®ç»åã®é¨åã®ã¿ã表示ããããã«å¦çãã¾ãã
ã¡ã¢: ãã®ä¾ã§ã¯ãXR ããã¤ã¹ã¨ç»é¢ã®ä¸¡æ¹ã«ãã¬ã¼ã ãè¦è¦çã«è¡¨ç¤ºãã¦ãã¾ãã ç»é¢ä¸ã®ãã£ã³ãã¹ããããå®è¡ã§ããé©åãªãµã¤ãºã§ãããã¨ã確èªããããã«ããã®å¹
ãåã
ã® XRView
ã®å¹
ã«ãã¥ã¼ã®æ°ãæãããã®ã«çãããªãããã«è¨å®ãã¾ãã ãã£ã³ãã¹ã®é«ãã¯å¸¸ã«ãã¥ã¼ãã¼ãã®é«ãã¨åãã§ãã ãã£ã³ãã¹ãµã¤ãºã調æ´ãã 2 è¡ã®ã³ã¼ãã¯ãé常㮠WebXR ã¬ã³ããªã³ã°ã«ã¼ãã§ã¯å¿
è¦ããã¾ããã
ä½ããã¬ã³ããªã³ã°ãå§ããåã« drawFrame()
ã«ãã£ã¦å¼ã³åºããã applyViewerControls()
颿°ã¯ãã¦ã¼ã¶ã¼ããã¼ãæ¼ãããããã¦ã¹ã®å³ãã¿ã³ãæ¼ããã¾ã¾ãã¦ã¹ããã©ãã°ããã¨ãã« handleKeyDown()
颿°ã¨ handlePointerMove()
颿°ã«ãã£ã¦è¨é²ããã 3 æ¹åã®ããããã®ãªãã»ãããã¨ã¼ãªãã»ãããããã³ããããªãã»ãããåå¾ãã¾ãã ãªãã¸ã§ã¯ãã®ãã¼ã¹åç
§ç©ºéãå
¥åã¨ãã¦åãåããå
¥åã®çµæã¨ä¸è´ããããã«ãªãã¸ã§ã¯ãã®ä½ç½®ã¨æ¹åã夿´ããæ°ããåç
§ç©ºéãè¿ãã¾ãã
function applyViewerControls(refSpace) {
if (
!mouseYaw &&
!mousePitch &&
!axialDistance &&
!transverseDistance &&
!verticalDistance
) {
return refSpace;
}
quat.identity(inverseOrientation);
quat.rotateX(inverseOrientation, inverseOrientation, -mousePitch);
quat.rotateY(inverseOrientation, inverseOrientation, -mouseYaw);
let newTransform = new XRRigidTransform(
{ x: transverseDistance, y: verticalDistance, z: axialDistance },
{
x: inverseOrientation[0],
y: inverseOrientation[1],
z: inverseOrientation[2],
w: inverseOrientation[3],
},
);
mat4.copy(mouseMatrix, newTransform.matrix);
return refSpace.getOffsetReferenceSpace(newTransform);
}
ãã¹ã¦ã®å
¥åãªãã»ãããã¼ãã®å ´åãå
ã®åç
§ç©ºéãè¿ãã ãã§ãã ãã以å¤ã®å ´åã¯ãmousePitch
㨠mouseYaw
ã®æ¹åã®å¤æ´ããããã®æ¹åã®éãæå®ããã¯ã©ã¼ã¿ããªã³ã使ãã¾ãã ããã«ãããinverseOrientation
ãç«æ¹ä½ã«é©ç¨ããã¨ããã¥ã¼ã¢ã¼ã®åããæ£ãã表示ããã¾ãã
次ã«ãç§»åã¾ãã¯æ¹å夿´ããããªãã¸ã§ã¯ãã®æ°ãã XRReferenceSpace
ã使ããããã«ä½¿ç¨ãã夿ãè¡¨ãæ°ãã XRRigidTransform
ãªãã¸ã§ã¯ãã使ãã¾ãã ä½ç½®ã¯ãx
ãy
ãz
ããããã®åè»¸ã«æ²¿ã£ã¦ç§»åãããªãã»ããã«å¯¾å¿ããæ°ãããã¯ãã«ã§ãã æ¹åã¯ãinverseOrientation
ã¯ã©ã¼ã¿ããªã³ã§ãã
å¤æã® matrix
ã mouseMatrix
ã«ã³ãã¼ãã¾ãã ããã¯ãå¾ã§ãã¦ã¹è¿½è·¡è¡åï¼Mouse tracking matrixï¼ãã¦ã¼ã¶ã¼ã«è¡¨ç¤ºããããã«ä½¿ç¨ãã¾ãï¼ãããã£ã¦ãããã¯é常ã¹ãããã§ããæé ã§ãï¼ã æå¾ã«ãXRRigidTransform
ããªãã¸ã§ã¯ãã®ç¾å¨ã® XRReferenceSpace
ã«æ¸¡ãã¦ããã®å¤æãçµ±åããã¦ã¼ã¶ã¼ã®åããèæ
®ããã¦ã¼ã¶ã¼ã«å¯¾ããç«æ¹ä½ã®é
ç½®ã表ãåç
§ç©ºéãåå¾ãã¾ãã ãã®æ°ããåç
§ç©ºéãå¼ã³åºãå
ã«è¿ãã¾ãã
renderScene()
颿°ã¯ãã¦ã¼ã¶ã¼ããã®ç¬éã«è¦ããä¸çã®é¨åãå®éã«ã¬ã³ããªã³ã°ããããã«å¼ã³åºããã¾ãã XR ã®ã¢ã«å¿
è¦ãª 3D 广ã確ç«ããããã«ãããããã®ç®ã§ãããã«ç°ãªãä½ç½®ã使ç¨ããããããã®ç®ã«å¯¾ã㦠1 åãã¤å¼ã³åºããã¾ãã
ãã®ã³ã¼ãã®ã»ã¨ãã©ã¯ãWebGL ã§ã®ã©ã¤ãã£ã³ã°ã®è¨äºã® drawScene()
颿°ããç´æ¥åå¾ããå
¸åç㪠WebGL ã¬ã³ããªã³ã°ã³ã¼ãã§ããããã®ä¾ã® WebGL ã¬ã³ããªã³ã°é¨åã®è©³ç´°ã«ã¤ãã¦ã¯ãããåç
§ãã¦ãã ããï¼GitHub ã§ã³ã¼ããè¦ãï¼ã ããããããã§ã¯ããã®ä¾ã«åºæã®ã³ã¼ãããå§ã¾ã£ã¦ããã®ã§ããã®é¨åã«ã¤ãã¦è©³ããè¦ã¦ããã¾ãã
const normalMatrix = mat4.create();
const modelViewMatrix = mat4.create();
function renderScene(gl, view, programInfo, buffers, texture, deltaTime) {
const xRotationForTime =
xRotationDegreesPerSecond * RADIANS_PER_DEGREE * deltaTime;
const yRotationForTime =
yRotationDegreesPerSecond * RADIANS_PER_DEGREE * deltaTime;
const zRotationForTime =
zRotationDegreesPerSecond * RADIANS_PER_DEGREE * deltaTime;
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
if (enableRotation) {
mat4.rotate(
cubeMatrix, // destination matrix
cubeMatrix, // matrix to rotate
zRotationForTime, // amount to rotate in radians
[0, 0, 1],
); // axis to rotate around (Z)
mat4.rotate(
cubeMatrix, // destination matrix
cubeMatrix, // matrix to rotate
yRotationForTime, // amount to rotate in radians
[0, 1, 0],
); // axis to rotate around (Y)
mat4.rotate(
cubeMatrix, // destination matrix
cubeMatrix, // matrix to rotate
xRotationForTime, // amount to rotate in radians
[1, 0, 0],
); // axis to rotate around (X)
}
mat4.multiply(modelViewMatrix, view.transform.inverse.matrix, cubeMatrix);
mat4.invert(normalMatrix, modelViewMatrix);
mat4.transpose(normalMatrix, normalMatrix);
displayMatrix(view.projectionMatrix, 4, projectionMatrixOut);
displayMatrix(modelViewMatrix, 4, modelMatrixOut);
displayMatrix(view.transform.matrix, 4, cameraMatrixOut);
displayMatrix(mouseMatrix, 4, mouseMatrixOut);
{
const numComponents = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
numComponents,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
}
{
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
gl.vertexAttribPointer(
programInfo.attribLocations.textureCoord,
numComponents,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);
}
{
const numComponents = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normal);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexNormal,
numComponents,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexNormal);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
gl.useProgram(programInfo.program);
gl.uniformMatrix4fv(
programInfo.uniformLocations.projectionMatrix,
false,
view.projectionMatrix,
);
gl.uniformMatrix4fv(
programInfo.uniformLocations.modelViewMatrix,
false,
modelViewMatrix,
);
gl.uniformMatrix4fv(
programInfo.uniformLocations.normalMatrix,
false,
normalMatrix,
);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
{
const vertexCount = 36;
const type = gl.UNSIGNED_SHORT;
const offset = 0;
gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
}
}
renderScene()
ã¯ãåã®ãã¬ã¼ã ãã¬ã³ããªã³ã°ããã¦ããçµéããæéå
ã«ã3 ã¤ã®è»¸ã®ããããã®å¨ãã§çºçããå転éãè¨ç®ãããã¨ããå§ã¾ãã¾ãã ãããã®å¤ã«ãããã¢ãã¡ã¼ã·ã§ã³ããç«æ¹ä½ã®å転ãé©åãªéã«èª¿æ´ãã¦ãã·ã¹ãã ã®è² è·ã«ãã£ã¦çºçããå¯è½æ§ã®ãããã¬ã¼ã ã¬ã¼ãã®å¤åã«é¢ä¿ãªãããã®ç§»åé度ãä¸å®ã«ä¿ãããããã«ãããã¨ãã§ãã¾ãã ãããã®å¤ã¯ãçµéæéãæå®ãã¦é©ç¨ããå転ã®ã©ã¸ã¢ã³æ°ã¨ãã¦è¨ç®ãã¦ã宿°ã® xRotationForTime
ãyRotationForTime
ãzRotationForTime
ã«æ ¼ç´ãã¾ãã
奥è¡ããã¹ããæå¹ã«ãã¦æ§æããå¾ãenableRotation
宿°ã®å¤ããã§ãã¯ãã¦ãç«æ¹ä½ã®å転ãæå¹ã«ãªã£ã¦ãããã©ããã確èªãã¾ãã ããã§ããå ´åã¯ãglMatrix ã使ç¨ãã¦ã3 ã¤ã®è»¸ãä¸å¿ã« cubeMatrix
ï¼ä¸ç空éã«å¯¾ããç«æ¹ä½ã®ç¾å¨ã®æ¹åã表ãï¼ãå転ããã¾ãã ç«æ¹ä½ã®ã°ãã¼ãã«ãªæ¹åã確ç«ãããããããããã¥ã¼ã®å¤æè¡åã®éè¡åã§ä¹ç®ãã¦ãæçµçãªã¢ãã«ãã¥ã¼è¡åãåå¾ãã¾ãã ãã®è¡åã¯ããªãã¸ã§ã¯ãã«é©ç¨ãã¦ãã¢ãã¡ã¼ã·ã§ã³ã®ç®çã§ãããå転ãããã ãã§ãªãããããç§»åãããæ¹åãå¤ããããã¦ã空éãä»ãããã¥ã¼ã¢ã¼ã®ã¢ã¼ã·ã§ã³ãã·ãã¥ã¬ã¼ããããã¨ããã¾ãã
次ã«ãã¢ãã«ãã¥ã¼è¡åãåå¾ãã¦å転ï¼éè¡åãè¨ç®ï¼ãã転置ï¼åã¨è¡ãå ¥ãæ¿ããï¼ãããã¨ã§ããã¥ã¼ã®æ£è¦è¡åãè¨ç®ãã¾ãã
ãã®ä¾ã§è¿½å ãããã³ã¼ãã®æå¾ã®æ°è¡ã¯ãã¦ã¼ã¶ã¼ã«ããåæã®ããã«è¡åã®å
容ã表示ãã颿°ã§ãã displayMatrix()
ã¸ã® 4 ã¤ã®å¼ã³åºãã§ãã 颿°ã®æ®ãã®é¨åã¯ããã®ã³ã¼ãã®æ´¾çå
ã§ããå¤ã WebGL ãµã³ãã«ã¨åä¸ã¾ãã¯æ¬è³ªçã«åä¸ã§ãã
ãã®ä¾ã§ã¯ã説æã®ããã«ãã·ã¼ã³ã®ã¬ã³ããªã³ã°ä¸ã«ä½¿ç¨ãã¦ããéè¦ãªè¡åã®å
容ã表示ãã¦ãã¾ãã ããã«ã¯ãdisplayMatrix()
颿°ã使ç¨ãã¾ãã ãã®é¢æ°ã¯ MathML ã使ç¨ãã¦è¡åãã¬ã³ããªã³ã°ããMathML ãã¦ã¼ã¶ã¼ã®ãã©ã¦ã¶ã¼ã§ãµãã¼ãããã¦ããªãå ´åã¯ãããé
åã«è¿ãå½¢å¼ã«ãã©ã¼ã«ããã¯ãã¾ãã
function displayMatrix(mat, rowLength, target) {
let outHTML = "";
if (mat && rowLength && rowLength <= mat.length) {
let numRows = mat.length / rowLength;
outHTML =
"<math xmlns='http://www.w3.org/1998/Math/MathML' display='block'>\n<mrow>\n<mo>[</mo>\n<mtable>\n";
for (let y = 0; y < numRows; y++) {
outHTML += "<mtr>\n";
for (let x = 0; x < rowLength; x++) {
outHTML += `<mtd><mn>${mat[x * rowLength + y].toFixed(2)}</mn></mtd>\n`;
}
outHTML += "</mtr>\n";
}
outHTML += "</mtable>\n<mo>]</mo>\n</mrow>\n</math>";
}
target.innerHTML = outHTML;
}
ããã«ãããtarget
ã§æå®ãããè¦ç´ ã®å
容ãã4x4 è¡åãå«ãæ°ãã使ããã <math>
è¦ç´ ã«ç½®ãæãããã¾ãã åã¨ã³ããªã¼ã¯ãå°æ°ç¹ä»¥ä¸ 2 æ¡ã¾ã§è¡¨ç¤ºãã¾ãã
æ®ãã®ã³ã¼ãã¯ãåã®ä¾ã§è¦ã¤ãã£ããã®ã¨åãã§ãã
initShaderProgram()
GLSL ã·ã§ã¼ãã¼ããã°ã©ã ãåæåããloadShader()
ãå¼ã³åºãã¦åã·ã§ã¼ãã¼ã®ããã°ã©ã ããã¼ãããã³ã³ã³ãã¤ã«ãã¦ãããåã·ã§ã¼ãã¼ã WebGL ã³ã³ããã¹ãã«ã¢ã¿ãããã¾ãã ããããã³ã³ãã¤ã«ãããã¨ãããã°ã©ã ã¯ãªã³ã¯ãããå¼ã³åºãå
ã«è¿ããã¾ãã
loadShader()
ã·ã§ã¼ãã¼ãªãã¸ã§ã¯ãã使ããæå®ãããã½ã¼ã¹ã³ã¼ãããã®ãªãã¸ã§ã¯ãã«ãã¼ããã¦ãããã³ã¼ããã³ã³ãã¤ã«ããã³ã³ãã¤ã©ãæåãããã¨ã確èªãã¦ãããæ°ããã³ã³ãã¤ã«ãããã·ã§ã¼ãã¼ãå¼ã³åºãå
ã«è¿ãã¾ãã ã¨ã©ã¼ãçºçããå ´åã¯ã代ããã« NULL
ãè¿ãã¾ãã
initBuffers()
WebGL ã«æ¸¡ããã¼ã¿ãå«ãã ãããã¡ã¼ãåæåãã¾ãã ãããã®ãããã¡ã¼ã«ã¯ãé ç¹ä½ç½®ã®é åãé ç¹æ³ç·ã®é åãç«æ¹ä½ã®åé¢ã®ãã¯ã¹ãã£ã¼åº§æ¨ãããã³é ç¹ã¤ã³ããã¯ã¹ã®é åï¼é ç¹ãªã¹ãã®ã©ã®ã¨ã³ããªã¼ãç«æ¹ä½ã®ããããã®è§ã表ãããæå®ï¼ãå«ã¾ãã¾ãã
loadTexture()
æå®ããã URL ã§ç»åããã¼ããããããã WebGL ãã¯ã¹ãã£ã¼ã使ãã¾ãã ç»åã®å¯¸æ³ã両æ¹ã¨ã 2 ã®ç´¯ä¹ã§ãªãå ´åï¼isPowerOf2()
颿°ãåç
§ï¼ããããããããç¡å¹ã¨ããã©ããã³ã°ãã¨ãã¸ã«åºå®ãã¾ãã ããã¯ããããããããã¯ã¹ãã£ã¼ã®æé©åãããã¬ã³ããªã³ã°ããWebGL 1 ã® 2 ã®ç´¯ä¹ã®å¯¸æ³ã®ãã¯ã¹ãã£ã¼ã«å¯¾ãã¦ã®ã¿æ©è½ããããã§ãã WebGL 2 ã¯ãããããããã«ä»»æã®å¯¸æ³ã®ãã¯ã¹ãã£ã¼ããµãã¼ããã¦ãã¾ãã
isPowerOf2()
æå®ãããå¤ã 2 ã®ç´¯ä¹ã®å ´åãtrue
ãè¿ãã¾ãã ãã以å¤ã®å ´å㯠false
ãè¿ãã¾ãã
ãã®ã³ã¼ãããã¹ã¦åå¾ãã¦ãä¸è¨ã«å«ã¾ãã¦ããªã HTML ããã³ãã®ä»ã® JavaScript ã³ã¼ãã追å ããã¨ããã®ä¾ã Glitch ã§è©¦ããã¨ãã«è¡¨ç¤ºããããã®ãå¾ããã¾ãã è¦ãã¦ããã¦ãã ãããæ©ãåã£ã¦è¿·åã«ãªã£ãããR ãã¼ãæ¼ãã ãã§æåã«æ»ããã¨ãã§ãã¾ãã
ãã³ã: XR ããã¤ã¹ããæã¡ã§ãªãå ´åã¯ãé¡ãç»é¢ã«é常ã«è¿ã¥ãã¦ããã£ã³ãã¹å ã®å·¦ç®ã¨å³ç®ã®ç»åã®å¢çã«æ²¿ã£ã¦é¼»ãä¸å¤®ã«é ç½®ããã¨ã3D 广ãå¾ããã¨ãã§ããããããã¾ããã ç»é¢ãéãã¦ç»åã«æ³¨ææ·±ãç¦ç¹ãåããããã£ããã¨åå¾ã«åããã¨ã§ãæçµçã« 3D ç»åã«ç¦ç¹ãåããããã¨ãã§ããã¯ãã§ãã ããã«ã¯ç·´ç¿ãå¿ è¦ã§ãè¦åã®éãã«ãã£ã¦ã¯ãæåéãé¼»ãç»é¢ã«è§¦ãã¦ããããããã¾ããã
ãã®ä¾ãåºçºç¹ã¨ãã¦ãã§ãããã¨ã¯ããããããã¾ãã ä¸çã«ãªãã¸ã§ã¯ãã追å ããããç§»åã³ã³ããã¼ã«ãæ¹åãã¦ãããªã¢ã«ã«ç§»åãã¦ã¿ã¦ãã ããã å£ã天äºãåºã追å ãã¦ãç¡éã«è¦ããå®å®ã«è¿·ãã®ã§ã¯ãªãã空éã«éãè¾¼ãã¾ãã è¡çªãã¹ããããããã¹ããã¾ãã¯ç«æ¹ä½ã®åé¢ã®ãã¯ã¹ãã£ã¼ã夿´ããæ©è½ã追å ãã¾ãã
èªåã§è¨å®ããã°ãã§ãããã¨ã«å¶éã¯ã»ã¨ãã©ããã¾ããã
é¢é£æ å ±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