UNPKG

lume

Version:

Build next-level interactive web applications.

133 lines (116 loc) 4.02 kB
import {numberAttribute, element, type ElementAttributes} from '@lume/element' import {onCleanup} from 'solid-js' import {DirectionalLight as ThreeDirectionalLight} from 'three/src/lights/DirectionalLight.js' import {DirectionalLightHelper} from 'three/src/helpers/DirectionalLightHelper.js' import {CameraHelper} from 'three/src/helpers/CameraHelper.js' import {LightWithShadow, type LightWithShadowAttributes} from './LightWithShadow.js' import {autoDefineElements} from '../LumeConfig.js' import {Motor} from '../core/Motor.js' export type DirectionalLightAttributes = | LightWithShadowAttributes | 'shadowCameraTop' | 'shadowCameraRight' | 'shadowCameraBottom' | 'shadowCameraLeft' // TODO @element jsdoc tag /** * @element lume-directional-light * @class DirectionalLight - * * Element: `<lume-directional-light>` * * This creates light with a particular direction all over the world. Think of * it like a point light infinitely (or very) far away, and the emitted light * rays are effectively all parallel. An example use case could be emulating * the sun, which is far enough away that on earth all the rays seem to be * parallel. * * The direction of the light is the direction from the light's * `position` to the world origin (the center of a scene's viewport). * * When casting shadows, an orthographic camera is used, and shadows are limited * to be within the ortho box specified by the `shadowCamera*` properties. While * light color affects all objects in a scene, only objects within the shadow * camera limits will be affects by shadows. * * ## Example * * <live-code id="liveExample"></live-code> * <script> * liveExample.content = directionalLightExample() * </script> * * @extends LightWithShadow */ export @element('lume-directional-light', autoDefineElements) class DirectionalLight extends LightWithShadow { /** * @property {number} intensity - * * `override` `attribute` * * Default: `1` * * The intensity of the light. * * The intensity of this element does not change behavior when [physically * correct lighting](../core/Scene#physicallycorrectlights) is enabled. */ @numberAttribute override intensity = 1 // These map to THREE.DirectionalLightShadow properties, which uses an orthographic camera for shadow projection. // https://threejs.org/docs/index.html?q=light#api/en/lights/shadows/DirectionalLightShadow @numberAttribute shadowCameraTop = 1000 @numberAttribute shadowCameraRight = 1000 @numberAttribute shadowCameraBottom = -1000 @numberAttribute shadowCameraLeft = -1000 override connectedCallback() { super.connectedCallback() this.three.castShadow = true this.createEffect(() => { const light = this.three const shadow = light.shadow shadow.camera.top = this.shadowCameraTop shadow.camera.right = this.shadowCameraRight shadow.camera.bottom = this.shadowCameraBottom shadow.camera.left = this.shadowCameraLeft shadow.needsUpdate = true this.needsUpdate() }) this.createEffect(() => { if (!this.debug) return if (!this.scene) return const lightHelper = new DirectionalLightHelper(this.three, this.shadowCameraTop - this.shadowCameraBottom) this.scene.three.add(lightHelper) const camHelper = new CameraHelper(this.three.shadow.camera) this.scene.three.add(camHelper) const task = Motor.addRenderTask(() => { lightHelper.update() camHelper.update() this.scene!.needsUpdate() }) onCleanup(() => { Motor.removeRenderTask(task) lightHelper.dispose() this.scene!.three.remove(lightHelper) camHelper.dispose() this.scene!.three.remove(camHelper) }) }) } override makeThreeObject3d() { return new ThreeDirectionalLight() } } declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'lume-directional-light': ElementAttributes<DirectionalLight, DirectionalLightAttributes> } } } declare global { interface HTMLElementTagNameMap { 'lume-directional-light': DirectionalLight } }