Skip to content

Commit

Permalink
Make aframe work with WebVR APIs 1.0 (aframevr#1423)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmarcos committed May 11, 2016
1 parent aca880d commit 1279ac5
Show file tree
Hide file tree
Showing 19 changed files with 859 additions and 209 deletions.
10 changes: 5 additions & 5 deletions docs/core/scene.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ The scene inherits from the [`Entity`][entity] class so it inherits all of its p

| Name | Description |
|---------|------------------------------------------------------------------------------------------------------------------------|
| enterVR | Switch to stereo renderer and enter fullscreen. Needs to be called within a user-generated event handler like `click`. |
| exitVR | Switch to mono renderer and exit fullscreen. |
| enterVR | Switch to stereo render and push content to the headset. Needs to be called within a user-generated event handler like `click`. the first time a page enters VR. |
| exitVR | Switch to mono renderer and stops presenting content on the headset. |
| reload | Revert the scene to its original state. |

## Events

| Name | Description |
|--------------|-------------------------------------|
| enter-vr | User has entered VR and fullscreen. |
| exit-vr | User has exited VR and fullscreen. |
| loaded | All nodes have loaded. |
| enter-vr | User has entered VR and headset started presenting content. |
| exit-vr | User has exited VR and headset stopped presenting content. |
| loaded | All nodes have loaded. |
| render-start | Render loop has started. |

## Scene Components
Expand Down
58 changes: 58 additions & 0 deletions examples/test/iframe/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>IFRAME</title>
<meta name="description" content="Scene contained in an iframe - A-Frame">
<script src="../../../dist/aframe.js"></script>
<style>
body {
background-color: black;
height: 100%;
margin: 0;
overflow: hidden;
padding: 0;
width: 100%;
}
iframe {
width: 100%;
height: 100%;
}

.enter-vr {
background-size: 70% 70%;
border: 0;
right: 50px;
bottom: 50px;
cursor: pointer;
height: 50px;
position: absolute;
border-radius: 6px;
transition: background-color .05s ease;
-webkit-transition: background-color .05s ease;
width: 100px;
z-index: 999999;
}

.enter-vr:hover {
background-color: #249889;
color: white;
}
</style>
</head>
<body>
<iframe id="aframe" src="/examples/animation/aframe-logo/?ui=false"></iframe>
<button class="enter-vr">ENTER VR</button>
</body>
<script>
var buttonEl = document.querySelector('.enter-vr');
var iframeWindow = document.querySelector('#aframe').contentWindow;
buttonEl.addEventListener('click', handleClick);
function handleClick() {
iframeWindow.postMessage({
type: 'vr',
data: 'enter'
}, '*');
}
</script>
</html>
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
"object-assign": "^4.0.1",
"present": "0.0.6",
"style-attr": "^1.0.2",
"three": "^0.75.0",
"three": "^0.76.1",
"tween.js": "^15.0.0",
"webvr-polyfill": "borismus/webvr-polyfill#3f47796"
"webvr-polyfill": "borismus/webvr-polyfill#f45f87a"
},
"devDependencies": {
"browserify": "^11.0.1",
Expand Down
131 changes: 73 additions & 58 deletions src/components/look-controls.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,42 @@
var registerComponent = require('../core/component').registerComponent;
var THREE = require('../lib/three');
var isMobile = require('../utils/').isMobile();

// To avoid recalculation at every mouse movement tick
var PI_2 = Math.PI / 2;
var radToDeg = THREE.Math.radToDeg;

module.exports.Component = registerComponent('look-controls', {
dependencies: ['position', 'rotation'],

schema: {
enabled: { default: true }
enabled: { default: true },
hmdEnabled: { default: true },
standing: { default: true }
},

init: function () {
this.previousPosition = new THREE.Vector3();
this.deltaPosition = new THREE.Vector3();
this.previousHMDPosition = new THREE.Vector3();
this.setupMouseControls();
this.setupHMDControls();
this.bindMethods();
},

update: function () {
if (!this.data.enabled) { return; }
update: function (oldData) {
var data = this.data;
var hmdEnabled = data.hmdEnabled;
if (!data.enabled) { return; }
if (!hmdEnabled && oldData && hmdEnabled !== oldData.hmdEnabled) {
this.pitchObject.rotation.set(0, 0, 0);
this.yawObject.rotation.set(0, 0, 0);
}
this.controls.standing = data.standing;
this.controls.update();
this.updateOrientation();
this.updatePosition();
},

play: function () {
this.previousPosition.set(0, 0, 0);
this.addEventListeners();
},

Expand Down Expand Up @@ -65,7 +74,6 @@ module.exports.Component = registerComponent('look-controls', {
this.dolly = new THREE.Object3D();
this.euler = new THREE.Euler();
this.controls = new THREE.VRControls(this.dolly);
this.zeroQuaternion = new THREE.Quaternion();
},

addEventListeners: function () {
Expand Down Expand Up @@ -109,75 +117,78 @@ module.exports.Component = registerComponent('look-controls', {

updateOrientation: (function () {
var hmdEuler = new THREE.Euler();
hmdEuler.order = 'YXZ';
return function () {
var pitchObject = this.pitchObject;
var yawObject = this.yawObject;
var hmdQuaternion = this.calculateHMDQuaternion();
hmdEuler.setFromQuaternion(hmdQuaternion);
this.el.setAttribute('rotation', {
x: THREE.Math.radToDeg(hmdEuler.x) + THREE.Math.radToDeg(pitchObject.rotation.x),
y: THREE.Math.radToDeg(hmdEuler.y) + THREE.Math.radToDeg(yawObject.rotation.y),
z: THREE.Math.radToDeg(hmdEuler.z)
});
var sceneEl = this.el.sceneEl;
var rotation;
hmdEuler.setFromQuaternion(hmdQuaternion, 'YXZ');
if (!sceneEl.is('vr-mode') || isNullVector(hmdEuler) || !this.data.hmdEnabled) {
// Mouse look only if HMD disabled or no info coming from the sensors
rotation = {
x: radToDeg(pitchObject.rotation.x),
y: radToDeg(yawObject.rotation.y),
z: 0
};
} else {
if (isMobile) {
// In mobile we allow camera rotation with touch events and sensors
rotation = {
x: radToDeg(hmdEuler.x) + radToDeg(pitchObject.rotation.x),
y: radToDeg(hmdEuler.y) + radToDeg(yawObject.rotation.y),
z: radToDeg(hmdEuler.z)
};
} else {
// Mouse rotation ignored with an active headset.
// The user head rotation takes priority
rotation = {
x: radToDeg(hmdEuler.x),
y: radToDeg(hmdEuler.y),
z: radToDeg(hmdEuler.z)
};
}
}
this.el.setAttribute('rotation', rotation);
};
})(),

calculateHMDQuaternion: (function () {
var hmdQuaternion = new THREE.Quaternion();
return function () {
var dolly = this.dolly;
if (!this.zeroed && !dolly.quaternion.equals(this.zeroQuaternion)) {
this.zeroOrientation();
this.zeroed = true;
}
hmdQuaternion.copy(this.zeroQuaternion).multiply(dolly.quaternion);
hmdQuaternion.copy(this.dolly.quaternion);
return hmdQuaternion;
};
})(),

updatePosition: function () {
var el = this.el;
var deltaPosition = this.calculateDeltaPosition();
var currentPosition = el.getComputedAttribute('position');
el.setAttribute('position', {
x: currentPosition.x + deltaPosition.x,
y: currentPosition.y + deltaPosition.y,
z: currentPosition.z + deltaPosition.z
});
},

calculateDeltaPosition: function () {
var dolly = this.dolly;
var deltaPosition = this.deltaPosition;
var previousPosition = this.previousPosition;
deltaPosition.copy(dolly.position);
deltaPosition.sub(previousPosition);
previousPosition.copy(dolly.position);
return deltaPosition;
},

updateHMDQuaternion: (function () {
var hmdQuaternion = new THREE.Quaternion();
updatePosition: (function () {
var deltaHMDPosition = new THREE.Vector3();
return function () {
var dolly = this.dolly;
this.controls.update();
if (!this.zeroed && !dolly.quaternion.equals(this.zeroQuaternion)) {
this.zeroOrientation();
this.zeroed = true;
}
hmdQuaternion.copy(this.zeroQuaternion).multiply(dolly.quaternion);
return hmdQuaternion;
var el = this.el;
var currentPosition = el.getComputedAttribute('position');
var currentHMDPosition;
var previousHMDPosition = this.previousHMDPosition;
var sceneEl = this.el.sceneEl;
currentHMDPosition = this.calculateHMDPosition();
deltaHMDPosition.copy(currentHMDPosition).sub(previousHMDPosition);
if (!sceneEl.is('vr-mode') || isNullVector(deltaHMDPosition)) { return; }
previousHMDPosition.copy(currentHMDPosition);
// Do nothing if we have not moved.
if (!sceneEl.is('vr-mode')) { return; }
el.setAttribute('position', {
x: currentPosition.x + deltaHMDPosition.x,
y: currentPosition.y + deltaHMDPosition.y,
z: currentPosition.z + deltaHMDPosition.z
});
};
})(),

zeroOrientation: function () {
var euler = new THREE.Euler();
euler.setFromQuaternion(this.dolly.quaternion.clone().inverse());
// Cancel out roll and pitch. We want to only reset yaw
euler.z = 0;
euler.x = 0;
this.zeroQuaternion.setFromEuler(euler);
calculateHMDPosition: function () {
var dolly = this.dolly;
var position = new THREE.Vector3();
dolly.updateMatrix();
position.setFromMatrixPosition(dolly.matrix);
return position;
},

onMouseMove: function (event) {
Expand Down Expand Up @@ -237,3 +248,7 @@ module.exports.Component = registerComponent('look-controls', {
this.touchStarted = false;
}
});

function isNullVector (vector) {
return vector.x === 0 && vector.y === 0 && vector.z === 0;
}
4 changes: 4 additions & 0 deletions src/components/scene/keyboard-shortcuts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var controls = new THREE.VRControls(new THREE.Object3D());
module.exports.Component = registerComponent('keyboard-shortcuts', {
schema: {
enterVR: { default: true },
exitVR: { default: true },
resetSensor: { default: true }
},

Expand All @@ -19,6 +20,9 @@ module.exports.Component = registerComponent('keyboard-shortcuts', {
if (self.enterVREnabled && event.keyCode === 70) { // f.
scene.enterVR();
}
if (self.enterVREnabled && event.keyCode === 27) { // escape.
scene.exitVR();
}
if (self.resetSensorEnabled && event.keyCode === 90) { // z.
controls.resetSensor();
}
Expand Down
10 changes: 7 additions & 3 deletions src/components/scene/vr-mode-ui.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var registerComponent = require('../../core/component').registerComponent;
var THREE = require('../../lib/three');
var utils = require('../../utils/');
var queryParams = utils.queryParams;

var dummyDolly = new THREE.Object3D();
var controls = new THREE.VRControls(dummyDolly);
Expand All @@ -27,6 +28,8 @@ module.exports.Component = registerComponent('vr-mode-ui', {
var self = this;
var scene = this.el;

if (queryParams.ui === 'false') { return; }

this.enterVR = scene.enterVR.bind(scene);
this.exitVR = scene.exitVR.bind(scene);
this.insideLoader = false;
Expand All @@ -51,7 +54,9 @@ module.exports.Component = registerComponent('vr-mode-ui', {
update: function () {
var scene = this.el;

if (!this.data.enabled || this.insideLoader) { return this.remove(); }
if (!this.data.enabled || this.insideLoader || queryParams.ui === 'false') {
return this.remove();
}
if (this.enterVREl || this.orientationModalEl) { return; }

// Add UI if enabled and not already present.
Expand Down Expand Up @@ -120,8 +125,7 @@ function createEnterVR (enterVRHandler, isMobile) {
var compatModal;
var compatModalLink;
var compatModalText;
// window.hasNonPolyfillWebVRSupport is set in src/index.js.
var hasWebVR = isMobile || window.hasNonPolyfillWebVRSupport;
var hasWebVR = isMobile || window.hasNativeWebVRImplementation;
var orientation;
var vrButton;
var wrapper;
Expand Down
Loading

0 comments on commit 1279ac5

Please sign in to comment.