UNPKG

mylingo3d

Version:

Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor

127 lines (107 loc) 4.22 kB
import { Reactive } from "@lincode/reactivity" import { mapRange } from "@tweakpane/core" import { DirectionalLight as ThreeDirectionalLight } from "three" import scene from "../../engine/scene" import { onBeforeRender } from "../../events/onBeforeRender" import { SHADOW_DISTANCE } from "../../globals" import IDirectionalLight, { directionalLightDefaults, directionalLightSchema } from "../../interface/IDirectionalLight" import { getCameraRendered } from "../../states/useCameraRendered" import { getShadowDistance } from "../../states/useShadowDistance" import LightBase from "../core/LightBase" import getWorldPosition from "../utils/getWorldPosition" import { vec2Point } from "../utils/vec2Point" export default class DirectionalLight extends LightBase<typeof ThreeDirectionalLight> implements IDirectionalLight { public static componentName = "directionalLight" public static defaults = directionalLightDefaults public static schema = directionalLightSchema protected override defaultShadowResolution = 1024 public constructor() { super(ThreeDirectionalLight) this.createEffect(() => { const light = this.lightState.get() if (!light) return scene.add(light.target) scene.attach(light) return () => { scene.remove(light.target) scene.remove(light) } }, [this.lightState.get]) this.createEffect(() => { const light = this.lightState.get() if (!light) return const camManager = getCameraRendered().userData.manager const offset = camManager ? Math.max( mapRange( camManager.innerZ * (camManager.fov / 75) * (1 / camManager.zoom), 500, 1000, 1, 1.5 ), 1 ) : 1 const shadowDistance = this.shadowDistanceState.get() ?? getShadowDistance() ?? SHADOW_DISTANCE const shadowCamera = light.shadow.camera shadowCamera.zoom = 500 / offset / shadowDistance shadowCamera.updateProjectionMatrix() const shadowBiasComputed = this.shadowBiasComputedState.get() const shadowResolutionComputed = this.shadowResolutionComputedState.get() if (!shadowBiasComputed || !shadowResolutionComputed) return const shadowBias = shadowBiasComputed light.shadow.bias = shadowBias * offset * (this.defaultShadowResolution / shadowResolutionComputed) * 0.5 return () => { light.shadow.bias = shadowBias } }, [ this.lightState.get, this.shadowDistanceState.get, getShadowDistance, getCameraRendered, this.shadowBiasComputedState.get, this.shadowResolutionComputedState.get ]) this.createEffect(() => { const light = this.lightState.get() if (!light) return const cam = getCameraRendered() const handle = onBeforeRender(() => { const camPos = getWorldPosition(cam) const lightPos = getWorldPosition(this.outerObject3d) light.position.copy(camPos).add(lightPos) light.target.position.copy(camPos).sub(lightPos) }) return () => { handle.cancel() } }, [getCameraRendered, this.lightState.get]) } public override getWorldPosition() { return vec2Point(getWorldPosition(this.outerObject3d)) } private shadowDistanceState = new Reactive<number | undefined>(undefined) public get shadowDistance() { return this.shadowDistanceState.get() } public set shadowDistance(val) { this.shadowDistanceState.set(val) } }