Giter Site home page Giter Site logo

yomotsu / camera-controls Goto Github PK

View Code? Open in Web Editor NEW
1.8K 33.0 231.0 1.96 MB

A camera control for three.js, similar to THREE.OrbitControls yet supports smooth transitions and more features.

Home Page: https://yomotsu.github.io/camera-controls/

License: MIT License

JavaScript 0.62% TypeScript 99.32% Shell 0.06%
threejs camera orbitcontrols

camera-controls's Introduction

camera-controls

A camera control for three.js, similar to THREE.OrbitControls yet supports smooth transitions and more features.

Latest NPM release Open in GitHub Codespaces

documentation

Examples

camera move default user input (Configurable)
Orbit rotation left mouse drag / touch: one-finger move
Dolly middle mouse drag, or mousewheel / touch: two-finger pinch-in or out
Truck (Pan) right mouse drag / touch: two-finger move or three-finger move

Usage

(The below code is for three.js users. If you use react-three-fiber (aka R3F), r3f-ready camera-controls is available on @react-three/drei

import * as THREE from 'three';
import CameraControls from 'camera-controls';

CameraControls.install( { THREE: THREE } );

// snip ( init three scene... )
const clock = new THREE.Clock();
const camera = new THREE.PerspectiveCamera( 60, width / height, 0.01, 1000 );
const cameraControls = new CameraControls( camera, renderer.domElement );

( function anim () {

	// snip
	const delta = clock.getDelta();
	const hasControlsUpdated = cameraControls.update( delta );

	requestAnimationFrame( anim );

	// you can skip this condition to render though
	if ( hasControlsUpdated ) {

		renderer.render( scene, camera );

	}

} )();

Important!

You must install three.js before using camera-controls. Not doing so will lead to runtime errors (undefined references to THREE).

Before creating a new CameraControls instance, call:

CameraControls.install( { THREE: THREE } );

You can then proceed to use CameraControls.

Note: If you do not wish to use the entire three.js to reduce file size(tree-shaking for example), make a subset to install.

import {
	Vector2,
	Vector3,
	Vector4,
	Quaternion,
	Matrix4,
	Spherical,
	Box3,
	Sphere,
	Raycaster,
} from 'three';

const subsetOfTHREE = {
	Vector2   : Vector2,
	Vector3   : Vector3,
	Vector4   : Vector4,
	Quaternion: Quaternion,
	Matrix4   : Matrix4,
	Spherical : Spherical,
	Box3      : Box3,
	Sphere    : Sphere,
	Raycaster : Raycaster,
};

CameraControls.install( { THREE: subsetOfTHREE } );

Constructor

CameraControls( camera, domElement )

  • camera is a THREE.PerspectiveCamera or THREE.OrthographicCamera to be controlled.
  • domElement is a HTMLElement for draggable area. (optional. if domElement is omitted here, can be connect later with .connect())

Terms

Orbit rotations

CameraControls uses Spherical Coordinates for orbit rotations.

If your camera is Y-up, the Azimuthal angle will be the angle for y-axis rotation and the Polar angle will be the angle for vertical position.

Dolly vs Zoom

  • A Zoom involves changing the lens focal length. In three.js, zooming is actually changing the camera FOV, and the camera is stationary (doesn't move).
  • A Dolly involves physically moving the camera to change the composition of the image in the frame.

See the demo

Properties

Name Type Default Description
.camera THREE.Perspective | THREE.Orthographic N/A The camera to be controlled
.enabled boolean true Whether or not the controls are enabled.
.active boolean false Returns true if the controls are active updating.
.currentAction ACTION N/A Getter for the current ACTION.
.distance number N/A Current distance.
.minDistance number Number.EPSILON Minimum distance for dolly. The value must be higher than 0
.maxDistance number Infinity Maximum distance for dolly.
.minZoom number 0.01 Minimum camera zoom.
.maxZoom number Infinity Maximum camera zoom.
.polarAngle number N/A Current polarAngle in radians.
.minPolarAngle number 0 In radians.
.maxPolarAngle number Math.PI In radians.
.azimuthAngle number N/A current azimuthAngle in radians ¹.
.minAzimuthAngle number -Infinity In radians.
.maxAzimuthAngle number Infinity In radians.
.boundaryFriction number 0.0 Friction ratio of the boundary.
.boundaryEnclosesCamera boolean false Whether camera position should be enclosed in the boundary or not.
.smoothTime number 0.25 Approximate time in seconds to reach the target. A smaller value will reach the target faster.
.draggingSmoothTime number 0.125 The smoothTime while dragging.
.azimuthRotateSpeed number 1.0 Speed of azimuth rotation.
.polarRotateSpeed number 1.0 Speed of polar rotation.
.dollySpeed number 1.0 Speed of mouse-wheel dollying.
.truckSpeed number 2.0 Speed of drag for truck and pedestal.
.verticalDragToForward boolean false The same as .screenSpacePanning in three.js's OrbitControls.
.dollyToCursor boolean false true to enable Dolly-in to the mouse cursor coords.
.dollyDragInverted boolean false true to invert direction when dollying or zooming via drag.
.interactiveArea DOMRect N/A Set drag-start, touches and wheel enable area in the domElement. each values are between 0 and 1 inclusive, where 0 is left/top and 1 is right/bottom of the screen.
.colliderMeshes array [] An array of Meshes to collide with camera ².
.infinityDolly boolean false true to enable Infinity Dolly for wheel and pinch. Use this with minDistance and maxDistance ³.
.restThreshold number 0.0025 Controls how soon the rest event fires as the camera slows
  1. Every 360 degrees turn is added to .azimuthAngle value, which is accumulative.
    360º = 360 * THREE.MathUtils.DEG2RAD = Math.PI * 2, 720º = Math.PI * 4.
    Tip: How to normalize accumulated azimuthAngle?
  2. Be aware colliderMeshes may decrease performance. The collision test uses 4 raycasters from the camera since the near plane has 4 corners.
  3. If the Dolly distance is less (or over) than the minDistance (or maxDistance), infinityDolly will keep the distance and pushes the target position instead.

Events

CameraControls instance emits the following events.
To subscribe, use cameraControl.addEventListener( 'eventname', function ).
To unsubscribe, use cameraControl.removeEventListener( 'eventname', function ).

Event name Timing
'controlstart' When the user starts to control the camera via mouse / touches. ¹
'control' When the user controls the camera (dragging).
'controlend' When the user ends to control the camera. ¹
'transitionstart' When any kind of transition starts, either user control or using a method with enableTransition = true
'update' When the camera position is updated.
'wake' When the camera starts moving.
'rest' When the camera movement is below .restThreshold ².
'sleep' When the camera end moving.
  1. mouseButtons.wheel (Mouse wheel control) does not emit 'controlstart' and 'controlend'. mouseButtons.wheel uses scroll-event internally, and scroll-event happens intermittently. That means "start" and "end" cannot be detected.
  2. Due to damping, sleep will usually fire a few seconds after the camera appears to have stopped moving. If you want to do something (e.g. enable UI, perform another transition) at the point when the camera has stopped, you probably want the rest event. This can be fine tuned using the .restThreshold parameter. See the Rest and Sleep Example.

User input config

Working example: user input config

button to assign behavior
mouseButtons.left CameraControls.ACTION.ROTATE* | CameraControls.ACTION.TRUCK | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE
mouseButtons.right CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK* | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE
mouseButtons.wheel ¹ CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE
mouseButtons.middle ² CameraControls.ACTION.ROTATE | CameraControls.ACTION.TRUCK | CameraControls.ACTION.OFFSET | CameraControls.ACTION.DOLLY* | CameraControls.ACTION.ZOOM | CameraControls.ACTION.NONE
  1. Mouse wheel event for scroll "up/down" on mac "up/down/left/right"
  2. Mouse click on wheel event "button"
  • * is the default.
  • The default of mouseButtons.wheel is:
    • DOLLY for Perspective camera.
    • ZOOM for Orthographic camera, and can't set DOLLY.
fingers to assign behavior
touches.one CameraControls.ACTION.TOUCH_ROTATE* | CameraControls.ACTION.TOUCH_TRUCK | CameraControls.ACTION.TOUCH_OFFSET | CameraControls.ACTION.DOLLY
touches.two ACTION.TOUCH_DOLLY_TRUCK | ACTION.TOUCH_DOLLY_OFFSET | ACTION.TOUCH_DOLLY_ROTATE | ACTION.TOUCH_ZOOM_TRUCK | ACTION.TOUCH_ZOOM_OFFSET | ACTION.TOUCH_ZOOM_ROTATE | ACTION.TOUCH_DOLLY | ACTION.TOUCH_ZOOM | CameraControls.ACTION.TOUCH_ROTATE | CameraControls.ACTION.TOUCH_TRUCK | CameraControls.ACTION.TOUCH_OFFSET | CameraControls.ACTION.NONE
touches.three ACTION.TOUCH_DOLLY_TRUCK | ACTION.TOUCH_DOLLY_OFFSET | ACTION.TOUCH_DOLLY_ROTATE | ACTION.TOUCH_ZOOM_TRUCK | ACTION.TOUCH_ZOOM_OFFSET | ACTION.TOUCH_ZOOM_ROTATE | CameraControls.ACTION.TOUCH_ROTATE | CameraControls.ACTION.TOUCH_TRUCK | CameraControls.ACTION.TOUCH_OFFSET | CameraControls.ACTION.NONE
  • * is the default.
  • The default of touches.two and touches.three is:
    • TOUCH_DOLLY_TRUCK for Perspective camera.
    • TOUCH_ZOOM_TRUCK for Orthographic camera, and can't set TOUCH_DOLLY_TRUCK and TOUCH_DOLLY.

Methods

rotate( azimuthAngle, polarAngle, enableTransition )

Rotate azimuthal angle(horizontal) and polar angle(vertical). Every value is added to the current value.

Name Type Description
azimuthAngle number Azimuth rotate angle. In radian.
polarAngle number Polar rotate angle. In radian.
enableTransition boolean Whether to move smoothly or immediately

If you want to rotate only one axis, put a angle for the axis to rotate, and 0 for another.

rotate( 20 * THREE.MathUtils.DEG2RAD, 0, true );

rotateAzimuthTo( azimuthAngle, enableTransition )

Rotate azimuthal angle(horizontal) to the given angle and keep the same polar angle(vertical) target.

Name Type Description
azimuthAngle number Azimuth rotate angle. In radian.
enableTransition boolean Whether to move smoothly or immediately

rotatePolarTo( polarAngle, enableTransition )

Rotate polar angle(vertical) to the given angle and keep the same azimuthal angle(horizontal) target.

Name Type Description
polarAngle number Polar rotate angle. In radian.
enableTransition boolean Whether to move smoothly or immediately

rotateTo( azimuthAngle, polarAngle, enableTransition )

Rotate azimuthal angle(horizontal) and polar angle(vertical) to the given angle. Camera view will rotate over the orbit pivot absolutely:

Azimuth angle

       0º
         \
 90º -----+----- -90º
           \
           180º

0º front, 90º (Math.PI / 2) left, -90º (- Math.PI / 2) right, 180º (Math.PI) back


Polar angle

     180º
      |
      90º
      |
      0º

180º (Math.PI) top/sky, 90º (Math.PI / 2) horizontal from view, 0º bottom/floor

Name Type Description
azimuthAngle number Azimuth rotate angle to. In radian.
polarAngle number Polar rotate angle to. In radian.
enableTransition boolean Whether to move smoothly or immediately

dolly( distance, enableTransition )

Dolly in/out camera position.

Name Type Description
distance number Distance of dollyIn
enableTransition boolean Whether to move smoothly or immediately

dollyTo( distance, enableTransition )

Dolly in/out camera position to given distance.

Name Type Description
distance number Distance of dollyIn
enableTransition boolean Whether to move smoothly or immediately

dollyInFixed( distance, enableTransition )

Dolly in, but does not change the distance between the target and the camera, and moves the target position instead. Specify a negative value for dolly out.

Name Type Description
distance number Distance of dollyIn
enableTransition boolean Whether to move smoothly or immediately

zoom( zoomStep, enableTransition )

Zoom in/out camera. The value is added to camera zoom.
Limits set with .minZoom and .maxZoom

Name Type Description
zoomStep number zoom scale
enableTransition boolean Whether to move smoothly or immediately

You can also make zoomIn function using camera.zoom property. e.g.

const zoomIn  = () => cameraControls.zoom(   camera.zoom / 2, true );
const zoomOut = () => cameraControls.zoom( - camera.zoom / 2, true );

zoomTo( zoom, enableTransition )

Zoom in/out camera to given scale. The value overwrites camera zoom.
Limits set with .minZoom and .maxZoom

Name Type Description
zoom number zoom scale
enableTransition boolean Whether to move smoothly or immediately

truck( x, y, enableTransition )

Truck and pedestal camera using current azimuthal angle.

Name Type Description
x number Horizontal translate amount
y number Vertical translate amount
enableTransition boolean Whether to move smoothly or immediately

lookInDirectionOf( x, y, z, enableTransition )

Look in the given point direction.

Name Type Description
x number point x
y number point y
z number point z
enableTransition boolean Whether to move smoothly or immediately

setFocalOffset( x, y, z, enableTransition )

Set focal offset using the screen parallel coordinates. z doesn't affect in Orthographic as with Dolly.

Name Type Description
x number Horizontal offset amount
y number Vertical offset amount
z number Depth offset amount. The result is the same as Dolly but unaffected by minDistance and maxDistance
enableTransition boolean Whether to move smoothly or immediately

setOrbitPoint( targetX, targetY, targetZ )

Set orbit point without moving the camera.

Name Type Description
targetX number Orbit center position x
targetY number Orbit center position y
targetZ number Orbit center position z

forward( distance, enableTransition )

Move forward / backward.

Name Type Description
distance number Amount to move forward / backward. Negative value to move backward
enableTransition boolean Whether to move smoothly or immediately

moveTo( x, y, z, enableTransition )

Move target position to given point.

Name Type Description
x number x coord to move center position
y number y coord to move center position
z number z coord to move center position
enableTransition boolean Whether to move smoothly or immediately

elevate( height, enableTransition )

Move up / down.

Name Type Description
height number Amount to move up / down. Negative value to move down
enableTransition boolean Whether to move smoothly or immediately

fitToBox( box3OrMesh, enableTransition, { paddingTop, paddingLeft, paddingBottom, paddingRight } )

Fit the viewport to the box or the bounding box of the object, using the nearest axis. paddings are in unit. set cover: true to fill enter screen.

Name Type Description
box3OrMesh THREE.Box3 | THREE.Mesh Axis aligned bounding box to fit the view.
enableTransition boolean Whether to move smoothly or immediately
options object Options
options.cover boolean Whether fill enter screen or not. Default is false
options.paddingTop number Padding top. Default is 0
options.paddingRight number Padding right. Default is 0
options.paddingBottom number Padding bottom. Default is 0
options.paddingLeft number Padding left. Default is 0

fitToSphere( sphereOrMesh, enableTransition )

Fit the viewport to the sphere or the bounding sphere of the object.

Name Type Description
sphereOrMesh THREE.Sphere | THREE.Mesh bounding sphere to fit the view.
enableTransition boolean Whether to move smoothly or immediately

setLookAt( positionX, positionY, positionZ, targetX, targetY, targetZ, enableTransition )

Look at the target from the position.

Name Type Description
positionX number Camera position x.
positionY number Camera position y.
positionZ number Camera position z.
targetX number Orbit center position x.
targetY number Orbit center position y.
targetZ number Orbit center position z.
enableTransition boolean Whether to move smoothly or immediately

lerpLookAt( positionAX, positionAY, positionAZ, targetAX, targetAY, targetAZ, positionBX, positionBY, positionBZ, targetBX, targetBY, targetBZ, t, enableTransition )

Similar to setLookAt, but it interpolates between two states.

Name Type Description
positionAX number The starting position x of look at from.
positionAY number The starting position y of look at from.
positionAZ number The starting position z of look at from.
targetAX number The starting position x of look at.
targetAY number The starting position y of look at.
targetAZ number The starting position z of look at.
positionBX number Look at from position x to interpolate towards.
positionBY number Look at from position y to interpolate towards.
positionBZ number Look at from position z to interpolate towards.
targetBX number look at position x to interpolate towards.
targetBY number look at position y to interpolate towards.
targetBZ number look at position z to interpolate towards.
t number Interpolation factor in the closed interval. The value must be a number between 0 to 1 inclusive, where 1 is 100%
enableTransition boolean Whether to move smoothly or immediately

setPosition( positionX, positionY, positionZ, enableTransition )

Set angle and distance by given position. An alias of setLookAt(), without target change. Thus keep gazing at the current target

Name Type Description
positionX number Position x of look at from.
positionY number Position y of look at from.
positionZ number Position z of look at from.
enableTransition boolean Whether to move smoothly or immediately

setTarget( targetX, targetY, targetZ, enableTransition )

Set the target position where gaze at. An alias of setLookAt(), without position change. Thus keep the same position.

Name Type Description
targetX number Position x of look at.
targetY number Position y of look at.
targetZ number Position z of look at.
enableTransition boolean Whether to move smoothly or immediately

setBoundary( box3? )

Set the boundary box that encloses the target of the camera. box3 is in THREE.Box3

Name Type Description
box3 THREE.Box3? Boundary area. No argument to remove the boundary.

setViewport( vector4? )

Set (or unset) the current viewport.
Set this when you want to use renderer viewport and .dollyToCursor feature at the same time.

See: THREE.WebGLRenderer.setViewport()

Name Type Description
vector4 THREE.Vector4? Vector4 that represents the viewport, or undefined for unsetting this.

setViewport( x, y, width, height )

Same as setViewport( vector4 ), but you can give it four numbers that represents a viewport instead:

Name Type Description
x number Leftmost of the viewport.
y number Bottommost of the viewport.
width number Width of the viewport.
height number Height of the viewport.

getTarget( out, receiveEndValue )

Returns the orbit center position, where the camera looking at.

Name Type Description
out THREE.Vector3 The receiving Vector3 instance to copy the result
receiveEndValue boolean Whether receive the transition end coords or current. default is true

getPosition( out, receiveEndValue )

Returns the camera position.

Name Type Description
out THREE.Vector3 The receiving Vector3 instance to copy the result
receiveEndValue boolean Whether receive the transition end coords or current. default is true

getSpherical( out, receiveEndValue )

Returns the spherical coordinates of the orbit.

Name Type Description
out THREE.Vector3 The receiving Spherical instance to copy the result
receiveEndValue boolean Whether receive the transition end coords or current. default is true

getFocalOffset( out, receiveEndValue )

Returns the focal offset, which is how much the camera appears to be translated in screen parallel coordinates.

Name Type Description
out THREE.Vector3 The receiving Vector3 instance to copy the result
receiveEndValue boolean Whether receive the transition end coords or current. default is true

saveState()

Set current camera position as the default position


normalizeRotations()

Normalize camera azimuth angle rotation between 0 and 360 degrees.


reset( enableTransition )

Reset all rotation and position to default.

Name Type Description
enableTransition boolean Whether to move smoothly or immediately

update( delta ): boolean

Update camera position and directions. This should be called in your tick loop and returns true if re-rendering is needed.

Name Type Description
delta number Delta time between previous update call

updateCameraUp()

When you change camera-up vector, run .updateCameraUp() to sync.


applyCameraUp()

Apply current camera-up direction to the camera.
The orbit system will be re-initialized with the current position.


connect()

Attach all internal event handlers to enable drag control.


disconnect()

Detach all internal event handlers to disable drag control.


dispose()

Dispose the cameraControls instance itself, remove all eventListeners.


addEventListener( type: string, listener: function )

Adds the specified event listener.


removeEventListener( type: string, listener: function )

Removes the specified event listener.


removeAllEventListeners( type: string )

Removes all listeners for the specified type.


toJSON()

Get all state in JSON string


fromJSON( json, enableTransition )

Reproduce the control state with JSON. enableTransition is where anim or not in a boolean.


Tips

Normalize accumulated azimuth angle:

If you need a normalized accumulated azimuth angle (between 0 and 360 deg), compute with THREE.MathUtils.euclideanModulo e.g.:

const TAU = Math.PI * 2;

function normalizeAngle( angle ) {

	return THREE.MathUtils.euclideanModulo( angle, TAU );

}

const normalizedAzimuthAngle = normalizeAngle( cameraControls.azimuthAngle );

Find the absolute angle to shortest azimuth rotatation:

You may rotate 380deg but actually, you expect to rotate -20deg.
To get the absolute angle, use the below:

const TAU = Math.PI * 2;

function absoluteAngle( targetAngle, sourceAngle ){

  const angle = targetAngle - sourceAngle
  return THREE.MathUtils.euclideanModulo( angle + Math.PI, TAU ) - Math.PI;

}

console.log( absoluteAngle( 380 * THREE.MathUtils.DEG2RAD, 0 ) * THREE.MathUtils.RAD2DEG ); // -20deg
console.log( absoluteAngle( -1000 * THREE.MathUtils.DEG2RAD, 0 ) * THREE.MathUtils.RAD2DEG ); // 80deg

Creating Complex Transitions

All methods that take the enableTransition parameter return a Promise can be used to create complex animations, for example:

async function complexTransition() {
	await cameraControls.rotateTo( Math.PI / 2, Math.PI / 4, true );
	await cameraControls.dollyTo( 3, true );
	await cameraControls.fitToSphere( mesh, true );
}

This will rotate the camera, then dolly, and finally fit to the bounding sphere of the mesh.

The speed and timing of transitions can be tuned using .restThreshold and .smoothTime.

If enableTransition is false, the promise will resolve immediately:

// will resolve immediately
await cameraControls.dollyTo( 3, false );

V2 Migration Guide

camera-controls used to use simple damping for its smooth transition. camera-controls v2 now uses SmoothDamp. one of the benefits of using SmoothDamp is, SmoothDamp transition can be controlled with smoothTime which is approximately the time it will take to reach the end position. Also, the Maximum speed of the transition can be set with max speed.

Due to the change, the following are needed. (if you haven't changed dampingFactor and draggingDampingFactor in v1.x, nothing is needed)

deprecated

  • dampingFactor (use smoothTime instead)
  • draggingDampingFactor (use draggingSmoothTime instead)

added

  • smoothTime
  • draggingSmoothTime
  • maxSpeed

...That's it!

Contributors

This project exists thanks to all the people who contribute.

Release

Pre-requisites:

  1. a npm registry up and running with a NPM_TOKEN
     $ export NPM_TOKEN=npm_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2. a Github PAT
      $ export GITHUB_TOKEN=github_pat_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
$ npm run release -- --dry-run

camera-controls's People

Contributors

a3ng7n avatar abernier avatar abusedmedia avatar acmcmc avatar andrewplummer avatar chenlong-frontend avatar cotlod avatar dependabot[bot] avatar dsafa avatar ervinoro avatar farfromrefug avatar himbeles avatar jbyte avatar jeanremy avatar jesusbill avatar juliendargelos avatar ketourneau avatar klich3 avatar looeee avatar michael-erskine avatar milewski avatar mixvar avatar n33kos avatar neilrackett avatar nikhilxb avatar paulmelnikow avatar subztep avatar wellcaffeinated avatar ybr3 avatar yomotsu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

camera-controls's Issues

Make mouse buttons configurable.

Would you accept a pull request that makes mouse buttons configurable? What should the API look like?

In my specific case I want to use the left mouse button to translate and the right button to rotate.

In case anyone is looking for a workaround, this works:

CameraControls.install({
    // Hack to make panning and orbiting work the way we want.
    THREE: {
        ...THREE,
        MOUSE: { ...THREE.MOUSE, LEFT: THREE.MOUSE.RIGHT, RIGHT: THREE.MOUSE.LEFT },
    },
});

An accessor cannot be declared in an ambient context.

Error in Angular 8 project using Angular CLI. (Note it still supporting typescript<3.6.0):

ERROR in node_modules/camera-controls/dist/CameraControls.d.ts:6:16 - error TS1086: An accessor cannot be declared in an ambient context.

6 static get ACTION(): Readonly;
~~~~~~
node_modules/camera-controls/dist/CameraControls.d.ts:50:9 - error TS1086: An accessor cannot be declared in an ambient context.

50 set phiSpeed(speed: number);
~~~~~~~~
node_modules/camera-controls/dist/CameraControls.d.ts:51:9 - error TS1086: An accessor cannot be declared in an ambient context.

51 set thetaSpeed(speed: number);
~~~~~~~~~~
node_modules/camera-controls/dist/CameraControls.d.ts:52:9 - error TS1086: An accessor cannot be declared in an ambient context.

52 get boundaryEnclosesCamera(): boolean;
~~~~~~~~~~~~~~~~~~~~~~
node_modules/camera-controls/dist/CameraControls.d.ts:53:9 - error TS1086: An accessor cannot be declared in an ambient context.

53 set boundaryEnclosesCamera(boundaryEnclosesCamera: boolean);
~~~~~~~~~~~~~~~~~~~~~~

Fixed wheel_update

I don't have permission to create a PR, so here's the code I changed:

		this.dollySpeed = 1.0;
		this.dollyTransition = false;

in dollyInternal:

scope.dolly( distance, scope.dollyTransition );

in onMouseWheel:

				dollyInternal( - delta, x, y );
				scope.dispatchEvent( {
					type: 'control',
					originalEvent: event,
				} );

=> now if we use dollyTransition = true, the wheel up/down is smooth, and it also dispatches an event, which is useful if we only want to render the 3d when something has changed.

delta?

In your update method, what is delta exactly? frame time delta? Because this gives me NaN on the camera position if left blank and if I set it to the time that passed since last frame it just goes crazy spinning anywhere (mostly to the poles tho, although i restricted polarangle the same way i did with orbitcontrols...)

I have to mention I am working on THREE r78, so i had to replace spherical.copy() as this threw me errors.

I am using your src and compile it myself with babel, so i can still make some adjustments.

Here is my "config" for orbitControls:

this.orbitControls.minPolarAngle = Math.PI / 2 - Math.PI / 4;
this.orbitControls.maxPolarAngle = Math.PI / 2 + Math.PI / 4;
this.orbitControls.maxDistance = 2.5;
this.orbitControls.minDistance = 1;
this.orbitControls.enableDamping = true;
this.orbitControls.dampingFactor = 0.1;
this.orbitControls.rotateSpeed = 0.05;
this.orbitControls.autoRitate = true;

the funny thing is, everything seems to work when i drag only slightly (so delta is below EPSILON). so obviously i am doing somthing wrong with the dampening?!

Alternating between two cameras

Hi! Thanks for this wonderful alternative to OrbitControls 😄

I have a view that's being used for scientific visualization, and it's helpful to let the user toggle between orthographic and perspective. As a result, I've created two cameras and two CameraControls instances, and I'm alternating between them. However, this isn't working perfectly.

If I dispose() the first one when adding the second one, when I reattach it, it no longer receives mouse events, and if I recreate it, it seems to have lost some of its internal state.

If I don't dispose() the first when adding the second, the mouse events intended for the second are sent to both.

I could maybe add an undispose() or reattach() method.

Alternatively, I could try to recreate the controls each time the camera changes, though I'm not sure how to correctly transfer the internal state from the old controls.

Do you have a suggestion for this? Thanks!

fitTo method for orthographic camera

Hi 👋
First of all thanks for these controls. I find that it works really well, even with an orthographic camera!

I noticed that there is no solution for using the fitTo method when using an orthographic camera. I actually have a solution that I'm currently using and I wonder if you'd like me to make a PR out of it?

It's a calculation that sets the camera.zoom value so that it fits perfectly with the boundaries.
If you'd like I'll make a PR out of it 👍

Event emission feature

Summary

I want cameraControls.on( ... ).
More exactly, I need cameraControls.on( 'navigate', ( event ) => { ... } ) for now.
Do you have any implementation idea?

Context

I'm planning to implement auto-pilot using this camera-controls.
My requirements are:

  • Do auto-pilot initially
  • When interaction happens on it, stops the auto-pilot

I know I can implement "move from here to there" on itself using some animation stuff,
but I think it's too overpowered for it.
So, instead, I want cameraControls.on( 'navigate', ( event ) => { ... } )-like thing, to achieve halt the auto-pilot when user attempts to move camera.

duration

is there any way to set the duration?

Disable Pan?

Is it possible to disable pan? There doesn't appear to be an option to, does anyone know of a workaround?

I also don't mind taking a shot at that in a PR.

use different pivot point and focalpoint

I would like to be able to pass a Vector3 to some of the functions (e.g. rotate) as an argument to allow me to set what point the camera will pivot/dolly around, whilst being able to control the focalPoint of the camera separately. Currently it seems like there is no way to change the camera lookAt coordinates without changing the target for the transitions. Is this possible?

Automatic camera transitions move twice as fast is a mouse button is down

First of all, thanks for this very useful asset!

You can see the reported behaviour in the fit example: https://yomotsu.github.io/camera-controls/examples/fit-and-padding.html

Zoom out, then press one of the buttons to fit the camera view back to the box, and try clicking the mouse buttons. The transition speed definitely zooms in when a mouse button is held.

I have an app where I select 3D object with the mouse (raycasting) and fit the camera when they are clicked, but this bug causes the motion to be kinda jerky. Any way to fix this?

saveState issue

Hi,

Thanks for the plugin.

I am getting the below error on save state.

screen shot 2018-06-09 at 6 20 16 pm

screen shot 2018-06-09 at 6 20 36 pm

FYI, I thinks we need to use _target instead of target.

Thanks,
Sabari.

Using camera-controls with Orthographic camera

I am just documenting this here for other users. Doesn't really need a fix (feel free to close this).

Problem
There is no .fov property for THREE.OrthographicCamera but this following line requires that the camera has a .fov or else we get NaN:

const targetDistance = offset.length() * Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180 );

Workaround
Just add a fov property when creating a THREE.OrthographicCamera.

possible infinite dolly?

When using dolly it is limited to approaching the orbit target as would be with zoom. That limitation isn't how a real world dolly operation would behave. I'd like the ability to continue to dolly in the current direction. Is that something that could be added? Perhaps moving the target like the forward function but along the current vector.

Savestate not working properly.

Hi,

I saved the state and tried to apply that after reload. But, the camera position is completely changed. Could you please help on this?

Please see the code below.

Get State
cameraControls.saveState(); var position = cameraControls._position0.toArray(); var target = cameraControls._target0.toArray()

Apply
cameraControls._target0.fromArray(target); cameraControls._position0.fromArray(position); cameraControls.reset();

Thanks,
Sabari.

README: The word `rotX` and `rotY` might be ambiguous

Usually we use the word "rotate X" for rotation around X axis, whereas the document uses rotation around Y axis.
I think we should use theta and phi instead for here?

#### `rotate( rotX, rotY, enableTransition )`
Rotate azimuthal angle(theta) and polar angle(phi). `rotX` and `rotY` are in radian. `enableTransition` is in a boolean
#### `rotateTo( rotX, rotY, enableTransition )`
Rotate azimuthal angle(theta) and polar angle(phi) to a given point.

pinch disable y-axis

Hi,

I disable the minPolarAngle and maxPolarAngle so that when i pinch the polar angle is lock and it will just move forward and backward. But is there a way when you move forward and backwards the y-axis will remain at y = 0 ? Now when i pinch here is a increase or decrease on y-axis .

thanks

Wheel event not dispatching

Hi 👋

I noticed that when using the mouse wheel/pinch to zoom in/out there's no event dispatched. This would be useful to have for instance if we want to trigger somethingwhen doing zooming the scene.

I would propose that the onMouseWheel function also dispatches an event, perhaps 'control' or 'update'? Or a new event type like 'zoom'? Which one do you find best suitable?

Thanks 👏

firing multiple methods at once

I really like the way the 'reset' motion works whereby the camera swoops back into position and rotates around the object if necessary. Is there any way to emulate this but for a specific coordinate? What im looking to do is basically combine the rotate function with the moveTo function so i can navigate the scene by moving the camera in spirals. Im struggling to figure out if its possible with this library, any suggestions?

rotateTo method reverting all rotations if multiple were made before

I am using camera-controls on a sphere acting as an earth globe with different POIs put onto it.
The rotateTo method is being used to rotate to one of the POIs after the user clicks on them.

If the sphere has been rotated multiple times and the user clicks on one POI, all the rotations will be reverted on moving to the point, resulting in the sphere being rotated multiple times.
This should be fine as a default expected behavior, because it is logical correct, but in my case, I would like to animate rotateTo using the smallest relative distance from the current position to the POIs position.
I resolved this by firing the saveState and reset methods on user input which seem to reset the "rotation value/state", but this solution feels a bit hacky.

Maybe it might be useful to implement some kind of option parameter to toggle between the current behavior and the "relative" one. Or is there another way to handle this which I am currently overseeing?

Include zoom in JSON state?

Hi, I was thinking the zoom probably should be included in the JSON state, since it's critical for the orthographic camera.

For completeness, I could also imagine adding an accessor to the camera controls to get this value. Though that isn't essential. I'm able to pick the zoom from the camera directly.

What do you think?

dispatchEvent needs more returned value

camera-controls dispatchEvent provides some returned values as {type:'xxx',originalEvent:event}.I am making a viewcube to control my model.so I need more values such as "phi,theta . . ." to support me to control the viewcube's camera.

Dolly state not preserved when using toJSON and fromJSON

Hello,

Thanks for a great camera!

I'm using camera-controls with all default settings, and storing the state in localStorage:

const controls = new CameraControls(camera, canvas);

const cached = localStorage.getItem('controls')
if (cached !== null) {
  controls.fromJSON(cached)
}

controls.addEventListener('update', storeControls)

// simple debounce
let timeoutId = 0
function storeControls(e) {
  clearTimeout(timeoutId)
  timeoutId = window.setTimeout(() => {
    localStorage.setItem('controls', e.target.toJSON())
  }, 100)
}

When I dolly in and out using the mouse wheel I can see the position Vector3 in localStorage update. However when I refresh the page and fromJSON is used, the dolly position is reset.

Cheers.

Not working properly with z-axis up

I am using CameraControls (camera-controls) package to manage Camera on Three.js

When space is Y-axis up (camera.up.set(0,1,0)) it works just right, but when Z axis is set up (camera.up.set(0,0,1)) it stops working as expected (the same way it works with y-axis up)

Any clue how could I make CameraControls package work z-axis up?

Unlock polar rotation

First of all, thanks for this very useful asset!
i just look for unlock polar rotation (update camera up vector) like TrackballControls, any way to fix that ?

Thanks !

Rotate to point?

Hi!
Thanks for a great library and contribution to the Three community.

Previously is was using the Three example OrbitControl, but since this library have more features, especially animations I am trying it out.
For my project I have sphere which the camera is orbiting around. Depending on user inputs I want to move the camera targeting different points(cities) that are displayed on the sphere(globe).
Perviously I was handling this, picking up the position of the point and calculating the new camera position. Whit this code;

targetClicked() {
   const pos = this.target.position;
   const camDistance = this.camera.position.length();
   this.camera.position.copy(point).normalize().multiplyScalar(camDistance);
   this.controls.update();
}

But is there away to calculate the target; azimuthAngle, polarAngle and use your rotateTo()?

[EDIT]
Sorry for disturbing. I found a solution.
It was a bit to simple, just using .setPosition() with my previous code.

targetClicked() {
   const pos = this.target.position.clone();
   const camDistance = this.camera.position.length();
   pos.normalize().multiplyScalar(camDistance);
   this.controls.setPosition(pos.x, pos.y, pos.z, true);

Easing Functions

Is there any way to pass easing function on the fly to not just lerp with Math.exp to falloff transitions?
Something like:
controller.easing=function (t) {
// easeOutQuad
return t * (2 - t);
}

compatability with react-three-fiber?

hi ;)
I gave it a try with react-three-fiber and it got very laggy! specially as I try to rotate things!
here is the piece of Code that I wrote to make it work with react-three-fiber:

import React, { useRef } from 'react';
import * as THREE from 'three';
import { ReactThreeFiber, extend, useFrame, useThree } from 'react-three-fiber';
import CameraControls from 'camera-controls';
CameraControls.install({ THREE: THREE });

extend({ CameraControls });

declare global {
  namespace JSX {
    interface IntrinsicElements {
      cameraControls: ReactThreeFiber.Object3DNode<
        CameraControls,
        typeof CameraControls
      >;
    }
  }
}

const CControls: React.FC<any> = () => {
  const ccontrolRef = useRef<any>(null);
  const { camera, gl, clock, scene } = useThree();
  useFrame(() => {
    if (ccontrolRef.current) {
      const delta = clock.getDelta();
      const hasControlsUpdated = ccontrolRef.current.update(delta);
      if (hasControlsUpdated) gl.render(scene, camera);
    }
  });
  return <cameraControls ref={ccontrolRef} args={[camera, gl.domElement]} />;
};

export default CControls;

am I doing something wrong here? or its not somehow compatible with react-three?

Exposing _spherical

I've got an application where the user would like to see the polar angle. What do you think about exposing _spherical as a public property?

Either it could be unprotected (and marked readonly) or an accessor could be added which copies it.

Truck boundaries limit

Hello! Thank you for putting the effort to have this. It is great.

I've been trying to modify it a bit in order to implement bound limits to the truck function, but I couldn't find a "nice" way to put it together. I always mess up with something.

I am working in a map that needs to be panned within the boundaries oif the model, but nothing I do does the purpose.

Any tip or advice?

Cannot add keyboard event listener on the same domElement as CameraControls

Given canvas my renderer's domElement which is used when creating CameraControls, when adding an event listener on keydown like so:

canvas.addEventListener("keydown", () => {
  console.log("This is not working");
});

Then the console.log is never logged. I tried adding a click event listener just to be sure it works and it does. Only the keyboard related events (keydown, keyup, keypress) don't work.

Any idea why?

Resizing the window crashes the render

Is there any reason why resizing the window cause the crash of the render?

I noticed that it is also not possible to resize the window on your examples.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.