How to add invert Y axis for mouse input on UniversalCamera?

I can invert the rotation for both x and y axes using invertRotation, but I want to support an option to just invert the Y axis. Does this already exist? If it was an ArcRotationCamera I could change the angularSensibilityY to be negative, but this doesn’t exist for the UniversalCamera.

Seems like fewer modern games are allowing users to invert the Y axis for mouse look. It used to be a standard feature for all FPS games.

Welcome to the community @Psyfun !!!

This is currently not supported you can definitely make a PR to add the option in freeCameraMouseInput if you want ?

Thanks. I may create a PR, but for now I just created my own custom mouse input prototype and removed the FreeCameraMouseInput on the camera. The changes to the existing class would be pretty trivial and would be backward compatible, but I am not sure how much it might impact other code that relies on it. For those interested here is the code I am using. It is based on the Walk and Look Around example in the documentation:

//The Mouse Manager to use the mouse (touch) to search around including above and below
var FreeCameraSearchInput = function (touchEnabled) {
    if (touchEnabled === void 0) { touchEnabled = true; }
    this.touchEnabled = touchEnabled;
    this.buttons = [0, 1, 2];
    this.angularSensibility = 2000.0;
    this.invertY = false;
}

//add attachment control which also contains the code to react to the input from the mouse 
FreeCameraSearchInput.prototype.attachControl = function (noPreventDefault) {
    var _this = this;
    var engine = this.camera.getEngine();
    var element = engine.getInputElement();
    var angle = { x: 0, y: 0 };
    if (!this._pointerInput) {
        this._pointerInput = function (p, s) {
            var evt = p.event;
            if (!_this.touchEnabled && evt.pointerType === "touch") {
                return;
            }
            if (p.type !== BABYLON.PointerEventTypes.POINTERMOVE && _this.buttons.indexOf(evt.button) === -1) {
                return;
            }
            if (p.type === BABYLON.PointerEventTypes.POINTERDOWN) {
                try {
                    evt.srcElement.setPointerCapture(evt.pointerId);
                }
                catch (e) {
                    //Nothing to do with the error. Execution will continue.
                }
                _this.previousPosition = {
                    x: evt.clientX,
                    y: evt.clientY
                };
                if (!noPreventDefault) {
                    evt.preventDefault();
                    element.focus();
                }
            }
            else if (p.type === BABYLON.PointerEventTypes.POINTERUP) {
                try {
                    evt.srcElement.releasePointerCapture(evt.pointerId);
                }
                catch (e) {
                    //Nothing to do with the error.
                }
                _this.previousPosition = null;
                if (!noPreventDefault) {
                    evt.preventDefault();
                }
            }
            else if (p.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                if (_this._onSearchMove && engine.isPointerLock) {
                    _this._onSearchMove(p.event);
                }
                else if (_this.previousPosition) {
                    var offsetX = evt.clientX - _this.previousPosition.x;
                    var offsetY = evt.clientY - _this.previousPosition.y;
                    angle.x += offsetX;
                    angle.y -= offsetY;
                    if (_this.camera.getScene().useRightHandedSystem) {
                        _this.camera.cameraRotation.y -= offsetX / _this.angularSensibility;
                    }
                    else {
                        _this.camera.cameraRotation.y += offsetX / _this.angularSensibility;
                    }
                    if (_this.invertY) {
                        _this.camera.cameraRotation.x -= offsetY / _this.angularSensibility;
                    }
                    else {
                        _this.camera.cameraRotation.x += offsetY / _this.angularSensibility;
                    }
                    _this.previousPosition = {
                        x: evt.clientX,
                        y: evt.clientY
                    };
                    if (!noPreventDefault) {
                        evt.preventDefault();
                    }
                }
            }
        };
    }
    this._onSearchMove = function (evt) {
        if (!engine.isPointerLock) {
            _this._onSearchMove(p.event);
        }
        var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
        var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
        if (_this.camera.getScene().useRightHandedSystem) {
            _this.camera.cameraRotation.y -= offsetX / _this.angularSensibility;
        }
        else {
            _this.camera.cameraRotation.y += offsetX / _this.angularSensibility;
        }
        if (_this.invertY) {
            _this.camera.cameraRotation.x -= offsetY / _this.angularSensibility;
        }
        else {
            _this.camera.cameraRotation.x += offsetY / _this.angularSensibility;
        }
        _this.previousPosition = null;
        if (!noPreventDefault) {
            evt.preventDefault();
        }
    };
    this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, BABYLON.PointerEventTypes.POINTERDOWN | BABYLON.PointerEventTypes.POINTERUP | BABYLON.PointerEventTypes.POINTERMOVE);
    element.addEventListener("mousemove", this._onSearchMove, false);
};

//Add detachment control
FreeCameraSearchInput.prototype.detachControl = function () {
    var engine = this.camera.getEngine();
    var element = engine.getInputElement();
    if (this._observer && element) {
        this.camera.getScene().onPointerObservable.remove(this._observer);
        element.removeEventListener("mousemove", this._onSearchMove);
        this._observer = null;
        this._onSearchMove = null;
        this.previousPosition = null;
    }
};

//Add the two required functions for names
FreeCameraSearchInput.prototype.getClassName = function () {
    return "FreeCameraSearchInput";
};

FreeCameraSearchInput.prototype.getSimpleName = function () {
    return "MouseSearchCamera";
};
1 Like