UNPKG

@takram/three-atmosphere

Version:
119 lines (102 loc) 3.75 kB
import { Vector2, Vector3, type Camera } from 'three' import { uniform } from 'three/tsl' import type { NodeBuilder } from 'three/webgpu' import { Ellipsoid, Geodetic } from '@takram/three-geospatial' import { getAltitudeCorrectionOffset } from '../getAltitudeCorrectionOffset' import { AtmosphereContextBase } from './AtmosphereContextBase' import { AtmosphereLUTNode } from './AtmosphereLUTNode' import { AtmosphereParameters } from './AtmosphereParameters' const vectorScratch = /*#__PURE__*/ new Vector3() const geodeticScratch = /*#__PURE__*/ new Geodetic() export class AtmosphereContext extends AtmosphereContextBase { lutNode: AtmosphereLUTNode matrixWorldToECEF = uniform('mat4').setName('matrixWorldToECEF') matrixECIToECEF = uniform('mat4').setName('matrixECIToECEF') sunDirectionECEF = uniform('vec3').setName('sunDirectionECEF') moonDirectionECEF = uniform('vec3').setName('moonDirectionECEF') matrixMoonFixedToECEF = uniform('mat4').setName('matrixMoonFixedToECEF') scatteringSampleCount = uniform(new Vector2(4, 14)) matrixECEFToWorld = uniform('mat4') .setName('matrixECEFToWorld') .onRenderUpdate((_, { value }) => { // The matrixWorldToECEF must be orthogonal. value.copy(this.matrixWorldToECEF.value).transpose() }) cameraPositionECEF = uniform('vec3') .setName('cameraPositionECEF') .onRenderUpdate((frame, { value }) => { const camera = this.camera ?? frame.camera if (camera == null) { return } value .setFromMatrixPosition(camera.matrixWorld) .applyMatrix4(this.matrixWorldToECEF.value) }) altitudeCorrectionECEF = uniform('vec3') .setName('altitudeCorrectionECEF') .onRenderUpdate((frame, { value }) => { const camera = this.camera ?? frame.camera if (camera == null) { return } getAltitudeCorrectionOffset( value .setFromMatrixPosition(camera.matrixWorld) .applyMatrix4(this.matrixWorldToECEF.value), this.parameters.bottomRadius, this.ellipsoid, value ) }) cameraHeight = uniform(0) .setName('cameraHeight') .onRenderUpdate((frame, self) => { const camera = this.camera ?? frame.camera if (camera == null) { return } const positionECEF = vectorScratch .setFromMatrixPosition(camera.matrixWorld) .applyMatrix4(this.matrixWorldToECEF.value) self.value = geodeticScratch.setFromECEF(positionECEF).height }) cameraPositionUnit = this.cameraPositionECEF .mul(this.parametersNode.worldToUnit) .toConst('cameraPositionUnit') altitudeCorrectionUnit = this.altitudeCorrectionECEF .mul(this.parametersNode.worldToUnit) .toConst('altitudeCorrectionUnit') camera?: Camera ellipsoid = Ellipsoid.WGS84 correctAltitude = true constrainCamera = true showGround = true accurateShadowScattering = true raymarchScattering = true constructor( parameters = new AtmosphereParameters(), lutNode = new AtmosphereLUTNode(parameters) ) { super(parameters) this.lutNode = lutNode } override dispose(): void { this.lutNode.dispose() super.dispose() } } /** @deprecated Use AtmosphereContext instead. */ export const AtmosphereContextNode = AtmosphereContext export function getAtmosphereContext(builder: NodeBuilder): AtmosphereContext { if (typeof builder.context.getAtmosphere !== 'function') { throw new Error('getAtmosphere() was not found in the builder context.') } const context = builder.context.getAtmosphere() if (!(context instanceof AtmosphereContext)) { throw new Error( 'getAtmosphere() must return an instanceof AtmosphereContext.' ) } return context }