lume
Version:
133 lines (116 loc) • 4.02 kB
text/typescript
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
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.
*/
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
shadowCameraTop = 1000
shadowCameraRight = 1000
shadowCameraBottom = -1000
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
}
}