I’m using ArcRotateCamera in a project that can switch between perspective and orthographic modes.
When in perspective, using the mouse wheel or trackpad to zoom the camera feels great. We can tune the sensitivity and it seems to animate the input when starting or stopping a zoom. I’d like to get mouse wheel input working in a simular way in orthographic mode.
I made a playground that can switch between the two modes (default is orthographic).
Use the mouse wheel or trackpad to zoom the camera
Switch modes to see the difference in feeling between the two modes. Scrolling in orthographic mode doesn’t feel as natural as it does in perspective mode.
My hack to get orthographic mode to feel like it is scrolling is to resize the orthographic bounds based on a scaler (cameraOrthoSize
). I set this scaler using mouse wheel input in an event.
How would you improve this to make it feel more like scrolling in perspective mode?
1 Like
Cedric
April 18, 2024, 1:45pm
2
to me, it looks like orthographic scroll is just too slow. So, increasing scroll speed maybe?
cc @PolygonalSun
No, I’m not talking about the speed. I can adjust the overall speed with dampeningFactor
.
In perspective mode, the zoom will start slowly and trail off when starting and stopping.
Yep! That feels so much better. Thank you
1 Like
Just a quick update in case someone needs this in the future. Here is a new version on the playground
Switch between Orthographic and Perspective mode
Scrolling in Orthographic mode will resize the ortho bounds
Fixed an issue where zooming out happend much faster than zooming in
Add a section of constants to the top of the PG so you can quickly adjust the settings
Here is all the camera-related code
// Constants
const ORTHO_SIZE = 10;
const MIN_ORTHO_SIZE = 1;
const MAX_ORTHO_SIZE = 50;
const DAMPENING_FACTOR = 0.25;
const SCROLL_SPEED_FACTOR = 100;
const SPEED = 0.1;
let targetTop, targetBottom, targetLeft, targetRight;
// Helper Function to adjust camera ortho size based on engine dimensions
const adjustOrthoSize = (engine, value) => {
targetTop = engine.getRenderHeight() / value / ORTHO_SIZE;
targetBottom = -(engine.getRenderHeight() / value / ORTHO_SIZE);
targetLeft = -(engine.getRenderWidth() / value / ORTHO_SIZE);
targetRight = engine.getRenderWidth() / value / ORTHO_SIZE;
}
// Function to setup the camera
const setupCamera = (scene) => {
let cameraOrthoSize = ORTHO_SIZE; // used to scale the orthographic bounds
const camera = new BABYLON.ArcRotateCamera(
"camera",
Math.PI / 2,
Math.PI / 2.5,
14,
new BABYLON.Vector3(0, 1, 0),
scene
);
camera.minZ = 0.1
camera.wheelDeltaPercentage = 0.01;
camera.upperBetaLimit = Math.PI / 1.5;
camera.lowerRadiusLimit = 2;
camera.upperRadiusLimit = 20;
camera.attachControl(document.getElementById("bjsCanvas"), true);
camera.mode = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
adjustOrthoSize(engine, cameraOrthoSize); // Initial size
// Handle scroll wheel event for camera zoom (assuming no perspective mode)
window.addEventListener("wheel", (event) => {
if (camera.mode.PERSPECTIVE_CAMERA) return;
const wheelEvent = event;
// Adjust the scaling factor based on the scroll speed
const scalingFactor = Math.abs(wheelEvent.deltaY) / SCROLL_SPEED_FACTOR;
// Calculate the change in ortho size as a percentage of the current size
const delta = cameraOrthoSize * scalingFactor * DAMPENING_FACTOR;
// Adjust the cameraOrthoSize based on the scroll input and the calculated delta
const newCameraOrthoSize = wheelEvent.deltaY > 0 ? cameraOrthoSize - delta : cameraOrthoSize + delta;
// Clamp the new value within some bounds
cameraOrthoSize = Math.max(MIN_ORTHO_SIZE, Math.min(MAX_ORTHO_SIZE, newCameraOrthoSize));
adjustOrthoSize(engine, cameraOrthoSize);
});
scene.onBeforeRenderObservable.add(() => {
camera.orthoTop += (targetTop - camera.orthoTop) * SPEED;
camera.orthoBottom += (targetBottom - camera.orthoBottom) * SPEED;
camera.orthoLeft += (targetLeft - camera.orthoLeft) * SPEED;
camera.orthoRight += (targetRight - camera.orthoRight) * SPEED;
});
return camera;
}
3 Likes