UNPKG

@itwin/core-frontend

Version:
157 lines 8.43 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { expectDefined } from "@itwin/core-bentley"; import { Matrix3d, Point3d } from "@itwin/core-geometry"; import { Matrix3, Matrix4 } from "./Matrix"; import { desync, sync } from "./Sync"; export const MAX_SAMPLE_POINTS = 40; // Maximum number of sample points to be used for the in-scattering and out-scattering computations. export class AtmosphereUniforms { _atmosphere; _ellipsoid; // Main shader uniforms _earthScaleMatrix = new Matrix3d(new Float64Array([1, 0, 0, 0, 1, 0, 0, 0, 1])); _inverseEllipsoidRotationMatrix = new Matrix3d(new Float64Array([1, 0, 0, 0, 1, 0, 0, 0, 1])); _atmosphereScaleMatrix = new Matrix3d(new Float64Array([1, 0, 0, 0, 1, 0, 0, 0, 1])); _atmosphereData = new Matrix4(); /** * uniform mat3 u_atmosphereData; * { { atmosphereRadiusScaleFactor, atmosphereMaxDensityThresholdScaleFactor, densityFalloff, 0 }, * { numViewRaySamples, numSunRaySamples, 0, 0 }, * { earthCenter.x, earthCenter.y, earthCenter.z, 0 }, * { scatteringCoefficients.x, scatteringCoefficients.y, scatteringCoefficients.z, 0 } } */ get atmosphereData() { return this._atmosphereData; } // Fragment shader uniforms _exposure = 0.0; // utility syncKey = 0; _scratchMatrix3d = new Matrix3d(); _scratchPoint3d = new Point3d(); update(target) { const atmosphereHasNotChanged = this._atmosphere && target.plan.atmosphere && this._atmosphere.equals(target.plan.atmosphere); const ellipsoidHasNotChanged = this._ellipsoid && target.plan.ellipsoid && this._ellipsoid.equals(target.plan.ellipsoid); if (atmosphereHasNotChanged && ellipsoidHasNotChanged) { return; } this._atmosphere = target.plan.atmosphere; this._ellipsoid = target.plan.ellipsoid; desync(this); if (!this._atmosphere || !this._ellipsoid) { return; } this._updateAtmosphereScaleMatrix(this._atmosphere.atmosphereHeightAboveEarth); this._updateExposure(this._atmosphere.exposure); this._updateDensityFalloff(this._atmosphere.densityFalloff); this._updateEarthCenter(this._ellipsoid.ellipsoidCenter, target.uniforms.frustum.viewMatrix); this._updateEarthScaleMatrix(this._ellipsoid.ellipsoidRadii); this._updateInverseEllipsoidRotationMatrix(this._ellipsoid.ellipsoidRotation, target.uniforms.frustum.viewMatrix.matrix); this._updateAtmosphereRadiusScaleFactor(this._atmosphere.atmosphereHeightAboveEarth); this._updateAtmosphereMaxDensityThresholdScaleFactor(this._atmosphere.depthBelowEarthForMaxDensity); this._updateNumViewRaySamples(this._atmosphere.numViewRaySamples); this._updateNumSunRaySamples(this._atmosphere.numSunRaySamples); this._updateScatteringCoefficients(this._atmosphere.scatteringStrength, this._atmosphere.wavelengths); } _updateEarthCenter(earthCenter, viewMatrix) { viewMatrix.multiplyPoint3d(earthCenter, this._scratchPoint3d); this._atmosphereData.data[8] = this._scratchPoint3d.x; this._atmosphereData.data[9] = this._scratchPoint3d.y; this._atmosphereData.data[10] = this._scratchPoint3d.z; } _updateInverseEllipsoidRotationMatrix(ellipsoidRotation, viewRotation) { viewRotation.inverse(this._scratchMatrix3d); ellipsoidRotation.multiplyMatrixInverseMatrix(this._scratchMatrix3d, this._inverseEllipsoidRotationMatrix); } _updateEarthScaleMatrix(earthRadii) { this._earthScaleMatrix.setAt(0, 0, earthRadii.x); this._earthScaleMatrix.setAt(1, 1, earthRadii.y); this._earthScaleMatrix.setAt(2, 2, earthRadii.z); } _updateAtmosphereScaleMatrix(heightAboveSurface) { const earthPolarRadius = this._earthScaleMatrix.at(2, 2); const scaleFactor = earthPolarRadius === 0 ? 1.0 : (earthPolarRadius + heightAboveSurface) / earthPolarRadius; this._earthScaleMatrix.scale(scaleFactor, this._atmosphereScaleMatrix); } _updateAtmosphereRadiusScaleFactor(atmosphereHeightAboveEarth) { const earthPolarRadius = this._earthScaleMatrix.at(2, 2); const minDensityThresholdRadius = earthPolarRadius + atmosphereHeightAboveEarth; const atmosphereRadiusScaleFactor = (earthPolarRadius === 0) ? 1 : (minDensityThresholdRadius / earthPolarRadius); this.atmosphereData.data[0] = atmosphereRadiusScaleFactor; } _updateAtmosphereMaxDensityThresholdScaleFactor(maxDensityDepthBelowEarth) { const earthPolarRadius = this._earthScaleMatrix.at(2, 2); const maxDensityThresholdRadius = earthPolarRadius - maxDensityDepthBelowEarth; const atmosphereMaxDensityThresholdScaleFactor = (earthPolarRadius === 0) ? 1 : (maxDensityThresholdRadius / earthPolarRadius); this.atmosphereData.data[1] = atmosphereMaxDensityThresholdScaleFactor; } _updateDensityFalloff(densityFalloff) { this.atmosphereData.data[2] = densityFalloff; } _updateScatteringCoefficients(scatteringStrength, wavelengths) { // Rayleigh scattering strength is inversely related to the 4th power of the wavelength -> 1/pow(wavelength, 4) // Because this produces very small values when the wavelengths are taken in nanometers, // we attempt to normalize them around 1 by taking the smallest wavelength of visible light as a baseline (violet light - 400nm) const violetLightWavelength = 400.0; this.atmosphereData.data[12] = ((violetLightWavelength / wavelengths.r) ** 4.0) * scatteringStrength; this.atmosphereData.data[13] = ((violetLightWavelength / wavelengths.g) ** 4.0) * scatteringStrength; this.atmosphereData.data[14] = ((violetLightWavelength / wavelengths.b) ** 4.0) * scatteringStrength; } _updateExposure(exposure) { this._exposure = exposure; } bindExposure(uniform) { if (!sync(this, uniform)) { uniform.setUniform1f(this._exposure); } } _updateNumViewRaySamples(_numViewRaySamples) { const numViewRaySamples = Math.max(0, Math.min(MAX_SAMPLE_POINTS, _numViewRaySamples)); this.atmosphereData.data[4] = numViewRaySamples; } _updateNumSunRaySamples(_numSunRaySamples) { const numSunRaySamples = Math.max(0, Math.min(MAX_SAMPLE_POINTS, _numSunRaySamples)); this.atmosphereData.data[5] = numSunRaySamples; } bindInverseRotationInverseEarthScaleMatrix(uniform) { if (!sync(this, uniform)) { this._earthScaleMatrix.multiplyMatrixInverseMatrix(this._inverseEllipsoidRotationMatrix, this._scratchMatrix3d); uniform.setMatrix3(Matrix3.fromMatrix3d(this._scratchMatrix3d)); } } bindInverseRotationInverseAtmosphereScaleMatrix(uniform) { if (!sync(this, uniform)) { this._atmosphereScaleMatrix.multiplyMatrixInverseMatrix(this._inverseEllipsoidRotationMatrix, this._scratchMatrix3d); uniform.setMatrix3(Matrix3.fromMatrix3d(this._scratchMatrix3d)); } } bindEarthScaleMatrix(uniform) { if (!sync(this, uniform)) uniform.setMatrix3(Matrix3.fromMatrix3d(this._earthScaleMatrix)); } bindAtmosphereScaleMatrix(uniform) { if (!sync(this, uniform)) uniform.setMatrix3(Matrix3.fromMatrix3d(this._atmosphereScaleMatrix)); } bindInverseEarthScaleMatrix(uniform) { if (!sync(this, uniform)) uniform.setMatrix3(Matrix3.fromMatrix3d(expectDefined(this._earthScaleMatrix.inverse()))); } bindInverseAtmosphereScaleMatrix(uniform) { if (!sync(this, uniform)) uniform.setMatrix3(Matrix3.fromMatrix3d(expectDefined(this._atmosphereScaleMatrix.inverse()))); } get isDisposed() { return true; } [Symbol.dispose]() { } /** @deprecated in 5.0 - will not be removed until after 2026-06-13. Use [Symbol.dispose] instead. */ dispose() { this[Symbol.dispose](); } } //# sourceMappingURL=AtmosphereUniforms.js.map