Reputation: 15622
From the code on my previous answer, I get a WebVR page that works fine in Desktop but in the mobile phone I'm not able to go closer to the model (looks more like a skybox).
Would like to be able to go towards / away from the model (using two fingers going, respectively, away from each other or closer), apart from looking around.
After some searching, found an example of where this functionality I look for is used.
How can I get that same mobile functionality working for my case?
Upvotes: 0
Views: 143
Reputation: 14655
If you want your experience to revolve around a model, moving the camera around it, and zooming in and out - I'd say the orbit controls are exacly what You're looking for:
<a-entity camera look-controls
orbit-controls="target: 0 1.6 -0.5; initialPosition: 0 5 15"></a-entity>
The camera will move around the defined target
. Works with mobile touch events.
Check it out with gltf
models here.
If you want to move the camera towars or away the direction it's looking at, as far as i know, You'll have to implement such behavior in a custom component. A poor mans version could look a bit like this:
AFRAME.registerComponent('pinch-controls', {
init: function() {
// moveCamera uses variables from 'this' scope
this.moveCamera.bind(this);
// we'll use this to get the 'pinch direction'
this.distance = 0;
// we'll keep here the camera's current direction
this.direction = new THREE.Vector3();
// camera entity reference
this.camera = document.querySelector("[camera]");
// listeners
document.body.addEventListener('touchstart', event => {
// we're interested only in two - finger pinches
if (event.touches.length != 2) return 0;
// calculate the distance
this.distance = this.calculatePinchDistance(event);
// we don't want the touch to rotate the camera around
this.el.setAttribute('look-controls', 'touchEnabled', false);
}, false);
document.body.addEventListener('touchend', event => {
// when the pinch ends - restore the look-controls
if (event.touches.length != 1) this.el.setAttribute('look-controls', 'touchEnabled', true);
}, false);
document.body.addEventListener('touchmove', event => {
// we're interested only in two - finger pinches
if (event.touches.length != 2) return 0;
// compare the distances to determine which direction should we move
var distance = this.calculatePinchDistance(event);
let speed = (distance < this.distance) ? -0.2 : 0.2;
this.moveCamera(speed);
// keep the distance for the next callback
this.distance = distance;
}, false);
},
calculatePinchDistance(event) {
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
return Math.sqrt(dx * dx + dy * dy);
},
moveCamera: function(speed) {
// get the camera direction, and multiply it by the desired 'speed'
this.el.sceneEl.camera.getWorldDirection(this.direction);
this.direction.multiplyScalar(speed);
// apply the change to the actual position
var pos = this.el.getAttribute("position");
pos.add(this.direction);
this.el.setAttribute("position", pos);
}
}
// HTML
// <a-entity camera look-controls pinch-controls></a-entity>
Check it out here
If you want to move the camera towards the model (instead of the direction it's facing), you can just replace extracting the camera direction (in moveCamera
) with calculating the camera <-> model direction:
// instead of
// this.el.sceneEl.camera.getWorldDirection(this.direction);
// grab the direction towards the model
this.direction.copy(this.el.object3D.position)
this.direction.add(modelReference.object3D.position)
this.direction.normalize();
// (...)
The final code used was
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Octant Cube - by Dodds, H. & Peres, T.</title>
<meta name="description" content="Present in the Taxonomy article">
<script src="https://kit.fontawesome.com/c9500776a0.js" crossorigin="anonymous"></script>
<script src="misc/codeBtn.js"></script>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/aframe-orbit-controls.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/aframe-supercraft-loader.js"></script>
<style>
#toggleBtn {
position: fixed;
z-index: 9999;
margin: 25px;
font-size: 3em;
color: rgb(128, 0, 128);
cursor: pointer;
}
#toggleBtn:hover {
color: rgba(128, 0, 128, 0.6);
}
</style>
<script>
// Models swap component
AFRAME.registerComponent('content-manager', {
init: function() {
const btn = document.querySelector("#toggleBtn")
const castle = document.querySelector("#castle")
const fish = document.querySelector("#fish")
btn.addEventListener("click", e => {
if (castle.getAttribute("visible")) {
castle.emit("fadeOut")
btn.classList.remove("fa-fish")
btn.classList.add("fa-landmark")
} else {
fish.emit("fadeOut")
btn.classList.remove("fa-landmark")
btn.classList.add("fa-fish")
}
})
fish.addEventListener('animationcomplete__fadeout', e => {
fish.setAttribute("visible", "false")
castle.setAttribute("visible", "true")
castle.emit("fadeIn")
})
castle.addEventListener('animationcomplete__fadeout', e => {
castle.setAttribute("visible", "false")
fish.setAttribute("visible", "true")
fish.emit("fadeIn")
})
}
})
// move the camera on pinching
AFRAME.registerComponent('pinch-controls', {
init: function() {
// bind the methods that use the scope variables
this.moveCamera.bind(this);
// use this to keep track whether the user is moving forward or backwards
this.distance = 0;
// store the camera direction here
this.direction = new THREE.Vector3();
// camera entity reference
this.camera = document.querySelector("[camera]");
document.body.addEventListener('touchstart', event => {
// react only on two finger pinches
if (event.touches.length != 2) return 0;
this.distance = this.calculatePinchDistance(event);
// prevent the look controls to rotate the camera while pinching
this.el.setAttribute('look-controls', 'touchEnabled', false);
}, false);
document.body.addEventListener('touchend', event => {
// restore the look-controls
if (event.touches.length != 1) this.el.setAttribute('look-controls', 'touchEnabled', true)
}, false);
document.body.addEventListener('wheel', e => {
this.moveCamera(e.deltaY < 0 ? -0.2 : 0.2);
})
document.body.addEventListener('touchmove', event => {
// we're interested only in pinching
if (event.touches.length != 2) return 0;
// calculate the pinch difference and move the camera
var distance = this.calculatePinchDistance(event);
let multiplier = (distance < this.distance) ? -0.2 : 0.2;;
if (!isNaN(multiplier)) this.moveCamera(multiplier);
// for later use
this.distance = distance;
}, false);
},
calculatePinchDistance: function(mouseEvent) {
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
return Math.sqrt(dx * dx + dy * dy);
},
moveCamera: function(speed) {
this.el.sceneEl.camera.getWorldDirection(this.direction);
this.direction.multiplyScalar(speed);
var pos = this.el.getAttribute("position");
pos.add(this.direction);
this.el.setAttribute("position", pos)
}
})
</script>
</head>
<body>
<a-scene background="color: #FAFAFA">
<a-assets>
<a-asset-item id="octant" src="octant.glb"></a-asset-item>
</a-assets>
<a-entity position="0 0.347 -4" rotation="0 60 -1" gltf-model="#octant" scale="5 5 5" animation__fadeIn="property: scale; dur: 150; from: 0.001 0.001 0.001; to: 0.5 0.5 0.5; easing: easeInQuad; startEvents: fadeIn" animation__fadeOut="property: scale; dur: 150; from: 0.5 0.5 0.5; to: 0.001 0.001 0.001; easing: easeInQuad; startEvents: fadeOut"></a-entity>
<a-entity camera look-controls
orbit-controls="target: 0 1.6 -0.5; initialPosition: 0 5 15"></a-entity>
</a-scene>
</body>
</html>
And this was the final result
Upvotes: 2