-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for WebXR Anchors Module
- Loading branch information
Showing
10 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
--- | ||
title: anchored | ||
type: components | ||
layout: docs | ||
parent_section: components | ||
source_code: src/components/anchored.js | ||
examples: [] | ||
--- | ||
|
||
[webxranchors]: https://immersive-web.github.io/anchors/ | ||
|
||
It requires a browser supporting the [WebXR Anchors module][webxranchors]. | ||
|
||
Fix any entity to a position and rotation in the real world. Apply the anchored component to an entity and call the method `el.components.createAnchor(position, quaternion)` to anchor it to a position and rotation corresponding to real world coordinates. | ||
|
||
|
||
## Example | ||
|
||
```html | ||
<a-entity id="myBox" anchored="persistent: true" geometry="primitive: box" material="color: red"></a-entity> | ||
``` | ||
|
||
## Properties | ||
|
||
| Properties | Description | | ||
|-------------------|-------------------------------------------------------------------------| | ||
| persistent | If the anchor persists on page reloads. The entity must have an id. | | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* global AFRAME */ | ||
AFRAME.registerComponent('anchor-grabbed-entity', { | ||
init: function () { | ||
this.el.addEventListener('grabstarted', this.deleteAnchor.bind(this)); | ||
this.el.addEventListener('grabended', this.updateAnchor.bind(this)); | ||
}, | ||
|
||
updateAnchor: function (evt) { | ||
var grabbedEl = evt.detail.grabbedEl; | ||
var anchoredComponent = grabbedEl.components.anchored; | ||
if (anchoredComponent) { | ||
anchoredComponent.createAnchor(grabbedEl.object3D.position, grabbedEl.object3D.quaternion); | ||
} | ||
}, | ||
|
||
deleteAnchor: function (evt) { | ||
var grabbedEl = evt.detail.grabbedEl; | ||
var anchoredComponent = grabbedEl.components.anchored; | ||
if (anchoredComponent) { | ||
anchoredComponent.deleteAnchor(); | ||
} | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* global AFRAME */ | ||
AFRAME.registerComponent('button', { | ||
init: function () { | ||
var buttonContainerEl = this.buttonContainerEl = document.createElement('div'); | ||
var buttonEl = this.buttonEl = document.createElement('button'); | ||
var style = document.createElement('style'); | ||
var css = | ||
'.a-button-container {box-sizing: border-box; display: inline-block; height: 34px; padding: 0;;' + | ||
'bottom: 20px; width: 150px; left: calc(50% - 75px); position: absolute; color: white;' + | ||
'font-size: 12px; line-height: 12px; border: none;' + | ||
'border-radius: 5px}' + | ||
'.a-button {cursor: pointer; padding: 0px 10px 0 10px; font-weight: bold; color: #666; border: 3px solid #666; box-sizing: border-box; vertical-align: middle; max-width: 200px; border-radius: 10px; height: 34px; background-color: white; margin: 0;}' + | ||
'.a-button:hover {border-color: #ef2d5e; color: #ef2d5e}'; | ||
|
||
if (style.styleSheet) { | ||
style.styleSheet.cssText = css; | ||
} else { | ||
style.appendChild(document.createTextNode(css)); | ||
} | ||
document.getElementsByTagName('head')[0].appendChild(style); | ||
|
||
buttonContainerEl.classList.add('a-button-container'); | ||
buttonEl.classList.add('a-button'); | ||
buttonEl.addEventListener('click', this.onClick.bind(this)); | ||
|
||
buttonContainerEl.appendChild(buttonEl); | ||
|
||
this.el.sceneEl.appendChild(buttonContainerEl); | ||
buttonEl.innerHTML = 'NEXT PAINTING'; | ||
}, | ||
|
||
onClick: function () { | ||
|
||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Anchor (Mixed Reality) • A-Frame</title> | ||
<meta name="description" content="Anchor (Mixed Reality) • A-Frame"> | ||
<script src="../../dist/aframe-master.js"></script> | ||
<script src="../../js/info-message.js"></script> | ||
<script src="https://unpkg.com/[email protected]/dist/aframe-environment-component.min.js"></script> | ||
<script src="anchor-grabbed-entity.js"></script> | ||
<script src="painting-changer.js"></script> | ||
<script src="painting.js"></script> | ||
</head> | ||
<body> | ||
<a-scene | ||
obb-collider="showColliders: false" | ||
renderer="colorManagement: true;" | ||
button | ||
xr-mode-ui="XRMode: ar" | ||
info-message="htmlSrc: #messageText"> | ||
<a-assets timeout="10000"> | ||
<!-- Model by theGentleGiant https://sketchfab.com/3d-models/vintage-painting-dani-3fdd92904c2b44028bef28b33e897d9f --> | ||
<a-asset-item id="painting" | ||
src="https://cdn.aframe.io/examples/mixed-reality/anchor/models/painting/scene.gltf" | ||
response-type="arraybuffer" crossorigin="anonymous"></a-asset-item> | ||
<a-asset-item id="messageText" src="message.html"></a-asset-item> | ||
<img id="helloaframe" src="https://cdn.aframe.io/examples/mixed-reality/anchor/images/helloaframe.png" crossorigin="anonymous"/> | ||
<img id="greco" src="https://cdn.aframe.io/examples/mixed-reality/anchor/images/greco.png" crossorigin="anonymous"/> | ||
<img id="mucha" src="https://cdn.aframe.io/examples/mixed-reality/anchor/images/mucha.png" crossorigin="anonymous"/> | ||
<img id="scream" src="https://cdn.aframe.io/examples/mixed-reality/anchor/images/scream.png" crossorigin="anonymous"/> | ||
<img id="vangogh" src="https://cdn.aframe.io/examples/mixed-reality/anchor/images/vangogh.png" crossorigin="anonymous"/> | ||
</a-assets> | ||
<a-entity | ||
id="painting" | ||
position="0 1.6 -0.75" | ||
gltf-model="#painting" | ||
anchored="persistent: true" | ||
painting | ||
painting-changer | ||
grabbable></a-entity> | ||
<a-entity id="rightHand" hand-tracking-grab-controls="hand: right" anchor-grabbed-entity></a-entity> | ||
<a-entity id="leftHand" hand-tracking-grab-controls="hand: left" anchor-grabbed-entity></a-entity> | ||
</a-scene> | ||
<script src="button.js"></script> | ||
</body> | ||
</html> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<p> | ||
This demo requires a browser supporting the <a href="https://immersive-web.github.io/anchors/">WebXR Anchors Module</a> | ||
</p> | ||
|
||
<p> | ||
In AR mode the user can pinch to grab the painting and release it at any position and orientation. The painting will remain anchored to the real world coordinate where it was released by the user. The anchor will persists upon page reload. | ||
</p> | ||
|
||
<p> | ||
Paintings by <a href="https://en.wikipedia.org/wiki/Vincent_van_Gogh">Van Gogh</a>, <a href="https://en.wikipedia.org/wiki/Alphonse_Mucha">Alphonse Mucha</a>, <a href="https://en.wikipedia.org/wiki/El_Greco">El Greco</a> and <a href="https://en.wikipedia.org/wiki/Edvard_Munch">Edvard Munch</a>. Frame model by <a href="https://sketchfab.com/3d-models/vintage-painting-dani-3fdd92904c2b44028bef28b33e897d9f">theGentleGiant</a> | ||
</p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* global AFRAME */ | ||
AFRAME.registerComponent('painting-changer', { | ||
init: function () { | ||
this.currentPaintingIndex = 0; | ||
this.paintings = [ | ||
'#greco', | ||
'#helloaframe', | ||
'#mucha', | ||
'#scream', | ||
'#vangogh' | ||
]; | ||
this.el.sceneEl.addEventListener('loaded', this.onLoaded.bind(this)); | ||
}, | ||
|
||
nextPainting: function () { | ||
this.currentPaintingIndex++; | ||
if (this.currentPaintingIndex === this.paintings.length) { | ||
this.currentPaintingIndex = 0; | ||
} | ||
this.el.setAttribute('painting', 'src', this.paintings[this.currentPaintingIndex]); | ||
}, | ||
|
||
onLoaded: function () { | ||
document.querySelector('.a-button').addEventListener('click', this.nextPainting.bind(this)); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* global AFRAME, THREE */ | ||
AFRAME.registerComponent('painting', { | ||
schema: {src: {type: 'map'}}, | ||
init: function () { | ||
this.updateSrc = this.updateSrc.bind(this); | ||
this.el.addEventListener('model-loaded', this.updateSrc); | ||
}, | ||
|
||
update: function () { | ||
if (this.data.src) { this.updateSrc(); } | ||
}, | ||
|
||
updateSrc: function () { | ||
var el = this.el; | ||
var src = this.data.src; | ||
var self = this; | ||
if (!el.components['gltf-model'].model || !this.data.src) { return; } | ||
el.sceneEl.systems.material.loadTexture(src, {src: src}, function textureLoaded (texture) { | ||
var gltf = self.el.getObject3D('mesh'); | ||
var gltfMaterial = gltf.children[0].children[0].children[0].children[0].children[0].material; | ||
texture.colorSpace = THREE.SRGBColorSpace; | ||
self.el.sceneEl.renderer.initTexture(texture); | ||
self.texture = texture; | ||
gltfMaterial.map = texture; | ||
gltfMaterial.needsUpdate = true; | ||
}); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* global XRRigidTransform, localStorage */ | ||
var registerComponent = require('../core/component').registerComponent; | ||
var utils = require('../utils/'); | ||
var warn = utils.debug('components:anchored:warn'); | ||
|
||
/** | ||
* Anchored component. | ||
* Feature only available in browsers that implement the WebXR anchors module. | ||
* Once anchored the entity remains to a fixed position in real-world space. | ||
* If the anchor is persistent, the anchor positioned remains across sessions or until the browser data is cleared. | ||
*/ | ||
module.exports.Component = registerComponent('anchored', { | ||
schema: { | ||
persistent: {default: false} | ||
}, | ||
|
||
init: function () { | ||
var webxrData = this.el.sceneEl.getAttribute('webxr'); | ||
var optionalFeaturesArray = webxrData.optionalFeatures; | ||
if (optionalFeaturesArray.indexOf('anchors') === -1) { | ||
optionalFeaturesArray.push('anchors'); | ||
this.el.sceneEl.setAttribute('webxr', webxrData); | ||
} | ||
|
||
this.requestPersistentAnchorPending = this.data.persistent; | ||
}, | ||
|
||
tick: function () { | ||
var sceneEl = this.el.sceneEl; | ||
var xrManager = sceneEl.renderer.xr; | ||
var frame; | ||
var refSpace; | ||
var pose; | ||
var object3D = this.el.object3D; | ||
|
||
if ((!sceneEl.is('ar-mode') && !sceneEl.is('vr-mode'))) { return; } | ||
if (!this.anchor && this.data.persistent && this.requestPersistentAnchorPending) { this.restorePersistentAnchor(); } | ||
if (!this.anchor) { return; } | ||
|
||
frame = sceneEl.frame; | ||
refSpace = xrManager.getReferenceSpace(); | ||
|
||
pose = frame.getPose(this.anchor.anchorSpace, refSpace); | ||
object3D.matrix.elements = pose.transform.matrix; | ||
object3D.matrix.decompose(object3D.position, object3D.rotation, object3D.scale); | ||
}, | ||
|
||
createAnchor: async function createAnchor (position, quaternion) { | ||
var sceneEl = this.el.sceneEl; | ||
var xrManager = sceneEl.renderer.xr; | ||
var frame; | ||
var referenceSpace; | ||
var anchorPose; | ||
var anchor; | ||
|
||
if (!anchorsSupported(sceneEl)) { | ||
warn('This browser doesn\'t support the WebXR anchors module'); | ||
return; | ||
} | ||
|
||
if (this.anchor) { this.deleteAnchor(); } | ||
|
||
frame = sceneEl.frame; | ||
referenceSpace = xrManager.getReferenceSpace(); | ||
anchorPose = new XRRigidTransform( | ||
{ | ||
x: position.x, | ||
y: position.y, | ||
z: position.z | ||
}, | ||
{ | ||
x: quaternion.x, | ||
y: quaternion.y, | ||
z: quaternion.z, | ||
w: quaternion.w | ||
}); | ||
anchor = await frame.createAnchor(anchorPose, referenceSpace); | ||
if (this.data.persistent) { | ||
if (this.el.id) { | ||
this.persistentHandle = await anchor.requestPersistentHandle(); | ||
localStorage.setItem(this.el.id, this.persistentHandle); | ||
} else { | ||
warn('The anchor won\'t be persisted because the entity has no assigned id.'); | ||
} | ||
} | ||
sceneEl.object3D.attach(this.el.object3D); | ||
this.anchor = anchor; | ||
}, | ||
|
||
restorePersistentAnchor: async function restorePersistentAnchor () { | ||
var xrManager = this.el.sceneEl.renderer.xr; | ||
var session = xrManager.getSession(); | ||
var persistentAnchors = session.persistentAnchors; | ||
var storedPersistentHandle; | ||
this.requestPersistentAnchorPending = false; | ||
if (!this.el.id) { | ||
warn('The entity associated to the persistent anchor cannot be retrieved because it doesn\'t have an assigned id.'); | ||
return; | ||
} | ||
if (persistentAnchors.length) { | ||
storedPersistentHandle = localStorage.getItem(this.el.id); | ||
for (var i = 0; i < persistentAnchors.length; ++i) { | ||
if (storedPersistentHandle !== persistentAnchors[i]) { continue; } | ||
this.anchor = await session.restorePersistentAnchor(persistentAnchors[i]); | ||
this.persistentHandle = persistentAnchors[i]; | ||
break; | ||
} | ||
} else { | ||
this.requestPersistentAnchorPending = true; | ||
} | ||
}, | ||
|
||
deleteAnchor: function () { | ||
var xrManager; | ||
var session; | ||
var anchor = this.anchor; | ||
|
||
if (!anchor) { return; } | ||
xrManager = this.el.sceneEl.renderer.xr; | ||
session = xrManager.getSession(); | ||
|
||
anchor.delete(); | ||
this.el.sceneEl.object3D.add(this.el.object3D); | ||
if (this.persistentHandle) { session.deletePersistentAnchor(this.persistentHandle); } | ||
this.anchor = undefined; | ||
} | ||
}); | ||
|
||
function anchorsSupported (sceneEl) { | ||
var xrManager = sceneEl.renderer.xr; | ||
var session = xrManager.getSession(); | ||
return (session && session.restorePersistentAnchor); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
require('./animation'); | ||
require('./anchored'); | ||
require('./camera'); | ||
require('./cursor'); | ||
require('./geometry'); | ||
|