@onerjs/addons 8.25.4 → 8.25.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/atmosphere/Shaders/ShadersInclude/atmosphereFragmentDeclaration.d.ts +5 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereFragmentDeclaration.js +12 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereFragmentDeclaration.js.map +1 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereFunctions.d.ts +6 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereFunctions.js +234 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereFunctions.js.map +1 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereUboDeclaration.d.ts +5 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereUboDeclaration.js +12 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereUboDeclaration.js.map +1 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereVertexDeclaration.d.ts +5 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereVertexDeclaration.js +12 -0
- package/atmosphere/Shaders/ShadersInclude/atmosphereVertexDeclaration.js.map +1 -0
- package/atmosphere/Shaders/ShadersInclude/depthFunctions.d.ts +5 -0
- package/atmosphere/Shaders/ShadersInclude/depthFunctions.js +19 -0
- package/atmosphere/Shaders/ShadersInclude/depthFunctions.js.map +1 -0
- package/atmosphere/Shaders/aerialPerspective.fragment.d.ts +9 -0
- package/atmosphere/Shaders/aerialPerspective.fragment.js +25 -0
- package/atmosphere/Shaders/aerialPerspective.fragment.js.map +1 -0
- package/atmosphere/Shaders/compositeAerialPerspective.fragment.d.ts +10 -0
- package/atmosphere/Shaders/compositeAerialPerspective.fragment.js +72 -0
- package/atmosphere/Shaders/compositeAerialPerspective.fragment.js.map +1 -0
- package/atmosphere/Shaders/compositeGlobeAtmosphere.fragment.d.ts +10 -0
- package/atmosphere/Shaders/compositeGlobeAtmosphere.fragment.js +96 -0
- package/atmosphere/Shaders/compositeGlobeAtmosphere.fragment.js.map +1 -0
- package/atmosphere/Shaders/compositeSky.fragment.d.ts +10 -0
- package/atmosphere/Shaders/compositeSky.fragment.js +75 -0
- package/atmosphere/Shaders/compositeSky.fragment.js.map +1 -0
- package/atmosphere/Shaders/diffuseSkyIrradiance.fragment.d.ts +13 -0
- package/atmosphere/Shaders/diffuseSkyIrradiance.fragment.js +49 -0
- package/atmosphere/Shaders/diffuseSkyIrradiance.fragment.js.map +1 -0
- package/atmosphere/Shaders/fullscreenTriangle.vertex.d.ts +7 -0
- package/atmosphere/Shaders/fullscreenTriangle.vertex.js +31 -0
- package/atmosphere/Shaders/fullscreenTriangle.vertex.js.map +1 -0
- package/atmosphere/Shaders/multiScattering.fragment.d.ts +9 -0
- package/atmosphere/Shaders/multiScattering.fragment.js +21 -0
- package/atmosphere/Shaders/multiScattering.fragment.js.map +1 -0
- package/atmosphere/Shaders/skyView.fragment.d.ts +9 -0
- package/atmosphere/Shaders/skyView.fragment.js +20 -0
- package/atmosphere/Shaders/skyView.fragment.js.map +1 -0
- package/atmosphere/Shaders/transmittance.fragment.d.ts +9 -0
- package/atmosphere/Shaders/transmittance.fragment.js +20 -0
- package/atmosphere/Shaders/transmittance.fragment.js.map +1 -0
- package/atmosphere/atmosphere.d.ts +418 -0
- package/atmosphere/atmosphere.js +1446 -0
- package/atmosphere/atmosphere.js.map +1 -0
- package/atmosphere/atmosphereOptions.d.ts +135 -0
- package/atmosphere/atmosphereOptions.js +4 -0
- package/atmosphere/atmosphereOptions.js.map +1 -0
- package/atmosphere/atmospherePBRMaterialPlugin.d.ts +72 -0
- package/atmosphere/atmospherePBRMaterialPlugin.js +230 -0
- package/atmosphere/atmospherePBRMaterialPlugin.js.map +1 -0
- package/atmosphere/atmospherePerCameraVariables.d.ts +102 -0
- package/atmosphere/atmospherePerCameraVariables.js +189 -0
- package/atmosphere/atmospherePerCameraVariables.js.map +1 -0
- package/atmosphere/atmospherePhysicalProperties.d.ts +154 -0
- package/atmosphere/atmospherePhysicalProperties.js +305 -0
- package/atmosphere/atmospherePhysicalProperties.js.map +1 -0
- package/atmosphere/atmospherePhysicalPropertiesOptions.d.ts +52 -0
- package/atmosphere/atmospherePhysicalPropertiesOptions.js +4 -0
- package/atmosphere/atmospherePhysicalPropertiesOptions.js.map +1 -0
- package/atmosphere/diffuseSkyIrradianceLut.d.ts +63 -0
- package/atmosphere/diffuseSkyIrradianceLut.js +199 -0
- package/atmosphere/diffuseSkyIrradianceLut.js.map +1 -0
- package/atmosphere/index.d.ts +6 -0
- package/atmosphere/index.js +9 -0
- package/atmosphere/index.js.map +1 -0
- package/atmosphere/sampling.d.ts +15 -0
- package/atmosphere/sampling.js +89 -0
- package/atmosphere/sampling.js.map +1 -0
- package/atmosphere/test/unit/sampling.test.d.ts +1 -0
- package/atmosphere/test/unit/sampling.test.js +77 -0
- package/atmosphere/test/unit/sampling.test.js.map +1 -0
- package/atmosphere/transmittanceLut.d.ts +68 -0
- package/atmosphere/transmittanceLut.js +207 -0
- package/atmosphere/transmittanceLut.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/msdfText/paragraphOptions.d.ts +1 -1
- package/msdfText/paragraphOptions.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,1446 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// MIT License
|
|
3
|
+
import { AtmospherePBRMaterialPlugin } from "./atmospherePBRMaterialPlugin.js";
|
|
4
|
+
import { AtmospherePerCameraVariables } from "./atmospherePerCameraVariables.js";
|
|
5
|
+
import { AtmospherePhysicalProperties } from "./atmospherePhysicalProperties.js";
|
|
6
|
+
import { Color3 } from "@onerjs/core/Maths/math.color.js";
|
|
7
|
+
import { Constants } from "@onerjs/core/Engines/constants.js";
|
|
8
|
+
import { DiffuseSkyIrradianceLut } from "./diffuseSkyIrradianceLut.js";
|
|
9
|
+
import { EffectRenderer, EffectWrapper } from "@onerjs/core/Materials/effectRenderer.js";
|
|
10
|
+
import { Observable } from "@onerjs/core/Misc/observable.js";
|
|
11
|
+
import { RegisterMaterialPlugin, UnregisterMaterialPlugin } from "@onerjs/core/Materials/materialPluginManager.js";
|
|
12
|
+
import { RenderTargetTexture } from "@onerjs/core/Materials/Textures/renderTargetTexture.js";
|
|
13
|
+
import { TransmittanceLut } from "./transmittanceLut.js";
|
|
14
|
+
import { UniformBuffer } from "@onerjs/core/Materials/uniformBuffer.js";
|
|
15
|
+
import { Vector3 } from "@onerjs/core/Maths/math.vector.js";
|
|
16
|
+
import "./Shaders/compositeAerialPerspective.fragment.js";
|
|
17
|
+
import "./Shaders/compositeSky.fragment.js";
|
|
18
|
+
import "./Shaders/compositeGlobeAtmosphere.fragment.js";
|
|
19
|
+
import "./Shaders/fullscreenTriangle.vertex.js";
|
|
20
|
+
import "./Shaders/multiScattering.fragment.js";
|
|
21
|
+
import "./Shaders/skyView.fragment.js";
|
|
22
|
+
import "./Shaders/aerialPerspective.fragment.js";
|
|
23
|
+
import "./Shaders/ShadersInclude/atmosphereFragmentDeclaration.js";
|
|
24
|
+
import "./Shaders/ShadersInclude/atmosphereFunctions.js";
|
|
25
|
+
import "./Shaders/ShadersInclude/atmosphereUboDeclaration.js";
|
|
26
|
+
import "./Shaders/ShadersInclude/atmosphereVertexDeclaration.js";
|
|
27
|
+
import "./Shaders/ShadersInclude/depthFunctions.js";
|
|
28
|
+
const MaterialPlugin = "atmo-pbr";
|
|
29
|
+
/**
|
|
30
|
+
* Renders a physically based atmosphere.
|
|
31
|
+
* Use {@link IsSupported} to check if the atmosphere is supported before creating an instance.
|
|
32
|
+
* @experimental
|
|
33
|
+
*/
|
|
34
|
+
export class Atmosphere {
|
|
35
|
+
/**
|
|
36
|
+
* Checks if the {@link Atmosphere} is supported.
|
|
37
|
+
* @param engine - The engine to check.
|
|
38
|
+
* @returns True if the atmosphere is supported, false otherwise.
|
|
39
|
+
*/
|
|
40
|
+
static IsSupported(engine) {
|
|
41
|
+
return !engine._badOS && !engine.isWebGPU && engine.version >= 2;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Controls the overall brightness of the atmosphere rendering.
|
|
45
|
+
*/
|
|
46
|
+
get exposure() {
|
|
47
|
+
return this._exposure;
|
|
48
|
+
}
|
|
49
|
+
set exposure(value) {
|
|
50
|
+
this._exposure = Math.max(0, value);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Affects the overall intensity of the multiple scattering.
|
|
54
|
+
*/
|
|
55
|
+
get multiScatteringIntensity() {
|
|
56
|
+
return this._multiScatteringIntensity;
|
|
57
|
+
}
|
|
58
|
+
set multiScatteringIntensity(value) {
|
|
59
|
+
const newValue = Math.max(0.0, value);
|
|
60
|
+
if (newValue !== this._multiScatteringIntensity) {
|
|
61
|
+
this._multiScatteringIntensity = value;
|
|
62
|
+
this._diffuseSkyIrradianceLut?.markDirty();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Affects the multiply scattered light contribution in the atmosphere by describing the average light color reflected off the ground.
|
|
67
|
+
*/
|
|
68
|
+
get groundAlbedo() {
|
|
69
|
+
return this._groundAlbedo;
|
|
70
|
+
}
|
|
71
|
+
set groundAlbedo(value) {
|
|
72
|
+
if (!this._groundAlbedo.equals(value)) {
|
|
73
|
+
this._groundAlbedo.copyFrom(value);
|
|
74
|
+
this._multiScatteringEffectWrapper?.dispose();
|
|
75
|
+
this._multiScatteringEffectWrapper = null;
|
|
76
|
+
this._hasRenderedMultiScatteringLut = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Can be used to clamp the multiple scattering to a minimum value.
|
|
81
|
+
*/
|
|
82
|
+
get minimumMultiScatteringColor() {
|
|
83
|
+
return this._minimumMultiScatteringColor;
|
|
84
|
+
}
|
|
85
|
+
set minimumMultiScatteringColor(value) {
|
|
86
|
+
if (!this._minimumMultiScatteringColor.equals(value)) {
|
|
87
|
+
const minimumScatteringColor = this._minimumMultiScatteringColor.copyFrom(value);
|
|
88
|
+
this._minimumMultiScattering.x = minimumScatteringColor.r * this._minimumMultiScatteringIntensity;
|
|
89
|
+
this._minimumMultiScattering.y = minimumScatteringColor.g * this._minimumMultiScatteringIntensity;
|
|
90
|
+
this._minimumMultiScattering.z = minimumScatteringColor.b * this._minimumMultiScatteringIntensity;
|
|
91
|
+
this._diffuseSkyIrradianceLut?.markDirty();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* This is an additional scaling factor applied to the {@link minimumMultiScatteringColor}.
|
|
96
|
+
*/
|
|
97
|
+
get minimumMultiScatteringIntensity() {
|
|
98
|
+
return this._minimumMultiScatteringIntensity;
|
|
99
|
+
}
|
|
100
|
+
set minimumMultiScatteringIntensity(value) {
|
|
101
|
+
const newValue = Math.max(0.0, value);
|
|
102
|
+
if (newValue !== this._minimumMultiScatteringIntensity) {
|
|
103
|
+
this._minimumMultiScatteringIntensity = value;
|
|
104
|
+
this._minimumMultiScattering.x = this._minimumMultiScatteringColor.r * value;
|
|
105
|
+
this._minimumMultiScattering.y = this._minimumMultiScatteringColor.g * value;
|
|
106
|
+
this._minimumMultiScattering.z = this._minimumMultiScatteringColor.b * value;
|
|
107
|
+
this._diffuseSkyIrradianceLut?.markDirty();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Can be used to force the diffuse irradiance towards a gray color.
|
|
112
|
+
*/
|
|
113
|
+
get diffuseSkyIrradianceDesaturationFactor() {
|
|
114
|
+
return this._diffuseSkyIrradianceDesaturationFactor;
|
|
115
|
+
}
|
|
116
|
+
set diffuseSkyIrradianceDesaturationFactor(value) {
|
|
117
|
+
const newValue = Math.max(value, 0.0);
|
|
118
|
+
if (newValue !== this._diffuseSkyIrradianceDesaturationFactor) {
|
|
119
|
+
this._diffuseSkyIrradianceDesaturationFactor = newValue;
|
|
120
|
+
this._diffuseSkyIrradianceLut?.markDirty();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* This is an additional amount of irradiance added to the diffuse irradiance.
|
|
125
|
+
*/
|
|
126
|
+
get additionalDiffuseSkyIrradianceIntensity() {
|
|
127
|
+
return this._additionalDiffuseSkyIrradianceIntensity;
|
|
128
|
+
}
|
|
129
|
+
set additionalDiffuseSkyIrradianceIntensity(value) {
|
|
130
|
+
value = Math.max(0.0, value);
|
|
131
|
+
if (value !== this._additionalDiffuseSkyIrradianceIntensity) {
|
|
132
|
+
this._additionalDiffuseSkyIrradianceIntensity = value;
|
|
133
|
+
this._additionalDiffuseSkyIrradianceColor.scaleToRef(value, this._additionalDiffuseSkyIrradiance);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* This is the color for the additional amount of irradiance added to the diffuse irradiance.
|
|
138
|
+
*/
|
|
139
|
+
get additionalDiffuseSkyIrradianceColor() {
|
|
140
|
+
return this._additionalDiffuseSkyIrradianceColor;
|
|
141
|
+
}
|
|
142
|
+
set additionalDiffuseSkyIrradianceColor(value) {
|
|
143
|
+
if (!this._additionalDiffuseSkyIrradianceColor.equals(value)) {
|
|
144
|
+
this._additionalDiffuseSkyIrradianceColor.copyFrom(value).scaleToRef(this._additionalDiffuseSkyIrradianceIntensity, this._additionalDiffuseSkyIrradiance);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The final additional diffuse irradiance, taking into account the intensity and color.
|
|
149
|
+
*/
|
|
150
|
+
get additionalDiffuseSkyIrradiance() {
|
|
151
|
+
return this._additionalDiffuseSkyIrradiance;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The intensity of the diffuse irradiance.
|
|
155
|
+
*/
|
|
156
|
+
get diffuseSkyIrradianceIntensity() {
|
|
157
|
+
return this._diffuseSkyIrradianceIntensity;
|
|
158
|
+
}
|
|
159
|
+
set diffuseSkyIrradianceIntensity(value) {
|
|
160
|
+
this._diffuseSkyIrradianceIntensity = Math.max(value, 0.0);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* True if the sky view LUT should be used for compositing the sky instead of a per-pixel ray march.
|
|
164
|
+
*/
|
|
165
|
+
get isSkyViewLutEnabled() {
|
|
166
|
+
return this._isSkyViewLutEnabled;
|
|
167
|
+
}
|
|
168
|
+
set isSkyViewLutEnabled(value) {
|
|
169
|
+
this._isSkyViewLutEnabled = value;
|
|
170
|
+
this._disposeSkyCompositor();
|
|
171
|
+
this._disposeGlobeAtmosphereCompositor();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Gets the sky view LUT render target or null if not enabled.
|
|
175
|
+
* @returns The render target.
|
|
176
|
+
*/
|
|
177
|
+
get skyViewLutRenderTarget() {
|
|
178
|
+
if (!this._isSkyViewLutEnabled) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
if (this._skyViewLutRenderTarget !== null) {
|
|
182
|
+
return this._skyViewLutRenderTarget;
|
|
183
|
+
}
|
|
184
|
+
const renderTarget = (this._skyViewLutRenderTarget = CreateRenderTargetTexture("atmo-skyView", { width: 128, height: 128 }, this.scene));
|
|
185
|
+
renderTarget.coordinatesMode = Constants.TEXTURE_EQUIRECTANGULAR_MODE;
|
|
186
|
+
this._skyViewLutEffectWrapper = CreateSkyViewEffectWrapper(this._engine, this.uniformBuffer);
|
|
187
|
+
return renderTarget;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* True if the aerial perspective LUT should be used.
|
|
191
|
+
* If false, full ray marching would be used instead.
|
|
192
|
+
*/
|
|
193
|
+
get isAerialPerspectiveLutEnabled() {
|
|
194
|
+
return this._isAerialPerspectiveLutEnabled;
|
|
195
|
+
}
|
|
196
|
+
set isAerialPerspectiveLutEnabled(value) {
|
|
197
|
+
this._isAerialPerspectiveLutEnabled = value;
|
|
198
|
+
this._disposeAerialPerspectiveCompositor();
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Gets the aerial perspective LUT render target or null if not enabled.
|
|
202
|
+
* @returns The render target.
|
|
203
|
+
*/
|
|
204
|
+
get aerialPerspectiveLutRenderTarget() {
|
|
205
|
+
if (!this._isAerialPerspectiveLutEnabled) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
if (this._aerialPerspectiveLutRenderTarget !== null) {
|
|
209
|
+
return this._aerialPerspectiveLutRenderTarget;
|
|
210
|
+
}
|
|
211
|
+
const scene = this.scene;
|
|
212
|
+
const name = "atmo-aerialPerspective";
|
|
213
|
+
const renderTarget = (this._aerialPerspectiveLutRenderTarget = CreateRenderTargetTexture(name, { width: 16, height: 64, layers: 32 }, scene, {}));
|
|
214
|
+
this._aerialPerspectiveLutEffectWrapper = CreateAerialPerspectiveEffectWrapper(this._engine, this.uniformBuffer);
|
|
215
|
+
return renderTarget;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The intensity of the aerial perspective.
|
|
219
|
+
*/
|
|
220
|
+
get aerialPerspectiveIntensity() {
|
|
221
|
+
return this._aerialPerspectiveIntensity;
|
|
222
|
+
}
|
|
223
|
+
set aerialPerspectiveIntensity(value) {
|
|
224
|
+
value = Math.max(0.001, value);
|
|
225
|
+
if (value !== this._aerialPerspectiveIntensity) {
|
|
226
|
+
// Define only needs to change if the value is changing between 1 and not 1.
|
|
227
|
+
const hasDefineChanged = (value === 1) !== (this._aerialPerspectiveIntensity === 1);
|
|
228
|
+
this._aerialPerspectiveIntensity = value;
|
|
229
|
+
if (hasDefineChanged) {
|
|
230
|
+
this._disposeAerialPerspectiveCompositor();
|
|
231
|
+
this._disposeGlobeAtmosphereCompositor();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* The amount of light transmitted into aerial perspective.
|
|
237
|
+
* A scale of 1 is physically correct.
|
|
238
|
+
*/
|
|
239
|
+
get aerialPerspectiveTransmittanceScale() {
|
|
240
|
+
return this._aerialPerspectiveTransmittanceScale;
|
|
241
|
+
}
|
|
242
|
+
set aerialPerspectiveTransmittanceScale(value) {
|
|
243
|
+
value = Math.max(0, value);
|
|
244
|
+
if (value !== this._aerialPerspectiveTransmittanceScale) {
|
|
245
|
+
this._aerialPerspectiveTransmittanceScale = value;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The amount of saturation applied to the aerial perspective.
|
|
250
|
+
* Reducing to zero desaturates the aerial perspective completely.
|
|
251
|
+
* A value of 1 has no effect.
|
|
252
|
+
*/
|
|
253
|
+
get aerialPerspectiveSaturation() {
|
|
254
|
+
return this._aerialPerspectiveSaturation;
|
|
255
|
+
}
|
|
256
|
+
set aerialPerspectiveSaturation(value) {
|
|
257
|
+
value = Math.max(0.0, value);
|
|
258
|
+
if (value !== this._aerialPerspectiveSaturation) {
|
|
259
|
+
this._aerialPerspectiveSaturation = value;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* A radiance bias applied to aerial perspective.
|
|
264
|
+
*/
|
|
265
|
+
get aerialPerspectiveRadianceBias() {
|
|
266
|
+
return this._aerialPerspectiveRadianceBias;
|
|
267
|
+
}
|
|
268
|
+
set aerialPerspectiveRadianceBias(value) {
|
|
269
|
+
if (value !== this._aerialPerspectiveRadianceBias) {
|
|
270
|
+
// Define only needs to change if the value is changing between 0 and not 0.
|
|
271
|
+
const hasDefineChanged = (value === 0) !== (this._aerialPerspectiveRadianceBias === 0);
|
|
272
|
+
this._aerialPerspectiveRadianceBias = value;
|
|
273
|
+
if (hasDefineChanged) {
|
|
274
|
+
this._disposeAerialPerspectiveCompositor();
|
|
275
|
+
this._disposeGlobeAtmosphereCompositor();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* True if the composition should be in linear space (e.g. for HDR rendering).
|
|
281
|
+
* Typically linear space is expected when ImageProcessing is enabled via PostProcesses.
|
|
282
|
+
* False for non-linear output.
|
|
283
|
+
*/
|
|
284
|
+
get isLinearSpaceComposition() {
|
|
285
|
+
return this._isLinearSpaceComposition;
|
|
286
|
+
}
|
|
287
|
+
set isLinearSpaceComposition(value) {
|
|
288
|
+
if (value !== this._isLinearSpaceComposition) {
|
|
289
|
+
this._isLinearSpaceComposition = value;
|
|
290
|
+
// Note, LUTs will remain in linear space. Up to compositors to apply gamma if needed.
|
|
291
|
+
this._disposeSkyCompositor();
|
|
292
|
+
this._disposeAerialPerspectiveCompositor();
|
|
293
|
+
this._disposeGlobeAtmosphereCompositor();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* True if the {@link light} value should be specified in linear space.
|
|
298
|
+
* If using PBRMaterials, light value is expected to be linear.
|
|
299
|
+
*/
|
|
300
|
+
get isLinearSpaceLight() {
|
|
301
|
+
return this._isLinearSpaceLight;
|
|
302
|
+
}
|
|
303
|
+
set isLinearSpaceLight(value) {
|
|
304
|
+
this._isLinearSpaceLight = value;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* The lookup table for transmittance.
|
|
308
|
+
*/
|
|
309
|
+
get transmittanceLut() {
|
|
310
|
+
return this._transmittanceLut;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Gets the multiple scattering LUT render target.
|
|
314
|
+
* @returns The render target.
|
|
315
|
+
*/
|
|
316
|
+
get multiScatteringLutRenderTarget() {
|
|
317
|
+
return this._multiScatteringLutRenderTarget;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* The lookup table for diffuse sky irradiance, or null if not enabled.
|
|
321
|
+
*/
|
|
322
|
+
get diffuseSkyIrradianceLut() {
|
|
323
|
+
return this._diffuseSkyIrradianceLut;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* The properties used to describe the size and optical parameters of the atmosphere.
|
|
327
|
+
*/
|
|
328
|
+
get physicalProperties() {
|
|
329
|
+
return this._physicalProperties;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* The height in kilometers of the scene's origin.
|
|
333
|
+
*/
|
|
334
|
+
get originHeight() {
|
|
335
|
+
return this._originHeight;
|
|
336
|
+
}
|
|
337
|
+
set originHeight(value) {
|
|
338
|
+
this._originHeight = value;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* When atmospheric scattering is applied to surfaces, if this value is set to true,
|
|
342
|
+
* a grayscale approximation of the transmittance is used to dim surfaces.
|
|
343
|
+
*
|
|
344
|
+
* When set to false, the atmospheric composition does not dim the surfaces behind it.
|
|
345
|
+
* It is up to the client application to apply transmittance manually.
|
|
346
|
+
*/
|
|
347
|
+
get applyApproximateTransmittance() {
|
|
348
|
+
return this._applyApproximateTransmittance;
|
|
349
|
+
}
|
|
350
|
+
set applyApproximateTransmittance(value) {
|
|
351
|
+
if (this._applyApproximateTransmittance !== value) {
|
|
352
|
+
this._applyApproximateTransmittance = value;
|
|
353
|
+
this._disposeSkyCompositor();
|
|
354
|
+
this._disposeAerialPerspectiveCompositor();
|
|
355
|
+
this._disposeGlobeAtmosphereCompositor();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* The directional lights in the scene which represent the suns illuminating the atmosphere.
|
|
360
|
+
* Each frame, the color and intensity of the lights are updated based on the camera position and the light's direction.
|
|
361
|
+
*/
|
|
362
|
+
get lights() {
|
|
363
|
+
return this._lights;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* The rendering group ID for the sky compositor.
|
|
367
|
+
* The sky will only be rendered for this group.
|
|
368
|
+
*/
|
|
369
|
+
get skyRenderingGroup() {
|
|
370
|
+
return this._skyRenderingGroup;
|
|
371
|
+
}
|
|
372
|
+
set skyRenderingGroup(value) {
|
|
373
|
+
this._skyRenderingGroup = value;
|
|
374
|
+
this.scene.renderingManager.getRenderingGroup(value);
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* The rendering group ID for the aerial perspective compositor.
|
|
378
|
+
* Aerial perspective will only be rendered for this group.
|
|
379
|
+
*/
|
|
380
|
+
get aerialPerspectiveRenderingGroup() {
|
|
381
|
+
return this._aerialPerspectiveRenderingGroup;
|
|
382
|
+
}
|
|
383
|
+
set aerialPerspectiveRenderingGroup(value) {
|
|
384
|
+
this._aerialPerspectiveRenderingGroup = value;
|
|
385
|
+
this.scene.renderingManager.getRenderingGroup(value);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* The rendering group ID for the globe atmosphere compositor.
|
|
389
|
+
* The globe atmosphere will only be rendered for this group.
|
|
390
|
+
*/
|
|
391
|
+
get globeAtmosphereRenderingGroup() {
|
|
392
|
+
return this._globeAtmosphereRenderingGroup;
|
|
393
|
+
}
|
|
394
|
+
set globeAtmosphereRenderingGroup(value) {
|
|
395
|
+
this._globeAtmosphereRenderingGroup = value;
|
|
396
|
+
this.scene.renderingManager.getRenderingGroup(value);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Gets the uniform buffer used to store the atmosphere's physical properties.
|
|
400
|
+
*/
|
|
401
|
+
get uniformBuffer() {
|
|
402
|
+
if (this._atmosphereUbo === null) {
|
|
403
|
+
const atmosphereUbo = (this._atmosphereUbo = new UniformBuffer(this._engine, undefined, true, "Atmosphere"));
|
|
404
|
+
atmosphereUbo.addUniform("peakRayleighScattering", 3);
|
|
405
|
+
atmosphereUbo.addUniform("planetRadius", 1);
|
|
406
|
+
// 16-byte boundary
|
|
407
|
+
atmosphereUbo.addUniform("peakMieScattering", 3);
|
|
408
|
+
atmosphereUbo.addUniform("atmosphereThickness", 1);
|
|
409
|
+
// 16-byte boundary
|
|
410
|
+
atmosphereUbo.addUniform("peakMieAbsorption", 3);
|
|
411
|
+
atmosphereUbo.addUniform("planetRadiusSquared", 1);
|
|
412
|
+
// 16-byte boundary
|
|
413
|
+
atmosphereUbo.addUniform("peakMieExtinction", 3);
|
|
414
|
+
atmosphereUbo.addUniform("atmosphereRadius", 1);
|
|
415
|
+
// 16-byte boundary
|
|
416
|
+
atmosphereUbo.addUniform("peakOzoneAbsorption", 3);
|
|
417
|
+
atmosphereUbo.addUniform("atmosphereRadiusSquared", 1);
|
|
418
|
+
// 16-byte boundary
|
|
419
|
+
atmosphereUbo.addUniform("horizonDistanceToAtmosphereEdge", 1);
|
|
420
|
+
atmosphereUbo.addUniform("horizonDistanceToAtmosphereEdgeSquared", 1);
|
|
421
|
+
atmosphereUbo.addUniform("planetRadiusWithOffset", 1);
|
|
422
|
+
atmosphereUbo.addUniform("planetRadiusOffset", 1);
|
|
423
|
+
// 16-byte boundary
|
|
424
|
+
atmosphereUbo.addUniform("atmosphereExposure", 1);
|
|
425
|
+
atmosphereUbo.addUniform("aerialPerspectiveRadianceBias", 1);
|
|
426
|
+
atmosphereUbo.addUniform("inverseAtmosphereThickness", 1);
|
|
427
|
+
atmosphereUbo.addUniform("aerialPerspectiveTransmittanceScale", 1);
|
|
428
|
+
// 16-byte boundary
|
|
429
|
+
atmosphereUbo.addUniform("inverseViewProjectionWithoutTranslation", 16);
|
|
430
|
+
// 16-byte boundary
|
|
431
|
+
atmosphereUbo.addUniform("directionToLight", 3);
|
|
432
|
+
atmosphereUbo.addUniform("multiScatteringIntensity", 1);
|
|
433
|
+
// 16-byte boundary
|
|
434
|
+
atmosphereUbo.addUniform("directionToLightRelativeToCameraGeocentricNormal", 3);
|
|
435
|
+
atmosphereUbo.addUniform("cameraRadius", 1);
|
|
436
|
+
// 16-byte boundary
|
|
437
|
+
atmosphereUbo.addUniform("lightRadianceAtCamera", 3);
|
|
438
|
+
atmosphereUbo.addUniform("diffuseSkyIrradianceDesaturationFactor", 1);
|
|
439
|
+
// 16-byte boundary
|
|
440
|
+
atmosphereUbo.addUniform("groundAlbedo", 3);
|
|
441
|
+
atmosphereUbo.addUniform("aerialPerspectiveSaturation", 1);
|
|
442
|
+
// 16-byte boundary
|
|
443
|
+
atmosphereUbo.addUniform("minMultiScattering", 3);
|
|
444
|
+
atmosphereUbo.addUniform("diffuseSkyIrradianceIntensity", 1);
|
|
445
|
+
// 16-byte boundary
|
|
446
|
+
atmosphereUbo.addUniform("cameraPositionGlobal", 3);
|
|
447
|
+
atmosphereUbo.addUniform("lightIntensity", 1);
|
|
448
|
+
// 16-byte boundary
|
|
449
|
+
atmosphereUbo.addUniform("clampedCameraPositionGlobal", 3);
|
|
450
|
+
atmosphereUbo.addUniform("aerialPerspectiveIntensity", 1);
|
|
451
|
+
// 16-byte boundary
|
|
452
|
+
atmosphereUbo.addUniform("cameraGeocentricNormal", 3);
|
|
453
|
+
atmosphereUbo.addUniform("clampedCameraRadius", 1);
|
|
454
|
+
// 16-byte boundary
|
|
455
|
+
atmosphereUbo.addUniform("cameraForward", 3);
|
|
456
|
+
atmosphereUbo.addUniform("clampedCameraHeight", 1);
|
|
457
|
+
// 16-byte boundary
|
|
458
|
+
atmosphereUbo.addUniform("cameraPosition", 3);
|
|
459
|
+
atmosphereUbo.addUniform("cosCameraHorizonAngleFromZenith", 1);
|
|
460
|
+
// 16-byte boundary
|
|
461
|
+
atmosphereUbo.addUniform("viewport", 4);
|
|
462
|
+
// 16-byte boundary
|
|
463
|
+
atmosphereUbo.addUniform("additionalDiffuseSkyIrradiance", 3);
|
|
464
|
+
atmosphereUbo.addUniform("cameraHeight", 1);
|
|
465
|
+
// 16-byte boundary
|
|
466
|
+
atmosphereUbo.addUniform("cameraNearPlane", 1);
|
|
467
|
+
atmosphereUbo.addUniform("originHeight", 1);
|
|
468
|
+
atmosphereUbo.addUniform("sinCameraAtmosphereHorizonAngleFromNadir", 1);
|
|
469
|
+
atmosphereUbo.create();
|
|
470
|
+
}
|
|
471
|
+
return this._atmosphereUbo;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Gets the camera-related variables for this atmosphere. Updated each frame.
|
|
475
|
+
*/
|
|
476
|
+
get cameraAtmosphereVariables() {
|
|
477
|
+
return this._cameraAtmosphereVariables;
|
|
478
|
+
}
|
|
479
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
480
|
+
// @ts-ignore
|
|
481
|
+
get _planetRadius() {
|
|
482
|
+
return this._physicalProperties.planetRadius;
|
|
483
|
+
}
|
|
484
|
+
set _planetRadius(value) {
|
|
485
|
+
this._physicalProperties.planetRadius = value;
|
|
486
|
+
}
|
|
487
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
488
|
+
// @ts-ignore
|
|
489
|
+
get _planetRadiusOffset() {
|
|
490
|
+
return this._physicalProperties.planetRadiusOffset;
|
|
491
|
+
}
|
|
492
|
+
set _planetRadiusOffset(value) {
|
|
493
|
+
this._physicalProperties.planetRadiusOffset = value;
|
|
494
|
+
}
|
|
495
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
496
|
+
// @ts-ignore
|
|
497
|
+
get _atmosphereThickness() {
|
|
498
|
+
return this._physicalProperties.atmosphereThickness;
|
|
499
|
+
}
|
|
500
|
+
set _atmosphereThickness(value) {
|
|
501
|
+
this._physicalProperties.atmosphereThickness = value;
|
|
502
|
+
}
|
|
503
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
504
|
+
// @ts-ignore
|
|
505
|
+
get _rayleighScatteringScale() {
|
|
506
|
+
return this._physicalProperties.rayleighScatteringScale;
|
|
507
|
+
}
|
|
508
|
+
set _rayleighScatteringScale(value) {
|
|
509
|
+
this._physicalProperties.rayleighScatteringScale = value;
|
|
510
|
+
}
|
|
511
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
512
|
+
// @ts-ignore
|
|
513
|
+
get _peakRayleighScatteringMm() {
|
|
514
|
+
this._physicalProperties.peakRayleighScattering.scaleToRef(1000.0, this._peakRayleighScatteringMmInternal);
|
|
515
|
+
return this._peakRayleighScatteringMmInternal;
|
|
516
|
+
}
|
|
517
|
+
set _peakRayleighScatteringMm(value) {
|
|
518
|
+
this._peakRayleighScatteringMmInternal.copyFrom(value);
|
|
519
|
+
this._peakRayleighScatteringMmInternal.scaleToRef(0.001, this._peakRayleighScatteringKm);
|
|
520
|
+
this._physicalProperties.peakRayleighScattering = this._peakRayleighScatteringKm;
|
|
521
|
+
}
|
|
522
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
523
|
+
// @ts-ignore
|
|
524
|
+
get _mieScatteringScale() {
|
|
525
|
+
return this._physicalProperties.mieScatteringScale;
|
|
526
|
+
}
|
|
527
|
+
set _mieScatteringScale(value) {
|
|
528
|
+
this._physicalProperties.mieScatteringScale = value;
|
|
529
|
+
}
|
|
530
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
531
|
+
// @ts-ignore
|
|
532
|
+
get _peakMieScatteringMm() {
|
|
533
|
+
this._physicalProperties.peakMieScattering.scaleToRef(1000.0, this._peakMieScatteringMmInternal);
|
|
534
|
+
return this._peakMieScatteringMmInternal;
|
|
535
|
+
}
|
|
536
|
+
set _peakMieScatteringMm(value) {
|
|
537
|
+
this._peakMieScatteringMmInternal.copyFrom(value);
|
|
538
|
+
this._peakMieScatteringMmInternal.scaleToRef(0.001, this._peakMieScatteringKm);
|
|
539
|
+
this._physicalProperties.peakMieScattering = this._peakMieScatteringKm;
|
|
540
|
+
}
|
|
541
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
542
|
+
// @ts-ignore
|
|
543
|
+
get _mieAbsorptionScale() {
|
|
544
|
+
return this._physicalProperties.mieAbsorptionScale;
|
|
545
|
+
}
|
|
546
|
+
set _mieAbsorptionScale(value) {
|
|
547
|
+
this._physicalProperties.mieAbsorptionScale = value;
|
|
548
|
+
}
|
|
549
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
550
|
+
// @ts-ignore
|
|
551
|
+
get _peakMieAbsorptionMm() {
|
|
552
|
+
this._physicalProperties.peakMieAbsorption.scaleToRef(1000.0, this._peakMieAbsorptionMmInternal);
|
|
553
|
+
return this._peakMieAbsorptionMmInternal;
|
|
554
|
+
}
|
|
555
|
+
set _peakMieAbsorptionMm(value) {
|
|
556
|
+
this._peakMieAbsorptionMmInternal.copyFrom(value);
|
|
557
|
+
this._peakMieAbsorptionMmInternal.scaleToRef(0.001, this._peakMieAbsorptionKm);
|
|
558
|
+
this._physicalProperties.peakMieAbsorption = this._peakMieAbsorptionKm;
|
|
559
|
+
}
|
|
560
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
561
|
+
// @ts-ignore
|
|
562
|
+
get _ozoneAbsorptionScale() {
|
|
563
|
+
return this._physicalProperties.ozoneAbsorptionScale;
|
|
564
|
+
}
|
|
565
|
+
set _ozoneAbsorptionScale(value) {
|
|
566
|
+
this._physicalProperties.ozoneAbsorptionScale = value;
|
|
567
|
+
}
|
|
568
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
569
|
+
// @ts-ignore
|
|
570
|
+
get _peakOzoneAbsorptionMm() {
|
|
571
|
+
this._physicalProperties.peakOzoneAbsorption.scaleToRef(1000.0, this._peakOzoneAbsorptionMmInternal);
|
|
572
|
+
return this._peakOzoneAbsorptionMmInternal;
|
|
573
|
+
}
|
|
574
|
+
set _peakOzoneAbsorptionMm(value) {
|
|
575
|
+
this._peakOzoneAbsorptionMmInternal.copyFrom(value);
|
|
576
|
+
this._peakOzoneAbsorptionMmInternal.scaleToRef(0.001, this._peakOzoneAbsorptionKm);
|
|
577
|
+
this._physicalProperties.peakOzoneAbsorption = this._peakOzoneAbsorptionKm;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Constructs the {@link Atmosphere}.
|
|
581
|
+
* @param name - The name of this instance.
|
|
582
|
+
* @param scene - The scene to which the atmosphere will be added.
|
|
583
|
+
* @param lights - The light sources that illuminate the atmosphere. Currently only supports one light, and that light should be the first light in the scene.
|
|
584
|
+
* @param options - The options used to create the atmosphere.
|
|
585
|
+
*/
|
|
586
|
+
constructor(name, scene, lights, options) {
|
|
587
|
+
this.name = name;
|
|
588
|
+
this.scene = scene;
|
|
589
|
+
this._directionToLight = Vector3.Zero();
|
|
590
|
+
this._tempSceneAmbient = new Color3();
|
|
591
|
+
this._additionalDiffuseSkyIrradiance = new Color3();
|
|
592
|
+
this._atmosphereUbo = null;
|
|
593
|
+
this._minimumMultiScattering = new Vector3();
|
|
594
|
+
this._cameraAtmosphereVariables = new AtmospherePerCameraVariables();
|
|
595
|
+
this._lightRadianceAtCamera = new Vector3();
|
|
596
|
+
this._linearLightColor = new Color3();
|
|
597
|
+
this._atmosphereUniformBufferAsArray = [];
|
|
598
|
+
this._effectRenderer = null;
|
|
599
|
+
this._isEnabled = true;
|
|
600
|
+
this._hasRenderedMultiScatteringLut = false;
|
|
601
|
+
this._multiScatteringEffectWrapper = null;
|
|
602
|
+
this._multiScatteringLutRenderTarget = null;
|
|
603
|
+
this._aerialPerspectiveLutEffectWrapper = null;
|
|
604
|
+
this._aerialPerspectiveLutEffectRenderer = null;
|
|
605
|
+
this._aerialPerspectiveLutRenderTarget = null;
|
|
606
|
+
this._skyViewLutEffectWrapper = null;
|
|
607
|
+
this._skyViewLutEffectRenderer = null;
|
|
608
|
+
this._skyViewLutRenderTarget = null;
|
|
609
|
+
this._aerialPerspectiveCompositorEffectWrapper = null;
|
|
610
|
+
this._skyCompositorEffectWrapper = null;
|
|
611
|
+
this._globeAtmosphereCompositorEffectWrapper = null;
|
|
612
|
+
this._onBeforeCameraRenderObserver = null;
|
|
613
|
+
this._onBeforeDrawPhaseObserver = null;
|
|
614
|
+
this._onAfterRenderingGroupObserver = null;
|
|
615
|
+
/**
|
|
616
|
+
* Called after the atmosphere variables have been updated for the specified camera.
|
|
617
|
+
*/
|
|
618
|
+
this.onAfterUpdateVariablesForCameraObservable = new Observable();
|
|
619
|
+
/**
|
|
620
|
+
* Called immediately before the light variables are finalized.
|
|
621
|
+
*/
|
|
622
|
+
this.onBeforeLightVariablesUpdateObservable = new Observable();
|
|
623
|
+
/**
|
|
624
|
+
* Called before the LUTs are rendered for this camera. This happens after the per-camera UBO update.
|
|
625
|
+
*/
|
|
626
|
+
this.onBeforeRenderLutsForCameraObservable = new Observable();
|
|
627
|
+
/**
|
|
628
|
+
* Called after the LUTs were rendered.
|
|
629
|
+
*/
|
|
630
|
+
this.onAfterRenderLutsForCameraObservable = new Observable();
|
|
631
|
+
/**
|
|
632
|
+
* If provided, this is the depth texture used for composition passes.
|
|
633
|
+
* Expects an infinite far plane on the camera (camera.maxZ = 0) and the non-linear depth accessible in red channel.
|
|
634
|
+
* @internal
|
|
635
|
+
*/
|
|
636
|
+
this.depthTexture = null;
|
|
637
|
+
// These fields and properties are used to interop with the inspector and not meant to be part of the API.
|
|
638
|
+
this._peakRayleighScatteringMmInternal = new Vector3();
|
|
639
|
+
this._peakRayleighScatteringKm = new Vector3();
|
|
640
|
+
this._peakMieScatteringMmInternal = new Vector3();
|
|
641
|
+
this._peakMieScatteringKm = new Vector3();
|
|
642
|
+
this._peakMieAbsorptionMmInternal = new Vector3();
|
|
643
|
+
this._peakMieAbsorptionKm = new Vector3();
|
|
644
|
+
this._peakOzoneAbsorptionMmInternal = new Vector3();
|
|
645
|
+
this._peakOzoneAbsorptionKm = new Vector3();
|
|
646
|
+
/**
|
|
647
|
+
* Gets the color of a light after being transmitted through the atmosphere to a point specified by its distance to the planet center and its geocentric normal.
|
|
648
|
+
* NOTE, the result is always a linear space color.
|
|
649
|
+
* @param directionToLight - The direction of the light.
|
|
650
|
+
* @param pointRadius - The distance from the planet center to the point in kilometers.
|
|
651
|
+
* @param pointGeocentricNormal - The geocentric normal at the point i.e., normalize(point - planet center).
|
|
652
|
+
* @param result - The color to store the result in.
|
|
653
|
+
* @returns The result color.
|
|
654
|
+
*/
|
|
655
|
+
this.getTransmittedColorToRef = (directionToLight, pointRadius, pointGeocentricNormal, result) => this._transmittanceLut.getTransmittedColorToRef(directionToLight, pointRadius, pointGeocentricNormal, result);
|
|
656
|
+
/**
|
|
657
|
+
* Gets the diffuse sky irradiance. Result is always in linear space.
|
|
658
|
+
* @param directionToLight - The direction of the point to the light.
|
|
659
|
+
* @param pointRadius - The distance from the planet center to the point in kilometers.
|
|
660
|
+
* @param pointGeocentricNormal - The geocentric normal at the point: normalize(point - planet center).
|
|
661
|
+
* @param lightIrradiance - The irradiance of the light.
|
|
662
|
+
* @param result - The color to store the result in.
|
|
663
|
+
* @returns The result color.
|
|
664
|
+
*/
|
|
665
|
+
this.getDiffuseSkyIrradianceToRef = (directionToLight, pointRadius, pointGeocentricNormal, lightIrradiance, result) => this._diffuseSkyIrradianceLut?.getDiffuseSkyIrradianceToRef(directionToLight, pointRadius, pointGeocentricNormal, lightIrradiance, result) ??
|
|
666
|
+
((result.r = 0), (result.g = 0), (result.b = 0), result);
|
|
667
|
+
const engine = (this._engine = scene.getEngine());
|
|
668
|
+
if (engine.isWebGPU) {
|
|
669
|
+
throw new Error("Atmosphere is not supported on WebGPU.");
|
|
670
|
+
}
|
|
671
|
+
if (engine.version < 2) {
|
|
672
|
+
throw new Error(`Atmosphere is not supported on WebGL ${engine.version}.`);
|
|
673
|
+
}
|
|
674
|
+
this._physicalProperties = options?.physicalProperties ?? new AtmospherePhysicalProperties();
|
|
675
|
+
this._physicalProperties.onChangedObservable.add(() => {
|
|
676
|
+
this._transmittanceLut?.markDirty();
|
|
677
|
+
});
|
|
678
|
+
if (lights.length !== 1) {
|
|
679
|
+
throw new Error("Atmosphere only supports one light source currently.");
|
|
680
|
+
}
|
|
681
|
+
this._lights = lights;
|
|
682
|
+
this.depthTexture = options?.depthTexture ?? null;
|
|
683
|
+
this._exposure = options?.exposure ?? 1.0;
|
|
684
|
+
this._isLinearSpaceLight = options?.isLinearSpaceLight ?? false;
|
|
685
|
+
this._isLinearSpaceComposition = options?.isLinearSpaceComposition ?? false;
|
|
686
|
+
this._applyApproximateTransmittance = options?.applyApproximateTransmittance ?? true;
|
|
687
|
+
this._aerialPerspectiveRadianceBias = options?.aerialPerspectiveRadianceBias ?? 0.0;
|
|
688
|
+
this._aerialPerspectiveTransmittanceScale = options?.aerialPerspectiveTransmittanceScale ?? 1.0;
|
|
689
|
+
this._aerialPerspectiveSaturation = options?.aerialPerspectiveSaturation ?? 1.0;
|
|
690
|
+
this._aerialPerspectiveIntensity = options?.aerialPerspectiveIntensity ?? 1.0;
|
|
691
|
+
this._diffuseSkyIrradianceDesaturationFactor = options?.diffuseSkyIrradianceDesaturationFactor ?? 0.5;
|
|
692
|
+
this._diffuseSkyIrradianceIntensity = options?.diffuseSkyIrradianceIntensity ?? 1.0;
|
|
693
|
+
this._additionalDiffuseSkyIrradianceIntensity = options?.additionalDiffuseSkyIrradianceIntensity ?? 0.01;
|
|
694
|
+
this._multiScatteringIntensity = options?.multiScatteringIntensity ?? 1.0;
|
|
695
|
+
this._minimumMultiScatteringIntensity = options?.minimumMultiScatteringIntensity ?? 0.000618;
|
|
696
|
+
this._isSkyViewLutEnabled = options?.isSkyViewLutEnabled ?? true;
|
|
697
|
+
this._isAerialPerspectiveLutEnabled = options?.isAerialPerspectiveLutEnabled ?? true;
|
|
698
|
+
this._originHeight = options?.originHeight ?? 0;
|
|
699
|
+
this._additionalDiffuseSkyIrradianceColor = options?.additionalDiffuseSkyIrradianceColor
|
|
700
|
+
? new Color3().copyFrom(options.additionalDiffuseSkyIrradianceColor)
|
|
701
|
+
: new Color3(163 / 255.0, 199 / 255.0, 1.0);
|
|
702
|
+
this._groundAlbedo = options?.groundAlbedo ? new Color3().copyFrom(options.groundAlbedo) : new Color3().set(124.0 / 255.0, 165.0 / 255.0, 1.0);
|
|
703
|
+
const minimumMultiScatteringColor = (this._minimumMultiScatteringColor = options?.minimumMultiScatteringColor
|
|
704
|
+
? new Color3().copyFrom(options.minimumMultiScatteringColor)
|
|
705
|
+
: new Color3(30.0 / 255.0, 40.0 / 255.0, 77.0 / 255.0));
|
|
706
|
+
this._skyRenderingGroup = options?.skyRenderingGroup ?? 0;
|
|
707
|
+
this._aerialPerspectiveRenderingGroup = options?.aerialPerspectiveRenderingGroup ?? 0;
|
|
708
|
+
this._globeAtmosphereRenderingGroup = options?.globeAtmosphereRenderingGroup ?? 0;
|
|
709
|
+
this._additionalDiffuseSkyIrradianceColor.scaleToRef(this._additionalDiffuseSkyIrradianceIntensity, this._additionalDiffuseSkyIrradiance);
|
|
710
|
+
this._minimumMultiScattering.x = minimumMultiScatteringColor.r * this._minimumMultiScatteringIntensity;
|
|
711
|
+
this._minimumMultiScattering.y = minimumMultiScatteringColor.g * this._minimumMultiScatteringIntensity;
|
|
712
|
+
this._minimumMultiScattering.z = minimumMultiScatteringColor.b * this._minimumMultiScatteringIntensity;
|
|
713
|
+
this._effectRenderer = new EffectRenderer(engine, {
|
|
714
|
+
// Full screen triangle.
|
|
715
|
+
indices: [0, 2, 1],
|
|
716
|
+
positions: [-1, -1, -1, 3, 3, -1],
|
|
717
|
+
});
|
|
718
|
+
this._transmittanceLut = new TransmittanceLut(this);
|
|
719
|
+
this._multiScatteringLutRenderTarget = CreateRenderTargetTexture("atmo-multiScattering", { width: 32, height: 32 }, scene);
|
|
720
|
+
if (options?.isDiffuseSkyIrradianceLutEnabled ?? true) {
|
|
721
|
+
this._diffuseSkyIrradianceLut = new DiffuseSkyIrradianceLut(this);
|
|
722
|
+
}
|
|
723
|
+
if (this._isSkyViewLutEnabled) {
|
|
724
|
+
this.skyViewLutRenderTarget;
|
|
725
|
+
}
|
|
726
|
+
if (this._isAerialPerspectiveLutEnabled) {
|
|
727
|
+
this.aerialPerspectiveLutRenderTarget;
|
|
728
|
+
}
|
|
729
|
+
// Before rendering, make sure the per-camera variables have been updated.
|
|
730
|
+
this._onBeforeCameraRenderObserver = scene.onBeforeCameraRenderObservable.add((x) => {
|
|
731
|
+
this._updatePerCameraVariables(x);
|
|
732
|
+
this._renderLutsForCamera();
|
|
733
|
+
});
|
|
734
|
+
{
|
|
735
|
+
const renderingManager = scene.renderingManager;
|
|
736
|
+
if (this._skyRenderingGroup >= 0) {
|
|
737
|
+
renderingManager.getRenderingGroup(this._skyRenderingGroup);
|
|
738
|
+
}
|
|
739
|
+
if (this._aerialPerspectiveRenderingGroup >= 0) {
|
|
740
|
+
renderingManager.getRenderingGroup(this._aerialPerspectiveRenderingGroup);
|
|
741
|
+
}
|
|
742
|
+
if (this._globeAtmosphereRenderingGroup >= 0) {
|
|
743
|
+
renderingManager.getRenderingGroup(this._globeAtmosphereRenderingGroup);
|
|
744
|
+
}
|
|
745
|
+
// Mark all rendering groups as being "not empty" before rendering the corresponding targets.
|
|
746
|
+
// This ensures onAfterRenderTargetsRenderObservable is called for empty groups,
|
|
747
|
+
// which allows the atmosphere to be rendered even when the groups are otherwise empty e.g.,
|
|
748
|
+
// a scene with only the atmosphere in it, and no other Meshes.
|
|
749
|
+
this._onBeforeDrawPhaseObserver = scene.onBeforeDrawPhaseObservable.add(() => {
|
|
750
|
+
if (this._skyRenderingGroup >= 0) {
|
|
751
|
+
renderingManager.getRenderingGroup(this._skyRenderingGroup)._empty = false;
|
|
752
|
+
}
|
|
753
|
+
if (this._aerialPerspectiveRenderingGroup >= 0) {
|
|
754
|
+
renderingManager.getRenderingGroup(this._aerialPerspectiveRenderingGroup)._empty = false;
|
|
755
|
+
}
|
|
756
|
+
if (this._globeAtmosphereRenderingGroup >= 0) {
|
|
757
|
+
renderingManager.getRenderingGroup(this._globeAtmosphereRenderingGroup)._empty = false;
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
// Draw compositors after the respective rendering group.
|
|
761
|
+
this._onAfterRenderingGroupObserver = scene.onAfterRenderingGroupObservable.add((group) => {
|
|
762
|
+
if (group.renderingManager !== scene.renderingManager) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const groupId = group.renderingGroupId;
|
|
766
|
+
if (this._skyRenderingGroup === groupId) {
|
|
767
|
+
this.drawSkyCompositor();
|
|
768
|
+
}
|
|
769
|
+
if (this._aerialPerspectiveRenderingGroup === groupId) {
|
|
770
|
+
this.drawAerialPerspectiveCompositor();
|
|
771
|
+
}
|
|
772
|
+
if (this._globeAtmosphereRenderingGroup === groupId) {
|
|
773
|
+
this.drawGlobeAtmosphereCompositor();
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
// Ensure the atmosphere is disposed when the scene is disposed.
|
|
778
|
+
scene.onDisposeObservable.addOnce(() => {
|
|
779
|
+
this.dispose();
|
|
780
|
+
});
|
|
781
|
+
// Registers a material plugin which will allow common materials to sample the atmosphere environment maps e.g.,
|
|
782
|
+
// sky view LUT for glossy reflections and diffuse sky illiminance LUT for irradiance.
|
|
783
|
+
// It also handles aerial perspective application when Atmosphere is not provided with a depth texture.
|
|
784
|
+
UnregisterMaterialPlugin(MaterialPlugin);
|
|
785
|
+
RegisterMaterialPlugin(MaterialPlugin, (material) => {
|
|
786
|
+
if (material.getClassName() === "PBRMaterial") {
|
|
787
|
+
return new AtmospherePBRMaterialPlugin(material, this, this.depthTexture === null);
|
|
788
|
+
}
|
|
789
|
+
return null;
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* @override
|
|
794
|
+
*/
|
|
795
|
+
dispose() {
|
|
796
|
+
this._onBeforeCameraRenderObserver?.remove();
|
|
797
|
+
this._onBeforeCameraRenderObserver = null;
|
|
798
|
+
this._onBeforeDrawPhaseObserver?.remove();
|
|
799
|
+
this._onBeforeDrawPhaseObserver = null;
|
|
800
|
+
this._onAfterRenderingGroupObserver?.remove();
|
|
801
|
+
this._onAfterRenderingGroupObserver = null;
|
|
802
|
+
this._globeAtmosphereCompositorEffectWrapper?.dispose();
|
|
803
|
+
this._globeAtmosphereCompositorEffectWrapper = null;
|
|
804
|
+
this._skyCompositorEffectWrapper?.dispose();
|
|
805
|
+
this._skyCompositorEffectWrapper = null;
|
|
806
|
+
this._aerialPerspectiveCompositorEffectWrapper?.dispose();
|
|
807
|
+
this._aerialPerspectiveCompositorEffectWrapper = null;
|
|
808
|
+
this._skyViewLutRenderTarget?.dispose();
|
|
809
|
+
this._skyViewLutRenderTarget = null;
|
|
810
|
+
this._skyViewLutEffectWrapper?.dispose();
|
|
811
|
+
this._skyViewLutEffectWrapper = null;
|
|
812
|
+
this._skyViewLutEffectRenderer?.dispose();
|
|
813
|
+
this._skyViewLutEffectRenderer = null;
|
|
814
|
+
this._aerialPerspectiveLutRenderTarget?.dispose();
|
|
815
|
+
this._aerialPerspectiveLutRenderTarget = null;
|
|
816
|
+
this._aerialPerspectiveLutEffectWrapper?.dispose();
|
|
817
|
+
this._aerialPerspectiveLutEffectWrapper = null;
|
|
818
|
+
this._aerialPerspectiveLutEffectRenderer?.dispose();
|
|
819
|
+
this._aerialPerspectiveLutEffectRenderer = null;
|
|
820
|
+
this._multiScatteringEffectWrapper?.dispose();
|
|
821
|
+
this._multiScatteringEffectWrapper = null;
|
|
822
|
+
this._multiScatteringLutRenderTarget?.dispose();
|
|
823
|
+
this._multiScatteringLutRenderTarget = null;
|
|
824
|
+
this._transmittanceLut?.dispose();
|
|
825
|
+
this._transmittanceLut = null;
|
|
826
|
+
this._diffuseSkyIrradianceLut?.dispose();
|
|
827
|
+
this._diffuseSkyIrradianceLut = null;
|
|
828
|
+
this._atmosphereUbo?.dispose();
|
|
829
|
+
this._atmosphereUbo = null;
|
|
830
|
+
this._effectRenderer?.dispose();
|
|
831
|
+
this._effectRenderer = null;
|
|
832
|
+
this._atmosphereUniformBufferAsArray.length = 0;
|
|
833
|
+
UnregisterMaterialPlugin(MaterialPlugin);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* True if the atmosphere is enabled.
|
|
837
|
+
* @returns - True if the atmosphere is enabled.
|
|
838
|
+
*/
|
|
839
|
+
isEnabled() {
|
|
840
|
+
return this._isEnabled;
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Sets the enabled state of the atmosphere.
|
|
844
|
+
* @param enabled - True to enable the atmosphere, false to disable it.
|
|
845
|
+
*/
|
|
846
|
+
setEnabled(enabled) {
|
|
847
|
+
this._isEnabled = enabled;
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* The class name of the {@link Atmosphere}.
|
|
851
|
+
* @returns - The class name of the atmosphere.
|
|
852
|
+
*/
|
|
853
|
+
getClassName() {
|
|
854
|
+
return "Atmosphere";
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Creates a new {@link EffectWrapper} for the multiple scattering LUT
|
|
858
|
+
* @returns The newly created {@link EffectWrapper}.
|
|
859
|
+
*/
|
|
860
|
+
_createMultiScatteringEffectWrapper() {
|
|
861
|
+
const engine = this._engine;
|
|
862
|
+
const name = "atmo-multiScattering";
|
|
863
|
+
const ubo = this.uniformBuffer;
|
|
864
|
+
const useUbo = ubo.useUbo;
|
|
865
|
+
const defines = ["#define POSITION_VEC2"];
|
|
866
|
+
if (!this._groundAlbedo.equals(Color3.BlackReadOnly)) {
|
|
867
|
+
defines.push("#define USE_GROUND_ALBEDO");
|
|
868
|
+
}
|
|
869
|
+
return new EffectWrapper({
|
|
870
|
+
engine,
|
|
871
|
+
name,
|
|
872
|
+
vertexShader: "fullscreenTriangle",
|
|
873
|
+
fragmentShader: "multiScattering",
|
|
874
|
+
attributeNames: ["position"],
|
|
875
|
+
uniformNames: ["depth", ...(useUbo ? [] : this.uniformBuffer.getUniformNames())],
|
|
876
|
+
uniformBuffers: useUbo ? [this.uniformBuffer.name] : [],
|
|
877
|
+
samplerNames: ["transmittanceLut"],
|
|
878
|
+
defines,
|
|
879
|
+
useShaderStore: true,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Draws the multiple scattering LUT using {@link EffectWrapper} and {@link EffectRenderer}.
|
|
884
|
+
*/
|
|
885
|
+
_drawMultiScatteringLut() {
|
|
886
|
+
const transmittanceLut = this._transmittanceLut.renderTarget;
|
|
887
|
+
DrawEffect(this._engine, this._effectRenderer, this._multiScatteringEffectWrapper, this._multiScatteringLutRenderTarget, (effectRenderer, renderTarget, effect, engine) => {
|
|
888
|
+
this.bindUniformBufferToEffect(effect);
|
|
889
|
+
engine.bindFramebuffer(renderTarget, undefined, undefined, undefined, true);
|
|
890
|
+
effectRenderer.bindBuffers(effect);
|
|
891
|
+
effect.setTexture("transmittanceLut", transmittanceLut);
|
|
892
|
+
effectRenderer.draw();
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Draws the aerial perspective compositor using {@link EffectWrapper} and {@link EffectRenderer}.
|
|
897
|
+
*/
|
|
898
|
+
drawAerialPerspectiveCompositor() {
|
|
899
|
+
// Only works if we have a depth texture.
|
|
900
|
+
if (this.depthTexture === null) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
const isEnabled = this.isEnabled();
|
|
904
|
+
if (!isEnabled) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
// Aerial perspective compositor only renders when inside the atmosphere.
|
|
908
|
+
const isOutsideAtmosphere = this._cameraAtmosphereVariables.clampedCameraRadius > this._physicalProperties.atmosphereRadius;
|
|
909
|
+
if (isOutsideAtmosphere) {
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
const engine = this._engine;
|
|
913
|
+
this._aerialPerspectiveCompositorEffectWrapper ?? (this._aerialPerspectiveCompositorEffectWrapper = CreateAerialPerspectiveCompositorEffectWrapper(engine, this.uniformBuffer, this._isAerialPerspectiveLutEnabled, this._isSkyViewLutEnabled, this._isLinearSpaceComposition, this._applyApproximateTransmittance, this._aerialPerspectiveIntensity, this._aerialPerspectiveRadianceBias));
|
|
914
|
+
const skyViewLut = this._isSkyViewLutEnabled ? this.skyViewLutRenderTarget : null;
|
|
915
|
+
const multiScatteringLut = this._multiScatteringLutRenderTarget;
|
|
916
|
+
const transmittanceLut = this._transmittanceLut.renderTarget;
|
|
917
|
+
const aerialPerspectiveLut = this._isAerialPerspectiveLutEnabled ? this.aerialPerspectiveLutRenderTarget : null;
|
|
918
|
+
if (!this._aerialPerspectiveCompositorEffectWrapper.isReady() ||
|
|
919
|
+
!(skyViewLut?.isReady() ?? true) ||
|
|
920
|
+
!multiScatteringLut.isReady() ||
|
|
921
|
+
!transmittanceLut.isReady() ||
|
|
922
|
+
!(aerialPerspectiveLut?.isReady() ?? true) ||
|
|
923
|
+
!this.depthTexture.isReady()) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
DrawEffect(engine, this._effectRenderer, this._aerialPerspectiveCompositorEffectWrapper, null, // No render target, it will render to the current buffer.
|
|
927
|
+
(effectRenderer, _, effect) => {
|
|
928
|
+
if (this.depthTexture === null) {
|
|
929
|
+
throw new Error("Depth texture is required for aerial perspective compositor.");
|
|
930
|
+
}
|
|
931
|
+
this.bindUniformBufferToEffect(effect);
|
|
932
|
+
effectRenderer.bindBuffers(effect);
|
|
933
|
+
effect.setTexture("transmittanceLut", transmittanceLut);
|
|
934
|
+
effect.setTexture("multiScatteringLut", multiScatteringLut);
|
|
935
|
+
if (this._isSkyViewLutEnabled) {
|
|
936
|
+
effect.setTexture("skyViewLut", skyViewLut);
|
|
937
|
+
}
|
|
938
|
+
if (this._isAerialPerspectiveLutEnabled) {
|
|
939
|
+
effect.setTexture("aerialPerspectiveLut", aerialPerspectiveLut);
|
|
940
|
+
}
|
|
941
|
+
effect.setTexture("depthTexture", this.depthTexture);
|
|
942
|
+
effectRenderer.draw();
|
|
943
|
+
}, 1, // depth to use in the compositor.
|
|
944
|
+
this.applyApproximateTransmittance ? Constants.ALPHA_PREMULTIPLIED_PORTERDUFF : Constants.ALPHA_ONEONE, true, // depthTest
|
|
945
|
+
false, // depthWrite
|
|
946
|
+
Constants.ALWAYS, // depthFunction
|
|
947
|
+
false // restoreDefaultFramebuffer
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Draws the sky compositor using {@link EffectWrapper} and {@link EffectRenderer}.
|
|
952
|
+
*/
|
|
953
|
+
drawSkyCompositor() {
|
|
954
|
+
const isEnabled = this.isEnabled();
|
|
955
|
+
if (!isEnabled) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
// The sky compositor only renders when inside the atmosphere.
|
|
959
|
+
const isOutsideAtmosphere = this._cameraAtmosphereVariables.clampedCameraRadius > this._physicalProperties.atmosphereRadius;
|
|
960
|
+
if (isOutsideAtmosphere) {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
if (this.depthTexture !== null && !this.depthTexture.isReady()) {
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const engine = this._engine;
|
|
967
|
+
this._skyCompositorEffectWrapper ?? (this._skyCompositorEffectWrapper = CreateSkyCompositorEffectWrapper(engine, this.uniformBuffer, this._isSkyViewLutEnabled, this._isLinearSpaceComposition, this._applyApproximateTransmittance));
|
|
968
|
+
const skyViewLut = this._isSkyViewLutEnabled ? this.skyViewLutRenderTarget : null;
|
|
969
|
+
const multiScatteringLut = this._multiScatteringLutRenderTarget;
|
|
970
|
+
const transmittanceLut = this._transmittanceLut.renderTarget;
|
|
971
|
+
if (!this._skyCompositorEffectWrapper.isReady() || !(skyViewLut?.isReady() ?? true) || !multiScatteringLut.isReady() || !transmittanceLut.isReady()) {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
DrawEffect(engine, this._effectRenderer, this._skyCompositorEffectWrapper, null, // No render target, it will render to the current buffer.
|
|
975
|
+
(effectRenderer, _, effect) => {
|
|
976
|
+
this.bindUniformBufferToEffect(effect);
|
|
977
|
+
effectRenderer.bindBuffers(effect);
|
|
978
|
+
effect.setTexture("multiScatteringLut", multiScatteringLut);
|
|
979
|
+
effect.setTexture("transmittanceLut", transmittanceLut);
|
|
980
|
+
if (this._isSkyViewLutEnabled) {
|
|
981
|
+
effect.setTexture("skyViewLut", skyViewLut);
|
|
982
|
+
}
|
|
983
|
+
effectRenderer.draw();
|
|
984
|
+
}, 1, // depth to use in the compositor.
|
|
985
|
+
this._applyApproximateTransmittance ? Constants.ALPHA_PREMULTIPLIED_PORTERDUFF : Constants.ALPHA_ONEONE, true, // depthTest
|
|
986
|
+
false, // depthWrite
|
|
987
|
+
Constants.EQUAL, // depthFunction
|
|
988
|
+
false // restoreDefaultFramebuffer
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Draws the globe atmosphere compositor using {@link EffectWrapper} and {@link EffectRenderer}.
|
|
993
|
+
*/
|
|
994
|
+
drawGlobeAtmosphereCompositor() {
|
|
995
|
+
const isEnabled = this.isEnabled();
|
|
996
|
+
if (!isEnabled) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
// Globe atmosphere compositor only renders when outside the atmosphere.
|
|
1000
|
+
const isOutsideAtmosphere = this._cameraAtmosphereVariables.clampedCameraRadius > this._physicalProperties.atmosphereRadius;
|
|
1001
|
+
if (!isOutsideAtmosphere) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const engine = this._engine;
|
|
1005
|
+
this._globeAtmosphereCompositorEffectWrapper ?? (this._globeAtmosphereCompositorEffectWrapper = CreateGlobeAtmosphereCompositorEffectWrapper(engine, this.uniformBuffer, this._isSkyViewLutEnabled, this._isLinearSpaceComposition, this._applyApproximateTransmittance, this._aerialPerspectiveIntensity, this._aerialPerspectiveRadianceBias, this.depthTexture !== null));
|
|
1006
|
+
const skyViewLut = this._isSkyViewLutEnabled ? this.skyViewLutRenderTarget : null;
|
|
1007
|
+
const multiScatteringLut = this._multiScatteringLutRenderTarget;
|
|
1008
|
+
const transmittanceLut = this._transmittanceLut.renderTarget;
|
|
1009
|
+
if (!this._globeAtmosphereCompositorEffectWrapper.isReady() || !(skyViewLut?.isReady() ?? true) || !multiScatteringLut.isReady() || !transmittanceLut.isReady()) {
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
if (this.depthTexture !== null && !this.depthTexture.isReady()) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
DrawEffect(engine, this._effectRenderer, this._globeAtmosphereCompositorEffectWrapper, null, // No render target, it will render to the current buffer.
|
|
1016
|
+
(effectRenderer, _, effect) => {
|
|
1017
|
+
this.bindUniformBufferToEffect(effect);
|
|
1018
|
+
effectRenderer.bindBuffers(effect);
|
|
1019
|
+
effect.setTexture("transmittanceLut", transmittanceLut);
|
|
1020
|
+
effect.setTexture("multiScatteringLut", multiScatteringLut);
|
|
1021
|
+
if (this._isSkyViewLutEnabled) {
|
|
1022
|
+
effect.setTexture("skyViewLut", skyViewLut);
|
|
1023
|
+
}
|
|
1024
|
+
if (this.depthTexture !== null) {
|
|
1025
|
+
effect.setTexture("depthTexture", this.depthTexture);
|
|
1026
|
+
}
|
|
1027
|
+
effectRenderer.draw();
|
|
1028
|
+
}, 1, // depth to use in the compositor.
|
|
1029
|
+
this._applyApproximateTransmittance ? Constants.ALPHA_PREMULTIPLIED_PORTERDUFF : Constants.ALPHA_ONEONE, true, // depthTest
|
|
1030
|
+
false, // depthWrite
|
|
1031
|
+
Constants.ALWAYS, // depthFunction
|
|
1032
|
+
false // restoreDefaultFramebuffer
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
_disposeSkyCompositor() {
|
|
1036
|
+
this._skyCompositorEffectWrapper?.dispose();
|
|
1037
|
+
this._skyCompositorEffectWrapper = null;
|
|
1038
|
+
}
|
|
1039
|
+
_disposeAerialPerspectiveCompositor() {
|
|
1040
|
+
this._aerialPerspectiveCompositorEffectWrapper?.dispose();
|
|
1041
|
+
this._aerialPerspectiveCompositorEffectWrapper = null;
|
|
1042
|
+
}
|
|
1043
|
+
_disposeGlobeAtmosphereCompositor() {
|
|
1044
|
+
this._globeAtmosphereCompositorEffectWrapper?.dispose();
|
|
1045
|
+
this._globeAtmosphereCompositorEffectWrapper = null;
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Updates the camera variables that are specific to the atmosphere.
|
|
1049
|
+
* @param camera - The camera to update the variables for.
|
|
1050
|
+
*/
|
|
1051
|
+
_updatePerCameraVariables(camera) {
|
|
1052
|
+
const light = this._lights[0];
|
|
1053
|
+
this._directionToLight.copyFrom(light.direction);
|
|
1054
|
+
this._directionToLight.scaleInPlace(-1);
|
|
1055
|
+
const properties = this._physicalProperties;
|
|
1056
|
+
const cameraAtmosphereVariables = this._cameraAtmosphereVariables;
|
|
1057
|
+
cameraAtmosphereVariables.update(camera, properties.planetRadius, properties.planetRadiusWithOffset, properties.atmosphereRadius, this._directionToLight, this.originHeight);
|
|
1058
|
+
this._transmittanceLut.updateLightParameters(light, cameraAtmosphereVariables.clampedCameraRadius, cameraAtmosphereVariables.cameraGeocentricNormal);
|
|
1059
|
+
this._linearLightColor.copyFrom(light.diffuse);
|
|
1060
|
+
this.getDiffuseSkyIrradianceToRef(this._directionToLight, 0, cameraAtmosphereVariables.cameraGeocentricNormal, this.lights[0].intensity, this._tempSceneAmbient);
|
|
1061
|
+
if (!this.isLinearSpaceLight) {
|
|
1062
|
+
this._tempSceneAmbient.toGammaSpaceToRef(this._tempSceneAmbient);
|
|
1063
|
+
}
|
|
1064
|
+
this.scene.ambientColor = this._tempSceneAmbient;
|
|
1065
|
+
this.onAfterUpdateVariablesForCameraObservable.notifyObservers(camera);
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Renders the lookup tables, some of which can vary per-camera.
|
|
1069
|
+
* It is expected that updatePerCameraVariables was previously called.
|
|
1070
|
+
*/
|
|
1071
|
+
_renderLutsForCamera() {
|
|
1072
|
+
{
|
|
1073
|
+
this.onBeforeLightVariablesUpdateObservable.notifyObservers();
|
|
1074
|
+
const light = this.lights[0];
|
|
1075
|
+
if (!this.isLinearSpaceLight) {
|
|
1076
|
+
light.diffuse = light.diffuse.toGammaSpaceToRef(light.diffuse);
|
|
1077
|
+
light.specular = light.specular.toGammaSpaceToRef(light.specular);
|
|
1078
|
+
}
|
|
1079
|
+
const intensity = light.intensity;
|
|
1080
|
+
this._lightRadianceAtCamera.set(intensity * this._linearLightColor.r, intensity * this._linearLightColor.g, intensity * this._linearLightColor.b);
|
|
1081
|
+
}
|
|
1082
|
+
if (this.uniformBuffer.useUbo) {
|
|
1083
|
+
this.updateUniformBuffer();
|
|
1084
|
+
}
|
|
1085
|
+
// Render the LUTs.
|
|
1086
|
+
const isEnabled = this.isEnabled();
|
|
1087
|
+
{
|
|
1088
|
+
this.onBeforeRenderLutsForCameraObservable.notifyObservers();
|
|
1089
|
+
// After UBO update we can render the global LUTs which use some of these values on the GPU.
|
|
1090
|
+
// TODO: Could break out update and UBOs to global vs. per-camera.
|
|
1091
|
+
this.renderGlobalLuts();
|
|
1092
|
+
// If atmosphere is enabled, render the per-camera LUTs (sky view and aerial perspective).
|
|
1093
|
+
if (isEnabled && !this._transmittanceLut.isDirty && this._hasRenderedMultiScatteringLut) {
|
|
1094
|
+
if (this._isSkyViewLutEnabled) {
|
|
1095
|
+
this._drawSkyViewLut();
|
|
1096
|
+
}
|
|
1097
|
+
// Only need to render aerial perspective LUT when inside the atmosphere.
|
|
1098
|
+
if (this._isAerialPerspectiveLutEnabled && this._cameraAtmosphereVariables.clampedCameraRadius <= this._physicalProperties.atmosphereRadius) {
|
|
1099
|
+
this._drawAerialPerspectiveLut();
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
this.onAfterRenderLutsForCameraObservable.notifyObservers();
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Renders the lookup tables that do not depend on a camera position.
|
|
1107
|
+
*/
|
|
1108
|
+
renderGlobalLuts() {
|
|
1109
|
+
const hasNewTransmittanceLut = this._transmittanceLut.render();
|
|
1110
|
+
if (hasNewTransmittanceLut) {
|
|
1111
|
+
this._hasRenderedMultiScatteringLut = false;
|
|
1112
|
+
this._diffuseSkyIrradianceLut?.markDirty();
|
|
1113
|
+
}
|
|
1114
|
+
if (!this._transmittanceLut.isDirty && !this._hasRenderedMultiScatteringLut) {
|
|
1115
|
+
this._multiScatteringEffectWrapper ?? (this._multiScatteringEffectWrapper = this._createMultiScatteringEffectWrapper());
|
|
1116
|
+
if (this._multiScatteringEffectWrapper?.isReady() && this._multiScatteringLutRenderTarget?.isReady()) {
|
|
1117
|
+
this._drawMultiScatteringLut();
|
|
1118
|
+
this._hasRenderedMultiScatteringLut = true;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (!this._transmittanceLut.isDirty && this._hasRenderedMultiScatteringLut) {
|
|
1122
|
+
this._diffuseSkyIrradianceLut?.render(); // Will only render if needed.
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Binds the atmosphere's uniform buffer to an {@link Effect}.
|
|
1127
|
+
* @param effect - The {@link Effect} to bind the uniform buffer to.
|
|
1128
|
+
*/
|
|
1129
|
+
bindUniformBufferToEffect(effect) {
|
|
1130
|
+
const uniformBuffer = this.uniformBuffer;
|
|
1131
|
+
const name = uniformBuffer.name;
|
|
1132
|
+
uniformBuffer.bindToEffect(effect, name);
|
|
1133
|
+
if (uniformBuffer.useUbo) {
|
|
1134
|
+
uniformBuffer.bindUniformBuffer();
|
|
1135
|
+
}
|
|
1136
|
+
else {
|
|
1137
|
+
this.updateUniformBuffer();
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Updates the atmosphere's uniform buffer.
|
|
1142
|
+
*/
|
|
1143
|
+
updateUniformBuffer() {
|
|
1144
|
+
const physicalProperties = this._physicalProperties;
|
|
1145
|
+
const cameraAtmosphereVariables = this._cameraAtmosphereVariables;
|
|
1146
|
+
const ubo = this.uniformBuffer;
|
|
1147
|
+
ubo.updateVector3("peakRayleighScattering", physicalProperties.rayleighScattering);
|
|
1148
|
+
ubo.updateFloat("planetRadius", physicalProperties.planetRadius);
|
|
1149
|
+
ubo.updateVector3("peakMieScattering", physicalProperties.mieScattering);
|
|
1150
|
+
ubo.updateFloat("atmosphereThickness", physicalProperties.atmosphereThickness);
|
|
1151
|
+
ubo.updateVector3("peakMieAbsorption", physicalProperties.mieAbsorption);
|
|
1152
|
+
ubo.updateFloat("planetRadiusSquared", physicalProperties.planetRadiusSquared);
|
|
1153
|
+
ubo.updateVector3("peakMieExtinction", physicalProperties.mieExtinction);
|
|
1154
|
+
ubo.updateFloat("atmosphereRadius", physicalProperties.atmosphereRadius);
|
|
1155
|
+
ubo.updateVector3("peakOzoneAbsorption", physicalProperties.ozoneAbsorption);
|
|
1156
|
+
ubo.updateFloat("atmosphereRadiusSquared", physicalProperties.atmosphereRadiusSquared);
|
|
1157
|
+
ubo.updateFloat("horizonDistanceToAtmosphereEdge", physicalProperties.horizonDistanceToAtmosphereEdge);
|
|
1158
|
+
ubo.updateFloat("horizonDistanceToAtmosphereEdgeSquared", physicalProperties.horizonDistanceToAtmosphereEdgeSquared);
|
|
1159
|
+
ubo.updateFloat("planetRadiusWithOffset", physicalProperties.planetRadiusWithOffset);
|
|
1160
|
+
ubo.updateFloat("planetRadiusOffset", physicalProperties.planetRadiusOffset);
|
|
1161
|
+
ubo.updateFloat("aerialPerspectiveRadianceBias", this._aerialPerspectiveRadianceBias);
|
|
1162
|
+
ubo.updateFloat("inverseAtmosphereThickness", 1 / physicalProperties.atmosphereThickness);
|
|
1163
|
+
ubo.updateFloat("aerialPerspectiveTransmittanceScale", this._aerialPerspectiveTransmittanceScale);
|
|
1164
|
+
ubo.updateMatrix("inverseViewProjectionWithoutTranslation", cameraAtmosphereVariables.inverseViewProjectionMatrixWithoutTranslation);
|
|
1165
|
+
ubo.updateVector3("directionToLight", this._directionToLight);
|
|
1166
|
+
ubo.updateFloat("multiScatteringIntensity", this.multiScatteringIntensity);
|
|
1167
|
+
ubo.updateVector3("directionToLightRelativeToCameraGeocentricNormal", cameraAtmosphereVariables.directionToLightRelativeToCameraGeocentricNormal);
|
|
1168
|
+
ubo.updateFloat("cameraRadius", cameraAtmosphereVariables.cameraRadius);
|
|
1169
|
+
ubo.updateVector3("lightRadianceAtCamera", this._lightRadianceAtCamera);
|
|
1170
|
+
ubo.updateFloat("diffuseSkyIrradianceDesaturationFactor", this._diffuseSkyIrradianceDesaturationFactor);
|
|
1171
|
+
ubo.updateColor3("groundAlbedo", this._groundAlbedo);
|
|
1172
|
+
ubo.updateFloat("aerialPerspectiveSaturation", this._aerialPerspectiveSaturation);
|
|
1173
|
+
ubo.updateVector3("minMultiScattering", this._minimumMultiScattering);
|
|
1174
|
+
ubo.updateFloat("diffuseSkyIrradianceIntensity", this._diffuseSkyIrradianceIntensity);
|
|
1175
|
+
ubo.updateVector3("cameraPositionGlobal", cameraAtmosphereVariables.cameraPositionGlobal);
|
|
1176
|
+
ubo.updateFloat("lightIntensity", this.lights[0].intensity);
|
|
1177
|
+
ubo.updateVector3("clampedCameraPositionGlobal", cameraAtmosphereVariables.clampedCameraPositionGlobal);
|
|
1178
|
+
ubo.updateFloat("aerialPerspectiveIntensity", this._aerialPerspectiveIntensity);
|
|
1179
|
+
ubo.updateVector3("cameraGeocentricNormal", cameraAtmosphereVariables.cameraGeocentricNormal);
|
|
1180
|
+
ubo.updateFloat("clampedCameraRadius", cameraAtmosphereVariables.clampedCameraRadius);
|
|
1181
|
+
ubo.updateVector3("cameraForward", cameraAtmosphereVariables.cameraForward);
|
|
1182
|
+
ubo.updateFloat("clampedCameraHeight", cameraAtmosphereVariables.clampedCameraHeight);
|
|
1183
|
+
ubo.updateVector3("cameraPosition", cameraAtmosphereVariables.cameraPosition);
|
|
1184
|
+
ubo.updateFloat("cosCameraHorizonAngleFromZenith", cameraAtmosphereVariables.cosCameraHorizonAngleFromZenith);
|
|
1185
|
+
ubo.updateVector4("viewport", cameraAtmosphereVariables.viewport);
|
|
1186
|
+
ubo.updateColor3("additionalDiffuseSkyIrradiance", this._additionalDiffuseSkyIrradiance);
|
|
1187
|
+
ubo.updateFloat("cameraHeight", cameraAtmosphereVariables.cameraHeight);
|
|
1188
|
+
ubo.updateFloat("cameraNearPlane", cameraAtmosphereVariables.cameraNearPlane);
|
|
1189
|
+
ubo.updateFloat("originHeight", this._originHeight);
|
|
1190
|
+
ubo.updateFloat("sinCameraAtmosphereHorizonAngleFromNadir", cameraAtmosphereVariables.sinCameraAtmosphereHorizonAngleFromNadir);
|
|
1191
|
+
ubo.updateFloat("atmosphereExposure", this._exposure);
|
|
1192
|
+
ubo.update();
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Draws the aerial perspective LUT using {@link EffectWrapper} and {@link EffectRenderer}.
|
|
1196
|
+
*/
|
|
1197
|
+
_drawAerialPerspectiveLut() {
|
|
1198
|
+
const transmittanceLut = this._transmittanceLut.renderTarget;
|
|
1199
|
+
const multiScatteringLut = this._multiScatteringLutRenderTarget;
|
|
1200
|
+
DrawEffect(this._engine, this._effectRenderer, this._aerialPerspectiveLutEffectWrapper, this._aerialPerspectiveLutRenderTarget, (effectRenderer, renderTarget, effect, engine) => {
|
|
1201
|
+
this.bindUniformBufferToEffect(effect);
|
|
1202
|
+
const layers = 32;
|
|
1203
|
+
effect.setTexture("transmittanceLut", transmittanceLut);
|
|
1204
|
+
effect.setTexture("multiScatteringLut", multiScatteringLut);
|
|
1205
|
+
for (let layer = 0; layer < layers; layer++) {
|
|
1206
|
+
engine.bindFramebuffer(renderTarget, undefined, undefined, undefined, true, undefined, layer);
|
|
1207
|
+
effectRenderer.bindBuffers(effect);
|
|
1208
|
+
effect.setFloat("layerIdx", layer);
|
|
1209
|
+
effectRenderer.draw();
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Draws the sky view LUT using {@link EffectWrapper} and {@link EffectRenderer}.
|
|
1215
|
+
*/
|
|
1216
|
+
_drawSkyViewLut() {
|
|
1217
|
+
const transmittanceLut = this._transmittanceLut.renderTarget;
|
|
1218
|
+
const multiScatteringLut = this._multiScatteringLutRenderTarget;
|
|
1219
|
+
DrawEffect(this._engine, this._effectRenderer, this._skyViewLutEffectWrapper, this._skyViewLutRenderTarget, (effectRenderer, renderTarget, effect, engine) => {
|
|
1220
|
+
this.bindUniformBufferToEffect(effect);
|
|
1221
|
+
engine.bindFramebuffer(renderTarget, undefined, undefined, undefined, true);
|
|
1222
|
+
effectRenderer.bindBuffers(effect);
|
|
1223
|
+
effect.setTexture("transmittanceLut", transmittanceLut);
|
|
1224
|
+
effect.setTexture("multiScatteringLut", multiScatteringLut);
|
|
1225
|
+
effectRenderer.draw();
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Creates an {@link EffectWrapper} with the given parameters.
|
|
1231
|
+
* @param engine - The engine to use.
|
|
1232
|
+
* @param name - The name of the effect wrapper.
|
|
1233
|
+
* @param fragmentShader - The fragment shader source.
|
|
1234
|
+
* @param uniformNames - The uniform names to use.
|
|
1235
|
+
* @param samplerNames - The sampler names to use.
|
|
1236
|
+
* @param uniformBuffers - The uniform buffers to use.
|
|
1237
|
+
* @param defineNames - Array of define names to prepend with "#define ".
|
|
1238
|
+
* @returns The effect wrapper.
|
|
1239
|
+
*/
|
|
1240
|
+
const CreateEffectWrapper = (engine, name, fragmentShader, uniformNames, samplerNames, uniformBuffers, defineNames) => {
|
|
1241
|
+
const defines = defineNames?.map((defineName) => `#define ${defineName}`) ?? [];
|
|
1242
|
+
return new EffectWrapper({
|
|
1243
|
+
engine,
|
|
1244
|
+
name,
|
|
1245
|
+
vertexShader: "fullscreenTriangle",
|
|
1246
|
+
fragmentShader,
|
|
1247
|
+
attributeNames: ["position"],
|
|
1248
|
+
uniformNames,
|
|
1249
|
+
uniformBuffers,
|
|
1250
|
+
samplerNames,
|
|
1251
|
+
defines,
|
|
1252
|
+
useShaderStore: true,
|
|
1253
|
+
});
|
|
1254
|
+
};
|
|
1255
|
+
const CreateRenderTargetTexture = (name, size, scene, options) => {
|
|
1256
|
+
const rtOptions = {
|
|
1257
|
+
generateMipMaps: false,
|
|
1258
|
+
generateDepthBuffer: false,
|
|
1259
|
+
generateStencilBuffer: false,
|
|
1260
|
+
gammaSpace: false,
|
|
1261
|
+
samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE,
|
|
1262
|
+
type: Constants.TEXTURETYPE_HALF_FLOAT,
|
|
1263
|
+
format: Constants.TEXTUREFORMAT_RGBA,
|
|
1264
|
+
...options,
|
|
1265
|
+
};
|
|
1266
|
+
const renderTarget = new RenderTargetTexture(name, size, scene, rtOptions);
|
|
1267
|
+
renderTarget.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;
|
|
1268
|
+
renderTarget.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;
|
|
1269
|
+
renderTarget.anisotropicFilteringLevel = 1;
|
|
1270
|
+
renderTarget.skipInitialClear = true;
|
|
1271
|
+
return renderTarget;
|
|
1272
|
+
};
|
|
1273
|
+
/**
|
|
1274
|
+
* Common setup and teardown for drawing LUTs or composition passes.
|
|
1275
|
+
* @param engine - The engine to use.
|
|
1276
|
+
* @param effectRenderer - The effect renderer to use.
|
|
1277
|
+
* @param effectWrapper - The effect wrapper to use.
|
|
1278
|
+
* @param renderTarget - The render target.
|
|
1279
|
+
* @param drawCallback - Callback function that performs the drawing.
|
|
1280
|
+
* @param depth - The depth value to set in the effect.
|
|
1281
|
+
* @param alphaMode - The alpha mode to set before drawing.
|
|
1282
|
+
* @param depthTest - Whether to enable depth testing.
|
|
1283
|
+
* @param depthWrite - Optional depth write state to set before drawing.
|
|
1284
|
+
* @param depthFunction - The depth function to set before drawing.
|
|
1285
|
+
* @param restoreDefaultFramebuffer - Whether to restore the default framebuffer after drawing.
|
|
1286
|
+
*/
|
|
1287
|
+
const DrawEffect = (engine, effectRenderer, effectWrapper, renderTarget, drawCallback, depth = 0, alphaMode = Constants.ALPHA_DISABLE, depthTest = true, depthWrite, depthFunction = Constants.LEQUAL, restoreDefaultFramebuffer = true) => {
|
|
1288
|
+
if ((renderTarget !== null && !renderTarget.isReady()) || !effectWrapper?.isReady()) {
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
// Set additional depth/stencil states before calling applyEffectWrapper.
|
|
1292
|
+
const currentDepthWrite = engine.getDepthWrite();
|
|
1293
|
+
if (depthWrite !== undefined) {
|
|
1294
|
+
engine.setDepthWrite(depthWrite);
|
|
1295
|
+
}
|
|
1296
|
+
const currentDepthFunction = engine.getDepthFunction();
|
|
1297
|
+
engine.setDepthFunction(depthFunction);
|
|
1298
|
+
// Likewise with the alpha mode, which can affect depth state too.
|
|
1299
|
+
const currentAlphaMode = engine.getAlphaMode();
|
|
1300
|
+
if (alphaMode !== Constants.ALPHA_DISABLE) {
|
|
1301
|
+
engine.setAlphaMode(alphaMode);
|
|
1302
|
+
}
|
|
1303
|
+
effectRenderer.saveStates();
|
|
1304
|
+
effectRenderer.setViewport();
|
|
1305
|
+
effectRenderer.applyEffectWrapper(effectWrapper, depthTest); // Note, stencil is false by default.
|
|
1306
|
+
const effect = effectWrapper.effect;
|
|
1307
|
+
effect.setFloat("depth", depth);
|
|
1308
|
+
// Call the specific drawing logic.
|
|
1309
|
+
drawCallback(effectRenderer, renderTarget?.renderTarget, effect, engine);
|
|
1310
|
+
// Restore state (order matters!)
|
|
1311
|
+
engine.setAlphaMode(currentAlphaMode);
|
|
1312
|
+
if (currentDepthWrite !== undefined) {
|
|
1313
|
+
engine.setDepthWrite(currentDepthWrite);
|
|
1314
|
+
}
|
|
1315
|
+
if (currentDepthFunction) {
|
|
1316
|
+
engine.setDepthFunction(currentDepthFunction);
|
|
1317
|
+
}
|
|
1318
|
+
effectRenderer.restoreStates();
|
|
1319
|
+
// And restore the default framebuffer.
|
|
1320
|
+
if (restoreDefaultFramebuffer) {
|
|
1321
|
+
engine.restoreDefaultFramebuffer();
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
/**
|
|
1325
|
+
* Creates an EffectWrapper for the sky compositor.
|
|
1326
|
+
* @param engine - The engine to use.
|
|
1327
|
+
* @param uniformBuffer - The uniform buffer to use.
|
|
1328
|
+
* @param isSkyViewLutEnabled - Whether the sky view LUT is enabled.
|
|
1329
|
+
* @param isLinearSpaceComposition - Whether composition is in linear space.
|
|
1330
|
+
* @param applyApproximateTransmittance - Whether to apply approximate transmittance.
|
|
1331
|
+
* @returns The created EffectWrapper.
|
|
1332
|
+
*/
|
|
1333
|
+
const CreateSkyCompositorEffectWrapper = (engine, uniformBuffer, isSkyViewLutEnabled, isLinearSpaceComposition, applyApproximateTransmittance) => {
|
|
1334
|
+
const useUbo = uniformBuffer.useUbo;
|
|
1335
|
+
const defines = ["COMPUTE_WORLD_RAY"];
|
|
1336
|
+
if (isSkyViewLutEnabled) {
|
|
1337
|
+
defines.push("USE_SKY_VIEW_LUT");
|
|
1338
|
+
}
|
|
1339
|
+
if (!isLinearSpaceComposition) {
|
|
1340
|
+
defines.push("OUTPUT_TO_SRGB");
|
|
1341
|
+
}
|
|
1342
|
+
if (applyApproximateTransmittance) {
|
|
1343
|
+
defines.push("APPLY_TRANSMITTANCE_BLENDING");
|
|
1344
|
+
}
|
|
1345
|
+
const textures = isSkyViewLutEnabled ? ["skyViewLut"] : ["transmittanceLut", "multiScatteringLut"];
|
|
1346
|
+
return CreateEffectWrapper(engine, "atmo-skyCompositor", "compositeSky", ["depth", ...(useUbo ? [] : uniformBuffer.getUniformNames())], textures, useUbo ? [uniformBuffer.name] : [], defines);
|
|
1347
|
+
};
|
|
1348
|
+
/**
|
|
1349
|
+
* Creates an EffectWrapper for the aerial perspective LUT.
|
|
1350
|
+
* @param engine - The engine to use.
|
|
1351
|
+
* @param uniformBuffer - The uniform buffer to use.
|
|
1352
|
+
* @returns The created EffectWrapper.
|
|
1353
|
+
*/
|
|
1354
|
+
const CreateAerialPerspectiveEffectWrapper = (engine, uniformBuffer) => CreateEffectWrapper(engine, "atmo-aerialPerspective", "aerialPerspective", ["layerIdx", "depth", ...(uniformBuffer.useUbo ? [] : uniformBuffer.getUniformNames())], ["transmittanceLut", "multiScatteringLut"], uniformBuffer.useUbo ? [uniformBuffer.name] : [], ["COMPUTE_WORLD_RAY"]);
|
|
1355
|
+
/**
|
|
1356
|
+
* Creates an EffectWrapper for the aerial perspective compositor.
|
|
1357
|
+
* @param engine - The engine to use.
|
|
1358
|
+
* @param uniformBuffer - The uniform buffer.
|
|
1359
|
+
* @param isAerialPerspectiveLutEnabled - Whether the aerial perspective LUT is enabled.
|
|
1360
|
+
* @param isSkyViewLutEnabled - Whether the sky view LUT is enabled.
|
|
1361
|
+
* @param isLinearSpaceComposition - Whether composition is in linear space.
|
|
1362
|
+
* @param applyApproximateTransmittance - Whether to apply approximate transmittance.
|
|
1363
|
+
* @param aerialPerspectiveIntensity - The aerial perspective intensity.
|
|
1364
|
+
* @param aerialPerspectiveRadianceBias - The aerial perspective radiance bias.
|
|
1365
|
+
* @returns The created EffectWrapper.
|
|
1366
|
+
*/
|
|
1367
|
+
const CreateAerialPerspectiveCompositorEffectWrapper = (engine, uniformBuffer, isAerialPerspectiveLutEnabled, isSkyViewLutEnabled, isLinearSpaceComposition, applyApproximateTransmittance, aerialPerspectiveIntensity, aerialPerspectiveRadianceBias) => {
|
|
1368
|
+
const useUbo = uniformBuffer.useUbo;
|
|
1369
|
+
const defines = ["COMPUTE_WORLD_RAY"];
|
|
1370
|
+
if (isAerialPerspectiveLutEnabled) {
|
|
1371
|
+
defines.push("USE_AERIAL_PERSPECTIVE_LUT");
|
|
1372
|
+
}
|
|
1373
|
+
if (isSkyViewLutEnabled) {
|
|
1374
|
+
defines.push("USE_SKY_VIEW_LUT");
|
|
1375
|
+
}
|
|
1376
|
+
if (aerialPerspectiveIntensity !== 1) {
|
|
1377
|
+
defines.push("APPLY_AERIAL_PERSPECTIVE_INTENSITY");
|
|
1378
|
+
}
|
|
1379
|
+
if (!isLinearSpaceComposition) {
|
|
1380
|
+
defines.push("OUTPUT_TO_SRGB");
|
|
1381
|
+
}
|
|
1382
|
+
if (applyApproximateTransmittance) {
|
|
1383
|
+
defines.push("APPLY_TRANSMITTANCE_BLENDING");
|
|
1384
|
+
}
|
|
1385
|
+
if (aerialPerspectiveRadianceBias !== 0.0) {
|
|
1386
|
+
defines.push("APPLY_AERIAL_PERSPECTIVE_RADIANCE_BIAS");
|
|
1387
|
+
}
|
|
1388
|
+
const samplers = ["transmittanceLut", "multiScatteringLut", "depthTexture"];
|
|
1389
|
+
if (isSkyViewLutEnabled) {
|
|
1390
|
+
samplers.push("skyViewLut");
|
|
1391
|
+
}
|
|
1392
|
+
if (isAerialPerspectiveLutEnabled) {
|
|
1393
|
+
samplers.push("aerialPerspectiveLut");
|
|
1394
|
+
}
|
|
1395
|
+
return CreateEffectWrapper(engine, "atmo-aerialPerspectiveCompositor", "compositeAerialPerspective", ["depth", ...(useUbo ? [] : uniformBuffer.getUniformNames())], samplers, useUbo ? [uniformBuffer.name] : [], defines);
|
|
1396
|
+
};
|
|
1397
|
+
/**
|
|
1398
|
+
* Creates an EffectWrapper for the globe atmosphere compositor.
|
|
1399
|
+
* @param engine - The engine to use.
|
|
1400
|
+
* @param uniformBuffer - The uniform buffer to use.
|
|
1401
|
+
* @param isSkyViewLutEnabled - Whether the sky view LUT is enabled.
|
|
1402
|
+
* @param isLinearSpaceComposition - Whether composition is in linear space.
|
|
1403
|
+
* @param applyApproximateTransmittance - Whether to apply approximate transmittance.
|
|
1404
|
+
* @param aerialPerspectiveIntensity - The aerial perspective intensity.
|
|
1405
|
+
* @param aerialPerspectiveRadianceBias - The aerial perspective radiance bias.
|
|
1406
|
+
* @param hasDepthTexture - Whether a depth texture is available.
|
|
1407
|
+
* @returns The created EffectWrapper.
|
|
1408
|
+
*/
|
|
1409
|
+
const CreateGlobeAtmosphereCompositorEffectWrapper = (engine, uniformBuffer, isSkyViewLutEnabled, isLinearSpaceComposition, applyApproximateTransmittance, aerialPerspectiveIntensity, aerialPerspectiveRadianceBias, hasDepthTexture) => {
|
|
1410
|
+
const useUbo = uniformBuffer.useUbo;
|
|
1411
|
+
const defines = ["COMPUTE_WORLD_RAY"];
|
|
1412
|
+
if (isSkyViewLutEnabled) {
|
|
1413
|
+
defines.push("USE_SKY_VIEW_LUT");
|
|
1414
|
+
}
|
|
1415
|
+
if (aerialPerspectiveIntensity !== 1) {
|
|
1416
|
+
defines.push("APPLY_AERIAL_PERSPECTIVE_INTENSITY");
|
|
1417
|
+
}
|
|
1418
|
+
if (!isLinearSpaceComposition) {
|
|
1419
|
+
defines.push("OUTPUT_TO_SRGB");
|
|
1420
|
+
}
|
|
1421
|
+
if (hasDepthTexture) {
|
|
1422
|
+
defines.push("HAS_DEPTH_TEXTURE");
|
|
1423
|
+
}
|
|
1424
|
+
if (applyApproximateTransmittance) {
|
|
1425
|
+
defines.push("APPLY_TRANSMITTANCE_BLENDING");
|
|
1426
|
+
}
|
|
1427
|
+
if (aerialPerspectiveRadianceBias !== 0.0) {
|
|
1428
|
+
defines.push("APPLY_AERIAL_PERSPECTIVE_RADIANCE_BIAS");
|
|
1429
|
+
}
|
|
1430
|
+
const samplers = ["transmittanceLut", "multiScatteringLut"];
|
|
1431
|
+
if (isSkyViewLutEnabled) {
|
|
1432
|
+
samplers.push("skyViewLut");
|
|
1433
|
+
}
|
|
1434
|
+
if (hasDepthTexture) {
|
|
1435
|
+
samplers.push("depthTexture");
|
|
1436
|
+
}
|
|
1437
|
+
return CreateEffectWrapper(engine, "atmo-globeAtmosphereCompositor", "compositeGlobeAtmosphere", ["depth", ...(useUbo ? [] : uniformBuffer.getUniformNames())], samplers, useUbo ? [uniformBuffer.name] : [], defines);
|
|
1438
|
+
};
|
|
1439
|
+
/**
|
|
1440
|
+
* Creates an EffectWrapper for the sky view LUT.
|
|
1441
|
+
* @param engine - The engine to use.
|
|
1442
|
+
* @param uniformBuffer - The uniform buffer to use.
|
|
1443
|
+
* @returns The created EffectWrapper.
|
|
1444
|
+
*/
|
|
1445
|
+
const CreateSkyViewEffectWrapper = (engine, uniformBuffer) => CreateEffectWrapper(engine, "atmo-skyView", "skyView", ["depth", ...(uniformBuffer.useUbo ? [] : uniformBuffer.getUniformNames())], ["transmittanceLut", "multiScatteringLut"], uniformBuffer.useUbo ? [uniformBuffer.name] : []);
|
|
1446
|
+
//# sourceMappingURL=atmosphere.js.map
|