En esta página, se te guiará para crear una aplicación de RA envolvente simple con WebXR.
Para comenzar, necesitarás un entorno de desarrollo compatible con WebXR.
Crea una página HTML
WebXR requiere la interacción del usuario para poder iniciar una sesión.
Crea un botón que llame a activateXR()
. Cuando se carga la página, el usuario puede usar este botón para iniciar la experiencia de RA.
Crea un archivo nuevo llamado index.html
y agrégale el siguiente código HTML:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Hello WebXR!</title>
<!-- three.js -->
<script src="https://unpkg.com/three@0.126.0/build/three.js"></script>
</head>
<body>
<!-- Starting an immersive WebXR session requires user interaction.
We start this one with a simple button. -->
<button onclick="activateXR()">Start Hello WebXR</button>
<script>
async function activateXR() {
// Add a canvas element and initialize a WebGL context that is compatible with WebXR.
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const gl = canvas.getContext("webgl", {xrCompatible: true});
// To be continued in upcoming steps.
}
</script>
</body>
</html>
Cómo inicializar three.js
No pasará mucho cuando presiones el botón Start. Para configurar un entorno 3D, puedes usar una biblioteca de renderización para mostrar una escena.
En este ejemplo, usarás three.js
, una biblioteca de renderización 3D de JavaScript que proporciona un renderizador WebGL. Three.js
controla la renderización, las cámaras y los gráficos de escenas, lo que facilita la visualización de contenido 3D en la Web.
Crea una escena
Por lo general, un entorno 3D se modela como una escena. Crea un THREE.Scene
que contenga elementos de RA.
El siguiente código te permite mirar un cuadro de color apagado en RA.
Agrega este código a la parte inferior de la función activateXR()
:
const scene = new THREE.Scene();
// The cube will have a different color on each side.
const materials = [
new THREE.MeshBasicMaterial({color: 0xff0000}),
new THREE.MeshBasicMaterial({color: 0x0000ff}),
new THREE.MeshBasicMaterial({color: 0x00ff00}),
new THREE.MeshBasicMaterial({color: 0xff00ff}),
new THREE.MeshBasicMaterial({color: 0x00ffff}),
new THREE.MeshBasicMaterial({color: 0xffff00})
];
// Create the cube and add it to the demo scene.
const cube = new THREE.Mesh(new THREE.BoxBufferGeometry(0.2, 0.2, 0.2), materials);
cube.position.set(1, 1, 1);
scene.add(cube);
Configura el procesamiento con tres.js
Para poder ver esta escena en RA, necesitarás un procesador y una cámara. El procesador usa WebGL para dibujar la escena en la pantalla. La cámara describe la viewport desde la que se ve la escena.
Agrega este código a la parte inferior de la función activateXR()
:
// Set up the WebGLRenderer, which handles rendering to the session's base layer.
const renderer = new THREE.WebGLRenderer({
alpha: true,
preserveDrawingBuffer: true,
canvas: canvas,
context: gl
});
renderer.autoClear = false;
// The API directly updates the camera matrices.
// Disable matrix auto updates so three.js doesn't attempt
// to handle the matrices independently.
const camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;
Crea una XRSession
El punto de entrada a WebXR es a través de XRSystem.requestSession()
. Usa el modo immersive-ar
para permitir la visualización de contenido renderizado en un entorno real.
Un XRReferenceSpace
describe el sistema de coordenadas que se usa para los objetos del mundo virtual.
El modo 'local'
es más adecuado para una experiencia de RA, con un espacio de referencia que tenga un origen cerca del usuario y un seguimiento estable.
Para crear un XRSession
y un XRReferenceSpace
, agrega este código a la parte inferior de la función activateXR()
:
// Initialize a WebXR session using "immersive-ar".
const session = await navigator.xr.requestSession("immersive-ar");
session.updateRenderState({
baseLayer: new XRWebGLLayer(session, gl)
});
// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');
Renderiza la escena
Ahora puedes renderizar la escena. XRSession.requestAnimationFrame()
programa una devolución de llamada que se ejecuta cuando el navegador está listo para dibujar un marco.
Durante la devolución de llamada del fotograma de animación, llama a XRFrame.getViewerPose()
para obtener la pose del usuario en relación con el espacio de coordenadas local.
Se usa para actualizar la cámara en la escena, lo que cambia la forma en que el usuario ve el mundo virtual antes de que el renderizador dibuje la escena con la cámara actualizada.
Agrega este código a la parte inferior de la función activateXR()
:
// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {
// Queue up the next draw request.
session.requestAnimationFrame(onXRFrame);
// Bind the graphics framebuffer to the baseLayer's framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer)
// Retrieve the pose of the device.
// XRFrame.getViewerPose can return null while the session attempts to establish tracking.
const pose = frame.getViewerPose(referenceSpace);
if (pose) {
// In mobile AR, we only have one view.
const view = pose.views[0];
const viewport = session.renderState.baseLayer.getViewport(view);
renderer.setSize(viewport.width, viewport.height)
// Use the view's transform matrix and projection matrix to configure the THREE.camera.
camera.matrix.fromArray(view.transform.matrix)
camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);
// Render the scene with THREE.WebGLRenderer.
renderer.render(scene, camera)
}
}
session.requestAnimationFrame(onXRFrame);
Ejecuta Hello WebXR
Navega al archivo WebXR en tu dispositivo. Deberías ver un cubo de color desde todos los lados.
Cómo agregar una prueba de posicionamiento
Una forma común de interactuar con el mundo de la RA es a través de una prueba de intersección, que encuentra una intersección entre un rayo y la geometría del mundo real. En Hello WebXR, usarás una prueba de posicionamiento para colocar un girasol en el mundo virtual.
Cómo quitar el cubo de demostración
Quita el cubo sin iluminación y reemplázalo por una escena que incluya iluminación:
const scene = new THREE.Scene();
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);
directionalLight.position.set(10, 15, 10);
scene.add(directionalLight);
Usa la función hit-test
Para inicializar la funcionalidad de prueba de hit, solicita la sesión con el atributo hit-test
. Busca el fragmento requestSession()
anterior y agrégale hit-test
:
const session = await navigator.xr.requestSession("immersive-ar", {requiredFeatures: ['hit-test']});
Agrega un cargador de modelos
Actualmente, la escena solo contiene un cubo de color. Para que la experiencia sea más interesante, agrega un cargador de modelos, que permite cargar modelos GLTF.
En la etiqueta <head>
de tu documento, agrega GLTFLoader
de three.js.
<!-- three.js -->
<script src="https://unpkg.com/three@0.126.0/build/three.js"></script>
<script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script>
Carga modelos GLTF
Usa el cargador de modelos del paso anterior para cargar un retículo de segmentación y un girasol desde la Web.
Agrega este código arriba de onXRFrame
:
const loader = new THREE.GLTFLoader();
let reticle;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", function(gltf) {
reticle = gltf.scene;
reticle.visible = false;
scene.add(reticle);
})
let flower;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", function(gltf) {
flower = gltf.scene;
});
// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {
Crea una fuente de prueba de hit
Para calcular intersecciones con objetos del mundo real, crea un XRHitTestSource
con XRSession.requestHitTestSource()
.
El rayo que se usa para la prueba de hit tiene el espacio de referencia viewer
como origen, lo que significa que la prueba de hit se realiza desde el centro del viewport.
Para crear una fuente de prueba de hit, agrega este código después de crear el espacio de referencia local
:
// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');
// Create another XRReferenceSpace that has the viewer as the origin.
const viewerSpace = await session.requestReferenceSpace('viewer');
// Perform hit testing using the viewer as origin.
const hitTestSource = await session.requestHitTestSource({ space: viewerSpace });
Cómo dibujar un retículo de objetivo
Para dejar claro dónde se colocará el girasol, agrega un retículo de objetivo a la escena. Este retículo parecerá adherirse a las superficies del mundo real, lo que indicará dónde se anclará el girasol.
XRFrame.getHitTestResults
muestra un array de XRHitTestResult
y expone las intersecciones con geometría real.
Usa estas intersecciones para posicionar el retículo de segmentación en cada fotograma.
camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0 && reticle) {
const hitPose = hitTestResults[0].getPose(referenceSpace);
reticle.visible = true;
reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
reticle.updateMatrixWorld(true);
}
Cómo agregar interacciones con el toque
XRSession
recibe eventos select
cuando el usuario completa una acción principal.
En una sesión de RA, corresponde a un toque en la pantalla.
Agrega este código durante la inicialización para que aparezca un nuevo girasol cuando el usuario presione la pantalla:
let flower;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", function(gltf) {
flower = gltf.scene;
});
session.addEventListener("select", (event) => {
if (flower) {
const clone = flower.clone();
clone.position.copy(reticle.position);
scene.add(clone);
}
});
Cómo probar la prueba de posicionamiento
Usa tu dispositivo móvil para navegar a la página. Después de que WebXR comprenda el entorno, el retículo debería aparecer en las superficies del mundo real. Presiona la pantalla para colocar un girasol, que se puede ver desde todos los lados.
Próximos pasos
- Lee la especificación de la API de WebXR Device.
- Consulta la documentación de referencia de WebXR en MDN Web Docs.
- Prueba las muestras de WebXR.
- Compila una app de realidad aumentada (RA) con la API de WebXR Device (codelab).