Skip to content

Instantly share code, notes, and snippets.

@GreyWorks
Last active June 13, 2019 12:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GreyWorks/f72c56be2b85b9a95115c7cf1dc9c6bb to your computer and use it in GitHub Desktop.
Save GreyWorks/f72c56be2b85b9a95115c7cf1dc9c6bb to your computer and use it in GitHub Desktop.
Babylon Arc Rotate Camera Slide Input
import { Nullable } from '@babylonjs/core/types';
import { CameraInputTypes } from '@babylonjs/core/Cameras/cameraInputsManager';
import { ArcRotateCameraPointersInput } from '@babylonjs/core/Cameras';
interface PointerTouch {
/**
* X coordinate of touch.
*/
x: number;
/**
* Y coordinate of touch.
*/
y: number;
/**
* Id of touch. Unique for each finger.
*/
pointerId: number;
/**
* Event type passed from DOM.
*/
type: any;
}
/**
* Manage the pointers inputs to control an arc rotate camera.
* @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
*/
export class ArcRotateCameraSlideInput extends ArcRotateCameraPointersInput {
/**
* Called on pointer POINTERMOVE event if only a single touch is active.
*/
protected onTouch(point: Nullable<PointerTouch>, offsetX: number, offsetY: number): void {
if (
this.panningSensibility !== 0 &&
((this._ctrlKey && this.camera._useCtrlForPanning) || (this as any)._isPanClick)
) {
// just move on Y axis
this.moveCamera(offsetY);
} else {
this.camera.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
this.camera.inertialBetaOffset -= offsetY / this.angularSensibilityY;
}
}
/**
* Called on pointer POINTERMOVE event if multiple touches are active.
*/
protected onMultiTouch(
pointA: Nullable<PointerTouch>,
pointB: Nullable<PointerTouch>,
previousPinchSquaredDistance: number,
pinchSquaredDistance: number,
previousMultiTouchPanPosition: Nullable<PointerTouch>,
multiTouchPanPosition: Nullable<PointerTouch>
): void {
if (previousPinchSquaredDistance === 0 && previousMultiTouchPanPosition === null) {
// First time this method is called for new pinch.
// Next time this is called there will be a
// previousPinchSquaredDistance and pinchSquaredDistance to compare.
return;
}
if (pinchSquaredDistance === 0 && multiTouchPanPosition === null) {
// Last time this method is called at the end of a pinch.
return;
}
const direction = this.pinchInwards ? 1 : -1;
if (this.multiTouchPanAndZoom) {
if (this.pinchDeltaPercentage) {
this.camera.inertialRadiusOffset +=
(pinchSquaredDistance - previousPinchSquaredDistance) *
0.001 *
this.camera.radius *
this.pinchDeltaPercentage;
} else {
this.camera.inertialRadiusOffset +=
(pinchSquaredDistance - previousPinchSquaredDistance) /
((this.pinchPrecision *
direction *
(this.angularSensibilityX + this.angularSensibilityY)) /
2);
}
if (
this.panningSensibility !== 0 &&
previousMultiTouchPanPosition &&
multiTouchPanPosition
) {
// just move on Y axis
const moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
this.moveCamera(moveDeltaY);
}
} else {
const that = this as any;
that._twoFingerActivityCount++;
const previousPinchDistance = Math.sqrt(previousPinchSquaredDistance);
const pinchDistance = Math.sqrt(pinchSquaredDistance);
if (
that._isPinching ||
(that._twoFingerActivityCount < 20 &&
Math.abs(pinchDistance - previousPinchDistance) >
this.camera.pinchToPanMaxDistance)
) {
// Since pinch has not been active long, assume we intend to zoom.
if (this.pinchDeltaPercentage) {
this.camera.inertialRadiusOffset +=
(pinchSquaredDistance - previousPinchSquaredDistance) *
0.001 *
this.camera.radius *
this.pinchDeltaPercentage;
} else {
this.camera.inertialRadiusOffset +=
(pinchSquaredDistance - previousPinchSquaredDistance) /
((this.pinchPrecision *
direction *
(this.angularSensibilityX + this.angularSensibilityY)) /
2);
}
// Since we are pinching, remain pinching on next iteration.
that._isPinching = true;
} else {
// Pause between pinch starting and moving implies not a zoom event.
// Pan instead.
if (
this.panningSensibility !== 0 &&
this.multiTouchPanning &&
multiTouchPanPosition &&
previousMultiTouchPanPosition
) {
const moveDeltaY = multiTouchPanPosition.y - previousMultiTouchPanPosition.y;
// just move on Y axis
this.moveCamera(moveDeltaY);
}
}
}
}
protected moveCamera(deltaY: number) {
const newTarget = this.camera.target.y + deltaY / this.camera!.panningSensibility;
const origin = this.camera!.panningOriginTarget;
const target = this.camera.target;
const panningDistanceLimit = this.camera.panningDistanceLimit!;
if (Math.abs(newTarget - origin.y) < panningDistanceLimit) {
// use this to slide the camera with the new target
this.camera!.target.set(0, newTarget, 0);
// use this if you want to rotate the camera to the new target
// this.camera!.target = newTarget;
} else if (newTarget - origin.y > panningDistanceLimit) {
// reset fixed top
this.camera.target.set(target.x, origin.y + panningDistanceLimit, target.z);
} else if (origin.y - newTarget > panningDistanceLimit) {
// reset fixed bottom
this.camera.target.set(target.x, origin.y - panningDistanceLimit, target.z);
}
}
}
(CameraInputTypes as any).ArcRotateCameraPointersInput = ArcRotateCameraSlideInput;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment