Customising panning inputs in an arcrotate camera

I would like to imitate a scroll type behaviour in a scene with an arcrotate camera.

I want the camera to move up or down on the y axis based on inputs typically used for scrolling (such as mouse wheel up and down, two finger scroll on the trackpad, up and down arrow keys)

After disabling beta rotation of the camera, disabling ctrl to pan, and adding

camera._panningMouseButton = 1;
I get the behaviour I want by pressing middle mouse and panning.

I would like to replicate this for the other inputs mentioned above.
I can’t find anything in the documentation to customise the panning input (some version of camera.keysUp or camera.keysDown but for panning?)

Here is a playground

If there isn’t a default property, I could create a custom class? I don’t understand this method very well so I’m looking for a way to solve the problem without this.
Would this functionality be easier to implement with a FreeCamera instead?

Thanks!

Asked and ChatGPT Response.
It’s a simple start

Also you can add event.preventDefault(); to your event listeners to avoid the default use of the mouse wheel.

// create a new ArcRotateCamera
var camera = new BABYLON.ArcRotateCamera(“Camera”, 0, 0, 10, BABYLON.Vector3.Zero(), scene);

// set the desired minimum and maximum values for the camera’s y position
camera.lowerRadiusLimit = 1;
camera.upperRadiusLimit = 100;

// listen for the appropriate input events and update the camera’s position
canvas.addEventListener(“wheel”, function(event) {
camera.radius += event.deltaY / 100; // adjust the radius based on the wheel delta
});

canvas.addEventListener(“keydown”, function(event) {
if (event.key === “ArrowUp”) {
camera.target.y += 1; // move the camera up
} else if (event.key === “ArrowDown”) {
camera.target.y -= 1; // move the camera down
}
});

canvas.addEventListener(“touchmove”, function(event) {
if (event.touches.length === 2) {
var deltaY = event.touches[0].clientY - event.touches[1].clientY;
camera.radius += deltaY / 100; // adjust the radius based on the touch delta
}
});

1 Like

That thing is quite smart, isn’t it :smile:
In any case, I suppose starting with preventDefault() is a good start.
I would be interested to see the result of your ‘collaboration’ with the AI… (in case you make it there).
Else, let us know…

1 Like

Hi and welcome to the Community?
Good question. I would say ‘yes’ from the reading above but I do not have all the details. Is it like a locked angle view? Fact is the arcRotateCamera is orbital. It works from a target with alpha,beta and radius offset from the target. There’s not much sense of having this alpha and beta (and setting the target) if you are not to rotate around a target, is there?

Hey! Thanks, glad to be here.
For my purposes, I’d like to rotate around a target but I disabled beta rotation simply because the camera panning axis is local and with beta rotation permitted, the y axis of the camera changes constantly. This interferes with the ‘scroll’ type interaction.

Thanks for the suggestion!

Gave this a shot with the arrow key event listeners but the motion is not as smooth as the natural panning action of the camera

Is there a way to make it smoother without compromising on speed?

Try using RequestAnimationFrame Method. It should be smoother. If you need to move slower just change 0.1 to a lower value from moveUp / MoveDown

// Using Request Animation Frame
let moveUp = false;
let moveDown = false;

canvas.addEventListener('keydown', function(event) {
event.preventDefault();
if (event.key === 'ArrowUp') {
    moveUp = true;
} else if (event.key === 'ArrowDown') {
    moveDown = true;
}
});

canvas.addEventListener('keyup', function(event) {
event.preventDefault();
if (event.key === 'ArrowUp') {
    moveUp = false;
} else if (event.key === 'ArrowDown') {
    moveDown = false;
}
});

function animateCamera() {
if (moveUp) {
    camera.target.y += 0.1;
}
if (moveDown) {
    camera.target.y -= 0.1;
}

requestAnimationFrame(animateCamera);
}

animateCamera();
1 Like

cc @PolygonalSun

By default, the ArcRotateCamera has a mouse wheel input that will zoom when you try to scroll. If you’re looking to change that behavior, I’d recommend first removing that and then adding an observer to the scene’s onPointerObservable observable:

const mousewheel = camera.inputs.attached.mousewheel;
    camera.inputs.remove(mousewheel);

    scene.onPointerObservable.add((eventData) => {
        const evt = eventData.event;
        // This is just an arbitrary number that I'm using to control how quickly it moves
        // This worked for me but YMMV
        const wheelSensitivity = 1500;
        const moveFactor = evt.deltaY / wheelSensitivity;

        camera.inertialPanningY += moveFactor;
    }, BABYLON.PointerEventTypes.POINTERWHEEL);

For smooth panning, you should add any deltas to the camera’s inertialPanningX/Y variables and it will gradually move and slow down as it reaches its goal. You can also create your own custom inputs if you want to define more detailed behaviors. If you want to limit movement, you might need to add something to scene.onBeforeRenderObservable to check where your camera is and zero out the inertialPanningX/Y variable if it tries to go too far. For the keyboard, it’s pretty much the same except you’ll increment on KEYDOWN.

const keyboard = camera.inputs.attached.keyboard;
camera.inputs.remove(keyboard);

scene.onKeyboardObservable.add((eventData) => {
        const evt = eventData.event;

        if (evt.key === 'ArrowUp') {
            camera.inertialPanningY += 0.05;
        }
        if (evt.key === 'ArrowDown') {
            camera.inertialPanningY -= 0.05;
        }
    }, BABYLON.KeyboardEventTypes.KEYDOWN);

Here’s a slight modification of the first PG that shows both of these: ArcRotateCamera Panning | Babylon.js Playground (babylonjs.com)

Lemme know if this works for you.

4 Likes

I’ve been experimenting with the Lerp function but this works MUCH better, thank you

1 Like