Does ArcRotateCamera consume MouseWheel input

Pretty straight forward question. I’ve got all keyboard and mouse events working fine except the mousewheel which seems to be consumed by the camera. For reference this is how I’m handling inputs so I might be doing something wrong with regards to the arcrotatecamera specifically.

  DeviceSourceManagerConfig() {
    this.GetDSM().onDeviceConnectedObservable.add((device) => {
      if (device.deviceType === this.GetGraphics().Devices.DeviceType.Keyboard) {
        device.onInputChangedObservable.add((event) => {
      if (device.deviceType === this.GetGraphics().Devices.DeviceType.Mouse) {
        device.onInputChangedObservable.add((event) => {

The console.log outputs everything except the mousewheel events. Should I be trying to access them some other way?

Thanks in advance.

The wheel input is processed in this class and at this line it is deciding whether to prevent the default event. As you can see there is a parameter noPreventDefault in the attachControl method. I don’t see any other reason why should it drop the event, however I am just an apprentice yet :smiley: so maybe there is another explanation. A Playground example could help a lot.


Yea that option is set, and toggling it doesn’t change what events are passing through so it doesn’t seem thats where the issue lies, especially since other commands are coming through. The question is mainly for anyone who understands the DeviceSourceManager and how it handles events since the only event that is being blocked is the mouse wheel. A playground isn’t really going to change the code much unless all you want to see is the DSM logging out console commands.

playerController.js:96 {inputIndex: 1, previousState: 790, currentState: 809}
playerController.js:96 {inputIndex: 0, previousState: 897, currentState: 901}
playerController.js:96 {inputIndex: 1, previousState: 809, currentState: 809}
playerController.js:96 {inputIndex: 0, previousState: 901, currentState: 903}
playerController.js:96 {inputIndex: 1, previousState: 809, currentState: 809}
playerController.js:96 {inputIndex: 0, previousState: 903, currentState: 965}
playerController.js:96 {inputIndex: 1, previousState: 809, currentState: 820}
playerController.js:96 {inputIndex: 0, previousState: 965, currentState: 960}
playerController.js:96 {inputIndex: 1, previousState: 820, currentState: 822}
playerController.js:96 {inputIndex: 0, previousState: 960, currentState: 901}
playerController.js:96 {inputIndex: 1, previousState: 822, currentState: 835}
playerController.js:96 {inputIndex: 0, previousState: 901, currentState: 899}
playerController.js:96 {inputIndex: 1, previousState: 835, currentState: 835}
playerController.js:96 {inputIndex: 0, previousState: 899, currentState: 899}
playerController.js:96 {inputIndex: 1, previousState: 835, currentState: 836}
playerController.js:96 {inputIndex: 0, previousState: 899, currentState: 862}
playerController.js:96 {inputIndex: 1, previousState: 836, currentState: 842}
playerController.js:96 {inputIndex: 0, previousState: 862, currentState: 2}
playerController.js:96 {inputIndex: 1, previousState: 842, currentState: 816}

InputIndex 0 and 1 are the x,y, I imagine mousewheel is probably 7 or 8 or something for my mouse.

Sometimes trying to reproduce the issue in the playground is really helpful to identifying where it lies. :smiley: I tried logging in inputs using the DSM and had no issues with it: Input mouse events | Babylon.js Playground ( Which version of Babylon are you using?


@PolygonalSun might have some insight on this

1 Like

I just did an update and it didn’t change. I’m using the npm versions

"version": "4.2.0"
"@babylonjs/core": "^4.2.0",
"@babylonjs/inspector": "^4.2.0",

To show I’m not doing anything crazy with the initialization here is the code, its virtually identical to this.

Input mouse events | Babylon.js Playground (

Which I updated to use the structure I am using currently and it does indeed output the mouse wheel events. But doesn’t hint at why.

export default class Graphics {
  constructor() {
    this.document = document.createElement(`canvas`) = `renderCanvas`
    this.canvas = document.getElementById(`renderCanvas`)
    this.engine = new Engine(this.canvas, true)
    this.scene = new Scene(this.engine)

    this.cameras = []

    this.lights = []

    window.addEventListener(`resize`, () => {

    this.start = this.init()

    if (this.start) {
      console.log(`Starting Graphics render loop!`)
      this.engine.runRenderLoop(() => { this.scene.render() })

    this.Maths = Maths
    this.MeshBuilder = MeshBuilder
    this.GridMaterial = GridMaterial
    this.Vector3 = Vector3
    this.Color3 = Color3
    this.Quaternion = Quaternion
    this.Devices = Devices

  init() {
    console.log(`Initializing graphics engine...`)
    let params = defaults_ArcRotateCamera = `camera1`
    params.scene = this.scene
    let camera = this.createCameraArcRotate(params)
    camera.maxZ = 1000000

    params = defaults_HemisphericaLight = `light1`
    params.scene = this.scene
    let light = this.createLightHemispheric(params)
    console.log(`Graphics engine initialized!`)
    return true

  createCameraArcRotate(params) {
    let camera = new ArcRotateCamera(,
      params.alpha, params.beta, params.radius,, params.scene)
    return camera

  initCamera(camera, speed = 10, wheelPrecision = 1, panningSensibility = 1) {
    camera.attachControl(this.canvas, true)
    camera.speed = speed
    camera.wheelPrecision = wheelPrecision
    camera.panningSensibility = panningSensibility
    return camera

  createLightHemispheric(params) {
    let light = new HemisphericLight(,
    return light

  initLight(light, intensity) {
    light.intensity = intensity
    return light


These are the camera defaults, just an object I expand before pushing it as a param to create the camera

const defaults_ArcRotateCamera = {
  name: `camera`,
  alpha: 4.7121,
  beta: 0,
  radius: 30,
  target: Vector3.Zero()

Edit: To be more thorough I updated it to just show my entire graphics class which in earlier posts you can see I’m making calls to. I’m using a class so that I don’t have to import things piecemeal around my application I just get Graphics related things from my graphics class. Stands to reason if I need one thing from there I’ll probably need a few things.

Ah, I know what’s going on. So in 4.2, the DeviceSourceManager/DeviceInputSystem didn’t have mousewheel support yet (it will be included in 5.0 and is currently active in the preview version). For v4.2, I’d recommend accessing pointerwheel events like this:

scene.onPointerObservable.add((eventData) => {
    if (eventData.type === PointerEventTypes.POINTERWHEEL) {
        // something with eventData.event
// or
scene.onPointerObservable.add((eventData) => {
    // something with eventData.event
}, PointerEventTypes.POINTERWHEEL);

That’s getting me closer. But I don’t see the PointerEventTypes in the Devices object. And when I console.log it I get undefined. I checked in the scene as well it comes up undefined.

scene.onPointerObservable.add((event) => {

With this I get an object called PointerInfo and in that object I get PointerEvents and WheelEvents and some other Objects.

The type however is numerical apparently wheel is type 8

event: WheelEvent {isTrusted: true, pointerId: 0, deltaX: -0, deltaY: 100, deltaZ: 0, …}
pickInfo: PickingInfo {_pickingUnavailable: true, hit: false, distance: 0, pickedPoint: null, pickedMesh: null, …}
type: 8

So I’ll do something like this.

      this.GetGraphics().scene.onPointerObservable.add((event) => {
        if (event.type === 8){

Not sure if this is correct but it’s doing what I expected. Is the npm version supposed to be that far behind 5.0. It looks like 4.2 is the latest stable release from the site. I’d have to look at the git to see, but seems like 4.2 is current.

Either way thanks for pointing me in the right direction. I knew there was something odd going on.

We recommend most users to use the latest versions of 5.0, and update frequently. Right now it’s alpha 60.

You can install it with npm i @babylonjs/core@preview. While 4.2 is the latest “stable release”, we really consider the 5.0 alpha to be the “current” version. The newest versions tend to have the fewest bugs and most features. We also never break backwards compatibility, so you don’t need to worry about APIs changing. We know it’s a bit confusing with the “stable” vs “alpha” naming; we’re considering changing that for the next version.

Edit: fixed npm command thanks to @sebavan

1 Like

Thank you for that info. I’ll upgrade it once I finish this pass over my application structure. Er actually that might be why I’m getting massive frame drops all of the sudden. Yea I’ll upgrade it and if anything comes up I know where to find you all.

Thank you all for your input, I really appreciate it.

1 Like

Just to let you know running latest does not install 5.0 it installs 4.2

Edit: To install the latest version for anyone following on this post you’ll want to do it explicitly.

npm i @babylonjs/core@5.0.0-alpha.60 @babylonjs/inspector@5.0.0-alpha.60 --save-dev
1 Like

You can use the shortcut npm i @babylonjs/core@preview


Ah my bad, I expected that to work but didn’t test it myself. Thanks for sharing the command.

Does your problem persist even in 5.0?

1 Like

Yes actually even in 5.0 it’s still ignoring the mousewheel calls. I’m slowly debugging to try and figure out why. Code still structured like I showed just can’t see where the disconnect is yet. So I’m just going over the git repo and the actual objects in use and seeing what I can find. In the meantime the patch you showed me works but it bugs me that its something that should work and doesn’t.

@sebavan I’ll give that a try. I already tested the explicit commands and they work fine.

1 Like