走向或远离移动中的模型
Go towards or away from the model in mobile
从 ,我得到一个 WebVR 页面,它在桌面上运行良好,但在移动设备上运行良好 phone 我无法靠近模型(看起来更像天空盒) .
除了环顾四周,还希望能够走向/远离模型(分别用两根手指远离或靠近)。
经过一番搜索,找到了 an example 我要查找的此功能的使用位置。
我怎样才能让相同的移动功能适用于我的案例?
1) 轨道控制
如果您希望您的体验围绕模型旋转、围绕模型移动相机并放大和缩小 - 我会说 orbit controls 正是您要找的东西:
<a-entity camera look-controls
orbit-controls="target: 0 1.6 -0.5; initialPosition: 0 5 15"></a-entity>
摄像机将围绕定义的 target
移动。适用于移动触摸事件。
用 gltf
个模型 here.
检查一下
2) 捏合移动相机
如果您想将相机移向或移开它所注视的方向,据我所知,您必须在自定义组件中实现此类行为。穷人版本可能看起来有点像这样:
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>
看看here
如果您想将相机移向模型(而不是它所面对的方向),您只需将提取相机方向(在 moveCamera
中)替换为计算相机 <-> 模型方向:
// 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();
// (...)
蒂亚戈编辑:
最终使用的代码是
<!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/aframe-orbit-controls@1.2.0/dist/aframe-orbit-controls.min.js"></script>
<script src="https://unpkg.com/aframe-supercraft-loader@1.1.3/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>
这就是最终结果
从
除了环顾四周,还希望能够走向/远离模型(分别用两根手指远离或靠近)。
经过一番搜索,找到了 an example 我要查找的此功能的使用位置。
我怎样才能让相同的移动功能适用于我的案例?
1) 轨道控制
如果您希望您的体验围绕模型旋转、围绕模型移动相机并放大和缩小 - 我会说 orbit controls 正是您要找的东西:
<a-entity camera look-controls
orbit-controls="target: 0 1.6 -0.5; initialPosition: 0 5 15"></a-entity>
摄像机将围绕定义的 target
移动。适用于移动触摸事件。
用 gltf
个模型 here.
2) 捏合移动相机
如果您想将相机移向或移开它所注视的方向,据我所知,您必须在自定义组件中实现此类行为。穷人版本可能看起来有点像这样:
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>
看看here
如果您想将相机移向模型(而不是它所面对的方向),您只需将提取相机方向(在 moveCamera
中)替换为计算相机 <-> 模型方向:
// 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();
// (...)
蒂亚戈编辑:
最终使用的代码是
<!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/aframe-orbit-controls@1.2.0/dist/aframe-orbit-controls.min.js"></script>
<script src="https://unpkg.com/aframe-supercraft-loader@1.1.3/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>
这就是最终结果