@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
117 lines (106 loc) • 4.21 kB
text/typescript
import {OrthographicCamera} from 'three';
import {OrthographicCameraAttribute, UpdateProjectionOptions} from '../CoreCamera';
import {CameraFrameMode} from '../CoreCameraFrameMode';
import {ORTHOGRAPHIC_CAMERA_DEFAULT} from '../CoreOrthographicCamera';
import {BaseCoreCameraFrameMode} from './_BaseCoreCameraFrameMode';
import {cameraSetViewOffset} from '../CoreCameraViewOffset';
import {coreObjectClassFactory} from '../../geometry/CoreObjectFactory';
interface CoreCameraOrthographicFrameModeOptions {
camera: OrthographicCamera;
mode: CameraFrameMode;
size: number;
aspect: number;
expectedAspectRatio: number;
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type BasicCoreCameraOrthographicFrameModeOptions = PartialBy<
CoreCameraOrthographicFrameModeOptions,
'expectedAspectRatio'
>;
interface UpdateOptions extends UpdateProjectionOptions {
cameraWithAttributes?: OrthographicCamera;
}
OrthographicCamera;
export class CoreCameraOrthographicFrameMode {
static updateCameraAspect(camera: OrthographicCamera, aspect: number, options?: UpdateOptions) {
const cameraWithAttributes = options?.cameraWithAttributes || camera;
const frameMode = BaseCoreCameraFrameMode.frameMode(cameraWithAttributes);
const expectedAspectRatio = BaseCoreCameraFrameMode.expectedAspectRatio(cameraWithAttributes) as
| number
| undefined;
const size = coreObjectClassFactory(cameraWithAttributes).attribValue(
cameraWithAttributes,
OrthographicCameraAttribute.SIZE
) as number | undefined;
if (size != null) {
this._update({
mode: frameMode,
camera: camera,
size: size,
aspect: aspect,
expectedAspectRatio,
});
}
if (options && options.resolution) {
cameraSetViewOffset(camera, options.resolution);
}
camera.updateProjectionMatrix();
}
private static _update(options: BasicCoreCameraOrthographicFrameModeOptions) {
const mode = options.mode;
if (mode == CameraFrameMode.DEFAULT || options.expectedAspectRatio == null) {
this._adjustFOVFromModeDefault(options);
} else {
const {expectedAspectRatio} = options;
if (mode == CameraFrameMode.COVER) {
this._adjustFOVFromModeCover({...options, expectedAspectRatio});
} else {
this._adjustFOVFromModeContain({...options, expectedAspectRatio});
}
}
// switch (mode) {
// case CameraFrameMode.DEFAULT: {
// return this._adjustFOVFromModeDefault(options);
// }
// case CameraFrameMode.COVER: {
// return this._adjustFOVFromModeCover(options);
// }
// case CameraFrameMode.CONTAIN: {
// return this._adjustFOVFromModeContain(options);
// }
// }
// TypeAssert.unreachable(mode);
}
private static _adjustFOVFromModeDefault(options: BasicCoreCameraOrthographicFrameModeOptions) {
this._adjustFOVFromSize(options.size != null ? options.size : 1, options);
}
private static _adjustFOVFromModeCover(options: CoreCameraOrthographicFrameModeOptions) {
const size = options.size != null ? options.size : 1;
if (options.aspect > options.expectedAspectRatio) {
// window too large
this._adjustFOVFromSize((options.expectedAspectRatio * size) / options.aspect, options);
} else {
// window too narrow
this._adjustFOVFromSize(size, options);
}
}
private static _adjustFOVFromModeContain(options: CoreCameraOrthographicFrameModeOptions) {
const size = options.size != null ? options.size : 1;
if (options.aspect > options.expectedAspectRatio) {
// window too large
this._adjustFOVFromSize(size, options);
} else {
// window too narrow
this._adjustFOVFromSize((options.expectedAspectRatio * size) / options.aspect, options);
}
}
private static _adjustFOVFromSize(size: number, options: BasicCoreCameraOrthographicFrameModeOptions) {
const horizontalSize = size * options.aspect;
const zoom = 1;
options.camera.left = ORTHOGRAPHIC_CAMERA_DEFAULT.left * horizontalSize * zoom;
options.camera.right = ORTHOGRAPHIC_CAMERA_DEFAULT.right * horizontalSize * zoom;
options.camera.top = ORTHOGRAPHIC_CAMERA_DEFAULT.top * size * zoom;
options.camera.bottom = ORTHOGRAPHIC_CAMERA_DEFAULT.bottom * size * zoom;
}
}