@zephyr3d/scene 0.9.22 → 0.9.24
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/dist/animation/joint_dynamics/collision.js +1 -7
- package/dist/animation/joint_dynamics/collision.js.map +1 -1
- package/dist/animation/joint_dynamics/constraints.js +2 -17
- package/dist/animation/joint_dynamics/constraints.js.map +1 -1
- package/dist/animation/joint_dynamics/controller.js +2 -20
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +1 -3
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/joint_dynamics/solver.js +14 -60
- package/dist/animation/joint_dynamics/solver.js.map +1 -1
- package/dist/animation/joint_dynamics/types.js +3 -3
- package/dist/animation/joint_dynamics/types.js.map +1 -1
- package/dist/app/app.js +23 -0
- package/dist/app/app.js.map +1 -1
- package/dist/app/scriptregistry.js +16 -53
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +2 -0
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/model.js +22 -0
- package/dist/asset/model.js.map +1 -1
- package/dist/blitter/bilateralblur.js +3 -1
- package/dist/blitter/bilateralblur.js.map +1 -1
- package/dist/blitter/blitter.js +3 -3
- package/dist/blitter/blitter.js.map +1 -1
- package/dist/camera/camera.js +398 -45
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/perspectivecamera.js +69 -2
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +9113 -8740
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/material/blinn.js +1 -1
- package/dist/material/blinn.js.map +1 -1
- package/dist/material/lambert.js +3 -3
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +8 -5
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +17 -10
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +1 -1
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +21 -6
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +33 -11
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/brdf.js +44 -12
- package/dist/material/mixins/pbr/brdf.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +149 -14
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mtoon.js +7 -4
- package/dist/material/mtoon.js.map +1 -1
- package/dist/material/pbrblueprint.js +5 -1
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrmr.js +1 -1
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/pbrsg.js +1 -1
- package/dist/material/pbrsg.js.map +1 -1
- package/dist/material/shader/helper.js +512 -334
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/skin.js +2 -2
- package/dist/material/skin.js.map +1 -1
- package/dist/material/terrain-cm.js +5 -5
- package/dist/material/terrain-cm.js.map +1 -1
- package/dist/material/water.js +6 -4
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/bloom.js +54 -4
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/compositor.js +41 -0
- package/dist/posteffect/compositor.js.map +1 -1
- package/dist/posteffect/posteffect.js +35 -0
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/sao.js +7 -6
- package/dist/posteffect/sao.js.map +1 -1
- package/dist/posteffect/skinsss.js +3 -3
- package/dist/posteffect/skinsss.js.map +1 -1
- package/dist/posteffect/ssgi.js +988 -436
- package/dist/posteffect/ssgi.js.map +1 -1
- package/dist/posteffect/ssr.js +83 -45
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/sss.js +18 -15
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/posteffect/taa.js +5 -4
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/posteffect/tonemap.js +15 -3
- package/dist/posteffect/tonemap.js.map +1 -1
- package/dist/render/abuffer_oit.js +2 -2
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/cluster_light.js +22 -16
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/drawable_mixin.js +8 -5
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +10 -5
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/envlight.js +298 -5
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/gpu_picking.js +7 -5
- package/dist/render/gpu_picking.js.map +1 -1
- package/dist/render/hzb.js +28 -19
- package/dist/render/hzb.js.map +1 -1
- package/dist/render/lightpass.js +18 -4
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/render_queue.js +37 -4
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +8 -3
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/blackboard.js +20 -48
- package/dist/render/rendergraph/blackboard.js.map +1 -1
- package/dist/render/rendergraph/device_pool_allocator.js +18 -58
- package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
- package/dist/render/rendergraph/executor.js +89 -115
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +1003 -715
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/frame_graph_context.js +1 -1
- package/dist/render/rendergraph/frame_graph_context.js.map +1 -1
- package/dist/render/rendergraph/frame_resource_requirements.js +14 -0
- package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -0
- package/dist/render/rendergraph/history_resource_manager.js +74 -140
- package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
- package/dist/render/rendergraph/history_resources.js +7 -5
- package/dist/render/rendergraph/history_resources.js.map +1 -1
- package/dist/render/rendergraph/render_context.js +19 -0
- package/dist/render/rendergraph/render_context.js.map +1 -0
- package/dist/render/rendergraph/render_pipeline.js +315 -0
- package/dist/render/rendergraph/render_pipeline.js.map +1 -0
- package/dist/render/rendergraph/rendergraph.js +158 -141
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/scene_render_context.js +267 -0
- package/dist/render/rendergraph/scene_render_context.js.map +1 -0
- package/dist/render/rendergraph/texture_affinity_cache.js +19 -0
- package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -0
- package/dist/render/rendergraph/types.js +19 -31
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/renderpass.js +3 -3
- package/dist/render/renderpass.js.map +1 -1
- package/dist/render/shadow_mask_pass.js +7 -6
- package/dist/render/shadow_mask_pass.js.map +1 -1
- package/dist/render/sky.js +257 -95
- package/dist/render/sky.js.map +1 -1
- package/dist/render/weightedblended_oit.js +4 -3
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +2 -0
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +10 -0
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +61 -2
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/light.js +178 -10
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/meshdrawable.js +89 -2
- package/dist/scene/meshdrawable.js.map +1 -1
- package/dist/scene/msdftext.js +2 -0
- package/dist/scene/msdftext.js.map +1 -1
- package/dist/scene/msdftextsprite.js +2 -0
- package/dist/scene/msdftextsprite.js.map +1 -1
- package/dist/scene/particlesys.js +2 -0
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/scene.js +34 -1
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/terrain-cm/grass.js +2 -1
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +2 -0
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/water.js +2 -0
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/atmosphere.js +5 -4
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/fog.js +10 -3
- package/dist/shaders/fog.js.map +1 -1
- package/dist/shaders/shadow.js +149 -40
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/ssgi_reprojection.js +118 -0
- package/dist/shaders/ssgi_reprojection.js.map +1 -0
- package/dist/shaders/ssr.js +322 -154
- package/dist/shaders/ssr.js.map +1 -1
- package/dist/shadow/esm.js +10 -7
- package/dist/shadow/esm.js.map +1 -1
- package/dist/shadow/pcf_opt.js +12 -12
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js +12 -12
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/pcss.js +16 -11
- package/dist/shadow/pcss.js.map +1 -1
- package/dist/shadow/shadow_impl.js +29 -3
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadowmapper.js +5 -2
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shadow/ssm.js +13 -13
- package/dist/shadow/ssm.js.map +1 -1
- package/dist/shadow/vsm.js +7 -7
- package/dist/shadow/vsm.js.map +1 -1
- package/dist/utility/physical.js +74 -0
- package/dist/utility/physical.js.map +1 -0
- package/dist/utility/rendermipmap.js +2 -2
- package/dist/utility/rendermipmap.js.map +1 -1
- package/dist/utility/serialization/manager.js +3 -1
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +3 -1
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +3 -1
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +598 -2
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/light.js +180 -9
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +43 -3
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +3 -1
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +3 -1
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +3 -1
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +2 -0
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/scene.js +70 -0
- package/dist/utility/serialization/scene/scene.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +3 -1
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +3 -1
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/text.js +3 -0
- package/dist/utility/serialization/scene/text.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +3 -1
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/values.js +59 -65
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
package/dist/render/sky.js
CHANGED
|
@@ -2,7 +2,7 @@ import { linearToGamma } from '../shaders/misc.js';
|
|
|
2
2
|
import { smoothNoise3D } from '../shaders/noise.js';
|
|
3
3
|
import { getDevice, getEngine } from '../app/api.js';
|
|
4
4
|
import { getDefaultAtmosphereParams, getAerialPerspectiveLut, renderAtmosphereLUTs, getAtmosphereParamsStruct, createTransmittanceLutProgram, createMultiScatteringLutProgram, createSkyViewLutProgram, createAPLutProgram, skyBox, atmosphereLUTRendered, getTransmittanceLut, getSkyViewLut } from '../shaders/atmosphere.js';
|
|
5
|
-
import { Matrix4x4, Disposable, DRef, Vector4, Vector2, Vector3, CubeFace, objectKeys } from '@zephyr3d/base';
|
|
5
|
+
import { Matrix4x4, Disposable, DRef, Vector4, Vector2, Vector3, CubeFace, objectKeys, DEPTH_FARTHEST, DEPTH_COMPARE_DEFAULT, DEPTH_COMPARE_FARTHER } from '@zephyr3d/base';
|
|
6
6
|
import { Primitive } from './primitive.js';
|
|
7
7
|
import { BoxShape } from '../shapes/box.js';
|
|
8
8
|
import '../shapes/capsule.js';
|
|
@@ -13,6 +13,7 @@ import '../shapes/sphere.js';
|
|
|
13
13
|
import '../shapes/tetrahedron.js';
|
|
14
14
|
import { prefilterCubemap } from '../utility/pmrem.js';
|
|
15
15
|
import { ShaderHelper } from '../material/shader/helper.js';
|
|
16
|
+
import { PHYSICAL_BAKE_EXPOSURE } from '../utility/physical.js';
|
|
16
17
|
import { fetchSampler } from '../utility/misc.js';
|
|
17
18
|
import { CubemapSHProjector } from '../utility/shprojector.js';
|
|
18
19
|
import { uniformSphereSamples, Fog } from '../values.js';
|
|
@@ -27,10 +28,30 @@ const fogTypeMap = {
|
|
|
27
28
|
none: Fog.FOG_TYPE_NONE
|
|
28
29
|
};
|
|
29
30
|
const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
30
|
-
/**
|
|
31
|
-
* The sky renderer
|
|
32
|
-
* @public
|
|
31
|
+
/**
|
|
32
|
+
* The sky renderer
|
|
33
|
+
* @public
|
|
33
34
|
*/ class SkyRenderer extends Disposable {
|
|
35
|
+
/**
|
|
36
|
+
* @internal
|
|
37
|
+
*
|
|
38
|
+
* The atmospheric scattering model predates photometric lighting and was authored around a
|
|
39
|
+
* sun input of 10. This normalization maps the physical daylight reference (100,000 lux at
|
|
40
|
+
* Sunny 16, whose camera exposure is 1 / 38,400) onto that model reference: 10 / (100000 / 38400).
|
|
41
|
+
*/ static PHYSICAL_ATMOSPHERE_LUMINANCE_SCALE = 3.84;
|
|
42
|
+
/**
|
|
43
|
+
* @internal
|
|
44
|
+
* Fixed exposure the physical sky bake is stored at. See {@link PHYSICAL_BAKE_EXPOSURE}.
|
|
45
|
+
*/ static PHYSICAL_BAKE_EXPOSURE = PHYSICAL_BAKE_EXPOSURE;
|
|
46
|
+
/**
|
|
47
|
+
* @internal
|
|
48
|
+
*
|
|
49
|
+
* Reference-exposure anchor previously used to lift authored fog colors into photometric space.
|
|
50
|
+
*
|
|
51
|
+
* @deprecated Physical fog now derives its luminance from `EnvLightWrapper.intensity`, mirroring
|
|
52
|
+
* Filament, which scales fog color by `iblLuminance`. Retained only because it documents the
|
|
53
|
+
* Sunny-16 equivalence: 38,400 = 1 / exposure(f/16, 1/125s, ISO 100).
|
|
54
|
+
*/ static FOG_PHYSICAL_LUMINANCE = 38400;
|
|
34
55
|
static _skyCamera = (()=>{
|
|
35
56
|
return new PerspectiveCamera(null, Math.PI * 0.5, 1, 20, 1);
|
|
36
57
|
})();
|
|
@@ -89,8 +110,16 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
89
110
|
_bindgroupFog = null;
|
|
90
111
|
_bindgroupFogNoDepth = null;
|
|
91
112
|
_format;
|
|
92
|
-
/**
|
|
93
|
-
*
|
|
113
|
+
/**
|
|
114
|
+
* @internal Scale lifting the authored 0..1 height-fog colors into the pre-exposed space for the
|
|
115
|
+
* current frame (1 in legacy, `EnvLightWrapper.intensity * cameraExposure` in physical).
|
|
116
|
+
*/ _fogLuminanceScale;
|
|
117
|
+
/**
|
|
118
|
+
* @internal Ratio converting the fog shader's atmosphere-derived LUT samples from the fixed bake
|
|
119
|
+
* exposure to the live one (1 in legacy).
|
|
120
|
+
*/ _fogPreExposure;
|
|
121
|
+
/**
|
|
122
|
+
* Creates an instance of SkyRenderer
|
|
94
123
|
*/ constructor(){
|
|
95
124
|
super();
|
|
96
125
|
this._skyType = 'scatter';
|
|
@@ -131,12 +160,14 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
131
160
|
this._bindgroupFog = new DRef();
|
|
132
161
|
this._bindgroupFogNoDepth = new DRef();
|
|
133
162
|
this._format = null;
|
|
163
|
+
this._fogLuminanceScale = 1;
|
|
164
|
+
this._fogPreExposure = 1;
|
|
134
165
|
}
|
|
135
166
|
/** @internal */ getHash(_ctx) {
|
|
136
167
|
return `${this.skyType}:${this.fogType}`;
|
|
137
168
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Gets the preferred environment texture format.
|
|
169
|
+
/**
|
|
170
|
+
* Gets the preferred environment texture format.
|
|
140
171
|
*/ get envTextureFormat() {
|
|
141
172
|
if (!this._format) {
|
|
142
173
|
const texCaps = getDevice().getDeviceCaps().textureCaps;
|
|
@@ -181,8 +212,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
181
212
|
}
|
|
182
213
|
return this._bakedSkyboxTexture.get();
|
|
183
214
|
}
|
|
184
|
-
/**
|
|
185
|
-
* The color used when sky type is `image`
|
|
215
|
+
/**
|
|
216
|
+
* The color used when sky type is `image`
|
|
186
217
|
*/ get skyColor() {
|
|
187
218
|
return this._skyColor;
|
|
188
219
|
}
|
|
@@ -192,8 +223,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
192
223
|
this.invalidate();
|
|
193
224
|
}
|
|
194
225
|
}
|
|
195
|
-
/**
|
|
196
|
-
* The image used when sky type is `image`
|
|
226
|
+
/**
|
|
227
|
+
* The image used when sky type is `image`
|
|
197
228
|
*/ get skyImage() {
|
|
198
229
|
return this._skyImage.get();
|
|
199
230
|
}
|
|
@@ -203,8 +234,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
203
234
|
this.invalidate();
|
|
204
235
|
}
|
|
205
236
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Window weights for SH projection
|
|
237
|
+
/**
|
|
238
|
+
* Window weights for SH projection
|
|
208
239
|
*/ get shWindowWeights() {
|
|
209
240
|
return this._shWindowWeights;
|
|
210
241
|
}
|
|
@@ -212,8 +243,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
212
243
|
this._shWindowWeights.set(weights);
|
|
213
244
|
this.invalidate();
|
|
214
245
|
}
|
|
215
|
-
/**
|
|
216
|
-
* Sample count for radiance convolution
|
|
246
|
+
/**
|
|
247
|
+
* Sample count for radiance convolution
|
|
217
248
|
*/ get radianceConvSamples() {
|
|
218
249
|
return this._radianceConvSamples;
|
|
219
250
|
}
|
|
@@ -223,8 +254,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
223
254
|
this.invalidate();
|
|
224
255
|
}
|
|
225
256
|
}
|
|
226
|
-
/**
|
|
227
|
-
* Sample count for irradiance convolution
|
|
257
|
+
/**
|
|
258
|
+
* Sample count for irradiance convolution
|
|
228
259
|
*/ get irradianceConvSamples() {
|
|
229
260
|
return this._irradianceConvSamples;
|
|
230
261
|
}
|
|
@@ -351,12 +382,12 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
351
382
|
this.invalidate();
|
|
352
383
|
}
|
|
353
384
|
}
|
|
354
|
-
/**
|
|
355
|
-
* Light density of the sky.
|
|
356
|
-
*
|
|
357
|
-
* @remarks
|
|
358
|
-
* This value controls how much cloud should be rendered when the sky type is scatter.
|
|
359
|
-
* Typically, the value should be in the range of 0 to 1.
|
|
385
|
+
/**
|
|
386
|
+
* Light density of the sky.
|
|
387
|
+
*
|
|
388
|
+
* @remarks
|
|
389
|
+
* This value controls how much cloud should be rendered when the sky type is scatter.
|
|
390
|
+
* Typically, the value should be in the range of 0 to 1.
|
|
360
391
|
*/ get cloudy() {
|
|
361
392
|
return this._cloudy;
|
|
362
393
|
}
|
|
@@ -366,8 +397,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
366
397
|
this.invalidate();
|
|
367
398
|
}
|
|
368
399
|
}
|
|
369
|
-
/**
|
|
370
|
-
* Intensity of the sky color
|
|
400
|
+
/**
|
|
401
|
+
* Intensity of the sky color
|
|
371
402
|
*/ get cloudIntensity() {
|
|
372
403
|
return this._cloudIntensity;
|
|
373
404
|
}
|
|
@@ -377,19 +408,19 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
377
408
|
this.invalidate();
|
|
378
409
|
}
|
|
379
410
|
}
|
|
380
|
-
/**
|
|
381
|
-
* Wind velocity
|
|
382
|
-
*
|
|
383
|
-
* @remarks
|
|
384
|
-
* This value affects the movement of the cloud
|
|
411
|
+
/**
|
|
412
|
+
* Wind velocity
|
|
413
|
+
*
|
|
414
|
+
* @remarks
|
|
415
|
+
* This value affects the movement of the cloud
|
|
385
416
|
*/ get wind() {
|
|
386
417
|
return this._wind;
|
|
387
418
|
}
|
|
388
419
|
set wind(val) {
|
|
389
420
|
this._wind.set(val);
|
|
390
421
|
}
|
|
391
|
-
/**
|
|
392
|
-
* Radiance map of the sky.
|
|
422
|
+
/**
|
|
423
|
+
* Radiance map of the sky.
|
|
393
424
|
*/ get radianceMap() {
|
|
394
425
|
if (!this._radianceMap.get()) {
|
|
395
426
|
this._radianceMap.set(getDevice().createCubeTexture(this.envTextureFormat, this._radianceMapWidth));
|
|
@@ -397,11 +428,11 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
397
428
|
}
|
|
398
429
|
return this._radianceMap.get();
|
|
399
430
|
}
|
|
400
|
-
/**
|
|
401
|
-
* Radiance map of the sky reused for sheen.
|
|
402
|
-
*
|
|
403
|
-
* @remarks
|
|
404
|
-
* Dynamic sky is smooth enough that the GGX-prefiltered radiance map is a practical approximation for sheen.
|
|
431
|
+
/**
|
|
432
|
+
* Radiance map of the sky reused for sheen.
|
|
433
|
+
*
|
|
434
|
+
* @remarks
|
|
435
|
+
* Dynamic sky is smooth enough that the GGX-prefiltered radiance map is a practical approximation for sheen.
|
|
405
436
|
*/ get sheenRadianceMap() {
|
|
406
437
|
return this.radianceMap;
|
|
407
438
|
}
|
|
@@ -419,8 +450,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
419
450
|
}
|
|
420
451
|
return this._radianceFrameBuffer.get();
|
|
421
452
|
}
|
|
422
|
-
/**
|
|
423
|
-
* Irradiance SH coeffecients buffer
|
|
453
|
+
/**
|
|
454
|
+
* Irradiance SH coeffecients buffer
|
|
424
455
|
*/ get irradianceSH() {
|
|
425
456
|
if (!this._irradianceSH.get()) {
|
|
426
457
|
const buffer = getDevice().createBuffer(4 * 4 * 9, {
|
|
@@ -430,8 +461,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
430
461
|
}
|
|
431
462
|
return this._irradianceSH.get();
|
|
432
463
|
}
|
|
433
|
-
/**
|
|
434
|
-
* Irradiance SH coeffecients texture
|
|
464
|
+
/**
|
|
465
|
+
* Irradiance SH coeffecients texture
|
|
435
466
|
*/ get irradianceSHFB() {
|
|
436
467
|
if (!this._irradianceSHFB.get()) {
|
|
437
468
|
const device = getDevice();
|
|
@@ -446,8 +477,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
446
477
|
}
|
|
447
478
|
return this._irradianceSHFB.get();
|
|
448
479
|
}
|
|
449
|
-
/**
|
|
450
|
-
* Cube texture for skybox.
|
|
480
|
+
/**
|
|
481
|
+
* Cube texture for skybox.
|
|
451
482
|
*/ get skyboxTexture() {
|
|
452
483
|
return this._skyboxTexture.get();
|
|
453
484
|
}
|
|
@@ -459,8 +490,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
459
490
|
}
|
|
460
491
|
}
|
|
461
492
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Additional euler rotation (in degrees) applied to skybox.
|
|
493
|
+
/**
|
|
494
|
+
* Additional euler rotation (in degrees) applied to skybox.
|
|
464
495
|
*/ get skyboxRotation() {
|
|
465
496
|
return this._skyboxRotation;
|
|
466
497
|
}
|
|
@@ -503,8 +534,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
503
534
|
/** @internal */ get fogPresents() {
|
|
504
535
|
return this._skyType === 'scatter' || this._fogType !== 'none';
|
|
505
536
|
}
|
|
506
|
-
/**
|
|
507
|
-
* Force the radiance map and irradiance map to be regenerated.
|
|
537
|
+
/**
|
|
538
|
+
* Force the radiance map and irradiance map to be regenerated.
|
|
508
539
|
*/ invalidate() {
|
|
509
540
|
this._bakedSkyboxDirty = true;
|
|
510
541
|
}
|
|
@@ -518,6 +549,18 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
518
549
|
return this._skyDistantLightLut.get().getColorAttachments()[0];
|
|
519
550
|
}
|
|
520
551
|
update(ctx) {
|
|
552
|
+
// Latch the fog scales for this frame. The bake path (updateBakedSkyMap) uses the sky camera
|
|
553
|
+
// whose scene is null, so it cannot read lightingMode itself; both bake and main pass run after
|
|
554
|
+
// update(), so caching them here keeps them consistent.
|
|
555
|
+
// The fog shader mixes two differently-scaled sources, so it needs both factors:
|
|
556
|
+
// - the atmosphere-derived LUTs (distant sky, aerial perspective) are stored at the fixed bake
|
|
557
|
+
// exposure, so they convert with the bake-to-live ratio;
|
|
558
|
+
// - the authored 0..1 fog colors are lifted by the environment intensity (lux) -- the same
|
|
559
|
+
// anchor the sky and IBL use, mirroring Filament's `fogColor *= iblLuminance` -- and then
|
|
560
|
+
// take the plain camera pre-exposure.
|
|
561
|
+
// Legacy leaves both at 1 so its authored colors are untouched.
|
|
562
|
+
this._fogPreExposure = SkyRenderer.getBakeToPreExposedScale(ctx);
|
|
563
|
+
this._fogLuminanceScale = ctx.scene.lightingMode === 'physical' ? ctx.scene.env.light.intensity * ShaderHelper.getPreExposure(ctx) : 1;
|
|
521
564
|
const useScatter = this._skyType === 'scatter';
|
|
522
565
|
if (useScatter || !atmosphereLUTRendered()) {
|
|
523
566
|
this.renderAtmosphereLUTs(ctx);
|
|
@@ -545,16 +588,11 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
545
588
|
}
|
|
546
589
|
if (this._bakedSkyboxDirty) {
|
|
547
590
|
this._bakedSkyboxDirty = false;
|
|
591
|
+
// updateBakedSkyMap derives the IBL (specular prefilter + irradiance SH) from the fog-free
|
|
592
|
+
// cubemap internally, before compositing fog. The distant-light LUT is re-baked here against
|
|
593
|
+
// the fogged cubemap to preserve the pre-refactor fog shading appearance.
|
|
548
594
|
this.updateBakedSkyMap(ctx);
|
|
549
595
|
this.renderSkyDistantLut(ctx, this._bakedSkyboxTexture.get());
|
|
550
|
-
if (ctx.scene.env.light.radianceMap && (ctx.scene.env.light.radianceMap === this.radianceMap || this._irradianceSH.get() && ctx.scene.env.light.irradianceSH === this.irradianceSH || this._irradianceSHFB.get() && ctx.scene.env.light.irradianceSHFB === this.irradianceSHFB)) {
|
|
551
|
-
prefilterCubemap(this._bakedSkyboxTexture.get(), 'ggx', this.radianceFramebuffer, this._radianceConvSamples);
|
|
552
|
-
ctx.scene.env.light.sheenRadianceMap = this.radianceMap;
|
|
553
|
-
this._shProjector.projectCubemapToTexture(this._bakedSkyboxTexture.get(), this.irradianceSHFB);
|
|
554
|
-
ctx.scene.env.light.irradianceSHFB = this.irradianceSHFB;
|
|
555
|
-
ctx.scene.env.light.irradianceSH = null;
|
|
556
|
-
ctx.scene.env.light.irradianceWindow = this._shWindowWeights;
|
|
557
|
-
}
|
|
558
596
|
}
|
|
559
597
|
const newSunLight = oldSunLight ? Vector3.mul(ctx.sunLight.color.xyz(), this.sunTransmittance(ctx.sunLight)) : Vector3.zero();
|
|
560
598
|
if (oldSunLight) {
|
|
@@ -565,7 +603,14 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
565
603
|
const cameraY = Math.min(this._heightFogParams.parameter2.y + MAX_FOG_HEIGHT, ctx.camera.getWorldPosition().y);
|
|
566
604
|
const p = Math.max(-125, Math.min(126, -this._heightFogParams.parameter1.w * (cameraY - this._heightFogParams.parameter2.y)));
|
|
567
605
|
this._heightFogParams.parameter3.z = this._heightFogParams.parameter2.x * Math.pow(2, p);
|
|
568
|
-
|
|
606
|
+
// The legacy directional fog term expects a display-relative 0..1 light color. It cannot be
|
|
607
|
+
// mixed directly with photometric illuminance; physical fog instead receives its radiance
|
|
608
|
+
// from the distant-sky integration below.
|
|
609
|
+
if (ctx.scene.lightingMode === 'physical') {
|
|
610
|
+
this._heightFogParams.lightColor.setXYZ(0, 0, 0);
|
|
611
|
+
} else {
|
|
612
|
+
this._heightFogParams.lightColor.set(newSunLight);
|
|
613
|
+
}
|
|
569
614
|
this._heightFogParams.lightDir.set(SkyRenderer._getSunDir(ctx.sunLight));
|
|
570
615
|
}
|
|
571
616
|
return oldSunLight;
|
|
@@ -573,7 +618,12 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
573
618
|
renderAtmosphereLUTs(ctx) {
|
|
574
619
|
this._atmosphereParams.lightDir.set(SkyRenderer._getSunDir(ctx.sunLight));
|
|
575
620
|
this._atmosphereParams.lightColor.set(SkyRenderer._getSunColor(ctx.sunLight));
|
|
576
|
-
|
|
621
|
+
// Physical: the sun input is photometric (lux), normalized onto the model's authored reference
|
|
622
|
+
// and stored at the fixed PHYSICAL_BAKE_EXPOSURE rather than the live camera exposure. That
|
|
623
|
+
// keeps the cached IBL bake exposure-independent while staying inside the environment cubemap's
|
|
624
|
+
// limited float range -- raw luminance would overflow it to Inf. Consumers rescale to the live
|
|
625
|
+
// exposure via getBakeToPreExposedScale().
|
|
626
|
+
this._atmosphereParams.lightColor.w *= this._atmosphereExposure * (ctx.scene.lightingMode === 'physical' ? SkyRenderer.PHYSICAL_ATMOSPHERE_LUMINANCE_SCALE * SkyRenderer.PHYSICAL_BAKE_EXPOSURE : 1);
|
|
577
627
|
this._atmosphereParams.cameraAspect = ctx.camera.getAspect();
|
|
578
628
|
this._atmosphereParams.cameraWorldMatrix.set(ctx.camera.worldMatrix);
|
|
579
629
|
renderAtmosphereLUTs(this._atmosphereParams);
|
|
@@ -586,6 +636,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
586
636
|
ctx.device.setFramebuffer(this._skyDistantLightLut.get());
|
|
587
637
|
ctx.device.clearFrameBuffer(new Vector4(0, 0, 0, 1), null, null);
|
|
588
638
|
this._bindgroupDistantLight.get().setTexture('skybox', skybox, fetchSampler('clamp_linear_nomip'));
|
|
639
|
+
this._bindgroupDistantLight.get().setValue('physical', ctx.scene.lightingMode === 'physical' ? 1 : 0);
|
|
589
640
|
ctx.device.setBindGroup(0, this._bindgroupDistantLight.get());
|
|
590
641
|
SkyRenderer._primitiveDistantLight.draw();
|
|
591
642
|
ctx.device.popDeviceStates();
|
|
@@ -615,10 +666,24 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
615
666
|
]){
|
|
616
667
|
camera.lookAtCubeFace(face);
|
|
617
668
|
this._bakedSkyboxFrameBuffer.get().setColorAttachmentCubeFace(0, face);
|
|
618
|
-
|
|
669
|
+
// Direct sunlight is represented by the scene's directional sun light. Keep the analytic
|
|
670
|
+
// sun disk out of both diffuse and specular IBL to avoid baking that direct contribution a
|
|
671
|
+
// second time. Atmospheric scattering and clouds remain in the cubemap.
|
|
672
|
+
this._renderSky(camera, false, false, this._getSkyBakeLuminanceScale(ctx));
|
|
619
673
|
}
|
|
620
674
|
device.popDeviceStates();
|
|
621
675
|
this.renderSkyDistantLut(ctx, tex);
|
|
676
|
+
// Publish the texture reference before deriving IBL so _updateIBLFromBakedSky reads the
|
|
677
|
+
// current cubemap.
|
|
678
|
+
this._bakedSkyboxTexture.set(tex);
|
|
679
|
+
// Derive the IBL from the fog-free cubemap. Height fog is a view/position-dependent participating
|
|
680
|
+
// medium applied per-pixel in screen space (see lightpass renderFog); baking it into the distant
|
|
681
|
+
// environment probe would both double-count it against that screen-space pass and wrongly lift the
|
|
682
|
+
// lower hemisphere (ground direction) from the atmosphere's dark value to a bright fog color. The
|
|
683
|
+
// same reasoning that keeps the sun disk out of the IBL applies to fog, for diffuse and specular alike.
|
|
684
|
+
this._updateIBLFromBakedSky(ctx, tex);
|
|
685
|
+
// Composite fog into the cubemap afterwards. This copy is only used as the visible skybox
|
|
686
|
+
// background (UNIFORM_NAME_BAKED_SKY_MAP), where the fogged distant sky is desired.
|
|
622
687
|
device.pushDeviceStates();
|
|
623
688
|
device.setFramebuffer(this._bakedSkyboxFrameBuffer.get());
|
|
624
689
|
for (const face of [
|
|
@@ -635,7 +700,21 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
635
700
|
}
|
|
636
701
|
device.popDeviceStates();
|
|
637
702
|
device.setRenderStates(saveRenderStates);
|
|
638
|
-
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* @internal
|
|
706
|
+
* Updates the scene's IBL (GGX-prefiltered specular radiance map + irradiance SH) from the given
|
|
707
|
+
* cubemap, provided the scene environment light is still driven by this dynamic sky. Must be called
|
|
708
|
+
* with the fog-free cubemap so height fog does not leak into the environment lighting.
|
|
709
|
+
*/ _updateIBLFromBakedSky(ctx, skybox) {
|
|
710
|
+
if (ctx.scene.env.light.radianceMap && (ctx.scene.env.light.radianceMap === this.radianceMap || this._irradianceSH.get() && ctx.scene.env.light.irradianceSH === this.irradianceSH || this._irradianceSHFB.get() && ctx.scene.env.light.irradianceSHFB === this.irradianceSHFB)) {
|
|
711
|
+
prefilterCubemap(skybox, 'ggx', this.radianceFramebuffer, this._radianceConvSamples);
|
|
712
|
+
ctx.scene.env.light.sheenRadianceMap = this.radianceMap;
|
|
713
|
+
this._shProjector.projectCubemapToTexture(skybox, this.irradianceSHFB);
|
|
714
|
+
ctx.scene.env.light.irradianceSHFB = this.irradianceSHFB;
|
|
715
|
+
ctx.scene.env.light.irradianceSH = null;
|
|
716
|
+
ctx.scene.env.light.irradianceWindow = this._shWindowWeights;
|
|
717
|
+
}
|
|
639
718
|
}
|
|
640
719
|
renderUberFog(camera, depthTexture) {
|
|
641
720
|
const device = getDevice();
|
|
@@ -655,13 +734,34 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
655
734
|
bindgroup.setValue('withAerialPerspective', this.skyType === 'scatter' ? 1 : 0);
|
|
656
735
|
bindgroup.setValue('fogType', this.mappedFogType);
|
|
657
736
|
bindgroup.setValue('atmosphereParams', this._atmosphereParams);
|
|
658
|
-
bindgroup.setValue('heightFogParams', this.
|
|
737
|
+
bindgroup.setValue('heightFogParams', this._getUploadHeightFogParams());
|
|
659
738
|
device.setProgram(fogProgram);
|
|
660
739
|
device.setBindGroup(0, bindgroup);
|
|
661
740
|
device.setVertexLayout(SkyRenderer._vertexLayout);
|
|
662
741
|
device.setRenderStates(renderStates);
|
|
663
742
|
device.draw('triangle-strip', 0, 4);
|
|
664
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* @internal
|
|
746
|
+
* Height-fog upload params with the authored base/directional colors lifted into the pre-exposed
|
|
747
|
+
* physical space when physical lighting is active, plus the pre-exposure the shader applies to its
|
|
748
|
+
* atmosphere-derived LUT samples. Legacy returns the stored params untouched so its upload stays
|
|
749
|
+
* byte-identical. Stored authored values are never mutated.
|
|
750
|
+
*/ _getUploadHeightFogParams() {
|
|
751
|
+
const scale = this._fogLuminanceScale;
|
|
752
|
+
const p = this._heightFogParams;
|
|
753
|
+
if (scale === 1 && this._fogPreExposure === 1) {
|
|
754
|
+
return p;
|
|
755
|
+
}
|
|
756
|
+
const p1 = p.parameter1;
|
|
757
|
+
const p4 = p.parameter4;
|
|
758
|
+
return {
|
|
759
|
+
...p,
|
|
760
|
+
parameter1: new Vector4(p1.x * scale, p1.y * scale, p1.z * scale, p1.w),
|
|
761
|
+
parameter4: new Vector4(p4.x * scale, p4.y * scale, p4.z * scale, p4.w),
|
|
762
|
+
preExposure: this._fogPreExposure
|
|
763
|
+
};
|
|
764
|
+
}
|
|
665
765
|
/** @internal */ renderFog(camera) {
|
|
666
766
|
const device = getDevice();
|
|
667
767
|
const currentFramebuffer = device.getFramebuffer();
|
|
@@ -679,14 +779,14 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
679
779
|
const savedRenderStates = device.getRenderStates();
|
|
680
780
|
this._prepareSkyBox(device);
|
|
681
781
|
this.renderUberFog(camera, depthBuffer);
|
|
682
|
-
/*
|
|
683
|
-
if (this._skyType === 'scatter') {
|
|
684
|
-
this.renderAtmosphericFog(ctx, depthBuffer);
|
|
685
|
-
}
|
|
686
|
-
*/ /*
|
|
687
|
-
if (this._fogType === 'height_fog') {
|
|
688
|
-
this.renderHeightFog(ctx, depthBuffer);
|
|
689
|
-
}
|
|
782
|
+
/*
|
|
783
|
+
if (this._skyType === 'scatter') {
|
|
784
|
+
this.renderAtmosphericFog(ctx, depthBuffer);
|
|
785
|
+
}
|
|
786
|
+
*/ /*
|
|
787
|
+
if (this._fogType === 'height_fog') {
|
|
788
|
+
this.renderHeightFog(ctx, depthBuffer);
|
|
789
|
+
}
|
|
690
790
|
*/ device.setRenderStates(savedRenderStates);
|
|
691
791
|
if (fogFramebuffer) {
|
|
692
792
|
device.popDeviceStates();
|
|
@@ -726,7 +826,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
726
826
|
}
|
|
727
827
|
const framebuffer = this._beginSingleColorPass(true);
|
|
728
828
|
try {
|
|
729
|
-
this._renderSky(skyCamera, true);
|
|
829
|
+
this._renderSky(skyCamera, true, true, this._getSkyScreenLuminanceScale(ctx));
|
|
730
830
|
} finally{
|
|
731
831
|
this._endSingleColorPass(framebuffer);
|
|
732
832
|
}
|
|
@@ -774,23 +874,67 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
774
874
|
});
|
|
775
875
|
}
|
|
776
876
|
}
|
|
777
|
-
/** @internal */ _renderSky(camera, depthTest) {
|
|
877
|
+
/** @internal */ _renderSky(camera, depthTest, includeSunDisk, luminanceScale = 1) {
|
|
778
878
|
const device = getDevice();
|
|
779
879
|
const savedRenderStates = device.getRenderStates();
|
|
780
880
|
this._prepareSkyBox(device);
|
|
781
881
|
if (this._skyType === 'scatter') {
|
|
782
|
-
|
|
882
|
+
// The atmosphere LUTs already hold physical luminance, so only the caller's exposure applies.
|
|
883
|
+
this._drawScattering(camera, depthTest, includeSunDisk, luminanceScale);
|
|
783
884
|
} else if (this._skyType === 'skybox' && this.skyboxTexture) {
|
|
784
|
-
this._drawSkybox(camera, depthTest);
|
|
885
|
+
this._drawSkybox(camera, depthTest, luminanceScale);
|
|
785
886
|
} else {
|
|
786
|
-
this._drawSkyColor(camera, depthTest);
|
|
887
|
+
this._drawSkyColor(camera, depthTest, luminanceScale);
|
|
787
888
|
}
|
|
788
889
|
device.setRenderStates(savedRenderStates);
|
|
789
890
|
}
|
|
790
|
-
/**
|
|
891
|
+
/**
|
|
892
|
+
* @internal
|
|
893
|
+
*
|
|
894
|
+
* Converts a value stored at {@link PHYSICAL_BAKE_EXPOSURE} into the live pre-exposed space.
|
|
895
|
+
*
|
|
896
|
+
* @remarks
|
|
897
|
+
* Everything derived from the cached sky bake (the IBL, the distant-light LUT, the visible baked
|
|
898
|
+
* skybox) is stored at the fixed reference exposure. Multiplying by this ratio yields the same
|
|
899
|
+
* result as if the live camera exposure had been baked in, without invalidating the cache when
|
|
900
|
+
* the camera stops down. Returns 1 in legacy.
|
|
901
|
+
*/ static getBakeToPreExposedScale(ctx) {
|
|
902
|
+
return ctx.scene.lightingMode === 'physical' ? ShaderHelper.getPreExposure(ctx) / SkyRenderer.PHYSICAL_BAKE_EXPOSURE : 1;
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* @internal
|
|
906
|
+
*
|
|
907
|
+
* Scale that normalizes a sky into the IBL bake's storage space.
|
|
908
|
+
*
|
|
909
|
+
* @remarks
|
|
910
|
+
* An authored 0..1 `skybox` / `image` is treated as an emitter of `EnvLightWrapper.intensity` lux.
|
|
911
|
+
* The scattering atmosphere needs no lift: its LUTs already carry photometric sun illuminance.
|
|
912
|
+
*
|
|
913
|
+
* Both are then scaled to {@link PHYSICAL_BAKE_EXPOSURE}. The bake is cached and only invalidated
|
|
914
|
+
* by sun changes, so it must be exposure-independent; storing it at raw photometric magnitude
|
|
915
|
+
* would overflow the environment cubemap's float range (see {@link PHYSICAL_BAKE_EXPOSURE}).
|
|
916
|
+
*
|
|
917
|
+
* Returns 1 in legacy so its bake stays byte-identical.
|
|
918
|
+
*/ _getSkyBakeLuminanceScale(ctx) {
|
|
919
|
+
if (ctx.scene.lightingMode !== 'physical') {
|
|
920
|
+
return 1;
|
|
921
|
+
}
|
|
922
|
+
// scatter already includes the bake exposure via renderAtmosphereLUTs().
|
|
923
|
+
return this._skyType === 'scatter' ? 1 : ctx.scene.env.light.intensity * SkyRenderer.PHYSICAL_BAKE_EXPOSURE;
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* @internal
|
|
927
|
+
*
|
|
928
|
+
* On-screen sky scale: the bake-time normalization converted from the stored reference exposure
|
|
929
|
+
* to the live one, so the visible sky lands in the same pre-exposed space as every lit surface.
|
|
930
|
+
*/ _getSkyScreenLuminanceScale(ctx) {
|
|
931
|
+
return this._getSkyBakeLuminanceScale(ctx) * SkyRenderer.getBakeToPreExposedScale(ctx);
|
|
932
|
+
}
|
|
933
|
+
/** @internal */ _drawSkyColor(camera, depthTest, luminanceScale) {
|
|
791
934
|
const device = getDevice();
|
|
792
935
|
const bindgroup = this._bindgroupSky.image.get();
|
|
793
936
|
bindgroup.setValue('color', this._skyColor);
|
|
937
|
+
bindgroup.setValue('luminanceScale', luminanceScale);
|
|
794
938
|
bindgroup.setTexture('texture', this._skyImage.get() ?? SkyRenderer._defaultSkyImage.get(), fetchSampler('clamp_linear_nomip'));
|
|
795
939
|
bindgroup.setValue('flip', device.getFramebuffer() && device.type === 'webgpu' ? -1 : 1);
|
|
796
940
|
bindgroup.setValue('srgbOut', device.getFramebuffer() ? 0 : 1);
|
|
@@ -798,10 +942,11 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
798
942
|
device.setBindGroup(0, bindgroup);
|
|
799
943
|
drawFullscreenQuad(depthTest ? SkyRenderer._renderStatesSky : SkyRenderer._renderStatesSkyNoDepthTest);
|
|
800
944
|
}
|
|
801
|
-
/** @internal */ _drawSkybox(camera, depthTest) {
|
|
945
|
+
/** @internal */ _drawSkybox(camera, depthTest, luminanceScale) {
|
|
802
946
|
const device = getDevice();
|
|
803
947
|
const bindgroup = this._bindgroupSky.skybox.get();
|
|
804
948
|
bindgroup.setTexture('skyCubeMap', this.skyboxTexture, fetchSampler('clamp_linear_nomip'));
|
|
949
|
+
bindgroup.setValue('luminanceScale', luminanceScale);
|
|
805
950
|
bindgroup.setValue('flip', device.getFramebuffer() && device.type === 'webgpu' ? new Vector4(1, -1, 1, 1) : new Vector4(1, 1, 1, 1));
|
|
806
951
|
bindgroup.setValue('viewProjMatrix', camera.viewProjectionMatrix);
|
|
807
952
|
bindgroup.setValue('worldMatrix', this._skyWorldMatrix);
|
|
@@ -877,7 +1022,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
877
1022
|
}
|
|
878
1023
|
return new Vector3(Math.exp(-sum.x), Math.exp(-sum.y), Math.exp(-sum.z));
|
|
879
1024
|
}
|
|
880
|
-
/** @internal */ _drawScattering(camera, depthTest) {
|
|
1025
|
+
/** @internal */ _drawScattering(camera, depthTest, includeSunDisk, luminanceScale) {
|
|
881
1026
|
const device = getDevice();
|
|
882
1027
|
const tLut = getTransmittanceLut();
|
|
883
1028
|
const skyLut = getSkyViewLut();
|
|
@@ -890,6 +1035,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
890
1035
|
bindgroup.setValue('worldMatrix', this._skyWorldMatrix);
|
|
891
1036
|
bindgroup.setValue('cameraPos', camera.getWorldPosition());
|
|
892
1037
|
bindgroup.setValue('srgbOut', device.getFramebuffer() ? 0 : 1);
|
|
1038
|
+
bindgroup.setValue('includeSunDisk', includeSunDisk ? 1 : 0);
|
|
1039
|
+
bindgroup.setValue('luminanceScale', luminanceScale);
|
|
893
1040
|
bindgroup.setTexture('tLut', tLut, fetchSampler('clamp_linear_nomip'));
|
|
894
1041
|
bindgroup.setTexture('skyLut', skyLut, fetchSampler('clamp_linear_nomip'));
|
|
895
1042
|
bindgroup.setValue('cloudy', this._cloudy);
|
|
@@ -930,9 +1077,14 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
930
1077
|
fragment (pb) {
|
|
931
1078
|
this.$outputs.color = pb.vec4();
|
|
932
1079
|
this.skybox = pb.texCube().uniform(0);
|
|
1080
|
+
this.physical = pb.int().uniform(0);
|
|
933
1081
|
pb.main(function() {
|
|
934
1082
|
this.$l.sunColor = pb.vec4();
|
|
935
|
-
|
|
1083
|
+
// Height-fog in-scattering is lit by the sky hemisphere. The old full-sphere average
|
|
1084
|
+
// is retained verbatim in legacy mode; in physical mode, mirror lower samples into the
|
|
1085
|
+
// upper hemisphere so a dark ground/lower sky cannot turn the horizon into a black band.
|
|
1086
|
+
this.$l.sampleDirection = this.$choice(pb.notEqual(this.physical, 0), pb.vec3(this.$inputs.vector.x, pb.abs(this.$inputs.vector.y), this.$inputs.vector.z), this.$inputs.vector);
|
|
1087
|
+
this.$l.skyColor = pb.textureSampleLevel(this.skybox, this.sampleDirection, 0).rgb;
|
|
936
1088
|
this.$outputs.color = pb.vec4(pb.mul(this.skyColor, 1 / 64), 1);
|
|
937
1089
|
});
|
|
938
1090
|
}
|
|
@@ -962,7 +1114,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
962
1114
|
this.$outputs.uv = pb.vec2();
|
|
963
1115
|
this.flip = pb.int().uniform(0);
|
|
964
1116
|
pb.main(function() {
|
|
965
|
-
this.$builtins.position = pb.vec4(this.$inputs.pos,
|
|
1117
|
+
this.$builtins.position = pb.vec4(this.$inputs.pos, DEPTH_FARTHEST, 1);
|
|
966
1118
|
this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));
|
|
967
1119
|
if (device.type !== 'webgpu') {
|
|
968
1120
|
this.$builtins.position.y = pb.neg(this.$builtins.position.y);
|
|
@@ -974,9 +1126,12 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
974
1126
|
this.color = pb.vec4().uniform(0);
|
|
975
1127
|
this.texture = pb.tex2D().uniform(0);
|
|
976
1128
|
this.srgbOut = pb.int().uniform(0);
|
|
1129
|
+
this.luminanceScale = pb.float().uniform(0);
|
|
977
1130
|
pb.main(function() {
|
|
978
1131
|
this.$l.sampleColor = pb.textureSampleLevel(this.texture, this.$inputs.uv, 0);
|
|
979
|
-
|
|
1132
|
+
// luminanceScale is 1 in legacy and for the IBL bake; on screen in physical mode it
|
|
1133
|
+
// carries the environment intensity (lux) pre-multiplied by the camera exposure.
|
|
1134
|
+
this.$l.outColor = pb.mul(this.sampleColor, this.color, this.luminanceScale);
|
|
980
1135
|
this.$if(pb.equal(this.srgbOut, 0), function() {
|
|
981
1136
|
this.$outputs.outColor = pb.vec4(this.outColor.rgb, 1);
|
|
982
1137
|
}).$else(function() {
|
|
@@ -1010,16 +1165,19 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1010
1165
|
this.$outputs.texCoord = this.$inputs.pos;
|
|
1011
1166
|
this.$l.worldPos = pb.add(this.cameraPos, pb.mul(this.worldMatrix, pb.vec4(this.$inputs.pos, 0)).xyz);
|
|
1012
1167
|
this.$builtins.position = pb.mul(this.viewProjMatrix, pb.vec4(this.worldPos, 1), this.flip);
|
|
1013
|
-
this.$builtins.position.z = this.$builtins.position.w;
|
|
1168
|
+
this.$builtins.position.z = ShaderHelper.farthestClipZ(this, this.$builtins.position.w);
|
|
1014
1169
|
});
|
|
1015
1170
|
},
|
|
1016
1171
|
fragment (pb) {
|
|
1017
1172
|
this.$outputs.outColor = pb.vec4();
|
|
1018
1173
|
this.skyCubeMap = pb.texCube().uniform(0);
|
|
1019
1174
|
this.srgbOut = pb.int().uniform(0);
|
|
1175
|
+
this.luminanceScale = pb.float().uniform(0);
|
|
1020
1176
|
pb.main(function() {
|
|
1021
1177
|
this.$l.texCoord = pb.normalize(this.$inputs.texCoord);
|
|
1022
|
-
|
|
1178
|
+
// luminanceScale is 1 in legacy and for the IBL bake; on screen in physical mode it
|
|
1179
|
+
// carries the environment intensity (lux) pre-multiplied by the camera exposure.
|
|
1180
|
+
this.$l.color = pb.mul(pb.textureSampleLevel(this.skyCubeMap, this.texCoord, 0).rgb, this.luminanceScale);
|
|
1023
1181
|
this.$if(pb.equal(this.srgbOut, 0), function() {
|
|
1024
1182
|
this.$outputs.outColor = pb.vec4(this.color, 1);
|
|
1025
1183
|
}).$else(function() {
|
|
@@ -1035,7 +1193,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1035
1193
|
}
|
|
1036
1194
|
if (!SkyRenderer._renderStatesSky) {
|
|
1037
1195
|
SkyRenderer._renderStatesSky = device.createRenderStateSet();
|
|
1038
|
-
SkyRenderer._renderStatesSky.useDepthState().enableTest(true).enableWrite(false).setCompareFunc(
|
|
1196
|
+
SkyRenderer._renderStatesSky.useDepthState().enableTest(true).enableWrite(false).setCompareFunc(DEPTH_COMPARE_DEFAULT);
|
|
1039
1197
|
SkyRenderer._renderStatesSky.useRasterizerState().setCullMode('none');
|
|
1040
1198
|
}
|
|
1041
1199
|
if (!SkyRenderer._renderStatesSkyNoDepthTest) {
|
|
@@ -1053,7 +1211,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1053
1211
|
SkyRenderer._renderStatesFogScatter = device.createRenderStateSet();
|
|
1054
1212
|
SkyRenderer._renderStatesFogScatter.useRasterizerState().setCullMode('none');
|
|
1055
1213
|
SkyRenderer._renderStatesFogScatter.useBlendingState().enable(true).setBlendFunc('one', 'src-alpha');
|
|
1056
|
-
SkyRenderer._renderStatesFogScatter.useDepthState().enableTest(true).enableWrite(false).setCompareFunc(
|
|
1214
|
+
SkyRenderer._renderStatesFogScatter.useDepthState().enableTest(true).enableWrite(false).setCompareFunc(DEPTH_COMPARE_FARTHER);
|
|
1057
1215
|
}
|
|
1058
1216
|
if (!SkyRenderer._renderStatesDistantLight) {
|
|
1059
1217
|
SkyRenderer._renderStatesDistantLight = device.createRenderStateSet();
|
|
@@ -1107,7 +1265,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1107
1265
|
this.$inputs.pos = pb.vec2().attrib('position');
|
|
1108
1266
|
this.$outputs.uv = pb.vec2();
|
|
1109
1267
|
pb.main(function() {
|
|
1110
|
-
this.$builtins.position = pb.vec4(this.$inputs.pos,
|
|
1268
|
+
this.$builtins.position = pb.vec4(this.$inputs.pos, DEPTH_FARTHEST, 1);
|
|
1111
1269
|
this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));
|
|
1112
1270
|
if (device.type === 'webgpu') {
|
|
1113
1271
|
this.$if(pb.notEqual(this.rt, 0), function() {
|
|
@@ -1134,11 +1292,11 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1134
1292
|
this.srgbOut = pb.int().uniform(0);
|
|
1135
1293
|
this.$outputs.outColor = pb.vec4();
|
|
1136
1294
|
pb.main(function() {
|
|
1137
|
-
this.$l.depthValue = noDepth ? pb.float(
|
|
1138
|
-
this.$l.clipSpacePos = pb.vec4(pb.sub(pb.mul(this.$inputs.uv, 2), pb.vec2(1)),
|
|
1295
|
+
this.$l.depthValue = noDepth ? pb.float(DEPTH_FARTHEST) : pb.textureSample(this.depthTex, this.$inputs.uv).r;
|
|
1296
|
+
this.$l.clipSpacePos = pb.vec4(pb.sub(pb.mul(this.$inputs.uv, 2), pb.vec2(1)), ShaderHelper.deviceDepthToClipZ(this, this.depthValue), 1);
|
|
1139
1297
|
this.$l.hPos = pb.mul(this.invProjViewMatrix, this.clipSpacePos);
|
|
1140
1298
|
this.$l.worldPos = pb.div(this.$l.hPos, this.$l.hPos.w).xyz;
|
|
1141
|
-
this.$l.isSky =
|
|
1299
|
+
this.$l.isSky = ShaderHelper.isFarthestDepth(this, this.$l.depthValue);
|
|
1142
1300
|
this.$l.color = calculateFog(this, this.withAerialPerspective, this.fogType, this.atmosphereParams, this.heightFogParams, this.$inputs.uv, this.isSky, this.cameraPosition, this.worldPos, 0, this.apLut, this.skyDistantLightLut);
|
|
1143
1301
|
this.$if(pb.equal(this.srgbOut, 0), function() {
|
|
1144
1302
|
this.$outputs.outColor = this.color;
|
|
@@ -1184,7 +1342,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1184
1342
|
pb.main(function() {
|
|
1185
1343
|
this.$outputs.worldDirection = pb.mul(this.worldMatrix, pb.vec4(this.$inputs.pos, 0)).xyz;
|
|
1186
1344
|
this.$builtins.position = pb.mul(this.viewProjMatrix, pb.vec4(pb.add(this.$outputs.worldDirection, this.cameraPos), 1), this.flip);
|
|
1187
|
-
this.$builtins.position.z = this.$builtins.position.w;
|
|
1345
|
+
this.$builtins.position.z = ShaderHelper.farthestClipZ(this, this.$builtins.position.w);
|
|
1188
1346
|
});
|
|
1189
1347
|
},
|
|
1190
1348
|
fragment (pb) {
|
|
@@ -1192,6 +1350,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1192
1350
|
this.tLut = pb.tex2D().uniform(0);
|
|
1193
1351
|
this.skyLut = pb.tex2D().uniform(0);
|
|
1194
1352
|
this.params = getAtmosphereParamsStruct(pb)().uniform(0);
|
|
1353
|
+
this.includeSunDisk = pb.int().uniform(0);
|
|
1195
1354
|
if (cloud) {
|
|
1196
1355
|
this.cloudy = pb.float().uniform(0);
|
|
1197
1356
|
this.cloudIntensity = pb.float().uniform(0);
|
|
@@ -1199,6 +1358,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1199
1358
|
this.velocity = pb.vec2().uniform(0);
|
|
1200
1359
|
}
|
|
1201
1360
|
this.srgbOut = pb.int().uniform(0);
|
|
1361
|
+
this.luminanceScale = pb.float().uniform(0);
|
|
1202
1362
|
pb.func('noise', [
|
|
1203
1363
|
pb.vec3('p'),
|
|
1204
1364
|
pb.float('t')
|
|
@@ -1222,7 +1382,7 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1222
1382
|
pb.main(function() {
|
|
1223
1383
|
// Calculate sky color
|
|
1224
1384
|
this.$l.sunColor = pb.vec4();
|
|
1225
|
-
this.$l.skyColor = skyBox(this, this.params, this.sunColor, this.$inputs.worldDirection, pb.float(0.01), this.tLut, this.skyLut).rgb;
|
|
1385
|
+
this.$l.skyColor = skyBox(this, this.params, this.sunColor, this.$inputs.worldDirection, pb.float(0.01), this.includeSunDisk, this.tLut, this.skyLut).rgb;
|
|
1226
1386
|
this.$l.rayDir = pb.normalize(this.$inputs.worldDirection);
|
|
1227
1387
|
this.$l.sunDir = this.params.lightDir;
|
|
1228
1388
|
// ad-hoc
|
|
@@ -1242,11 +1402,11 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1242
1402
|
this.noiseValue = pb.smoothStep(1, pb.add(1, this.cloudy), this.noiseValue);
|
|
1243
1403
|
});
|
|
1244
1404
|
// use sun color as cloud color
|
|
1245
|
-
/*
|
|
1246
|
-
this.$l.sunColor = pb.mul(
|
|
1247
|
-
pb.textureSampleLevel(this.skyLut, viewDirToUV(this, this.sunDir), 0),
|
|
1248
|
-
this.sunIntensity
|
|
1249
|
-
);
|
|
1405
|
+
/*
|
|
1406
|
+
this.$l.sunColor = pb.mul(
|
|
1407
|
+
pb.textureSampleLevel(this.skyLut, viewDirToUV(this, this.sunDir), 0),
|
|
1408
|
+
this.sunIntensity
|
|
1409
|
+
);
|
|
1250
1410
|
*/ this.$l.cloudColor = pb.mul(this.sunColor.rgb, this.sunIntensity, pb.mul(this.noiseValue, this.cloudIntensity));
|
|
1251
1411
|
}
|
|
1252
1412
|
// Compute sky color
|
|
@@ -1258,6 +1418,8 @@ const defaultSkyWorldMatrix = Matrix4x4.identity();
|
|
|
1258
1418
|
} else {
|
|
1259
1419
|
this.$l.color = this.skyColor;
|
|
1260
1420
|
}
|
|
1421
|
+
// 1 for legacy and for the IBL bake; the camera pre-exposure when drawn on screen.
|
|
1422
|
+
this.color = pb.mul(this.color, this.luminanceScale);
|
|
1261
1423
|
this.$if(pb.equal(this.srgbOut, 0), function() {
|
|
1262
1424
|
this.$outputs.outColor = pb.vec4(this.color, 1);
|
|
1263
1425
|
}).$else(function() {
|