UNPKG

@pmndrs/uikit

Version:

Build performant 3D user interfaces with Three.js and yoga.

69 lines (68 loc) 2.87 kB
import { Camera, OrthographicCamera, PerspectiveCamera, Vector2 } from 'three'; import { batch, signal } from '@preact/signals-core'; import { searchFor } from '../utils.js'; import { Container } from './container.js'; const vectorHelper = new Vector2(); export class Fullscreen extends Container { renderer; sizeX; sizeY; transformTranslateZ; pixelSize; constructor(renderer, properties, initialClasses, config) { const sizeX = signal(0); const sizeY = signal(0); const transformTranslateZ = signal(0); const pixelSize = signal(0); super(properties, initialClasses, { ...config, defaultOverrides: { sizeX, sizeY, pixelSize, transformTranslateZ, pointerEvents: 'listener', ...config?.defaultOverrides, }, }); this.renderer = renderer; this.sizeX = sizeX; this.sizeY = sizeY; this.transformTranslateZ = transformTranslateZ; this.pixelSize = pixelSize; } update(delta) { super.update(delta); const camera = searchFor(this, Camera, 2, true); if (!(camera instanceof PerspectiveCamera || camera instanceof OrthographicCamera)) { throw new Error(`fullscreen can only be added to a camera`); } const distanceToCamera = this.properties.peek().distanceToCamera ?? camera.near + 0.1; batch(() => { let pixelSize; if (camera instanceof PerspectiveCamera) { const cameraHeight = 2 * Math.tan((Math.PI * camera.fov) / 360) * distanceToCamera; pixelSize = cameraHeight / this.renderer.getSize(vectorHelper).y; this.sizeY.value = cameraHeight; this.sizeX.value = cameraHeight * camera.aspect; } else if (camera instanceof OrthographicCamera) { const cameraHeight = (camera.top - camera.bottom) / camera.zoom; const cameraWidth = (camera.right - camera.left) / camera.zoom; pixelSize = cameraHeight / this.renderer.getSize(vectorHelper).y; this.sizeY.value = cameraHeight; this.sizeX.value = cameraWidth; } else { //to make TS happy, this else branch cannot happen return; } //if we are in a screen-based xr session, apply the pixel ratio to the pixel size to display the UI in the same size as outside of XR if (this.renderer.xr.getSession()?.interactionMode === 'screen-space') { pixelSize *= window.devicePixelRatio; } this.pixelSize.value = pixelSize; this.transformTranslateZ.value = -distanceToCamera / pixelSize; }); } }