mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-25 12:25:52 -08:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90305de2de | ||
|
|
1a2451f4d3 | ||
|
|
f43c4273a1 | ||
|
|
b201fb69fc | ||
|
|
c2047278e4 | ||
|
|
a03fc7a947 | ||
|
|
db74147021 | ||
|
|
4e0c2e69c5 | ||
|
|
ed135d1306 | ||
|
|
b7642b4a81 | ||
|
|
6beca88785 | ||
|
|
3bd1d4c1f0 |
113
examples/al-vr.html
Normal file
113
examples/al-vr.html
Normal file
@@ -0,0 +1,113 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://unpkg.com/three@0.157.0/build/three.module.js",
|
||||
"three/addons/": "https://unpkg.com/three@0.157.0/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
|
||||
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
||||
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
import * as THREE from 'three';
|
||||
|
||||
let aladin;
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin(
|
||||
'#aladin-lite-div',
|
||||
{
|
||||
survey: 'P/DSS2/color', // set a survey
|
||||
projection: 'TAN', // set a projection
|
||||
fov: 70, // initial field of view in degrees
|
||||
target: '338.98958 33.96', // initial target
|
||||
cooFrame: 'equatorial', // set galactic frame
|
||||
showCooGrid: true, // set the grid
|
||||
fullScreen: true,
|
||||
vr: {animation: animate.bind(renderer)},
|
||||
}
|
||||
);
|
||||
|
||||
//aladin.setOverlayImageLayer("https://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI")
|
||||
initScene(aladin.view.imageCanvas);
|
||||
aladin.setRenderer(renderer);
|
||||
});
|
||||
|
||||
let renderer = null;
|
||||
let scene = null;
|
||||
let camera = null;
|
||||
let cubeMesh = null;
|
||||
// let controls = null;
|
||||
|
||||
/**
|
||||
* Initializes a 3D scene, camera, and renderer for virtual reality (VR).
|
||||
*
|
||||
* @param {HTMLCanvasElement} canvas - The HTML canvas element to render the
|
||||
* 3D scene
|
||||
*/
|
||||
function initScene(canvas) {
|
||||
scene = new THREE.Scene();
|
||||
|
||||
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
scene.add(camera);
|
||||
|
||||
renderer = new THREE.WebGLRenderer({canvas: canvas, context: canvas.getContext('webgl2', {xrCompatible: true})}); // NOTE Une différence ici
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.xr.enabled = true;
|
||||
// renderer.xr.setReferenceSpaceType('local');
|
||||
renderer.autoClear = false;
|
||||
|
||||
const light = new THREE.PointLight(0xffffff, 10);
|
||||
light.position.set(0, 2, 1);
|
||||
scene.add(light);
|
||||
|
||||
const planeGeometry = new THREE.PlaneGeometry(10, 10);
|
||||
const planeMaterial = new THREE.MeshPhongMaterial({ color: 0xff00ff });
|
||||
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
|
||||
planeMesh.position.set(0, -1, 0);
|
||||
planeMesh.rotation.x = -Math.PI / 2;
|
||||
scene.add(planeMesh);
|
||||
|
||||
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
const cubeMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
|
||||
cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial);
|
||||
cubeMesh.position.set(0, 0, -2);
|
||||
scene.add(cubeMesh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to animate the 3D scene and rendering it.
|
||||
*/
|
||||
function animate() {
|
||||
cubeMesh.rotation.x += 0.001;
|
||||
cubeMesh.rotation.y += 0.001;
|
||||
|
||||
renderer.render( scene, camera );
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Initializes a WebGL2 context and handles potential errors.
|
||||
// */
|
||||
// function initWebGL2() {
|
||||
// // canvas = aladin.view.imageCanvas;
|
||||
// canvas = document.getElementById(aladin.view.imageCanvas);
|
||||
// // gl = canvas.getContext("webgl2", { alpha: true });
|
||||
// gl = canvas.getContext('webgl2');
|
||||
// if (!gl) { // If the gl didn't create properly
|
||||
// alert('This browser doesn\'t support WebGL2');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,8 +9,8 @@ pub mod vao {
|
||||
use crate::object::element_array_buffer::ElementArrayBuffer;
|
||||
|
||||
use crate::webgl_ctx::WebGlContext;
|
||||
use std::collections::HashMap;
|
||||
use crate::Abort;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct VertexArrayObject {
|
||||
array_buffer: HashMap<&'static str, ArrayBuffer>,
|
||||
@@ -88,7 +88,10 @@ pub mod vao {
|
||||
}*/
|
||||
|
||||
pub fn num_elements(&self) -> usize {
|
||||
self.element_array_buffer.as_ref().unwrap_abort().num_elements()
|
||||
self.element_array_buffer
|
||||
.as_ref()
|
||||
.unwrap_abort()
|
||||
.num_elements()
|
||||
}
|
||||
|
||||
pub fn num_instances(&self) -> i32 {
|
||||
@@ -155,6 +158,7 @@ pub mod vao {
|
||||
|
||||
pub fn unbind(&self) {
|
||||
self.vao.gl.bind_vertex_array(None);
|
||||
self._shader.unbind(&self.vao.gl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +174,9 @@ pub mod vao {
|
||||
}
|
||||
|
||||
impl<'a, 'b> ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
||||
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
|
||||
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) -> &Self {
|
||||
self.vao.gl.draw_arrays(mode, byte_offset, size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn draw_elements_with_i32(
|
||||
@@ -180,11 +185,12 @@ pub mod vao {
|
||||
num_elements: Option<i32>,
|
||||
type_: u32,
|
||||
byte_offset: i32,
|
||||
) {
|
||||
) -> &Self {
|
||||
let num_elements = num_elements.unwrap_or(self.vao.num_elements() as i32);
|
||||
self.vao
|
||||
.gl
|
||||
.draw_elements_with_i32(mode, num_elements, type_, byte_offset);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn draw_elements_instanced_with_i32(
|
||||
@@ -192,7 +198,7 @@ pub mod vao {
|
||||
mode: u32,
|
||||
offset_element_idx: i32,
|
||||
num_instances: i32,
|
||||
) {
|
||||
) -> &Self {
|
||||
self.vao.gl.draw_elements_instanced_with_i32(
|
||||
mode,
|
||||
self.vao.num_elements() as i32,
|
||||
@@ -200,10 +206,12 @@ pub mod vao {
|
||||
offset_element_idx,
|
||||
num_instances,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unbind(&self) {
|
||||
self.vao.gl.bind_vertex_array(None);
|
||||
self._shader.unbind(&self.vao.gl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,7 +452,10 @@ pub mod vao {
|
||||
}*/
|
||||
|
||||
pub fn num_elements(&self) -> usize {
|
||||
self.element_array_buffer.as_ref().unwrap_abort().num_elements()
|
||||
self.element_array_buffer
|
||||
.as_ref()
|
||||
.unwrap_abort()
|
||||
.num_elements()
|
||||
}
|
||||
|
||||
pub fn num_instances(&self) -> i32 {
|
||||
@@ -511,7 +522,8 @@ pub mod vao {
|
||||
}
|
||||
|
||||
pub fn unbind(&self) {
|
||||
//self.vao.gl.bind_vertex_array(None);
|
||||
self.vao.gl.bind_vertex_array(None);
|
||||
self._shader.unbind(&self.vao.gl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,13 +540,15 @@ pub mod vao {
|
||||
}
|
||||
use crate::object::array_buffer::VertexBufferObject;
|
||||
impl<'a, 'b> ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
||||
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
|
||||
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) -> &Self {
|
||||
for (attr, buf) in self.vao.array_buffer.iter() {
|
||||
buf.bind();
|
||||
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
||||
}
|
||||
|
||||
self.vao.gl.draw_arrays(mode, byte_offset, size);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn draw_elements_with_i32(
|
||||
@@ -543,7 +557,7 @@ pub mod vao {
|
||||
num_elements: Option<i32>,
|
||||
type_: u32,
|
||||
byte_offset: i32,
|
||||
) {
|
||||
) -> &Self {
|
||||
for (attr, buf) in self.vao.array_buffer.iter() {
|
||||
buf.bind();
|
||||
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
||||
@@ -555,6 +569,7 @@ pub mod vao {
|
||||
self.vao
|
||||
.gl
|
||||
.draw_elements_with_i32(mode, num_elements, type_, byte_offset);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn draw_elements_instanced_with_i32(
|
||||
@@ -562,7 +577,7 @@ pub mod vao {
|
||||
mode: u32,
|
||||
offset_element_idx: i32,
|
||||
num_instances: i32,
|
||||
) {
|
||||
) -> &Self {
|
||||
for (attr, buf) in self.vao.array_buffer.iter() {
|
||||
buf.bind();
|
||||
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
||||
@@ -587,10 +602,12 @@ pub mod vao {
|
||||
offset_element_idx,
|
||||
num_instances,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unbind(&self) {
|
||||
//self.vao.gl.bind_vertex_array(None);
|
||||
self.vao.gl.bind_vertex_array(None);
|
||||
self.shader.unbind(&self.vao.gl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,6 +733,9 @@ pub mod vao {
|
||||
|
||||
pub fn unbind(&self) {
|
||||
//self.vao.gl.bind_vertex_array(None);
|
||||
|
||||
self.vao.gl.bind_vertex_array(None);
|
||||
self.shader.unbind(&self.vao.gl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -875,7 +875,7 @@ impl App {
|
||||
&self.colormaps,
|
||||
&self.projection,
|
||||
)?;
|
||||
|
||||
/*
|
||||
// Draw the catalog
|
||||
//let fbo_view = &self.fbo_view;
|
||||
//catalogs.draw(&gl, shaders, camera, colormaps, fbo_view)?;
|
||||
@@ -903,7 +903,7 @@ impl App {
|
||||
self.line_renderer.draw(&self.camera)?;
|
||||
//let dpi = self.camera.get_dpi();
|
||||
//ui.draw(&gl, dpi)?;
|
||||
|
||||
*/
|
||||
// Reset the flags about the user action
|
||||
self.camera.reset();
|
||||
|
||||
|
||||
@@ -1047,7 +1047,8 @@ impl HiPS {
|
||||
Some(self.num_idx as i32),
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
);
|
||||
)
|
||||
.unbind();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -225,7 +225,8 @@ impl RayTracer {
|
||||
None,
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
);
|
||||
)
|
||||
.unbind();
|
||||
#[cfg(feature = "webgl2")]
|
||||
shader
|
||||
.attach_uniform("position_tex", &self.position_tex)
|
||||
@@ -236,6 +237,7 @@ impl RayTracer {
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
)
|
||||
.unbind();
|
||||
}
|
||||
|
||||
pub fn is_rendering(&self, camera: &CameraViewPort) -> bool {
|
||||
|
||||
@@ -612,7 +612,8 @@ impl Image {
|
||||
Some(num_indices),
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
((off_indices as usize) * std::mem::size_of::<u16>()) as i32,
|
||||
);
|
||||
)
|
||||
.unbind();
|
||||
|
||||
off_indices += self.num_indices[idx];
|
||||
}
|
||||
|
||||
@@ -259,7 +259,8 @@ impl Layers {
|
||||
None,
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
);
|
||||
)
|
||||
.unbind();
|
||||
}
|
||||
|
||||
// The first layer must be paint independently of its alpha channel
|
||||
|
||||
@@ -50,6 +50,7 @@ import { ContextMenu } from "./gui/ContextMenu.js";
|
||||
import { ALEvent } from "./events/ALEvent.js";
|
||||
import { Color } from './Color.js';
|
||||
import { ImageFITS } from "./ImageFITS.js";
|
||||
import { VRButton } from "./VRButton.js";
|
||||
import { DefaultActionsForContextMenu } from "./DefaultActionsForContextMenu.js";
|
||||
import A from "./A.js";
|
||||
|
||||
@@ -458,7 +459,8 @@ export let Aladin = (function () {
|
||||
//this.discoverytree = new DiscoveryTree(this);
|
||||
//}
|
||||
|
||||
this.view.redraw();
|
||||
// [ ] That might pose problems
|
||||
//this.view.redraw();
|
||||
|
||||
// go to full screen ?
|
||||
if (options.fullScreen) {
|
||||
@@ -471,6 +473,11 @@ export let Aladin = (function () {
|
||||
this.contextMenu = new ContextMenu(this);
|
||||
this.contextMenu.attachTo(this.view.catalogCanvas, DefaultActionsForContextMenu.getDefaultActions(this));
|
||||
}
|
||||
|
||||
// initialize the VR button
|
||||
if (options.vr) {
|
||||
this.aladinDiv.appendChild(VRButton.createButton(this.view));
|
||||
}
|
||||
};
|
||||
|
||||
/**** CONSTANTS ****/
|
||||
@@ -671,6 +678,11 @@ export let Aladin = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
// @API
|
||||
Aladin.prototype.setRenderer = function(renderer) {
|
||||
this.options.vr.renderer = renderer;
|
||||
}
|
||||
|
||||
Aladin.prototype.setFrame = function (frameName) {
|
||||
if (!frameName) {
|
||||
return;
|
||||
|
||||
252
src/js/VRButton.js
Normal file
252
src/js/VRButton.js
Normal file
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* This is an adaptation of the original VRButton.
|
||||
* Original at:
|
||||
* https://github.com/mrdoob/three.js/blob/dev/examples/jsm/webxr/VRButton.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* VRButton class that handles the creation of a VR session
|
||||
*
|
||||
* @class VRButton
|
||||
*/
|
||||
class VRButton {
|
||||
/**
|
||||
* Constructs a VRButton
|
||||
*
|
||||
* @static
|
||||
* @param {View} view - The aladin view
|
||||
* @return {HTMLButtonElement|HTMLAnchorElement} The VR mode button or an
|
||||
* error message
|
||||
*/
|
||||
static createButton(view) {
|
||||
const button = document.createElement('button');
|
||||
|
||||
/**
|
||||
* Function for handling the process of entering VR mode.
|
||||
*/
|
||||
function showEnterVR(/* device*/) {
|
||||
let currentSession = null;
|
||||
|
||||
/**
|
||||
* Callback function to handle when the XR session is started
|
||||
*
|
||||
* @param {XRSession} session - The XR session that has been started
|
||||
*/
|
||||
async function onSessionStarted(session) {
|
||||
session.addEventListener('end', onSessionEnded);
|
||||
|
||||
let gl = view.imageCanvas.getContext('webgl2');
|
||||
await gl.makeXRCompatible();
|
||||
|
||||
session.updateRenderState({
|
||||
baseLayer: new XRWebGLLayer(session, gl)
|
||||
});
|
||||
|
||||
await view.options.vr.renderer.xr.setSession(session);
|
||||
button.textContent = 'EXIT VR';
|
||||
|
||||
// view.options.vr.renderer.setAnimationLoop(view.redrawVR.bind(view));
|
||||
|
||||
session.requestReferenceSpace('local-floor').then((refSpace) => {
|
||||
const xrRefSpace = refSpace;
|
||||
session.requestAnimationFrame((t, frame) => {view.redrawVR(t, frame, xrRefSpace)});
|
||||
});
|
||||
|
||||
currentSession = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to render the whole scene
|
||||
*/
|
||||
// NOTE A supprimer
|
||||
function onXRAnimationFrame(t, xrFrame) {
|
||||
currentSession.requestAnimationFrame(onXRAnimationFrame);
|
||||
view.redrawVR();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to handle when the XR session ends
|
||||
*/
|
||||
function onSessionEnded(/* event*/) {
|
||||
currentSession.removeEventListener('end', onSessionEnded);
|
||||
|
||||
button.textContent = 'ENTER VR';
|
||||
|
||||
currentSession = null;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
button.style.display = '';
|
||||
|
||||
button.style.cursor = 'pointer';
|
||||
button.style.left = 'calc(50% - 50px)';
|
||||
button.style.width = '100px';
|
||||
|
||||
button.textContent = 'ENTER VR';
|
||||
|
||||
button.onmouseenter = function() {
|
||||
button.style.opacity = '1.0';
|
||||
};
|
||||
|
||||
button.onmouseleave = function() {
|
||||
button.style.opacity = '0.5';
|
||||
};
|
||||
|
||||
button.onclick = function() {
|
||||
if (currentSession === null) {
|
||||
// WebXR's requestReferenceSpace only works if the corresponding
|
||||
// feature was requested at session creation time. For simplicity,
|
||||
// just ask for the interesting ones as optional features, but be
|
||||
// aware that the requestReferenceSpace call will fail if it turns
|
||||
// out to be unavailable.
|
||||
// ('local' is always available for immersive sessions and doesn't
|
||||
// need to be requested separately.)
|
||||
|
||||
const sessionInit = {optionalFeatures: ['local-floor']};
|
||||
navigator.xr.requestSession(
|
||||
'immersive-vr', sessionInit).then(onSessionStarted);
|
||||
} else {
|
||||
currentSession.end();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for disabling the VR mode button
|
||||
*
|
||||
* @param {HTMLButtonElement} button - The VR mode button element to
|
||||
* be disabled
|
||||
*/
|
||||
function disableButton() {
|
||||
button.style.display = '';
|
||||
|
||||
button.style.cursor = 'auto';
|
||||
button.style.left = 'calc(50% - 75px)';
|
||||
button.style.width = '150px';
|
||||
|
||||
button.onmouseenter = null;
|
||||
button.onmouseleave = null;
|
||||
|
||||
button.onclick = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for handling the case where WebXR is not supported
|
||||
*
|
||||
* @description This function disables the VR mode button and displays a
|
||||
* message indicating that VR is not supported
|
||||
*
|
||||
* @param {HTMLButtonElement} button - The VR mode button element to be
|
||||
* disabled and updated with a message
|
||||
*/
|
||||
function showWebXRNotFound() {
|
||||
disableButton();
|
||||
|
||||
button.textContent = 'VR NOT SUPPORTED';
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for handling the case where VR is not allowed due to an
|
||||
* exception
|
||||
*
|
||||
* @description This function disables the VR mode button, logs an
|
||||
* exception to the console, and displays a message indicating that VR
|
||||
* is not allowed
|
||||
*
|
||||
* @param {any} exception - The exception object or error that indicates
|
||||
* why VR is not allowed
|
||||
* @param {HTMLButtonElement} button - The VR mode button element to be
|
||||
* disabled and updated with a message
|
||||
*/
|
||||
function showVRNotAllowed(exception) {
|
||||
disableButton();
|
||||
|
||||
console.warn('Exception when trying to call xr.isSessionSupported',
|
||||
exception);
|
||||
|
||||
button.textContent = 'VR NOT ALLOWED';
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for styling an HTML element with specific CSS properties
|
||||
*
|
||||
* @param {HTMLElement} element - The HTML element to be styled
|
||||
*/
|
||||
function stylizeElement(element) {
|
||||
element.style.position = 'absolute';
|
||||
element.style.bottom = '20px';
|
||||
element.style.padding = '12px 6px';
|
||||
element.style.border = '1px solid #fff';
|
||||
element.style.borderRadius = '4px';
|
||||
element.style.background = 'rgba(0,0,0,0.1)';
|
||||
element.style.color = '#fff';
|
||||
element.style.font = 'normal 13px sans-serif';
|
||||
element.style.textAlign = 'center';
|
||||
element.style.opacity = '0.5';
|
||||
element.style.outline = 'none';
|
||||
element.style.zIndex = '999';
|
||||
}
|
||||
|
||||
if ('xr' in navigator) {
|
||||
button.id = 'VRButton';
|
||||
button.style.display = 'none';
|
||||
|
||||
stylizeElement(button);
|
||||
|
||||
navigator.xr.isSessionSupported('immersive-vr').then(function(supported) {
|
||||
supported ? showEnterVR() : showWebXRNotFound();
|
||||
|
||||
if (supported && VRButton.xrSessionIsGranted) {
|
||||
button.click();
|
||||
}
|
||||
}).catch(showVRNotAllowed);
|
||||
|
||||
return button;
|
||||
} else {
|
||||
const message = document.createElement('a');
|
||||
|
||||
if (window.isSecureContext === false) {
|
||||
message.href = document.location.href.replace(/^http:/, 'https:');
|
||||
message.innerHTML = 'WEBXR NEEDS HTTPS';
|
||||
} else {
|
||||
message.href = 'https://immersiveweb.dev/';
|
||||
message.innerHTML = 'WEBXR NOT AVAILABLE';
|
||||
}
|
||||
|
||||
message.style.left = 'calc(50% - 90px)';
|
||||
message.style.width = '180px';
|
||||
message.style.textDecoration = 'none';
|
||||
|
||||
stylizeElement(message);
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener for the "sessiongranted" event to track the XR
|
||||
* session being granted.
|
||||
*
|
||||
* @description This method checks if the WebXR API is available and
|
||||
* registers a listener for the "sessiongranted" event to track when an
|
||||
* XR session is granted. It sets the `VRButton.xrSessionIsGranted`
|
||||
* property to `true` when the event is triggered.
|
||||
*/
|
||||
static registerSessionGrantedListener() {
|
||||
if ('xr' in navigator) {
|
||||
// WebXRViewer (based on Firefox) has a bug where addEventListener
|
||||
// throws a silent exception and aborts execution entirely.
|
||||
if (/WebXRViewer\//i.test(navigator.userAgent)) return;
|
||||
|
||||
navigator.xr.addEventListener('sessiongranted', () => {
|
||||
VRButton.xrSessionIsGranted = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VRButton.xrSessionIsGranted = false;
|
||||
VRButton.registerSessionGrantedListener();
|
||||
|
||||
export {VRButton};
|
||||
@@ -370,7 +370,7 @@ export let View = (function () {
|
||||
}
|
||||
|
||||
this.computeNorder();
|
||||
this.redraw();
|
||||
//this.redraw();
|
||||
};
|
||||
|
||||
var pixelateCanvasContext = function (ctx, pixelateFlag) {
|
||||
@@ -1059,6 +1059,41 @@ export let View = (function () {
|
||||
|
||||
View.FPS_INTERVAL = 1000 / 140;
|
||||
|
||||
|
||||
View.prototype.redrawVR = function (t, frame, xrRefSpace) {
|
||||
const session = frame.session;
|
||||
session.requestAnimationFrame((t, frame) => {this.redrawVR(t, frame, xrRefSpace)});
|
||||
|
||||
let pose = frame.getViewerPose(xrRefSpace);
|
||||
|
||||
if (!pose) return;
|
||||
|
||||
// Elapsed time since last loop
|
||||
const now = Date.now();
|
||||
const elapsedTime = now - this.then;
|
||||
|
||||
// If enough time has elapsed, draw the next frame
|
||||
//if (elapsedTime >= View.FPS_INTERVAL) {
|
||||
// Get ready for next frame by setting then=now, but also adjust for your
|
||||
// specified fpsInterval not being a multiple of RAF's interval (16.7ms)
|
||||
|
||||
// Drawing code
|
||||
try {
|
||||
this.moving = this.wasm.update(elapsedTime);
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
|
||||
////// 2. Draw catalogues////////
|
||||
const isViewRendering = this.wasm.isRendering();
|
||||
if (isViewRendering || this.needRedraw) {
|
||||
this.drawAllOverlays();
|
||||
}
|
||||
this.needRedraw = false;
|
||||
|
||||
this.options.vr.animation();
|
||||
}
|
||||
|
||||
/**
|
||||
* redraw the whole view
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user