Three.js 以椭圆形旋转相机
Three.js rotating the camera in elliptical shape
我想让我的相机 perspectiveCamera
围绕椭圆形或矩形的场景旋转。我似乎想不出一种方法让相机在碰到边缘时自动缩小,这样场景就不会被切断。
出于可视化目的,我非常想要 this effect
我一整天都在尝试硬编码位置(这不是正确的解决方案)我做不到。
一个非常粗略的曲线概念(鼠标事件的代码取自here):
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(10, 10, -10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
scene.add(new THREE.GridHelper(20, 20, 0x404040, 0x404040));
// island
var boxGeo = new THREE.BoxBufferGeometry();
boxGeo.translate(0, 0.5, 0);
var boxMat = new THREE.MeshLambertMaterial({
color: 0x909090
});
for (let x = -5; x < 6; x++) {
for (let y = -3; y < 4; y++) {
let box = new THREE.Mesh(boxGeo, boxMat);
box.scale.y = THREE.Math.randInt(1, 3);
box.position.set(x - 0.5, 0, y - 0.5);
scene.add(box);
let edgesGeo = new THREE.EdgesGeometry(boxGeo);
let edges = new THREE.LineSegments(edgesGeo, new THREE.LineBasicMaterial({
color: 0xaaaaaa
}));
box.add(edges);
}
}
//path
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(0, 6, 6),
new THREE.Vector3(12, 6, 0),
new THREE.Vector3(0, 6, -6),
new THREE.Vector3(-12, 6, 0)
])
curve.closed = true;
curve.getPoint(0, camera.position);
camera.lookAt(scene.position);
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var currentPoint = 0;
var currPoint = 0;
document.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event) {
event.preventDefault();
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
document.addEventListener('mouseout', onDocumentMouseOut, false);
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
currPoint = (targetRotation - targetRotationOnMouseDown) * 0.05;
}
function onDocumentMouseUp(event) {
document.removeEventListener('mousemove', onDocumentMouseMove, false);
document.removeEventListener('mouseup', onDocumentMouseUp, false);
document.removeEventListener('mouseout', onDocumentMouseOut, false);
}
function onDocumentMouseOut(event) {
document.removeEventListener('mousemove', onDocumentMouseMove, false);
document.removeEventListener('mouseup', onDocumentMouseUp, false);
document.removeEventListener('mouseout', onDocumentMouseOut, false);
}
render();
function render() {
requestAnimationFrame(render);
curve.getPoint(currPoint, camera.position);
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
@prisoner849 的某些问题的副本已修复 已修复的某些定义。
想过只是编辑那个答案,但认为我做了太多改变。如果这不合适,很高兴将其删除
修复不连续错误
删除对 window 尺寸的依赖
使代码句柄调整大小
处理鼠标捕获
注意:从 v69 开始,鼠标捕获在 Chrome 上的 iframe 中不起作用,在此处实现的 Safari 中也不起作用。它确实适用于 Firefox。换句话说,单击图像,将 拖到 window 之外。如果您是 iframe,您将在拖出框架后立即停止获取事件。如果您是顶级框架,您将继续在 window.
之外获取事件事件
这有很多问题。
如果您保持代码不变,并且您在 iframe 中,那么如果用户
在 iframe 中单击并拖动,将鼠标移出 iframe,然后
松开鼠标按钮,拖动将卡在鼠标上,直到
用户在框架中单击(mouseup 事件永远不会到达)
一个解决方案是向 mouseout
添加一个侦听器以删除所有
听众。该解决方案的问题是一旦鼠标
触摸 iframe 的边缘或 window 鼠标断开连接
拖动这是一个糟糕的用户体验。
另一种可能的解决方案是仅在 mouseout 时断开鼠标
在 iframe 中,但仍然存在问题,即一旦用户
离开 iframe 鼠标断开连接,即使他们不松手
鼠标并最终拖回到框架中
检查其他站点,大多数站点似乎都选择只让鼠标
陷入拖动模式(嵌入式 google 地图将此行为显示为
three.js 相机控制作为两个例子)。
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
var canvas = renderer.domElement
document.body.appendChild(canvas);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(10, 10, -10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
scene.add(new THREE.GridHelper(20, 20, 0x404040, 0x404040));
// island
var boxGeo = new THREE.BoxBufferGeometry();
boxGeo.translate(0, 0.5, 0);
var boxMat = new THREE.MeshLambertMaterial({
color: 0x909090
});
for (let x = -5; x < 6; x++) {
for (let y = -3; y < 4; y++) {
let box = new THREE.Mesh(boxGeo, boxMat);
box.scale.y = THREE.Math.randInt(1, 3);
box.position.set(x - 0.5, 0, y - 0.5);
scene.add(box);
let edgesGeo = new THREE.EdgesGeometry(boxGeo);
let edges = new THREE.LineSegments(edgesGeo, new THREE.LineBasicMaterial({
color: 0xaaaaaa
}));
box.add(edges);
}
}
//path
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(0, 6, 6),
new THREE.Vector3(12, 6, 0),
new THREE.Vector3(0, 6, -6),
new THREE.Vector3(-12, 6, 0)
])
curve.closed = true;
curve.getPoint(0, camera.position);
camera.lookAt(scene.position);
var mouseXOnMouseDown = 0;
var currPoint = 0;
var currPointOnMouseDown = 0;
canvas.addEventListener('mousedown', onCanvasMouseDown, true);
function onCanvasMouseDown(event) {
event.preventDefault();
event.stopPropagation();
window.addEventListener('mousemove', onDocumentMouseMove, true);
window.addEventListener('mouseup', removeListeners, true);
mouseXOnMouseDown = event.clientX;
currPointOnMouseDown = currPoint;
}
function onDocumentMouseMove(event) {
event.preventDefault();
event.stopPropagation();
var deltaMouseX = event.clientX - mouseXOnMouseDown;
currPoint = THREE.Math.euclideanModulo(currPointOnMouseDown + deltaMouseX * 0.0005, 1);
}
function removeListeners() {
window.removeEventListener('mousemove', onDocumentMouseMove, true);
window.removeEventListener('mouseup', removeListeners, true);
}
render();
function resize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resize(renderer)) {
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
curve.getPoint(currPoint, camera.position);
camera.lookAt(scene.position);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
html, body {
height: 100%;
margin: 0;
}
canvas {
width: 100%;
height: 100%;
display; block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
我想让我的相机 perspectiveCamera
围绕椭圆形或矩形的场景旋转。我似乎想不出一种方法让相机在碰到边缘时自动缩小,这样场景就不会被切断。
出于可视化目的,我非常想要 this effect
我一整天都在尝试硬编码位置(这不是正确的解决方案)我做不到。
一个非常粗略的曲线概念(鼠标事件的代码取自here):
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(10, 10, -10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
scene.add(new THREE.GridHelper(20, 20, 0x404040, 0x404040));
// island
var boxGeo = new THREE.BoxBufferGeometry();
boxGeo.translate(0, 0.5, 0);
var boxMat = new THREE.MeshLambertMaterial({
color: 0x909090
});
for (let x = -5; x < 6; x++) {
for (let y = -3; y < 4; y++) {
let box = new THREE.Mesh(boxGeo, boxMat);
box.scale.y = THREE.Math.randInt(1, 3);
box.position.set(x - 0.5, 0, y - 0.5);
scene.add(box);
let edgesGeo = new THREE.EdgesGeometry(boxGeo);
let edges = new THREE.LineSegments(edgesGeo, new THREE.LineBasicMaterial({
color: 0xaaaaaa
}));
box.add(edges);
}
}
//path
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(0, 6, 6),
new THREE.Vector3(12, 6, 0),
new THREE.Vector3(0, 6, -6),
new THREE.Vector3(-12, 6, 0)
])
curve.closed = true;
curve.getPoint(0, camera.position);
camera.lookAt(scene.position);
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var currentPoint = 0;
var currPoint = 0;
document.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event) {
event.preventDefault();
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
document.addEventListener('mouseout', onDocumentMouseOut, false);
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
currPoint = (targetRotation - targetRotationOnMouseDown) * 0.05;
}
function onDocumentMouseUp(event) {
document.removeEventListener('mousemove', onDocumentMouseMove, false);
document.removeEventListener('mouseup', onDocumentMouseUp, false);
document.removeEventListener('mouseout', onDocumentMouseOut, false);
}
function onDocumentMouseOut(event) {
document.removeEventListener('mousemove', onDocumentMouseMove, false);
document.removeEventListener('mouseup', onDocumentMouseUp, false);
document.removeEventListener('mouseout', onDocumentMouseOut, false);
}
render();
function render() {
requestAnimationFrame(render);
curve.getPoint(currPoint, camera.position);
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
@prisoner849 的某些问题的副本已修复 已修复的某些定义。 想过只是编辑那个答案,但认为我做了太多改变。如果这不合适,很高兴将其删除
修复不连续错误
删除对 window 尺寸的依赖
使代码句柄调整大小
处理鼠标捕获
注意:从 v69 开始,鼠标捕获在 Chrome 上的 iframe 中不起作用,在此处实现的 Safari 中也不起作用。它确实适用于 Firefox。换句话说,单击图像,将 拖到 window 之外。如果您是 iframe,您将在拖出框架后立即停止获取事件。如果您是顶级框架,您将继续在 window.
之外获取事件事件这有很多问题。
如果您保持代码不变,并且您在 iframe 中,那么如果用户 在 iframe 中单击并拖动,将鼠标移出 iframe,然后 松开鼠标按钮,拖动将卡在鼠标上,直到 用户在框架中单击(mouseup 事件永远不会到达)
一个解决方案是向
mouseout
添加一个侦听器以删除所有 听众。该解决方案的问题是一旦鼠标 触摸 iframe 的边缘或 window 鼠标断开连接 拖动这是一个糟糕的用户体验。另一种可能的解决方案是仅在 mouseout 时断开鼠标 在 iframe 中,但仍然存在问题,即一旦用户 离开 iframe 鼠标断开连接,即使他们不松手 鼠标并最终拖回到框架中
检查其他站点,大多数站点似乎都选择只让鼠标 陷入拖动模式(嵌入式 google 地图将此行为显示为 three.js 相机控制作为两个例子)。
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
var canvas = renderer.domElement
document.body.appendChild(canvas);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(10, 10, -10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
scene.add(new THREE.GridHelper(20, 20, 0x404040, 0x404040));
// island
var boxGeo = new THREE.BoxBufferGeometry();
boxGeo.translate(0, 0.5, 0);
var boxMat = new THREE.MeshLambertMaterial({
color: 0x909090
});
for (let x = -5; x < 6; x++) {
for (let y = -3; y < 4; y++) {
let box = new THREE.Mesh(boxGeo, boxMat);
box.scale.y = THREE.Math.randInt(1, 3);
box.position.set(x - 0.5, 0, y - 0.5);
scene.add(box);
let edgesGeo = new THREE.EdgesGeometry(boxGeo);
let edges = new THREE.LineSegments(edgesGeo, new THREE.LineBasicMaterial({
color: 0xaaaaaa
}));
box.add(edges);
}
}
//path
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(0, 6, 6),
new THREE.Vector3(12, 6, 0),
new THREE.Vector3(0, 6, -6),
new THREE.Vector3(-12, 6, 0)
])
curve.closed = true;
curve.getPoint(0, camera.position);
camera.lookAt(scene.position);
var mouseXOnMouseDown = 0;
var currPoint = 0;
var currPointOnMouseDown = 0;
canvas.addEventListener('mousedown', onCanvasMouseDown, true);
function onCanvasMouseDown(event) {
event.preventDefault();
event.stopPropagation();
window.addEventListener('mousemove', onDocumentMouseMove, true);
window.addEventListener('mouseup', removeListeners, true);
mouseXOnMouseDown = event.clientX;
currPointOnMouseDown = currPoint;
}
function onDocumentMouseMove(event) {
event.preventDefault();
event.stopPropagation();
var deltaMouseX = event.clientX - mouseXOnMouseDown;
currPoint = THREE.Math.euclideanModulo(currPointOnMouseDown + deltaMouseX * 0.0005, 1);
}
function removeListeners() {
window.removeEventListener('mousemove', onDocumentMouseMove, true);
window.removeEventListener('mouseup', removeListeners, true);
}
render();
function resize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resize(renderer)) {
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
curve.getPoint(currPoint, camera.position);
camera.lookAt(scene.position);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
html, body {
height: 100%;
margin: 0;
}
canvas {
width: 100%;
height: 100%;
display; block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>