Skip to content

Instantly share code, notes, and snippets.

@alexsr
Created August 17, 2020 15:35
Show Gist options
  • Save alexsr/08f25b5ced95d5bfe8ad7fed493830e0 to your computer and use it in GitHub Desktop.
Save alexsr/08f25b5ced95d5bfe8ad7fed493830e0 to your computer and use it in GitHub Desktop.
Three JS Camera Controller for typical CG camera
import * as THREE from 'three'
export class CameraController {
camera: THREE.Camera;
invertControls: boolean;
domElement: HTMLElement;
controls: PointerLockControls;
moveForward: boolean;
moveBackward: boolean;
moveLeft: boolean;
moveRight: boolean;
moveUp: boolean;
moveDown: boolean;
moveSpeed: number;
rotationSpeed: number;
angles: THREE.Vector2;
movedAngles: THREE.Vector2;
rotation: THREE.Quaternion;
rotationEnabled: boolean;
disposeEventListeners: () => void;
constructor(camera: THREE.Camera, domElement: HTMLElement, invertControls: boolean = false) {
this.camera = camera;
this.camera.position.set(0, 0, 1);
this.domElement = domElement;
this.invertControls = invertControls;
this.moveForward = false;
this.moveBackward = false;
this.moveLeft = false;
this.moveRight = false;
this.moveUp = false;
this.moveDown = false;
this.moveSpeed = 5.0;
this.rotationSpeed = 10.0;
this.angles = new THREE.Vector2(0, 0);
this.movedAngles = new THREE.Vector2(0, 0);
this.rotation = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), this.angles.y).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), this.angles.x));
this.rotationEnabled = false;
const onKeyDown = (event: KeyboardEvent) => {
console.log(event);
switch (event.keyCode) {
case 38: // up
case 87: // w
this.moveForward = true;
event.preventDefault()
break;
case 37: // left
case 65: // a
this.moveLeft = true;
event.preventDefault()
break;
case 40: // down
case 83: // s
this.moveBackward = true;
event.preventDefault()
break;
case 39: // right
case 68: // d
this.moveRight = true;
event.preventDefault()
break;
case 69: // e
this.moveUp = true;
event.preventDefault()
break;
case 81: // q
this.moveDown = true;
event.preventDefault()
break;
}
};
const onKeyUp = (event: KeyboardEvent) => {
switch (event.keyCode) {
case 38: // up
case 87: // w
this.moveForward = false;
event.preventDefault()
break;
case 37: // left
case 65: // a
this.moveLeft = false;
event.preventDefault()
break;
case 40: // down
case 83: // s
this.moveBackward = false;
event.preventDefault()
break;
case 39: // right
case 68: // d
this.moveRight = false;
event.preventDefault()
break;
case 69: // e
this.moveUp = false;
event.preventDefault()
break;
case 81: // q
this.moveDown = false;
event.preventDefault()
break;
}
};
const onMouseMove = (event: MouseEvent) => {
if (this.rotationEnabled) {
this.movedAngles = new THREE.Vector2(-event.movementY / 180.0 * Math.PI, -event.movementX / 180.0 * Math.PI);
}
}
this.domElement.addEventListener("click", () => {
this.domElement.requestPointerLock();
});
this.domElement.addEventListener("mousedown", () => {
this.rotationEnabled = true;
});
this.domElement.addEventListener("mouseup", () => {
this.rotationEnabled = false;
})
document.addEventListener('pointerlockchange', () => {
if (document.pointerLockElement === this.domElement) {
document.addEventListener("keydown", onKeyDown);
document.addEventListener("keyup", onKeyUp);
this.domElement.addEventListener("mousemove", onMouseMove);
} else {
document.removeEventListener("keydown", onKeyDown);
document.removeEventListener("keyup", onKeyUp);
this.domElement.removeEventListener("mousemove", onMouseMove);
}
}, false);
}
update(dt: number) {
let movement = new THREE.Vector3(Number(this.moveRight) - Number(this.moveLeft),
Number(this.moveUp) - Number(this.moveDown),
Number(this.moveBackward) - Number(this.moveForward)).multiplyScalar(this.moveSpeed * dt);
this.angles = this.angles.add(this.movedAngles.multiplyScalar(dt * this.rotationSpeed));
this.rotation = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), this.angles.y).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), this.angles.x));
movement = movement.applyQuaternion(this.rotation);
let newPos = this.camera.position.add(movement);
console.log(newPos);
this.camera.position.set(newPos.x, newPos.y, newPos.z);
this.camera.rotation.setFromQuaternion(this.rotation);
this.movedAngles = new THREE.Vector2(0, 0);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment