@zephyr3d/scene 0.9.22 → 0.9.23

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.
Files changed (234) hide show
  1. package/dist/animation/joint_dynamics/collision.js +1 -7
  2. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  3. package/dist/animation/joint_dynamics/constraints.js +2 -17
  4. package/dist/animation/joint_dynamics/constraints.js.map +1 -1
  5. package/dist/animation/joint_dynamics/controller.js +2 -20
  6. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  7. package/dist/animation/joint_dynamics/joint_dynamics_system.js +1 -3
  8. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  9. package/dist/animation/joint_dynamics/solver.js +14 -60
  10. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  11. package/dist/animation/joint_dynamics/types.js +3 -3
  12. package/dist/animation/joint_dynamics/types.js.map +1 -1
  13. package/dist/app/app.js +23 -0
  14. package/dist/app/app.js.map +1 -1
  15. package/dist/app/scriptregistry.js +16 -53
  16. package/dist/app/scriptregistry.js.map +1 -1
  17. package/dist/asset/assetmanager.js +2 -0
  18. package/dist/asset/assetmanager.js.map +1 -1
  19. package/dist/asset/model.js +22 -0
  20. package/dist/asset/model.js.map +1 -1
  21. package/dist/blitter/bilateralblur.js +3 -1
  22. package/dist/blitter/bilateralblur.js.map +1 -1
  23. package/dist/blitter/blitter.js +3 -3
  24. package/dist/blitter/blitter.js.map +1 -1
  25. package/dist/camera/camera.js +398 -45
  26. package/dist/camera/camera.js.map +1 -1
  27. package/dist/camera/perspectivecamera.js +69 -2
  28. package/dist/camera/perspectivecamera.js.map +1 -1
  29. package/dist/index.d.ts +9113 -8734
  30. package/dist/index.js +9 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/material/blinn.js +1 -1
  33. package/dist/material/blinn.js.map +1 -1
  34. package/dist/material/lambert.js +3 -3
  35. package/dist/material/lambert.js.map +1 -1
  36. package/dist/material/material.js +8 -5
  37. package/dist/material/material.js.map +1 -1
  38. package/dist/material/meshmaterial.js +17 -10
  39. package/dist/material/meshmaterial.js.map +1 -1
  40. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  41. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  42. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  43. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  44. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +21 -6
  45. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  46. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +1 -1
  47. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  48. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +1 -1
  49. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  50. package/dist/material/mixins/lit.js +33 -11
  51. package/dist/material/mixins/lit.js.map +1 -1
  52. package/dist/material/mixins/pbr/brdf.js +44 -12
  53. package/dist/material/mixins/pbr/brdf.js.map +1 -1
  54. package/dist/material/mixins/pbr/common.js +149 -14
  55. package/dist/material/mixins/pbr/common.js.map +1 -1
  56. package/dist/material/mtoon.js +7 -4
  57. package/dist/material/mtoon.js.map +1 -1
  58. package/dist/material/pbrblueprint.js +5 -1
  59. package/dist/material/pbrblueprint.js.map +1 -1
  60. package/dist/material/pbrmr.js +1 -1
  61. package/dist/material/pbrmr.js.map +1 -1
  62. package/dist/material/pbrsg.js +1 -1
  63. package/dist/material/pbrsg.js.map +1 -1
  64. package/dist/material/shader/helper.js +186 -11
  65. package/dist/material/shader/helper.js.map +1 -1
  66. package/dist/material/skin.js +2 -2
  67. package/dist/material/skin.js.map +1 -1
  68. package/dist/material/terrain-cm.js +5 -5
  69. package/dist/material/terrain-cm.js.map +1 -1
  70. package/dist/material/water.js +6 -4
  71. package/dist/material/water.js.map +1 -1
  72. package/dist/posteffect/bloom.js +54 -4
  73. package/dist/posteffect/bloom.js.map +1 -1
  74. package/dist/posteffect/compositor.js +41 -0
  75. package/dist/posteffect/compositor.js.map +1 -1
  76. package/dist/posteffect/posteffect.js +35 -0
  77. package/dist/posteffect/posteffect.js.map +1 -1
  78. package/dist/posteffect/sao.js +7 -6
  79. package/dist/posteffect/sao.js.map +1 -1
  80. package/dist/posteffect/skinsss.js +3 -3
  81. package/dist/posteffect/skinsss.js.map +1 -1
  82. package/dist/posteffect/ssgi.js +988 -436
  83. package/dist/posteffect/ssgi.js.map +1 -1
  84. package/dist/posteffect/ssr.js +83 -45
  85. package/dist/posteffect/ssr.js.map +1 -1
  86. package/dist/posteffect/sss.js +18 -15
  87. package/dist/posteffect/sss.js.map +1 -1
  88. package/dist/posteffect/taa.js +5 -4
  89. package/dist/posteffect/taa.js.map +1 -1
  90. package/dist/posteffect/tonemap.js +15 -3
  91. package/dist/posteffect/tonemap.js.map +1 -1
  92. package/dist/render/abuffer_oit.js +2 -2
  93. package/dist/render/abuffer_oit.js.map +1 -1
  94. package/dist/render/cluster_light.js +12 -6
  95. package/dist/render/cluster_light.js.map +1 -1
  96. package/dist/render/drawable_mixin.js +8 -5
  97. package/dist/render/drawable_mixin.js.map +1 -1
  98. package/dist/render/dualdepthpeeling_oit.js +10 -5
  99. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  100. package/dist/render/envlight.js +298 -5
  101. package/dist/render/envlight.js.map +1 -1
  102. package/dist/render/gpu_picking.js +7 -5
  103. package/dist/render/gpu_picking.js.map +1 -1
  104. package/dist/render/hzb.js +28 -19
  105. package/dist/render/hzb.js.map +1 -1
  106. package/dist/render/lightpass.js +18 -4
  107. package/dist/render/lightpass.js.map +1 -1
  108. package/dist/render/render_queue.js +37 -4
  109. package/dist/render/render_queue.js.map +1 -1
  110. package/dist/render/renderer.js +8 -3
  111. package/dist/render/renderer.js.map +1 -1
  112. package/dist/render/rendergraph/blackboard.js +20 -48
  113. package/dist/render/rendergraph/blackboard.js.map +1 -1
  114. package/dist/render/rendergraph/device_pool_allocator.js +18 -58
  115. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  116. package/dist/render/rendergraph/executor.js +89 -115
  117. package/dist/render/rendergraph/executor.js.map +1 -1
  118. package/dist/render/rendergraph/forward_plus_builder.js +1003 -715
  119. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  120. package/dist/render/rendergraph/frame_graph_context.js +1 -1
  121. package/dist/render/rendergraph/frame_graph_context.js.map +1 -1
  122. package/dist/render/rendergraph/frame_resource_requirements.js +14 -0
  123. package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -0
  124. package/dist/render/rendergraph/history_resource_manager.js +74 -140
  125. package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  126. package/dist/render/rendergraph/history_resources.js +7 -5
  127. package/dist/render/rendergraph/history_resources.js.map +1 -1
  128. package/dist/render/rendergraph/render_context.js +19 -0
  129. package/dist/render/rendergraph/render_context.js.map +1 -0
  130. package/dist/render/rendergraph/render_pipeline.js +315 -0
  131. package/dist/render/rendergraph/render_pipeline.js.map +1 -0
  132. package/dist/render/rendergraph/rendergraph.js +158 -141
  133. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  134. package/dist/render/rendergraph/scene_render_context.js +267 -0
  135. package/dist/render/rendergraph/scene_render_context.js.map +1 -0
  136. package/dist/render/rendergraph/texture_affinity_cache.js +19 -0
  137. package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -0
  138. package/dist/render/rendergraph/types.js +19 -31
  139. package/dist/render/rendergraph/types.js.map +1 -1
  140. package/dist/render/renderpass.js +3 -3
  141. package/dist/render/renderpass.js.map +1 -1
  142. package/dist/render/shadow_mask_pass.js +7 -6
  143. package/dist/render/shadow_mask_pass.js.map +1 -1
  144. package/dist/render/sky.js +197 -35
  145. package/dist/render/sky.js.map +1 -1
  146. package/dist/render/weightedblended_oit.js +4 -3
  147. package/dist/render/weightedblended_oit.js.map +1 -1
  148. package/dist/scene/basesprite.js +2 -0
  149. package/dist/scene/basesprite.js.map +1 -1
  150. package/dist/scene/batchgroup.js +10 -0
  151. package/dist/scene/batchgroup.js.map +1 -1
  152. package/dist/scene/environment.js +61 -2
  153. package/dist/scene/environment.js.map +1 -1
  154. package/dist/scene/light.js +178 -10
  155. package/dist/scene/light.js.map +1 -1
  156. package/dist/scene/meshdrawable.js +89 -2
  157. package/dist/scene/meshdrawable.js.map +1 -1
  158. package/dist/scene/msdftext.js +2 -0
  159. package/dist/scene/msdftext.js.map +1 -1
  160. package/dist/scene/msdftextsprite.js +2 -0
  161. package/dist/scene/msdftextsprite.js.map +1 -1
  162. package/dist/scene/particlesys.js +2 -0
  163. package/dist/scene/particlesys.js.map +1 -1
  164. package/dist/scene/scene.js +34 -1
  165. package/dist/scene/scene.js.map +1 -1
  166. package/dist/scene/terrain-cm/grass.js +2 -1
  167. package/dist/scene/terrain-cm/grass.js.map +1 -1
  168. package/dist/scene/terrain-cm/terrain-cm.js +2 -0
  169. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  170. package/dist/scene/water.js +2 -0
  171. package/dist/scene/water.js.map +1 -1
  172. package/dist/shaders/atmosphere.js +5 -4
  173. package/dist/shaders/atmosphere.js.map +1 -1
  174. package/dist/shaders/fog.js +10 -3
  175. package/dist/shaders/fog.js.map +1 -1
  176. package/dist/shaders/shadow.js +96 -29
  177. package/dist/shaders/shadow.js.map +1 -1
  178. package/dist/shaders/ssgi_reprojection.js +118 -0
  179. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  180. package/dist/shaders/ssr.js +322 -154
  181. package/dist/shaders/ssr.js.map +1 -1
  182. package/dist/shadow/esm.js +10 -7
  183. package/dist/shadow/esm.js.map +1 -1
  184. package/dist/shadow/pcf_opt.js +12 -12
  185. package/dist/shadow/pcf_opt.js.map +1 -1
  186. package/dist/shadow/pcf_pd.js +12 -12
  187. package/dist/shadow/pcf_pd.js.map +1 -1
  188. package/dist/shadow/pcss.js +15 -11
  189. package/dist/shadow/pcss.js.map +1 -1
  190. package/dist/shadow/shadow_impl.js +20 -2
  191. package/dist/shadow/shadow_impl.js.map +1 -1
  192. package/dist/shadow/shadowmapper.js +5 -2
  193. package/dist/shadow/shadowmapper.js.map +1 -1
  194. package/dist/shadow/ssm.js +13 -13
  195. package/dist/shadow/ssm.js.map +1 -1
  196. package/dist/shadow/vsm.js +7 -7
  197. package/dist/shadow/vsm.js.map +1 -1
  198. package/dist/utility/physical.js +74 -0
  199. package/dist/utility/physical.js.map +1 -0
  200. package/dist/utility/rendermipmap.js +2 -2
  201. package/dist/utility/rendermipmap.js.map +1 -1
  202. package/dist/utility/serialization/manager.js +3 -1
  203. package/dist/utility/serialization/manager.js.map +1 -1
  204. package/dist/utility/serialization/scene/animation.js +3 -1
  205. package/dist/utility/serialization/scene/animation.js.map +1 -1
  206. package/dist/utility/serialization/scene/batch.js +3 -1
  207. package/dist/utility/serialization/scene/batch.js.map +1 -1
  208. package/dist/utility/serialization/scene/camera.js +598 -2
  209. package/dist/utility/serialization/scene/camera.js.map +1 -1
  210. package/dist/utility/serialization/scene/light.js +180 -9
  211. package/dist/utility/serialization/scene/light.js.map +1 -1
  212. package/dist/utility/serialization/scene/material.js +43 -3
  213. package/dist/utility/serialization/scene/material.js.map +1 -1
  214. package/dist/utility/serialization/scene/mesh.js +3 -1
  215. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  216. package/dist/utility/serialization/scene/node.js +3 -1
  217. package/dist/utility/serialization/scene/node.js.map +1 -1
  218. package/dist/utility/serialization/scene/particle.js +3 -1
  219. package/dist/utility/serialization/scene/particle.js.map +1 -1
  220. package/dist/utility/serialization/scene/primitive.js +2 -0
  221. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  222. package/dist/utility/serialization/scene/scene.js +70 -0
  223. package/dist/utility/serialization/scene/scene.js.map +1 -1
  224. package/dist/utility/serialization/scene/sprite.js +3 -1
  225. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  226. package/dist/utility/serialization/scene/terrain.js +3 -1
  227. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  228. package/dist/utility/serialization/scene/text.js +3 -0
  229. package/dist/utility/serialization/scene/text.js.map +1 -1
  230. package/dist/utility/serialization/scene/water.js +3 -1
  231. package/dist/utility/serialization/scene/water.js.map +1 -1
  232. package/dist/values.js +2 -3
  233. package/dist/values.js.map +1 -1
  234. package/package.json +3 -3
@@ -1,8 +1,9 @@
1
- import { Vector3, Vector4, Vector2 } from '@zephyr3d/base';
1
+ import { Vector3, Vector4, Vector2, REVERSE_Z, DEPTH_FARTHEST, DEPTH_REDUCE_CLOSER, DEPTH_REDUCE_FARTHER } from '@zephyr3d/base';
2
2
  import { RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_LIGHT, MaterialVaryingFlags, MAX_CLUSTERED_LIGHTS, MORPH_WEIGHTS_VECTOR_COUNT, MORPH_TARGET_POSITION, MORPH_TARGET_NORMAL, MORPH_TARGET_TANGENT, MORPH_ATTRIBUTE_VECTOR_COUNT } from '../../values.js';
3
3
  import { ProgramBuilder } from '@zephyr3d/device';
4
4
  import { decodeNormalizedFloatFromRGBA, linearToGamma } from '../../shaders/misc.js';
5
5
  import { getSamplerOptions, fetchSampler } from '../../utility/misc.js';
6
+ import { PHYSICAL_BAKE_EXPOSURE } from '../../utility/physical.js';
6
7
  import { getDevice } from '../../app/api.js';
7
8
  import { getDefaultAtmosphereParams, getAtmosphereParamsStruct } from '../../shaders/atmosphere.js';
8
9
  import { getDefaultHeightFogParams, getHeightFogParamsStruct, calculateFog } from '../../shaders/fog.js';
@@ -173,6 +174,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
173
174
  pb.float('shadowDebugCascades'),
174
175
  pb.float('frameDeltaTime'),
175
176
  pb.float('elapsedTime'),
177
+ pb.float('preExposure'),
176
178
  pb.int('framestamp')
177
179
  ]);
178
180
  if (ctx.renderPass.type === RENDER_PASS_TYPE_SHADOWMAP) {
@@ -271,12 +273,12 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
271
273
  scope[UNIFORM_NAME_SHADOW_MAP] = tex.uniform(0);
272
274
  }
273
275
  if (ctx.drawEnvLight) {
274
- ctx.env.light.envLight.initShaderBindings(pb);
276
+ ctx.env.light.envLight.initShaderBindings(pb, ctx);
275
277
  }
276
278
  if (ctx.linearDepthTexture) {
277
279
  // Depth values must never be filtered across geometry edges; nearest
278
280
  // matches the default sampler for unfilterable float formats.
279
- scope[UNIFORM_NAME_LINEAR_DEPTH_MAP] = pb.tex2D().uniform(0).withSampler(getSamplerOptions('clamp_nearest_nomip'));
281
+ scope[UNIFORM_NAME_LINEAR_DEPTH_MAP] = pb.tex2D().sampleType('unfilterable-float').uniform(0).withSampler(getSamplerOptions('clamp_nearest_nomip'));
280
282
  scope[UNIFORM_NAME_LINEAR_DEPTH_MAP_SIZE] = pb.vec2().uniform(0);
281
283
  }
282
284
  if (ctx.sceneColorTexture) {
@@ -286,7 +288,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
286
288
  }
287
289
  if (ctx.HiZTexture) {
288
290
  // Matches the fetchSampler('clamp_nearest') previously passed at runtime
289
- scope[UNIFORM_NAME_HIZ_DEPTH_MAP] = pb.tex2D().uniform(0).withSampler(getSamplerOptions('clamp_nearest'));
291
+ scope[UNIFORM_NAME_HIZ_DEPTH_MAP] = pb.tex2D().sampleType('unfilterable-float').uniform(0).withSampler(getSamplerOptions('clamp_nearest'));
290
292
  scope[UNIFORM_NAME_HIZ_DEPTH_MAP_INFO] = pb.vec4().uniform(0);
291
293
  }
292
294
  }
@@ -703,6 +705,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
703
705
  shadowDebugCascades: camera.shadowDebugCascades ? 1 : 0,
704
706
  frameDeltaTime: ctx.device.frameInfo.elapsedFrame * 0.001,
705
707
  elapsedTime: ctx.device.frameInfo.elapsedOverall * 0.001,
708
+ preExposure: this.getPreExposure(ctx),
706
709
  framestamp: ctx.device.frameInfo.frameCounter
707
710
  };
708
711
  if (ctx.motionVectors && ctx.renderPass.type === RENDER_PASS_TYPE_DEPTH) {
@@ -746,12 +749,72 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
746
749
  bindGroup.setTexture(UNIFORM_NAME_AERIALPERSPECTIVE_LUT, aerialPerspectiveLUT);
747
750
  bindGroup.setTexture(UNIFORM_NAME_SKYDISTANTLIGHT_LUT, skyDistantLightLUT);
748
751
  }
752
+ /**
753
+ * @internal
754
+ *
755
+ * Camera pre-exposure factor for scene-linear lighting quantities.
756
+ *
757
+ * @remarks
758
+ * Physical lighting authors light intensities in photometric units (lux, candela, cd/m²), whose
759
+ * magnitudes (~1e5 for daylight) neither fit an rgba16f render target nor leave usable headroom
760
+ * for specular highlights. Following Filament, the camera exposure is folded into every light
761
+ * quantity on the CPU so the HDR target stays near 1.0 and downstream passes need no unit
762
+ * awareness. Legacy returns 1 so its uploads stay byte-identical.
763
+ */ static getPreExposure(ctx) {
764
+ return ctx.scene.lightingMode === 'physical' ? ctx.camera.exposure : 1;
765
+ }
766
+ /**
767
+ * @internal
768
+ *
769
+ * Light color/intensity vector with the camera pre-exposure folded into the intensity component.
770
+ *
771
+ * @remarks
772
+ * Only the intensity (`w`) is scaled; the color stays untouched, matching Filament's
773
+ * `FScene::prepareDynamicLights`. The light's own cached vector is never mutated because it is
774
+ * shared across every camera rendering the scene.
775
+ */ static getPreExposedColorIntensity(light, ctx, out) {
776
+ const src = light.diffuseAndIntensity;
777
+ const result = out ?? new Vector4();
778
+ result.setXYZW(src.x, src.y, src.z, src.w * this.getPreExposure(ctx));
779
+ return result;
780
+ }
781
+ /**
782
+ * @internal
783
+ *
784
+ * Environment lighting scale uploaded as `light.envLightStrength`.
785
+ *
786
+ * @remarks
787
+ * Legacy uses the unitless {@link EnvLightWrapper.strength}.
788
+ *
789
+ * Physical returns the ratio that converts the cached sky bake from its fixed storage exposure
790
+ * (`SkyRenderer.PHYSICAL_BAKE_EXPOSURE`) to the live camera exposure. Every environment source is
791
+ * normalized into that one space before it reaches the IBL -- the scattering atmosphere emits
792
+ * photometric luminance, authored 0..1 skyboxes/panoramas are lifted by
793
+ * {@link EnvLightWrapper.intensity} -- so no pass consuming `envLightStrength` has to know the
794
+ * sky type.
795
+ *
796
+ * The bake cannot simply hold raw cd/m²: the environment cubemap is `rg11b10uf`/`rgba16f` and a
797
+ * daylight sun overflows it to Inf, which `prefilterCubemap` then spreads across the whole IBL.
798
+ *
799
+ * {@link EnvLightWrapper.strength} multiplies the result in both modes. It is the only per-frame
800
+ * dimmer for environment lighting: the photometric `intensity` reaches the image solely through
801
+ * the cached bake, and a `scatter` sky does not even consult it (its brightness comes from the
802
+ * sun), so without this factor there would be no way to turn the IBL down without re-baking.
803
+ */ static getEnvLightLuminance(ctx) {
804
+ const env = ctx.env;
805
+ if (!env) {
806
+ return 0;
807
+ }
808
+ const strength = env.light.strength ?? 0;
809
+ return ctx.scene.lightingMode === 'physical' ? this.getPreExposure(ctx) / PHYSICAL_BAKE_EXPOSURE * strength : strength;
810
+ }
749
811
  /** @internal */ static setLightUniforms(bindGroup, ctx, clusterParams, countParams, lightBuffer, lightIndexTexture) {
812
+ const envLightStrength = this.getEnvLightLuminance(ctx);
750
813
  bindGroup.setValue('light', {
751
814
  sunDir: ctx.sunLight ? ctx.sunLight.directionAndCutoff.xyz().scaleBy(-1) : this.defaultSunDir,
752
815
  clusterParams: clusterParams,
753
816
  countParams: countParams,
754
- envLightStrength: ctx.env.light.strength ?? 0,
817
+ envLightStrength,
755
818
  envLightSpecularStrength: ctx.env.light.specularStrength ?? 1,
756
819
  lightIndexTexSize: new Int32Array([
757
820
  lightIndexTexture.width,
@@ -772,7 +835,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
772
835
  }
773
836
  bindGroup.setTexture(UNIFORM_NAME_BAKED_SKY_MAP, ctx.scene.env.sky.getBakedSkyTexture(ctx));
774
837
  if (ctx.drawEnvLight) {
775
- ctx.env.light.envLight.updateBindGroup(bindGroup);
838
+ ctx.env.light.envLight.updateBindGroup(bindGroup, ctx);
776
839
  }
777
840
  }
778
841
  /** @internal */ static setLightUniformsShadow(bindGroup, ctx, light) {
@@ -781,7 +844,7 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
781
844
  this._lightUniformShadow.shadowCascades = shadowMapParams.numShadowCascades;
782
845
  this._lightUniformShadow.positionAndRange.set(light.positionAndRange);
783
846
  this._lightUniformShadow.directionAndCutoff.set(light.directionAndCutoff);
784
- this._lightUniformShadow.diffuseAndIntensity.set(light.diffuseAndIntensity);
847
+ this.getPreExposedColorIntensity(light, ctx, this._lightUniformShadow.diffuseAndIntensity);
785
848
  this._lightUniformShadow.extraParams.set(light.extraParams);
786
849
  this._lightUniformShadow.cascadeDistances.set(shadowMapParams.cascadeDistances);
787
850
  this._lightUniformShadow.depthBiasValues.set(shadowMapParams.depthBiasValues[0]);
@@ -790,13 +853,13 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
790
853
  shadowMapParams.impl.getParams(this._lightUniformShadow.implParams);
791
854
  this._lightUniformShadow.shadowMatrices.set(shadowMapParams.shadowMatrices);
792
855
  this._lightUniformShadow.shadowStrength = light.shadow.shadowStrength;
793
- this._lightUniformShadow.envLightStrength = ctx.env?.light.strength ?? 0;
856
+ this._lightUniformShadow.envLightStrength = this.getEnvLightLuminance(ctx);
794
857
  this._lightUniformShadow.envLightSpecularStrength = ctx.env?.light.specularStrength ?? 1;
795
858
  bindGroup.setValue('light', this._lightUniformShadow);
796
859
  bindGroup.setTexture(UNIFORM_NAME_SHADOW_MAP, shadowMapParams.shadowMap, shadowMapParams.shadowMapSampler);
797
860
  bindGroup.setTexture(UNIFORM_NAME_BAKED_SKY_MAP, ctx.scene.env.sky.getBakedSkyTexture(ctx));
798
861
  if (ctx.drawEnvLight) {
799
- ctx.env.light.envLight.updateBindGroup(bindGroup);
862
+ ctx.env.light.envLight.updateBindGroup(bindGroup, ctx);
800
863
  }
801
864
  }
802
865
  /**
@@ -878,6 +941,36 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
878
941
  return scope[UNIFORM_NAME_BAKED_SKY_MAP];
879
942
  }
880
943
  /**
944
+ * Samples the baked sky cubemap in the same pre-exposed space as the scene color buffer.
945
+ *
946
+ * @remarks
947
+ * The bake is cached and therefore exposure-independent, stored at the fixed
948
+ * `PHYSICAL_BAKE_EXPOSURE`. Anything that blends it against already-pre-exposed lit color (water
949
+ * reflection, blueprint sky lookups) must first convert it to the live exposure.
950
+ * `envLightStrength` carries exactly that ratio in physical mode, and the legacy environment
951
+ * strength (its established meaning) otherwise.
952
+ *
953
+ * @param scope - Current shader scope
954
+ * @param direction - Sampling direction
955
+ * @returns Pre-exposed sky radiance
956
+ */ static sampleBakedSkyPreExposed(scope, direction) {
957
+ const pb = scope.$builder;
958
+ return pb.mul(pb.textureSampleLevel(this.getBakedSkyTexture(scope), direction, 0).rgb, this.getEnvLightStrength(scope));
959
+ }
960
+ /**
961
+ * Gets the camera pre-exposure factor.
962
+ *
963
+ * @remarks
964
+ * The multiplier every photometric quantity is scaled by before it reaches the HDR target. 1 in
965
+ * legacy. Use it for material-authored emitters (emissive), which are not covered by the CPU-side
966
+ * light pre-exposure.
967
+ *
968
+ * @param scope - Current shader scope
969
+ * @returns The pre-exposure factor
970
+ */ static getPreExposureUniform(scope) {
971
+ return scope.camera.preExposure;
972
+ }
973
+ /**
881
974
  * Gets the elapsed time in seconds
882
975
  * @param scope - Current shader scope
883
976
  * @returns The elapsed time in seconds
@@ -1288,6 +1381,9 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
1288
1381
  */ static linearDepthToNonLinear(scope, depth, nearFar) {
1289
1382
  const pb = scope.$builder;
1290
1383
  nearFar = nearFar ?? this.getCameraParams(scope);
1384
+ if (REVERSE_Z) {
1385
+ return pb.div(pb.sub(pb.div(pb.mul(nearFar.x, nearFar.y), depth), nearFar.x), pb.sub(nearFar.y, nearFar.x));
1386
+ }
1291
1387
  return pb.div(pb.sub(nearFar.y, pb.div(pb.mul(nearFar.x, nearFar.y), depth)), pb.sub(nearFar.y, nearFar.x));
1292
1388
  }
1293
1389
  /**
@@ -1300,6 +1396,9 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
1300
1396
  */ static nonLinearDepthToLinear(scope, depth, nearFar) {
1301
1397
  const pb = scope.$builder;
1302
1398
  nearFar = nearFar ?? this.getCameraParams(scope);
1399
+ if (REVERSE_Z) {
1400
+ return pb.div(pb.mul(nearFar.x, nearFar.y), pb.mix(nearFar.x, nearFar.y, depth));
1401
+ }
1303
1402
  return pb.div(pb.mul(nearFar.x, nearFar.y), pb.mix(nearFar.y, nearFar.x, depth));
1304
1403
  }
1305
1404
  /**
@@ -1312,9 +1411,85 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
1312
1411
  */ static nonLinearDepthToLinearNormalized(scope, depth, nearFar) {
1313
1412
  const pb = scope.$builder;
1314
1413
  nearFar = nearFar ?? this.getCameraParams(scope);
1414
+ if (REVERSE_Z) {
1415
+ return pb.div(nearFar.x, pb.mix(nearFar.x, nearFar.y, depth));
1416
+ }
1315
1417
  return pb.div(nearFar.x, pb.mix(nearFar.y, nearFar.x, depth));
1316
1418
  }
1317
1419
  /**
1420
+ * Converts normalized linear depth back to device non-linear depth.
1421
+ *
1422
+ * @remarks
1423
+ * The normalized linear depth convention (range [near/far, 1] with 1 at
1424
+ * the far plane, as produced by {@link ShaderHelper.nonLinearDepthToLinearNormalized})
1425
+ * is independent of the engine depth convention; only the mapping to
1426
+ * device depth flips under reverse-Z.
1427
+ *
1428
+ * @param scope - Current shader scope
1429
+ * @param depth - The normalized linear depth
1430
+ * @param nearFar - A vector that contains the near clip plane in x component and the far clip plane in y component
1431
+ * @returns The device non-linear depth
1432
+ */ static linearNormalizedToNonLinearDepth(scope, depth, nearFar) {
1433
+ const pb = scope.$builder;
1434
+ nearFar = nearFar ?? this.getCameraParams(scope);
1435
+ if (REVERSE_Z) {
1436
+ return pb.div(pb.sub(pb.div(nearFar.x, depth), nearFar.x), pb.sub(nearFar.y, nearFar.x));
1437
+ }
1438
+ return pb.div(pb.sub(pb.div(nearFar.x, depth), nearFar.y), pb.sub(nearFar.x, nearFar.y));
1439
+ }
1440
+ /**
1441
+ * Maps a device depth value to the canonical clip-space z coordinate
1442
+ * (GL [-1,1] under standard-Z, zero-to-one under reverse-Z), suitable for
1443
+ * unprojection with the engine's inverse projection matrices.
1444
+ *
1445
+ * @param scope - Current shader scope
1446
+ * @param depth - The device depth value
1447
+ * @returns The canonical clip-space z
1448
+ */ static deviceDepthToClipZ(scope, depth) {
1449
+ const pb = scope.$builder;
1450
+ return REVERSE_Z ? depth : pb.sub(pb.mul(depth, 2), 1);
1451
+ }
1452
+ /**
1453
+ * Clip-space z that places a vertex exactly on the far plane (sky domes,
1454
+ * background geometry).
1455
+ *
1456
+ * @param scope - Current shader scope
1457
+ * @param w - The clip-space w coordinate of the vertex
1458
+ * @returns The clip-space z value for the far plane
1459
+ */ static farthestClipZ(scope, w) {
1460
+ return REVERSE_Z ? 0 : w;
1461
+ }
1462
+ /**
1463
+ * Tests whether a device depth value equals the cleared (farthest) depth,
1464
+ * i.e. no geometry was rendered at this position.
1465
+ *
1466
+ * @param scope - Current shader scope
1467
+ * @param depth - The device depth value
1468
+ * @returns Boolean expression, true for background pixels
1469
+ */ static isFarthestDepth(scope, depth) {
1470
+ return scope.$builder.equal(depth, DEPTH_FARTHEST);
1471
+ }
1472
+ /**
1473
+ * Selects the closer of two device depth values.
1474
+ *
1475
+ * @param scope - Current shader scope
1476
+ * @param a - First device depth value
1477
+ * @param b - Second device depth value
1478
+ * @returns The value closer to the camera
1479
+ */ static closerDepth(scope, a, b) {
1480
+ return scope.$builder[DEPTH_REDUCE_CLOSER](a, b);
1481
+ }
1482
+ /**
1483
+ * Selects the farther of two device depth values.
1484
+ *
1485
+ * @param scope - Current shader scope
1486
+ * @param a - First device depth value
1487
+ * @param b - Second device depth value
1488
+ * @returns The value farther from the camera
1489
+ */ static fartherDepth(scope, a, b) {
1490
+ return scope.$builder[DEPTH_REDUCE_FARTHER](a, b);
1491
+ }
1492
+ /**
1318
1493
  * Sample linear depth from linear depth texture
1319
1494
  * @param scope - Current shader scope
1320
1495
  * @param tex - The linear depth texture
@@ -1335,8 +1510,8 @@ const UNIFORM_NAME_MORPH_INFO = 'Z_UniformMorphInfo';
1335
1510
  pb.mat4('mat')
1336
1511
  ], function() {
1337
1512
  this.$l.linearDepth = that.sampleLinearDepth(this, depthTex, this.uv, 0);
1338
- this.$l.nonLinearDepth = pb.div(pb.sub(pb.div(this.cameraNearFar.x, this.linearDepth), this.cameraNearFar.y), pb.sub(this.cameraNearFar.x, this.cameraNearFar.y));
1339
- this.$l.clipSpacePos = pb.vec4(pb.sub(pb.mul(this.uv, 2), pb.vec2(1)), pb.sub(pb.mul(pb.clamp(this.nonLinearDepth, 0, 1), 2), 1), 1);
1513
+ this.$l.nonLinearDepth = that.linearNormalizedToNonLinearDepth(this, this.linearDepth, this.cameraNearFar);
1514
+ this.$l.clipSpacePos = pb.vec4(pb.sub(pb.mul(this.uv, 2), pb.vec2(1)), that.deviceDepthToClipZ(this, pb.clamp(this.nonLinearDepth, 0, 1)), 1);
1340
1515
  this.$l.wPos = pb.mul(this.mat, this.clipSpacePos);
1341
1516
  this.$return(pb.vec4(pb.div(this.wPos.xyz, this.wPos.w), this.linearDepth));
1342
1517
  });