@zephyr3d/scene 0.9.25 → 0.9.27

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 (299) hide show
  1. package/dist/animation/animationset.js +92 -30
  2. package/dist/animation/animationset.js.map +1 -1
  3. package/dist/animation/hair/gpu_hair_simulation.js +1090 -0
  4. package/dist/animation/hair/gpu_hair_simulation.js.map +1 -0
  5. package/dist/animation/joint_dynamics/controller.js +7 -5
  6. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  7. package/dist/animation/joint_dynamics/convex_collider.js +320 -0
  8. package/dist/animation/joint_dynamics/convex_collider.js.map +1 -0
  9. package/dist/animation/joint_dynamics/joint_dynamics_system.js +81 -5
  10. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  11. package/dist/animation/morphtrack.js +3 -4
  12. package/dist/animation/morphtrack.js.map +1 -1
  13. package/dist/animation/skeleton.js +79 -25
  14. package/dist/animation/skeleton.js.map +1 -1
  15. package/dist/animation/spring/multi_chain_spring_system.js +577 -179
  16. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  17. package/dist/animation/spring/spring_collider.js +4 -3
  18. package/dist/animation/spring/spring_collider.js.map +1 -1
  19. package/dist/animation/spring/spring_node_pose_tracker.js +40 -0
  20. package/dist/animation/spring/spring_node_pose_tracker.js.map +1 -0
  21. package/dist/animation/spring/spring_particle.js +2 -0
  22. package/dist/animation/spring/spring_particle.js.map +1 -1
  23. package/dist/animation/spring/spring_system.js +11 -3
  24. package/dist/animation/spring/spring_system.js.map +1 -1
  25. package/dist/animation/spring_modifier.js +10 -0
  26. package/dist/animation/spring_modifier.js.map +1 -1
  27. package/dist/app/engine.js +53 -43
  28. package/dist/app/engine.js.map +1 -1
  29. package/dist/app/scriptingsystem.js +119 -6
  30. package/dist/app/scriptingsystem.js.map +1 -1
  31. package/dist/app/scriptregistry.js +3 -2
  32. package/dist/app/scriptregistry.js.map +1 -1
  33. package/dist/asset/assetmanager.js +284 -67
  34. package/dist/asset/assetmanager.js.map +1 -1
  35. package/dist/asset/loaders/zhair/zhair_format.js +288 -0
  36. package/dist/asset/loaders/zhair/zhair_format.js.map +1 -0
  37. package/dist/asset/loaders/zhair/zhair_loader.js +221 -0
  38. package/dist/asset/loaders/zhair/zhair_loader.js.map +1 -0
  39. package/dist/asset/model.js +184 -69
  40. package/dist/asset/model.js.map +1 -1
  41. package/dist/camera/camera.js +268 -44
  42. package/dist/camera/camera.js.map +1 -1
  43. package/dist/camera/perspectivecamera.js +3 -1
  44. package/dist/camera/perspectivecamera.js.map +1 -1
  45. package/dist/index.d.ts +9044 -5139
  46. package/dist/index.js +17 -6
  47. package/dist/index.js.map +1 -1
  48. package/dist/material/eye.js +932 -0
  49. package/dist/material/eye.js.map +1 -0
  50. package/dist/material/hair.js +917 -0
  51. package/dist/material/hair.js.map +1 -0
  52. package/dist/material/hairstrand.js +842 -0
  53. package/dist/material/hairstrand.js.map +1 -0
  54. package/dist/material/hairstrand_data.js +162 -0
  55. package/dist/material/hairstrand_data.js.map +1 -0
  56. package/dist/material/lambert.js +5 -2
  57. package/dist/material/lambert.js.map +1 -1
  58. package/dist/material/material.js +48 -10
  59. package/dist/material/material.js.map +1 -1
  60. package/dist/material/meshmaterial.js +120 -19
  61. package/dist/material/meshmaterial.js.map +1 -1
  62. package/dist/material/mixins/albedocolor.js +1 -1
  63. package/dist/material/mixins/albedocolor.js.map +1 -1
  64. package/dist/material/mixins/lightmodel/blinnphong.js +5 -3
  65. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  66. package/dist/material/mixins/lightmodel/lambert.js +5 -4
  67. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  68. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +3 -3
  69. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  70. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
  71. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  72. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +3 -3
  73. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  74. package/dist/material/mixins/lit.js +106 -19
  75. package/dist/material/mixins/lit.js.map +1 -1
  76. package/dist/material/mixins/pbr/common.js +4 -4
  77. package/dist/material/mixins/pbr/common.js.map +1 -1
  78. package/dist/material/mixins/texture.js +48 -11
  79. package/dist/material/mixins/texture.js.map +1 -1
  80. package/dist/material/mtoon.js +6 -5
  81. package/dist/material/mtoon.js.map +1 -1
  82. package/dist/material/pbrblueprint.js +146 -28
  83. package/dist/material/pbrblueprint.js.map +1 -1
  84. package/dist/material/pbrblueprint_instance.js +501 -0
  85. package/dist/material/pbrblueprint_instance.js.map +1 -0
  86. package/dist/material/pbrmr.js +15 -16
  87. package/dist/material/pbrmr.js.map +1 -1
  88. package/dist/material/shader/helper.js +734 -23
  89. package/dist/material/shader/helper.js.map +1 -1
  90. package/dist/material/shader/terrain_blend.js +55 -0
  91. package/dist/material/shader/terrain_blend.js.map +1 -0
  92. package/dist/material/skin.js +192 -32
  93. package/dist/material/skin.js.map +1 -1
  94. package/dist/material/spriteblueprint.js +16 -1
  95. package/dist/material/spriteblueprint.js.map +1 -1
  96. package/dist/material/subsurfaceprofile.js +86 -23
  97. package/dist/material/subsurfaceprofile.js.map +1 -1
  98. package/dist/material/water.js +2059 -72
  99. package/dist/material/water.js.map +1 -1
  100. package/dist/posteffect/bloom.js +167 -7
  101. package/dist/posteffect/bloom.js.map +1 -1
  102. package/dist/posteffect/coloradjust.js +2 -1
  103. package/dist/posteffect/coloradjust.js.map +1 -1
  104. package/dist/posteffect/compositor.js.map +1 -1
  105. package/dist/posteffect/fxaa.js +2 -1
  106. package/dist/posteffect/fxaa.js.map +1 -1
  107. package/dist/posteffect/grayscale.js +3 -1
  108. package/dist/posteffect/grayscale.js.map +1 -1
  109. package/dist/posteffect/motionblur.js +664 -56
  110. package/dist/posteffect/motionblur.js.map +1 -1
  111. package/dist/posteffect/posteffect.js +12 -1
  112. package/dist/posteffect/posteffect.js.map +1 -1
  113. package/dist/posteffect/sao.js +46 -44
  114. package/dist/posteffect/sao.js.map +1 -1
  115. package/dist/posteffect/skinsss.js +368 -69
  116. package/dist/posteffect/skinsss.js.map +1 -1
  117. package/dist/posteffect/ssgi.js +16 -9
  118. package/dist/posteffect/ssgi.js.map +1 -1
  119. package/dist/posteffect/ssr.js +3 -0
  120. package/dist/posteffect/ssr.js.map +1 -1
  121. package/dist/posteffect/sss.js +121 -36
  122. package/dist/posteffect/sss.js.map +1 -1
  123. package/dist/posteffect/taa.js.map +1 -1
  124. package/dist/posteffect/tonemap.js +44 -1
  125. package/dist/posteffect/tonemap.js.map +1 -1
  126. package/dist/render/abuffer_oit.js +8 -2
  127. package/dist/render/abuffer_oit.js.map +1 -1
  128. package/dist/render/clipmap.js +156 -5
  129. package/dist/render/clipmap.js.map +1 -1
  130. package/dist/render/cull_visitor.js +20 -0
  131. package/dist/render/cull_visitor.js.map +1 -1
  132. package/dist/render/depthpass.js +36 -2
  133. package/dist/render/depthpass.js.map +1 -1
  134. package/dist/render/drawable_mixin.js +26 -1
  135. package/dist/render/drawable_mixin.js.map +1 -1
  136. package/dist/render/dualdepthpeeling_oit.js +3 -2
  137. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  138. package/dist/render/envlight.js +1 -1
  139. package/dist/render/envlight.js.map +1 -1
  140. package/dist/render/fbm_wavegenerator.js +6 -3
  141. package/dist/render/fbm_wavegenerator.js.map +1 -1
  142. package/dist/render/fft_wavegenerator.js +57 -15
  143. package/dist/render/fft_wavegenerator.js.map +1 -1
  144. package/dist/render/gerstner_wavegenerator.js +130 -20
  145. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  146. package/dist/render/globalbindgroup_allocator.js +3 -0
  147. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  148. package/dist/render/hzb.js +80 -22
  149. package/dist/render/hzb.js.map +1 -1
  150. package/dist/render/lightpass.js +6 -3
  151. package/dist/render/lightpass.js.map +1 -1
  152. package/dist/render/oit.js +29 -0
  153. package/dist/render/oit.js.map +1 -0
  154. package/dist/render/render_queue.js +39 -0
  155. package/dist/render/render_queue.js.map +1 -1
  156. package/dist/render/renderer.js +4 -0
  157. package/dist/render/renderer.js.map +1 -1
  158. package/dist/render/rendergraph/blackboard.js +1 -0
  159. package/dist/render/rendergraph/blackboard.js.map +1 -1
  160. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  161. package/dist/render/rendergraph/executor.js +2 -0
  162. package/dist/render/rendergraph/executor.js.map +1 -1
  163. package/dist/render/rendergraph/forward_plus_builder.js +379 -10
  164. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  165. package/dist/render/rendergraph/frame_resource_requirements.js +1 -0
  166. package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -1
  167. package/dist/render/rendergraph/history_resources.js +8 -1
  168. package/dist/render/rendergraph/history_resources.js.map +1 -1
  169. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  170. package/dist/render/rendergraph/texture_affinity_cache.js +1 -1
  171. package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -1
  172. package/dist/render/rendergraph/types.js.map +1 -1
  173. package/dist/render/shadow_mask_pass.js +73 -8
  174. package/dist/render/shadow_mask_pass.js.map +1 -1
  175. package/dist/render/sky.js +166 -126
  176. package/dist/render/sky.js.map +1 -1
  177. package/dist/render/underwater.js +624 -0
  178. package/dist/render/underwater.js.map +1 -0
  179. package/dist/render/water_caustics.js +1380 -0
  180. package/dist/render/water_caustics.js.map +1 -0
  181. package/dist/render/weightedblended_oit.js +3 -2
  182. package/dist/render/weightedblended_oit.js.map +1 -1
  183. package/dist/scene/basesprite.js +8 -0
  184. package/dist/scene/basesprite.js.map +1 -1
  185. package/dist/scene/batchgroup.js +3 -0
  186. package/dist/scene/batchgroup.js.map +1 -1
  187. package/dist/scene/environment.js +4 -1
  188. package/dist/scene/environment.js.map +1 -1
  189. package/dist/scene/hair.js +963 -0
  190. package/dist/scene/hair.js.map +1 -0
  191. package/dist/scene/light.js +5 -1
  192. package/dist/scene/light.js.map +1 -1
  193. package/dist/scene/mesh.js +481 -47
  194. package/dist/scene/mesh.js.map +1 -1
  195. package/dist/scene/meshdrawable.js +6 -0
  196. package/dist/scene/meshdrawable.js.map +1 -1
  197. package/dist/scene/msdftext.js +3 -0
  198. package/dist/scene/msdftext.js.map +1 -1
  199. package/dist/scene/msdftextsprite.js +3 -0
  200. package/dist/scene/msdftextsprite.js.map +1 -1
  201. package/dist/scene/particlesys.js +6 -0
  202. package/dist/scene/particlesys.js.map +1 -1
  203. package/dist/scene/scene.js +3 -0
  204. package/dist/scene/scene.js.map +1 -1
  205. package/dist/scene/scene_node.js +6 -1
  206. package/dist/scene/scene_node.js.map +1 -1
  207. package/dist/scene/terrain-cm/grass.js +3 -0
  208. package/dist/scene/terrain-cm/grass.js.map +1 -1
  209. package/dist/scene/terrain-cm/grassmaterial.js +3 -0
  210. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  211. package/dist/scene/terrain-cm/terrain-cm.js +6 -0
  212. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  213. package/dist/scene/terrain-cm/texture_cache.js +309 -0
  214. package/dist/scene/terrain-cm/texture_cache.js.map +1 -0
  215. package/dist/scene/water.js +546 -4
  216. package/dist/scene/water.js.map +1 -1
  217. package/dist/shaders/atmosphere.js.map +1 -1
  218. package/dist/shaders/diffusion.js +54 -0
  219. package/dist/shaders/diffusion.js.map +1 -0
  220. package/dist/shaders/shadow.js +33 -21
  221. package/dist/shaders/shadow.js.map +1 -1
  222. package/dist/shaders/temporal.js +71 -33
  223. package/dist/shaders/temporal.js.map +1 -1
  224. package/dist/shaders/water.js +22 -19
  225. package/dist/shaders/water.js.map +1 -1
  226. package/dist/shaders/water_medium.js +56 -0
  227. package/dist/shaders/water_medium.js.map +1 -0
  228. package/dist/shadow/dom.js +546 -0
  229. package/dist/shadow/dom.js.map +1 -0
  230. package/dist/shadow/pcf_opt.js +3 -5
  231. package/dist/shadow/pcf_opt.js.map +1 -1
  232. package/dist/shadow/pcf_pd.js +1 -1
  233. package/dist/shadow/pcf_pd.js.map +1 -1
  234. package/dist/shadow/receiver_bias.js +41 -0
  235. package/dist/shadow/receiver_bias.js.map +1 -0
  236. package/dist/shadow/shader.js +20 -60
  237. package/dist/shadow/shader.js.map +1 -1
  238. package/dist/shadow/shadow_impl.js +89 -0
  239. package/dist/shadow/shadow_impl.js.map +1 -1
  240. package/dist/shadow/shadow_region.js +1 -1
  241. package/dist/shadow/shadow_region.js.map +1 -1
  242. package/dist/shadow/shadowmapper.js +150 -37
  243. package/dist/shadow/shadowmapper.js.map +1 -1
  244. package/dist/shapes/shape.js +11 -2
  245. package/dist/shapes/shape.js.map +1 -1
  246. package/dist/shapes/sphere.js +50 -9
  247. package/dist/shapes/sphere.js.map +1 -1
  248. package/dist/utility/blueprint/common/constants.js +112 -2
  249. package/dist/utility/blueprint/common/constants.js.map +1 -1
  250. package/dist/utility/blueprint/material/func.js +142 -49
  251. package/dist/utility/blueprint/material/func.js.map +1 -1
  252. package/dist/utility/blueprint/material/ir.js +490 -25
  253. package/dist/utility/blueprint/material/ir.js.map +1 -1
  254. package/dist/utility/blueprint/material/texture.js +898 -4
  255. package/dist/utility/blueprint/material/texture.js.map +1 -1
  256. package/dist/utility/serialization/manager.js +434 -101
  257. package/dist/utility/serialization/manager.js.map +1 -1
  258. package/dist/utility/serialization/scene/animation.js +401 -5
  259. package/dist/utility/serialization/scene/animation.js.map +1 -1
  260. package/dist/utility/serialization/scene/batch.js +4 -0
  261. package/dist/utility/serialization/scene/batch.js.map +1 -1
  262. package/dist/utility/serialization/scene/camera.js +186 -26
  263. package/dist/utility/serialization/scene/camera.js.map +1 -1
  264. package/dist/utility/serialization/scene/common.js +26 -5
  265. package/dist/utility/serialization/scene/common.js.map +1 -1
  266. package/dist/utility/serialization/scene/hair.js +1141 -0
  267. package/dist/utility/serialization/scene/hair.js.map +1 -0
  268. package/dist/utility/serialization/scene/light.js +84 -4
  269. package/dist/utility/serialization/scene/light.js.map +1 -1
  270. package/dist/utility/serialization/scene/material.js +1867 -166
  271. package/dist/utility/serialization/scene/material.js.map +1 -1
  272. package/dist/utility/serialization/scene/mesh.js +231 -14
  273. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  274. package/dist/utility/serialization/scene/node.js +141 -7
  275. package/dist/utility/serialization/scene/node.js.map +1 -1
  276. package/dist/utility/serialization/scene/particle.js +4 -0
  277. package/dist/utility/serialization/scene/particle.js.map +1 -1
  278. package/dist/utility/serialization/scene/primitive.js +18 -0
  279. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  280. package/dist/utility/serialization/scene/sprite.js +4 -0
  281. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  282. package/dist/utility/serialization/scene/terrain.js +4 -0
  283. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  284. package/dist/utility/serialization/scene/text.js +4 -0
  285. package/dist/utility/serialization/scene/text.js.map +1 -1
  286. package/dist/utility/serialization/scene/water.js +1105 -21
  287. package/dist/utility/serialization/scene/water.js.map +1 -1
  288. package/dist/utility/serialization/types.js.map +1 -1
  289. package/dist/utility/shprojector.js +9 -8
  290. package/dist/utility/shprojector.js.map +1 -1
  291. package/dist/values.js +49 -2
  292. package/dist/values.js.map +1 -1
  293. package/package.json +3 -3
  294. package/dist/render/rendergraph/frame_graph_context.js +0 -41
  295. package/dist/render/rendergraph/frame_graph_context.js.map +0 -1
  296. package/dist/shaders/ssgi.js +0 -63
  297. package/dist/shaders/ssgi.js.map +0 -1
  298. package/dist/shaders/ssgi_reprojection.js +0 -118
  299. package/dist/shaders/ssgi_reprojection.js.map +0 -1
@@ -6,6 +6,7 @@ import { SSGI } from '../posteffect/ssgi.js';
6
6
  import { SSR } from '../posteffect/ssr.js';
7
7
  import { SSS } from '../posteffect/sss.js';
8
8
  import { SkinSSS } from '../posteffect/skinsss.js';
9
+ import { SubsurfaceProfile } from '../material/subsurfaceprofile.js';
9
10
  import { Tonemap } from '../posteffect/tonemap.js';
10
11
  import { FXAA } from '../posteffect/fxaa.js';
11
12
  import { Bloom } from '../posteffect/bloom.js';
@@ -89,7 +90,9 @@ const SSS_QUALITY_PRESET_SETTINGS = {
89
90
  *
90
91
  * @public
91
92
  */ class Camera extends SceneNode {
92
- /** @internal Halton 2-3 sequence used for TAA jittering. */ static _halton23 = halton23(16);
93
+ /** @internal Halton 2-3 sequence used for TAA jittering. An 8-phase cycle
94
+ * repeats faster than the history accumulation window, so residual jitter
95
+ * ripple is attenuated further than with a 16-phase cycle. */ static _halton23 = halton23(8);
93
96
  /** @internal Per-camera history resources. */ static _historyData = new WeakMap();
94
97
  /** @internal Per-camera history resource manager. */ static _historyResourceManager = new WeakMap();
95
98
  /** @internal Screen adapter for this camera */ _screenAdapter;
@@ -121,6 +124,7 @@ const SSS_QUALITY_PRESET_SETTINGS = {
121
124
  /** @internal Render path selection for scene renderer. */ _renderPath;
122
125
  /** @internal Whether command buffers may be reused for optimization. */ _commandBufferReuse;
123
126
  /** @internal Hi-Z acceleration enable (primarily for SSR). */ _HiZ;
127
+ _HiZNearest;
124
128
  /** @internal Screen-space shadow mask enable (Forward+ deferred shadows). */ _screenSpaceShadowMask;
125
129
  /** @internal If true, a float point backbuffer will be used. The default value is true */ _HDR;
126
130
  /** @internal Tonemap enable flag (via post effect). */ _toneMap;
@@ -134,6 +138,8 @@ const SSS_QUALITY_PRESET_SETTINGS = {
134
138
  /** @internal Motion blur enable flag (via post effect). */ _motionBlur;
135
139
  /** @internal Motion blur post effect reference. */ _postEffectMotionBlur;
136
140
  /** @internal Motion blur strength. */ _motionBlurStrength;
141
+ /** @internal Motion blur shutter bias. */ _motionBlurShutterBias;
142
+ /** @internal Motion blur maximum streak length in pixels. */ _motionBlurMaxLength;
137
143
  /** @internal Bloom enable flag (via post effect). */ _bloom;
138
144
  /** @internal Bloom post effect reference. */ _postEffectBloom;
139
145
  /** @internal Bloom downsample level cap. */ _bloomMaxDownsampleLevels;
@@ -141,6 +147,8 @@ const SSS_QUALITY_PRESET_SETTINGS = {
141
147
  /** @internal Bloom threshold. */ _bloomThreshold;
142
148
  /** @internal Bloom threshold knee (soft thresholding). */ _bloomThresholdKnee;
143
149
  /** @internal Bloom intensity. */ _bloomIntensity;
150
+ /** @internal */ _bloomFilterRadius;
151
+ /** @internal */ _bloomKarisAverage;
144
152
  /** @internal Color adjustment enable flag (via post effect). */ _colorAdjustEnabled;
145
153
  /** @internal Color adjustment post effect reference. */ _postEffectColorAdjust;
146
154
  /** @internal Color adjustment saturation. */ _colorAdjustSaturation;
@@ -196,15 +204,20 @@ const SSS_QUALITY_PRESET_SETTINGS = {
196
204
  /** @internal Skin SSS post effect reference. */ _postEffectSkinSSS;
197
205
  /** @internal Skin SSS final blend strength. */ _skinSSSStrength;
198
206
  /** @internal Skin SSS mask opacity bias. */ _skinSSSOpacity;
199
- /** @internal Skin SSS blur tap spacing in pixels. */ _skinSSSSampleStep;
207
+ /** @internal Skin SSS maximum blur tap spacing in pixels. */ _skinSSSSampleStep;
208
+ /** @internal Skin SSS world-space scatter radius. */ _skinSSSScatterRadius;
209
+ /** @internal Skin SSS smoothing ("beauty filter") amount. */ _skinSSSSmoothness;
200
210
  /** @internal Skin SSS depth rejection scale. */ _skinSSSDepthScale;
201
211
  /** @internal Skin SSS blurred multiplier boost. */ _skinSSSColorBoost;
212
+ _skinSSSGlow;
213
+ _skinSSSProfilePreset;
214
+ _skinSSSProfile;
215
+ _skinSSSScatterTint;
202
216
  /** @internal SSAO enable flag (via post effect). */ _SSAO;
203
217
  /** @internal SSAO post effect reference. */ _postEffectSSAO;
204
- /** @internal SSAO scale (sampling radius multiplier). */ _SSAOScale;
218
+ /** @internal SSAO scale (sampling radius multiplier). */ _SSAOOcclusionRadius;
205
219
  /** @internal SSAO bias (self-shadowing reduction). */ _SSAOBias;
206
- /** @internal SSAO sample radius. */ _SSAORadius;
207
- /** @internal SSAO intensity. */ _SSAOIntensity;
220
+ /** @internal SSAO sample radius. */ /** @internal SSAO intensity. */ _SSAOIntensity;
208
221
  /** @internal SSAO blur depth cutoff. */ _SSAOBlurDepthCutoff;
209
222
  /** @internal Pending GPU-pick promise (one-shot). */ _pickResultPromise;
210
223
  /** @internal Resolver for the pending pick promise. */ _pickResultResolve;
@@ -259,6 +272,7 @@ const SSS_QUALITY_PRESET_SETTINGS = {
259
272
  this._screenAdapter = new ScreenAdapter();
260
273
  this._adapted = false;
261
274
  this._HiZ = false;
275
+ this._HiZNearest = false;
262
276
  this._screenSpaceShadowMask = true;
263
277
  this._HDR = true;
264
278
  this._toneMap = true;
@@ -272,6 +286,8 @@ const SSS_QUALITY_PRESET_SETTINGS = {
272
286
  this._motionBlur = false;
273
287
  this._postEffectMotionBlur = new DRef();
274
288
  this._motionBlurStrength = 1;
289
+ this._motionBlurShutterBias = 0.5;
290
+ this._motionBlurMaxLength = 40;
275
291
  this._bloom = false;
276
292
  this._postEffectBloom = new DRef();
277
293
  this._bloomMaxDownsampleLevels = 4;
@@ -279,6 +295,8 @@ const SSS_QUALITY_PRESET_SETTINGS = {
279
295
  this._bloomThreshold = 0.8;
280
296
  this._bloomThresholdKnee = 0;
281
297
  this._bloomIntensity = 1;
298
+ this._bloomFilterRadius = 1;
299
+ this._bloomKarisAverage = true;
282
300
  this._colorAdjustEnabled = false;
283
301
  this._postEffectColorAdjust = new DRef();
284
302
  this._colorAdjustSaturation = 1;
@@ -346,14 +364,19 @@ const SSS_QUALITY_PRESET_SETTINGS = {
346
364
  this._skinSSSStrength = 1;
347
365
  this._skinSSSOpacity = 0.18;
348
366
  this._skinSSSSampleStep = 2;
367
+ this._skinSSSScatterRadius = 0.02;
368
+ this._skinSSSSmoothness = 0;
349
369
  this._skinSSSDepthScale = 80;
350
370
  this._skinSSSColorBoost = 1;
371
+ this._skinSSSGlow = 0;
372
+ this._skinSSSProfilePreset = 'skin_default';
373
+ this._skinSSSProfile = null;
374
+ this._skinSSSScatterTint = new Vector4(1, 1, 1, 1);
351
375
  this._SSAO = false;
352
376
  this._postEffectSSAO = new DRef();
353
- this._SSAOScale = 10;
354
- this._SSAOBias = 1;
355
- this._SSAOIntensity = 0.025;
356
- this._SSAORadius = 100;
377
+ this._SSAOOcclusionRadius = 0.25;
378
+ this._SSAOBias = 0.05;
379
+ this._SSAOIntensity = 1;
357
380
  this._SSAOBlurDepthCutoff = 2;
358
381
  this._pickResult = null;
359
382
  this._commandBufferReuse = true;
@@ -424,6 +447,24 @@ const SSS_QUALITY_PRESET_SETTINGS = {
424
447
  this._HiZ = !!val;
425
448
  }
426
449
  /**
450
+ * Whether the Hi-Z pyramid carries its nearest-depth channel.
451
+ *
452
+ * The pyramid's own channel answers "what is the farthest thing in this screen
453
+ * region", which is what occlusion and ray marching want; this one answers
454
+ * "what is the nearest", which is what a proximity query wants. It doubles the
455
+ * pyramid's bandwidth, so it is off unless something asks for it.
456
+ *
457
+ * Materials that query it - water's shoreline foam - turn it on by themselves,
458
+ * the way a transmissive material turns on the scene colour copy, so this only
459
+ * has to be set to force the channel on for something the renderer cannot see
460
+ * coming. Ignored on WebGL1, which has no pyramid at all.
461
+ */ get HiZNearest() {
462
+ return this._HiZNearest;
463
+ }
464
+ set HiZNearest(val) {
465
+ this._HiZNearest = !!val;
466
+ }
467
+ /**
427
468
  * Whether the screen-space shadow mask is enabled.
428
469
  *
429
470
  * When enabled, shadow-casting lights are lit through the clustered pass and
@@ -480,6 +521,38 @@ const SSS_QUALITY_PRESET_SETTINGS = {
480
521
  }
481
522
  }
482
523
  /**
524
+ * How much of the motion blur streak lies ahead of where an object is now,
525
+ * as a fraction of its length. 0 trails the streak fully behind the object,
526
+ * 0.5 (the default) centres it. See {@link MotionBlur.shutterBias}.
527
+ */ get motionBlurShutterBias() {
528
+ return this._motionBlurShutterBias;
529
+ }
530
+ set motionBlurShutterBias(val) {
531
+ this._motionBlurShutterBias = val;
532
+ if (this._postEffectMotionBlur.get()) {
533
+ this._postEffectMotionBlur.get().shutterBias = val;
534
+ // The effect clamps; read it back so the camera and the effect cannot
535
+ // disagree about what was actually applied.
536
+ this._motionBlurShutterBias = this._postEffectMotionBlur.get().shutterBias;
537
+ }
538
+ }
539
+ /**
540
+ * Longest motion blur streak, in pixels at render resolution. This is the
541
+ * ceiling {@link Camera.motionBlurStrength} runs into; raising it costs
542
+ * samples in proportion. See {@link MotionBlur.maxBlurLength}.
543
+ */ get motionBlurMaxLength() {
544
+ return this._motionBlurMaxLength;
545
+ }
546
+ set motionBlurMaxLength(val) {
547
+ this._motionBlurMaxLength = val;
548
+ if (this._postEffectMotionBlur.get()) {
549
+ this._postEffectMotionBlur.get().maxBlurLength = val;
550
+ // The effect clamps; read it back so the camera and the effect cannot
551
+ // disagree about what was actually applied.
552
+ this._motionBlurMaxLength = this._postEffectMotionBlur.get().maxBlurLength;
553
+ }
554
+ }
555
+ /**
483
556
  * Gets whether Bloom is enabled.
484
557
  */ get bloom() {
485
558
  return this._postEffectBloom.get().enabled;
@@ -542,6 +615,48 @@ const SSS_QUALITY_PRESET_SETTINGS = {
542
615
  this._postEffectBloom.get().intensity = val;
543
616
  }
544
617
  }
618
+ /**
619
+ * Radius of the tent filter used to upsample the bloom pyramid, in source texels.
620
+ *
621
+ * @remarks
622
+ * See {@link Bloom.filterRadius}. 1 is the natural width; raising it softens the halo but past
623
+ * ~2 the tent's taps stop overlapping and a grid pattern reappears.
624
+ */ get bloomFilterRadius() {
625
+ return this._bloomFilterRadius;
626
+ }
627
+ set bloomFilterRadius(val) {
628
+ this._bloomFilterRadius = Math.max(0, val);
629
+ if (this._postEffectBloom.get()) {
630
+ this._postEffectBloom.get().filterRadius = this._bloomFilterRadius;
631
+ }
632
+ }
633
+ /**
634
+ * Whether the first bloom downsample uses the Karis average to suppress fireflies.
635
+ *
636
+ * @remarks
637
+ * See {@link Bloom.karisAverage}. On by default; costs a little halo reach in exchange for
638
+ * stability on high-frequency speculars.
639
+ */ get bloomKarisAverage() {
640
+ return this._bloomKarisAverage;
641
+ }
642
+ set bloomKarisAverage(val) {
643
+ this._bloomKarisAverage = !!val;
644
+ if (this._postEffectBloom.get()) {
645
+ this._postEffectBloom.get().karisAverage = this._bloomKarisAverage;
646
+ }
647
+ }
648
+ /**
649
+ * Whether tone mapping dithers its result before the 8-bit write.
650
+ *
651
+ * @remarks
652
+ * See {@link Tonemap.dither}. On by default; removes the banding shallow gradients such as bloom
653
+ * halos otherwise show once quantized. Turn it off for reproducible pixel captures.
654
+ */ get toneMapDither() {
655
+ return this._postEffectTonemap.get().dither;
656
+ }
657
+ set toneMapDither(val) {
658
+ this._postEffectTonemap.get().dither = !!val;
659
+ }
545
660
  /** Whether color adjustment is enabled. */ get colorAdjust() {
546
661
  return this._postEffectColorAdjust.get().enabled;
547
662
  }
@@ -825,7 +940,7 @@ const SSS_QUALITY_PRESET_SETTINGS = {
825
940
  this.invalidateSSGIHistory();
826
941
  }
827
942
  }
828
- /** Whether WebGPU SSGI temporal accumulation is enabled. */ get ssgiTemporal() {
943
+ /** Whether SSGI temporal accumulation is enabled. Has no effect on WebGL1, which has no motion vectors. */ get ssgiTemporal() {
829
944
  return this._ssgiTemporal;
830
945
  }
831
946
  set ssgiTemporal(val) {
@@ -1055,7 +1170,7 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1055
1170
  this._postEffectSkinSSS.get().opacity = this._skinSSSOpacity;
1056
1171
  }
1057
1172
  }
1058
- /** Pixel spacing between blur taps. The reference shader uses 2. */ get skinSSSSampleStep() {
1173
+ /** Maximum pixel spacing between blur taps. Caps the projected scatter radius for close-ups. */ get skinSSSSampleStep() {
1059
1174
  return this._skinSSSSampleStep;
1060
1175
  }
1061
1176
  set skinSSSSampleStep(val) {
@@ -1064,6 +1179,24 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1064
1179
  this._postEffectSkinSSS.get().sampleStep = this._skinSSSSampleStep;
1065
1180
  }
1066
1181
  }
1182
+ /** World-space scatter radius. The blur width shrinks with distance to keep this constant. */ get skinSSSScatterRadius() {
1183
+ return this._skinSSSScatterRadius;
1184
+ }
1185
+ set skinSSSScatterRadius(val) {
1186
+ this._skinSSSScatterRadius = Math.max(0, val ?? 0);
1187
+ if (this._postEffectSkinSSS.get()) {
1188
+ this._postEffectSkinSSS.get().scatterRadius = this._skinSSSScatterRadius;
1189
+ }
1190
+ }
1191
+ /** Skin smoothing ("beauty filter") amount for the dedicated Skin SSS post effect. */ get skinSSSSmoothness() {
1192
+ return this._skinSSSSmoothness;
1193
+ }
1194
+ set skinSSSSmoothness(val) {
1195
+ this._skinSSSSmoothness = Math.max(0, Math.min(1, val ?? 0));
1196
+ if (this._postEffectSkinSSS.get()) {
1197
+ this._postEffectSkinSSS.get().smoothness = this._skinSSSSmoothness;
1198
+ }
1199
+ }
1067
1200
  /** Depth rejection scale. The reference shader uses 80. */ get skinSSSDepthScale() {
1068
1201
  return this._skinSSSDepthScale;
1069
1202
  }
@@ -1082,6 +1215,76 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1082
1215
  this._postEffectSkinSSS.get().colorBoost = this._skinSSSColorBoost;
1083
1216
  }
1084
1217
  }
1218
+ /**
1219
+ * Additive, deliberately non-conserving bleed for the Skin SSS post effect.
1220
+ *
1221
+ * @remarks
1222
+ * 0 (the default) keeps the effect energy conserving: light added to the dark
1223
+ * side of the terminator is light removed from the lit side. Raising it adds
1224
+ * the diffused term again without subtracting anything, for skin that reads as
1225
+ * lit from within; around 1 approximates the look the effect had before it
1226
+ * conserved energy.
1227
+ */ get skinSSSGlow() {
1228
+ return this._skinSSSGlow;
1229
+ }
1230
+ set skinSSSGlow(val) {
1231
+ this._skinSSSGlow = Math.max(0, val ?? 0);
1232
+ if (this._postEffectSkinSSS.get()) {
1233
+ this._postEffectSkinSSS.get().glow = this._skinSSSGlow;
1234
+ }
1235
+ }
1236
+ /**
1237
+ * Subsurface profile preset driving the Skin SSS per-channel scatter radii.
1238
+ *
1239
+ * @remarks
1240
+ * The ratio between the red, green and blue radii is what gives a scattering
1241
+ * surface its character - red travels furthest in skin, which is the
1242
+ * red-to-yellow gradient at the terminator. Switching presets changes that
1243
+ * ratio, so `wax` and `jade` are the same code path rather than special cases;
1244
+ * {@link Camera.skinSSSScatterRadius} still sets how far the light reaches.
1245
+ *
1246
+ * Applies to the whole pass. Per-material profiles need the profile-slot path
1247
+ * used by {@link SSS} instead.
1248
+ */ get skinSSSProfilePreset() {
1249
+ return this._skinSSSProfilePreset;
1250
+ }
1251
+ set skinSSSProfilePreset(val) {
1252
+ this._skinSSSProfilePreset = val ?? 'skin_default';
1253
+ if (this._skinSSSProfile) {
1254
+ this._skinSSSProfile.preset = this._skinSSSProfilePreset;
1255
+ }
1256
+ if (this._postEffectSkinSSS.get()) {
1257
+ this._postEffectSkinSSS.get().profile = this.getSkinSSSProfile();
1258
+ }
1259
+ }
1260
+ /**
1261
+ * The profile object backing {@link Camera.skinSSSProfilePreset}, created on
1262
+ * first use so that cameras which never enable Skin SSS do not consume one of
1263
+ * the 255 global profile slots.
1264
+ * @internal
1265
+ */ getSkinSSSProfile() {
1266
+ if (!this._skinSSSProfile) {
1267
+ this._skinSSSProfile = new SubsurfaceProfile();
1268
+ this._skinSSSProfile.preset = this._skinSSSProfilePreset;
1269
+ }
1270
+ return this._skinSSSProfile;
1271
+ }
1272
+ /**
1273
+ * Tint applied to the light the Skin SSS post effect redistributes.
1274
+ *
1275
+ * @remarks
1276
+ * White (the default) leaves the effect energy conserving. Because it
1277
+ * multiplies only the difference between the diffused and original diffuse, a
1278
+ * warm tint colors the terminator without washing the whole surface.
1279
+ */ get skinSSSScatterTint() {
1280
+ return this._skinSSSScatterTint;
1281
+ }
1282
+ set skinSSSScatterTint(val) {
1283
+ this._skinSSSScatterTint.set(val);
1284
+ if (this._postEffectSkinSSS.get()) {
1285
+ this._postEffectSkinSSS.get().scatterTint = this._skinSSSScatterTint;
1286
+ }
1287
+ }
1085
1288
  /** @internal */ get ssrParams() {
1086
1289
  return this._ssrParams;
1087
1290
  }
@@ -1093,13 +1296,19 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1093
1296
  set SSAO(val) {
1094
1297
  this._postEffectSSAO.get().enabled = !!val;
1095
1298
  }
1096
- /** SSAO scale */ get SSAOScale() {
1097
- return this._SSAOScale;
1299
+ /**
1300
+ * SSAO occlusion radius, in world units (metres).
1301
+ *
1302
+ * @remarks
1303
+ * Replaces the old `SSAOScale`, which was a far-plane-relative multiplier and
1304
+ * carried no physical meaning.
1305
+ */ get SSAOOcclusionRadius() {
1306
+ return this._SSAOOcclusionRadius;
1098
1307
  }
1099
- set SSAOScale(val) {
1100
- this._SSAOScale = val;
1308
+ set SSAOOcclusionRadius(val) {
1309
+ this._SSAOOcclusionRadius = val;
1101
1310
  if (this._postEffectSSAO.get()) {
1102
- this._postEffectSSAO.get().scale = val;
1311
+ this._postEffectSSAO.get().occlusionRadius = val;
1103
1312
  }
1104
1313
  }
1105
1314
  /** SSAO bias */ get SSAOBias() {
@@ -1111,15 +1320,6 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1111
1320
  this._postEffectSSAO.get().bias = val;
1112
1321
  }
1113
1322
  }
1114
- /** SSAO radius */ get SSAORadius() {
1115
- return this._SSAORadius;
1116
- }
1117
- set SSAORadius(val) {
1118
- this._SSAORadius = val;
1119
- if (this._postEffectSSAO.get()) {
1120
- this._postEffectSSAO.get().radius = val;
1121
- }
1122
- }
1123
1323
  /** SSAO intensity */ get SSAOIntensity() {
1124
1324
  return this._SSAOIntensity;
1125
1325
  }
@@ -1546,22 +1746,42 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1546
1746
  skinSSS.strength = this._skinSSSStrength;
1547
1747
  skinSSS.opacity = this._skinSSSOpacity;
1548
1748
  skinSSS.sampleStep = this._skinSSSSampleStep;
1749
+ skinSSS.scatterRadius = this._skinSSSScatterRadius;
1750
+ skinSSS.smoothness = this._skinSSSSmoothness;
1549
1751
  skinSSS.depthScale = this._skinSSSDepthScale;
1550
1752
  skinSSS.colorBoost = this._skinSSSColorBoost;
1753
+ skinSSS.glow = this._skinSSSGlow;
1754
+ skinSSS.profile = this.getSkinSSSProfile();
1755
+ skinSSS.scatterTint = this._skinSSSScatterTint;
1551
1756
  this._postEffectSkinSSS.set(skinSSS);
1552
1757
  this._compositor.appendPostEffect(skinSSS);
1553
1758
  }
1554
1759
  if (!this._postEffectSSAO.get()) {
1555
1760
  const ssao = new SAO();
1556
1761
  ssao.enabled = false;
1557
- ssao.scale = this._SSAOScale;
1762
+ ssao.occlusionRadius = this._SSAOOcclusionRadius;
1558
1763
  ssao.bias = this._SSAOBias;
1559
- ssao.radius = this._SSAORadius;
1560
1764
  ssao.intensity = this._SSAOIntensity;
1561
1765
  ssao.blurDepthCutoff = this._SSAOBlurDepthCutoff;
1562
1766
  this._postEffectSSAO.set(ssao);
1563
1767
  this._compositor.appendPostEffect(ssao);
1564
1768
  }
1769
+ // Every effect from here down shares the `end` layer, and appendPostEffect keeps insertion
1770
+ // order within a layer, so the chain is TAA -> MotionBlur -> Bloom -> Tonemap -> ColorAdjust
1771
+ // -> FXAA.
1772
+ //
1773
+ // The resolve leads because everything after it spreads energy -- Bloom spatially, MotionBlur
1774
+ // along the velocity field -- and doing that to an unconverged frame turns the per-frame
1775
+ // brightness swing of a sub-pixel specular highlight into a pulsing halo that no later pass can
1776
+ // take back: the halo is low frequency, so the 3x3 neighbourhood TAA's history clip is built
1777
+ // from pulses in step with it and admits the pulsing value as valid.
1778
+ //
1779
+ // The display chain sits in `end` rather than `transparent` specifically so that TAA does not
1780
+ // have to move. Effects in the transparent layer read the linear depth from before the
1781
+ // TransmissionDepth pass rewrites it with the full scene depth, and TAA dilates its velocities
1782
+ // by that depth; run there, it reads opaque-only depth and picks up its neighbours' motion on
1783
+ // any geometry the prepass never saw (alpha-blended hair, most visibly). None of the display
1784
+ // effects read depth at all, so moving them instead is free.
1565
1785
  if (!this._postEffectTAA.get()) {
1566
1786
  const taa = new TAA();
1567
1787
  taa.enabled = false;
@@ -1572,9 +1792,28 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1572
1792
  const motionBlur = new MotionBlur();
1573
1793
  motionBlur.enabled = false;
1574
1794
  motionBlur.strength = this._motionBlurStrength;
1795
+ motionBlur.shutterBias = this._motionBlurShutterBias;
1796
+ motionBlur.maxBlurLength = this._motionBlurMaxLength;
1575
1797
  this._postEffectMotionBlur.set(motionBlur);
1576
1798
  this._compositor.appendPostEffect(motionBlur);
1577
1799
  }
1800
+ // Bloom is created before Tonemap because it must see scene-linear radiance:
1801
+ // its threshold, its blur and its additive compose are all only meaningful in linear light.
1802
+ // Running it after the ACES curve compressed everything into [0, 1] flattened the emitter range
1803
+ // (a 100x brighter emitter produced the same halo) and made the compose hard-clip.
1804
+ if (!this._postEffectBloom.get()) {
1805
+ const bloom = new Bloom();
1806
+ bloom.enabled = false;
1807
+ bloom.maxDownsampleLevel = this._bloomMaxDownsampleLevels;
1808
+ bloom.downsampleLimit = this._bloomDownsampleLimit;
1809
+ bloom.threshold = this._bloomThreshold;
1810
+ bloom.thresholdKnee = this._bloomThresholdKnee;
1811
+ bloom.intensity = this._bloomIntensity;
1812
+ bloom.filterRadius = this._bloomFilterRadius;
1813
+ bloom.karisAverage = this._bloomKarisAverage;
1814
+ this._postEffectBloom.set(bloom);
1815
+ this._compositor.appendPostEffect(bloom);
1816
+ }
1578
1817
  if (!this._postEffectTonemap.get()) {
1579
1818
  const tonemap = new Tonemap();
1580
1819
  tonemap.enabled = true;
@@ -1598,17 +1837,6 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1598
1837
  this._postEffectFXAA.set(fxaa);
1599
1838
  this._compositor.appendPostEffect(fxaa);
1600
1839
  }
1601
- if (!this._postEffectBloom.get()) {
1602
- const bloom = new Bloom();
1603
- bloom.enabled = false;
1604
- bloom.maxDownsampleLevel = this._bloomMaxDownsampleLevels;
1605
- bloom.downsampleLimit = this._bloomDownsampleLimit;
1606
- bloom.threshold = this._bloomThreshold;
1607
- bloom.thresholdKnee = this._bloomThresholdKnee;
1608
- bloom.intensity = this._bloomIntensity;
1609
- this._postEffectBloom.set(bloom);
1610
- this._compositor.appendPostEffect(bloom);
1611
- }
1612
1840
  }
1613
1841
  /** @internal */ syncPostProcessingMode(scene) {
1614
1842
  const tonemap = this._postEffectTonemap.get();
@@ -1617,15 +1845,11 @@ const SSS_QUALITY_PRESET_SETTINGS = {
1617
1845
  // keeps its plain exposure multiplier.
1618
1846
  const usePhysicalExposure = scene.lightingMode === 'physical';
1619
1847
  tonemap.exposure = usePhysicalExposure ? 1 : this._tonemapExposure;
1620
- const bloom = this._postEffectBloom.get();
1848
+ // The chain order no longer depends on the lighting mode: Bloom always precedes Tonemap, so it
1849
+ // always works on scene-linear radiance. Only the SSGI histories still care about the switch.
1621
1850
  if (this._postProcessingLightingMode !== scene.lightingMode) {
1622
1851
  // SSGI histories contain scene-linear radiance. Never reuse them across lighting unit models.
1623
1852
  this.invalidateSSGIHistory();
1624
- if (scene.lightingMode === 'physical') {
1625
- this._compositor.movePostEffectBefore(bloom, tonemap);
1626
- } else {
1627
- this._compositor.movePostEffectAfter(bloom, this._postEffectFXAA.get());
1628
- }
1629
1853
  this._postProcessingLightingMode = scene.lightingMode;
1630
1854
  }
1631
1855
  }