Initial work on perspective camera control for the 3D demo
This commit is contained in:
parent
7360a41a60
commit
049b8eba97
|
@ -12,6 +12,7 @@ import * as glmatrix from 'gl-matrix';
|
|||
|
||||
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
||||
import {DemoAppController} from "./app-controller";
|
||||
import {PerspectiveCamera} from "./camera";
|
||||
import {mat4, vec2} from "gl-matrix";
|
||||
import {PathfinderMeshData} from "./meshes";
|
||||
import {ShaderMap, ShaderProgramSource} from "./shader-loader";
|
||||
|
@ -19,7 +20,6 @@ import {BUILTIN_FONT_URI, TextLayout, PathfinderGlyph} from "./text";
|
|||
import {PathfinderError, panic, unwrapNull} from "./utils";
|
||||
import {PathfinderDemoView, Timings} from "./view";
|
||||
import SSAAStrategy from "./ssaa-strategy";
|
||||
import { OrthographicCamera } from "./camera";
|
||||
|
||||
const TEXT: string = "Lorem ipsum dolor sit amet";
|
||||
|
||||
|
@ -27,6 +27,10 @@ const FONT: string = 'open-sans';
|
|||
|
||||
const PIXELS_PER_UNIT: number = 1.0;
|
||||
|
||||
const FOV: number = 45.0;
|
||||
const NEAR_CLIP_PLANE: number = 0.01;
|
||||
const FAR_CLIP_PLANE: number = 1000.0;
|
||||
|
||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||
none: NoAAStrategy,
|
||||
ssaa: SSAAStrategy,
|
||||
|
@ -82,9 +86,8 @@ class ThreeDView extends PathfinderDemoView {
|
|||
|
||||
this.appController = appController;
|
||||
|
||||
this.camera = new OrthographicCamera(this.canvas);
|
||||
this.camera.onPan = () => this.setDirty();
|
||||
this.camera.onZoom = () => this.setDirty();
|
||||
this.camera = new PerspectiveCamera(this.canvas);
|
||||
this.camera.onChange = () => this.setDirty();
|
||||
}
|
||||
|
||||
uploadPathMetadata(pathCount: number) {
|
||||
|
@ -140,9 +143,13 @@ class ThreeDView extends PathfinderDemoView {
|
|||
|
||||
protected get worldTransform() {
|
||||
const transform = glmatrix.mat4.create();
|
||||
const translation = this.camera.translation;
|
||||
glmatrix.mat4.fromTranslation(transform, [translation[0], translation[1], 0]);
|
||||
glmatrix.mat4.scale(transform, transform, [this.camera.scale, this.camera.scale, 1.0]);
|
||||
glmatrix.mat4.perspective(transform,
|
||||
FOV / 180.0 * Math.PI,
|
||||
this.canvas.width / this.canvas.height,
|
||||
NEAR_CLIP_PLANE,
|
||||
FAR_CLIP_PLANE);
|
||||
glmatrix.mat4.translate(transform, transform, this.camera.translation);
|
||||
glmatrix.mat4.mul(transform, transform, this.camera.rotationMatrix);
|
||||
return transform;
|
||||
}
|
||||
|
||||
|
@ -150,7 +157,7 @@ class ThreeDView extends PathfinderDemoView {
|
|||
|
||||
private appController: ThreeDController;
|
||||
|
||||
camera: OrthographicCamera;
|
||||
camera: PerspectiveCamera;
|
||||
}
|
||||
|
||||
class ThreeDGlyph extends PathfinderGlyph {
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
import * as glmatrix from 'gl-matrix';
|
||||
import {PathfinderView} from "./view";
|
||||
|
||||
const SCALE_FACTOR: number = 1.0 / 100.0;
|
||||
const ORTHOGRAPHIC_ZOOM_SPEED: number = 1.0 / 100.0;
|
||||
|
||||
const PERSPECTIVE_MOVEMENT_SPEED: number = 10.0;
|
||||
const PERSPECTIVE_ROTATION_SPEED: number = 1.0 / 300.0;
|
||||
|
||||
const MOVEMENT_INTERVAL_DELAY: number = 10;
|
||||
|
||||
export abstract class Camera {
|
||||
constructor(canvas: HTMLCanvasElement) {
|
||||
|
@ -49,7 +54,7 @@ export class OrthographicCamera extends Camera {
|
|||
glmatrix.vec2.sub(absoluteTranslation, this.translation, mouseLocation);
|
||||
glmatrix.vec2.scale(absoluteTranslation, absoluteTranslation, 1.0 / this.scale);
|
||||
|
||||
this.scale *= 1.0 - event.deltaY * window.devicePixelRatio * SCALE_FACTOR;
|
||||
this.scale *= 1.0 - event.deltaY * window.devicePixelRatio * ORTHOGRAPHIC_ZOOM_SPEED;
|
||||
|
||||
glmatrix.vec2.scale(absoluteTranslation, absoluteTranslation, this.scale);
|
||||
glmatrix.vec2.add(this.translation, absoluteTranslation, mouseLocation);
|
||||
|
@ -73,3 +78,77 @@ export class OrthographicCamera extends Camera {
|
|||
translation: glmatrix.vec2;
|
||||
scale: number;
|
||||
}
|
||||
|
||||
export class PerspectiveCamera extends Camera {
|
||||
constructor(canvas: HTMLCanvasElement) {
|
||||
super(canvas);
|
||||
|
||||
this.translation = glmatrix.vec3.create();
|
||||
this.rotation = glmatrix.vec2.create();
|
||||
this.movementDelta = glmatrix.vec3.create();
|
||||
this.movementInterval = null;
|
||||
|
||||
this.canvas.addEventListener('mousedown', event => this.onMouseDown(event), false);
|
||||
this.canvas.addEventListener('mouseup', event => this.onMouseUp(event), false);
|
||||
this.canvas.addEventListener('mousemove', event => this.onMouseMove(event), false);
|
||||
|
||||
this.onChange = null;
|
||||
}
|
||||
|
||||
private onMouseDown(event: MouseEvent): void {
|
||||
if (document.pointerLockElement !== this.canvas) {
|
||||
this.canvas.requestPointerLock();
|
||||
return;
|
||||
}
|
||||
|
||||
this.movementDelta = glmatrix.vec3.fromValues(PERSPECTIVE_MOVEMENT_SPEED, 0.0, 0.0);
|
||||
if (event.button !== 1)
|
||||
this.movementDelta[0] = -this.movementDelta[0];
|
||||
|
||||
this.movementInterval = window.setInterval(() => this.move(), MOVEMENT_INTERVAL_DELAY);
|
||||
}
|
||||
|
||||
private onMouseUp(event: MouseEvent): void {
|
||||
if (this.movementInterval != null) {
|
||||
window.clearInterval(this.movementInterval);
|
||||
this.movementDelta = glmatrix.vec3.create();
|
||||
}
|
||||
}
|
||||
|
||||
private move() {
|
||||
const delta = glmatrix.vec3.clone(this.movementDelta);
|
||||
glmatrix.vec3.transformMat4(delta, delta, this.rotationMatrix);
|
||||
glmatrix.vec3.add(this.translation, this.translation, delta);
|
||||
|
||||
if (this.onChange != null)
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
private onMouseMove(event: MouseEvent): void {
|
||||
if (document.pointerLockElement !== this.canvas)
|
||||
return;
|
||||
|
||||
this.rotation[0] += event.movementY * PERSPECTIVE_ROTATION_SPEED;
|
||||
this.rotation[1] += event.movementX * PERSPECTIVE_ROTATION_SPEED;
|
||||
|
||||
if (this.onChange != null)
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
get rotationMatrix(): glmatrix.mat4 {
|
||||
const matrix = glmatrix.mat4.create();
|
||||
glmatrix.mat4.fromXRotation(matrix, this.rotation[0]);
|
||||
glmatrix.mat4.rotateY(matrix, matrix, this.rotation[1]);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
onChange: (() => void) | null;
|
||||
|
||||
translation: glmatrix.vec3;
|
||||
|
||||
/// Pitch and yaw Euler angles.
|
||||
rotation: glmatrix.vec2;
|
||||
|
||||
private movementDelta: glmatrix.vec3;
|
||||
private movementInterval: number | null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue