I am trying to get my camera perspectiveCamera
to rotate around a scene that is elliptical or rectangular in shape. I cant seem to figure out a way to get the camera to automatically zoom out when it hits an edge so that the scene doesn't get cut off.
for visualization purposes I want pretty much this effect
I've been trying all day and short of hardcoding positions (which can't be the right solution) I'm falling short.
Copy of @prisoner849's with certain issues fixed for some definition of fixed. Thought about just editing that answer but thought I was making too many changes. Happy to take this down if this is inappropriate
Fix discontinuity bug
Remove dependency on window size
Make code handle resize
Handle mouse capture
note: mouse capture doesn't work in an iframe on Chrome as of v69, nor Safari as implemented here. It does work in Firefox. In other words, click on the image, drag outside the window. If you're an iframe you'll stop getting events as soon as you drag outside the frame. If you're the top level frame you'll continue to get events event outside the window.
This has a bunch of issues.
If you leave the code as is the and you're in an iframe then if the user clicks and drags in the iframe, moves the mouse out of the iframe and then lets off the mouse button the dragging will be stuck to the mouse until the user clicks in the frame (the mouseup event never arrives)
One solution to that is to add a listener to mouseout
to remove all
the listeners. The problem with that solution is as soon as the mouse
touches the edge of the iframe or the window the mouse disconnects from
dragging which is a horrible UX.
One other possible solution is to only disconnect the mouse on mouseout in an iframe but that still has the issue that as soon as the user goes out of the iframe the mouse disconnects even if they don't let off the mouse and end up dragging back into the frame
checking other sites it appears most sites choose to just let the mouse get stuck in dragging mode (embedded google maps shows this behavior as does the three.js camera controls as two examples).
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>