@zephyr3d/scene 0.9.27 → 0.10.0

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 (502) hide show
  1. package/README.md +60 -27
  2. package/dist/animation/animation_bank.js +634 -0
  3. package/dist/animation/animation_bank.js.map +1 -0
  4. package/dist/animation/animation_bank_gpu.js +256 -0
  5. package/dist/animation/animation_bank_gpu.js.map +1 -0
  6. package/dist/animation/animationset.js +54 -0
  7. package/dist/animation/animationset.js.map +1 -1
  8. package/dist/animation/cloth/gpu_cloth_component.js +406 -0
  9. package/dist/animation/cloth/gpu_cloth_component.js.map +1 -0
  10. package/dist/animation/cloth/gpu_cloth_system.js +332 -202
  11. package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
  12. package/dist/animation/gpu_animation_driver.js +289 -0
  13. package/dist/animation/gpu_animation_driver.js.map +1 -0
  14. package/dist/animation/joint_dynamics/collision.js +112 -1
  15. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  16. package/dist/animation/joint_dynamics/controller.js +6 -0
  17. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  18. package/dist/animation/joint_dynamics/joint_dynamics_system.js +11 -0
  19. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  20. package/dist/animation/joint_dynamics/solver.js +50 -12
  21. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  22. package/dist/animation/joint_dynamics/types.js.map +1 -1
  23. package/dist/animation/skeleton.js +279 -55
  24. package/dist/animation/skeleton.js.map +1 -1
  25. package/dist/animation/skin_palette_atlas.js +252 -0
  26. package/dist/animation/skin_palette_atlas.js.map +1 -0
  27. package/dist/animation/spring/multi_chain_spring_system.js +298 -38
  28. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  29. package/dist/animation/spring/spring_chain.js +2 -0
  30. package/dist/animation/spring/spring_chain.js.map +1 -1
  31. package/dist/animation/spring/spring_collider.js +159 -21
  32. package/dist/animation/spring/spring_collider.js.map +1 -1
  33. package/dist/animation/spring/spring_particle.js +1 -0
  34. package/dist/animation/spring/spring_particle.js.map +1 -1
  35. package/dist/animation/spring/spring_solver.js +173 -0
  36. package/dist/animation/spring/spring_solver.js.map +1 -0
  37. package/dist/animation/spring/spring_system.js +249 -24
  38. package/dist/animation/spring/spring_system.js.map +1 -1
  39. package/dist/animation/spring_modifier.js +32 -1
  40. package/dist/animation/spring_modifier.js.map +1 -1
  41. package/dist/app/app.js +26 -0
  42. package/dist/app/app.js.map +1 -1
  43. package/dist/app/engine.js +86 -15
  44. package/dist/app/engine.js.map +1 -1
  45. package/dist/app/gamepad.js +191 -0
  46. package/dist/app/gamepad.js.map +1 -0
  47. package/dist/app/inputactions.js +271 -0
  48. package/dist/app/inputactions.js.map +1 -0
  49. package/dist/app/inputmgr.js +331 -22
  50. package/dist/app/inputmgr.js.map +1 -1
  51. package/dist/app/loading.js +138 -0
  52. package/dist/app/loading.js.map +1 -0
  53. package/dist/app/pipelinecache.js +209 -0
  54. package/dist/app/pipelinecache.js.map +1 -0
  55. package/dist/app/runtimescript.js +25 -0
  56. package/dist/app/runtimescript.js.map +1 -1
  57. package/dist/app/scriptingsystem.js +54 -0
  58. package/dist/app/scriptingsystem.js.map +1 -1
  59. package/dist/app/scriptregistry.js +7 -2
  60. package/dist/app/scriptregistry.js.map +1 -1
  61. package/dist/asset/asset_manifest.js +59 -0
  62. package/dist/asset/asset_manifest.js.map +1 -0
  63. package/dist/asset/asset_preload.js +258 -0
  64. package/dist/asset/asset_preload.js.map +1 -0
  65. package/dist/asset/assetmanager.js +117 -65
  66. package/dist/asset/assetmanager.js.map +1 -1
  67. package/dist/asset/loaders/ktx2/basis/LICENSE +201 -0
  68. package/dist/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  69. package/dist/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  70. package/dist/asset/loaders/ktx2/basis_location.js +17 -0
  71. package/dist/asset/loaders/ktx2/basis_location.js.map +1 -0
  72. package/dist/asset/loaders/ktx2/ktx2_loader.js +88 -0
  73. package/dist/asset/loaders/ktx2/ktx2_loader.js.map +1 -0
  74. package/dist/asset/loaders/ktx2/ktx2_targets.js +118 -0
  75. package/dist/asset/loaders/ktx2/ktx2_targets.js.map +1 -0
  76. package/dist/asset/loaders/ktx2/transcoder_pool.js +259 -0
  77. package/dist/asset/loaders/ktx2/transcoder_pool.js.map +1 -0
  78. package/dist/asset/mesh_lod_builder.js +104 -0
  79. package/dist/asset/mesh_lod_builder.js.map +1 -0
  80. package/dist/asset/mesh_settings.js +111 -0
  81. package/dist/asset/mesh_settings.js.map +1 -0
  82. package/dist/asset/meshopt_decoder.js +18 -0
  83. package/dist/asset/meshopt_decoder.js.map +1 -0
  84. package/dist/asset/meshopt_simplifier.js +26 -0
  85. package/dist/asset/meshopt_simplifier.js.map +1 -0
  86. package/dist/asset/model.js +171 -1
  87. package/dist/asset/model.js.map +1 -1
  88. package/dist/asset/texture_settings.js +231 -0
  89. package/dist/asset/texture_settings.js.map +1 -0
  90. package/dist/asset/zmsh_binary.js +131 -0
  91. package/dist/asset/zmsh_binary.js.map +1 -0
  92. package/dist/asset/zsdf_binary.js +111 -0
  93. package/dist/asset/zsdf_binary.js.map +1 -0
  94. package/dist/blitter/bilateralblur.js +1 -2
  95. package/dist/blitter/bilateralblur.js.map +1 -1
  96. package/dist/blitter/gaussianblur.js +1 -6
  97. package/dist/blitter/gaussianblur.js.map +1 -1
  98. package/dist/camera/base.js +31 -10
  99. package/dist/camera/base.js.map +1 -1
  100. package/dist/camera/camera.js +104 -178
  101. package/dist/camera/camera.js.map +1 -1
  102. package/dist/camera/follow.js +342 -0
  103. package/dist/camera/follow.js.map +1 -0
  104. package/dist/camera/fps.js +9 -7
  105. package/dist/camera/fps.js.map +1 -1
  106. package/dist/camera/orbit.js +46 -19
  107. package/dist/camera/orbit.js.map +1 -1
  108. package/dist/index.d.ts +25436 -15990
  109. package/dist/index.js +65 -11
  110. package/dist/index.js.map +1 -1
  111. package/dist/material/blinn.js +3 -0
  112. package/dist/material/blinn.js.map +1 -1
  113. package/dist/material/eye.js +1 -1
  114. package/dist/material/eye.js.map +1 -1
  115. package/dist/material/hair.js +2 -3
  116. package/dist/material/hair.js.map +1 -1
  117. package/dist/material/lambert.js +4 -1
  118. package/dist/material/lambert.js.map +1 -1
  119. package/dist/material/material.js +66 -4
  120. package/dist/material/material.js.map +1 -1
  121. package/dist/material/meshmaterial.js +118 -45
  122. package/dist/material/meshmaterial.js.map +1 -1
  123. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  124. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  125. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  126. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  127. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +34 -61
  128. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  129. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -2
  130. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  131. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +2 -1
  132. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  133. package/dist/material/mixins/lit.js +191 -83
  134. package/dist/material/mixins/lit.js.map +1 -1
  135. package/dist/material/mixins/pbr/common.js +31 -206
  136. package/dist/material/mixins/pbr/common.js.map +1 -1
  137. package/dist/material/mtoon.js +1 -1
  138. package/dist/material/mtoon.js.map +1 -1
  139. package/dist/material/pbrmr.js +3 -0
  140. package/dist/material/pbrmr.js.map +1 -1
  141. package/dist/material/pbrsg.js +3 -0
  142. package/dist/material/pbrsg.js.map +1 -1
  143. package/dist/material/sdf_debug.js +78 -0
  144. package/dist/material/sdf_debug.js.map +1 -0
  145. package/dist/material/shader/helper.js +333 -191
  146. package/dist/material/shader/helper.js.map +1 -1
  147. package/dist/material/shader/terrain_blend.js +204 -43
  148. package/dist/material/shader/terrain_blend.js.map +1 -1
  149. package/dist/material/skin.js +331 -297
  150. package/dist/material/skin.js.map +1 -1
  151. package/dist/material/skinprofile.js +1058 -0
  152. package/dist/material/skinprofile.js.map +1 -0
  153. package/dist/material/sss.js +353 -0
  154. package/dist/material/sss.js.map +1 -0
  155. package/dist/material/sss_kernel.js +265 -0
  156. package/dist/material/sss_kernel.js.map +1 -0
  157. package/dist/material/sssprofile.js +879 -0
  158. package/dist/material/sssprofile.js.map +1 -0
  159. package/dist/material/subsurfaceprofile.js +4 -8
  160. package/dist/material/subsurfaceprofile.js.map +1 -1
  161. package/dist/material/terrain-cm.js +464 -188
  162. package/dist/material/terrain-cm.js.map +1 -1
  163. package/dist/material/unlit.js +3 -0
  164. package/dist/material/unlit.js.map +1 -1
  165. package/dist/material/water.js +1261 -1438
  166. package/dist/material/water.js.map +1 -1
  167. package/dist/node_modules/meshoptimizer/LICENSE +21 -0
  168. package/dist/node_modules/meshoptimizer/meshopt_decoder.js +197 -0
  169. package/dist/node_modules/meshoptimizer/meshopt_decoder.js.map +1 -0
  170. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js +677 -0
  171. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js.map +1 -0
  172. package/dist/physics/character.js +226 -0
  173. package/dist/physics/character.js.map +1 -0
  174. package/dist/physics/collider.js +209 -0
  175. package/dist/physics/collider.js.map +1 -0
  176. package/dist/physics/events.js +79 -0
  177. package/dist/physics/events.js.map +1 -0
  178. package/dist/physics/joint.js +272 -0
  179. package/dist/physics/joint.js.map +1 -0
  180. package/dist/physics/node_physics.js +234 -0
  181. package/dist/physics/node_physics.js.map +1 -0
  182. package/dist/physics/part.js +91 -0
  183. package/dist/physics/part.js.map +1 -0
  184. package/dist/physics/rigid_body.js +379 -0
  185. package/dist/physics/rigid_body.js.map +1 -0
  186. package/dist/physics/vehicle.js +335 -0
  187. package/dist/physics/vehicle.js.map +1 -0
  188. package/dist/physics/world.js +25 -0
  189. package/dist/physics/world.js.map +1 -0
  190. package/dist/posteffect/bloom.js +49 -14
  191. package/dist/posteffect/bloom.js.map +1 -1
  192. package/dist/posteffect/motionblur.js +106 -106
  193. package/dist/posteffect/motionblur.js.map +1 -1
  194. package/dist/posteffect/postsss.js +572 -0
  195. package/dist/posteffect/postsss.js.map +1 -0
  196. package/dist/posteffect/sao.js +2 -6
  197. package/dist/posteffect/sao.js.map +1 -1
  198. package/dist/posteffect/skinsss.js +605 -355
  199. package/dist/posteffect/skinsss.js.map +1 -1
  200. package/dist/posteffect/ssgi.js +91 -162
  201. package/dist/posteffect/ssgi.js.map +1 -1
  202. package/dist/posteffect/ssr.js +3 -11
  203. package/dist/posteffect/ssr.js.map +1 -1
  204. package/dist/posteffect/sss.js +4 -13
  205. package/dist/posteffect/sss.js.map +1 -1
  206. package/dist/posteffect/taa.js +1 -0
  207. package/dist/posteffect/taa.js.map +1 -1
  208. package/dist/render/abuffer_oit.js +3 -2
  209. package/dist/render/abuffer_oit.js.map +1 -1
  210. package/dist/render/clipmap.js +179 -64
  211. package/dist/render/clipmap.js.map +1 -1
  212. package/dist/render/cluster_light.js +958 -224
  213. package/dist/render/cluster_light.js.map +1 -1
  214. package/dist/render/cull_visitor.js +25 -5
  215. package/dist/render/cull_visitor.js.map +1 -1
  216. package/dist/render/debug_views.js +37 -0
  217. package/dist/render/debug_views.js.map +1 -0
  218. package/dist/render/depthpass.js +5 -1
  219. package/dist/render/depthpass.js.map +1 -1
  220. package/dist/render/drawable_mixin.js +53 -6
  221. package/dist/render/drawable_mixin.js.map +1 -1
  222. package/dist/render/dualdepthpeeling_oit.js +5 -5
  223. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  224. package/dist/render/envlight.js +196 -113
  225. package/dist/render/envlight.js.map +1 -1
  226. package/dist/render/fbm_wavegenerator.js +5 -10
  227. package/dist/render/fbm_wavegenerator.js.map +1 -1
  228. package/dist/render/fft_wavegenerator.js +247 -157
  229. package/dist/render/fft_wavegenerator.js.map +1 -1
  230. package/dist/render/gerstner_wavegenerator.js +16 -38
  231. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  232. package/dist/render/gi/probe_volume.js +1334 -0
  233. package/dist/render/gi/probe_volume.js.map +1 -0
  234. package/dist/render/gi/scene_gi.js +282 -0
  235. package/dist/render/gi/scene_gi.js.map +1 -0
  236. package/dist/render/gi/voxel_atlas.js +198 -0
  237. package/dist/render/gi/voxel_atlas.js.map +1 -0
  238. package/dist/render/gi/voxel_lighting.js +652 -0
  239. package/dist/render/gi/voxel_lighting.js.map +1 -0
  240. package/dist/render/gi/voxel_scene.js +642 -0
  241. package/dist/render/gi/voxel_scene.js.map +1 -0
  242. package/dist/render/gi/voxelize_pass.js +223 -0
  243. package/dist/render/gi/voxelize_pass.js.map +1 -0
  244. package/dist/render/globalbindgroup_allocator.js +3 -2
  245. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  246. package/dist/render/gpu_picking.js +9 -36
  247. package/dist/render/gpu_picking.js.map +1 -1
  248. package/dist/render/instance_culling.js +499 -0
  249. package/dist/render/instance_culling.js.map +1 -0
  250. package/dist/render/lightpass.js +19 -8
  251. package/dist/render/lightpass.js.map +1 -1
  252. package/dist/render/lod.js +46 -0
  253. package/dist/render/lod.js.map +1 -0
  254. package/dist/render/primitive.js +301 -9
  255. package/dist/render/primitive.js.map +1 -1
  256. package/dist/render/primitive_readback.js +209 -0
  257. package/dist/render/primitive_readback.js.map +1 -0
  258. package/dist/render/render_queue.js +162 -11
  259. package/dist/render/render_queue.js.map +1 -1
  260. package/dist/render/renderer.js +10 -7
  261. package/dist/render/renderer.js.map +1 -1
  262. package/dist/render/rendergraph/blackboard.js +14 -1
  263. package/dist/render/rendergraph/blackboard.js.map +1 -1
  264. package/dist/render/rendergraph/executor.js +136 -0
  265. package/dist/render/rendergraph/executor.js.map +1 -1
  266. package/dist/render/rendergraph/forward_plus_builder.js +272 -55
  267. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  268. package/dist/render/rendergraph/frame_graph_context.js +41 -0
  269. package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
  270. package/dist/render/rendergraph/scene_render_context.js +31 -2
  271. package/dist/render/rendergraph/scene_render_context.js.map +1 -1
  272. package/dist/render/rendergraph/types.js.map +1 -1
  273. package/dist/render/renderpass.js +28 -5
  274. package/dist/render/renderpass.js.map +1 -1
  275. package/dist/render/sdf/box_allocator.js +98 -0
  276. package/dist/render/sdf/box_allocator.js.map +1 -0
  277. package/dist/render/sdf/global_sdf.js +865 -0
  278. package/dist/render/sdf/global_sdf.js.map +1 -0
  279. package/dist/render/sdf/scene_sdf.js +562 -0
  280. package/dist/render/sdf/scene_sdf.js.map +1 -0
  281. package/dist/render/sdf/sdf_atlas.js +227 -0
  282. package/dist/render/sdf/sdf_atlas.js.map +1 -0
  283. package/dist/render/sdf/sdf_programs.js +42 -0
  284. package/dist/render/sdf/sdf_programs.js.map +1 -0
  285. package/dist/render/sdf/sdf_view.js +199 -0
  286. package/dist/render/sdf/sdf_view.js.map +1 -0
  287. package/dist/render/sdf/waterline.js +610 -0
  288. package/dist/render/sdf/waterline.js.map +1 -0
  289. package/dist/render/shadow_mask_pass.js +142 -25
  290. package/dist/render/shadow_mask_pass.js.map +1 -1
  291. package/dist/render/shore_wave_generator.js +1193 -0
  292. package/dist/render/shore_wave_generator.js.map +1 -0
  293. package/dist/render/sky.js +516 -86
  294. package/dist/render/sky.js.map +1 -1
  295. package/dist/render/transmission_thickness_pass.js +477 -0
  296. package/dist/render/transmission_thickness_pass.js.map +1 -0
  297. package/dist/render/underwater.js +58 -158
  298. package/dist/render/underwater.js.map +1 -1
  299. package/dist/render/virtualtexture/virtual_texture.js +1214 -0
  300. package/dist/render/virtualtexture/virtual_texture.js.map +1 -0
  301. package/dist/render/volumetric_cloud/cloud_common.js +472 -0
  302. package/dist/render/volumetric_cloud/cloud_common.js.map +1 -0
  303. package/dist/render/volumetric_cloud/cloud_noise.js +189 -0
  304. package/dist/render/volumetric_cloud/cloud_noise.js.map +1 -0
  305. package/dist/render/volumetric_cloud/debug_view.js +131 -0
  306. package/dist/render/volumetric_cloud/debug_view.js.map +1 -0
  307. package/dist/render/volumetric_cloud/resources.js +380 -0
  308. package/dist/render/volumetric_cloud/resources.js.map +1 -0
  309. package/dist/render/volumetric_cloud/sky_cache.js +380 -0
  310. package/dist/render/volumetric_cloud/sky_cache.js.map +1 -0
  311. package/dist/render/volumetric_cloud/volumetric_cloud.js +318 -0
  312. package/dist/render/volumetric_cloud/volumetric_cloud.js.map +1 -0
  313. package/dist/render/water_caustics.js +134 -319
  314. package/dist/render/water_caustics.js.map +1 -1
  315. package/dist/render/water_foam.js +627 -0
  316. package/dist/render/water_foam.js.map +1 -0
  317. package/dist/render/water_interaction.js +1795 -0
  318. package/dist/render/water_interaction.js.map +1 -0
  319. package/dist/render/weightedblended_oit.js +3 -3
  320. package/dist/render/weightedblended_oit.js.map +1 -1
  321. package/dist/scene/basesprite.js +9 -4
  322. package/dist/scene/basesprite.js.map +1 -1
  323. package/dist/scene/batchgroup.js +108 -12
  324. package/dist/scene/batchgroup.js.map +1 -1
  325. package/dist/scene/environment.js +28 -7
  326. package/dist/scene/environment.js.map +1 -1
  327. package/dist/scene/foliage.js +1020 -0
  328. package/dist/scene/foliage.js.map +1 -0
  329. package/dist/scene/foliage_buckets.js +147 -0
  330. package/dist/scene/foliage_buckets.js.map +1 -0
  331. package/dist/scene/foliage_mask.js +358 -0
  332. package/dist/scene/foliage_mask.js.map +1 -0
  333. package/dist/scene/hair.js +15 -4
  334. package/dist/scene/hair.js.map +1 -1
  335. package/dist/scene/light.js +179 -13
  336. package/dist/scene/light.js.map +1 -1
  337. package/dist/scene/mesh.js +327 -45
  338. package/dist/scene/mesh.js.map +1 -1
  339. package/dist/scene/meshdrawable.js +6 -0
  340. package/dist/scene/meshdrawable.js.map +1 -1
  341. package/dist/scene/msdftext.js +9 -3
  342. package/dist/scene/msdftext.js.map +1 -1
  343. package/dist/scene/msdftextsprite.js +9 -3
  344. package/dist/scene/msdftextsprite.js.map +1 -1
  345. package/dist/scene/particlesys.js +8 -2
  346. package/dist/scene/particlesys.js.map +1 -1
  347. package/dist/scene/physics_settings.js +157 -0
  348. package/dist/scene/physics_settings.js.map +1 -0
  349. package/dist/scene/scene.js +190 -44
  350. package/dist/scene/scene.js.map +1 -1
  351. package/dist/scene/scene_node.js +147 -6
  352. package/dist/scene/scene_node.js.map +1 -1
  353. package/dist/scene/terrain-cm/bladegrassmaterial.js +735 -0
  354. package/dist/scene/terrain-cm/bladegrassmaterial.js.map +1 -0
  355. package/dist/scene/terrain-cm/grass.js +881 -42
  356. package/dist/scene/terrain-cm/grass.js.map +1 -1
  357. package/dist/scene/terrain-cm/grass_gpu.js +929 -0
  358. package/dist/scene/terrain-cm/grass_gpu.js.map +1 -0
  359. package/dist/scene/terrain-cm/grassmaterial.js +180 -9
  360. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  361. package/dist/scene/terrain-cm/terrain-cm.js +465 -36
  362. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  363. package/dist/scene/terrain-cm/terrain_gi_albedo.js +257 -0
  364. package/dist/scene/terrain-cm/terrain_gi_albedo.js.map +1 -0
  365. package/dist/scene/terrain-cm/terrain_rvt.js +395 -0
  366. package/dist/scene/terrain-cm/terrain_rvt.js.map +1 -0
  367. package/dist/scene/update_queue.js +54 -0
  368. package/dist/scene/update_queue.js.map +1 -0
  369. package/dist/scene/water.js +633 -268
  370. package/dist/scene/water.js.map +1 -1
  371. package/dist/scene/water_surface_sampler.js +324 -0
  372. package/dist/scene/water_surface_sampler.js.map +1 -0
  373. package/dist/scene/wind.js +317 -0
  374. package/dist/scene/wind.js.map +1 -0
  375. package/dist/shaders/atmosphere.js +388 -166
  376. package/dist/shaders/atmosphere.js.map +1 -1
  377. package/dist/shaders/fog.js +100 -32
  378. package/dist/shaders/fog.js.map +1 -1
  379. package/dist/shaders/gi.js +365 -0
  380. package/dist/shaders/gi.js.map +1 -0
  381. package/dist/shaders/ltc_rect.js +202 -0
  382. package/dist/shaders/ltc_rect.js.map +1 -0
  383. package/dist/shaders/misc.js +1 -10
  384. package/dist/shaders/misc.js.map +1 -1
  385. package/dist/shaders/noise.js +5 -1
  386. package/dist/shaders/noise.js.map +1 -1
  387. package/dist/shaders/probes.js +309 -0
  388. package/dist/shaders/probes.js.map +1 -0
  389. package/dist/shaders/sdf.js +537 -0
  390. package/dist/shaders/sdf.js.map +1 -0
  391. package/dist/shaders/shadow.js +104 -70
  392. package/dist/shaders/shadow.js.map +1 -1
  393. package/dist/shaders/skin_brdf.js +243 -0
  394. package/dist/shaders/skin_brdf.js.map +1 -0
  395. package/dist/shaders/ssgi.js +63 -0
  396. package/dist/shaders/ssgi.js.map +1 -0
  397. package/dist/shaders/ssgi_reprojection.js +118 -0
  398. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  399. package/dist/shaders/ssr.js +6 -159
  400. package/dist/shaders/ssr.js.map +1 -1
  401. package/dist/shaders/temporal.js +38 -27
  402. package/dist/shaders/temporal.js.map +1 -1
  403. package/dist/shaders/water.js +32 -82
  404. package/dist/shaders/water.js.map +1 -1
  405. package/dist/shaders/water_medium.js +7 -21
  406. package/dist/shaders/water_medium.js.map +1 -1
  407. package/dist/shadow/dom.js +110 -19
  408. package/dist/shadow/dom.js.map +1 -1
  409. package/dist/shadow/esm.js +3 -3
  410. package/dist/shadow/esm.js.map +1 -1
  411. package/dist/shadow/pcf_opt.js +15 -48
  412. package/dist/shadow/pcf_opt.js.map +1 -1
  413. package/dist/shadow/pcf_pd.js +15 -53
  414. package/dist/shadow/pcf_pd.js.map +1 -1
  415. package/dist/shadow/pcss.js +34 -9
  416. package/dist/shadow/pcss.js.map +1 -1
  417. package/dist/shadow/shadow_impl.js +3 -8
  418. package/dist/shadow/shadow_impl.js.map +1 -1
  419. package/dist/shadow/shadow_region.js +40 -2
  420. package/dist/shadow/shadow_region.js.map +1 -1
  421. package/dist/shadow/shadowmapper.js +93 -53
  422. package/dist/shadow/shadowmapper.js.map +1 -1
  423. package/dist/shadow/ssm.js +18 -72
  424. package/dist/shadow/ssm.js.map +1 -1
  425. package/dist/shadow/vsm.js +3 -3
  426. package/dist/shadow/vsm.js.map +1 -1
  427. package/dist/shapes/shape.js +44 -1
  428. package/dist/shapes/shape.js.map +1 -1
  429. package/dist/utility/buoyancy.js +287 -0
  430. package/dist/utility/buoyancy.js.map +1 -0
  431. package/dist/utility/physical.js +10 -1
  432. package/dist/utility/physical.js.map +1 -1
  433. package/dist/utility/pmrem.js +17 -43
  434. package/dist/utility/pmrem.js.map +1 -1
  435. package/dist/utility/sdf/bake.js +435 -0
  436. package/dist/utility/sdf/bake.js.map +1 -0
  437. package/dist/utility/sdf/bvh.js +576 -0
  438. package/dist/utility/sdf/bvh.js.map +1 -0
  439. package/dist/utility/serialization/manager.js +34 -6
  440. package/dist/utility/serialization/manager.js.map +1 -1
  441. package/dist/utility/serialization/scene/animation.js +46 -5
  442. package/dist/utility/serialization/scene/animation.js.map +1 -1
  443. package/dist/utility/serialization/scene/batch.js +11 -4
  444. package/dist/utility/serialization/scene/batch.js.map +1 -1
  445. package/dist/utility/serialization/scene/camera.js +87 -254
  446. package/dist/utility/serialization/scene/camera.js.map +1 -1
  447. package/dist/utility/serialization/scene/cloth.js +25 -0
  448. package/dist/utility/serialization/scene/cloth.js.map +1 -0
  449. package/dist/utility/serialization/scene/common.js +14 -6
  450. package/dist/utility/serialization/scene/common.js.map +1 -1
  451. package/dist/utility/serialization/scene/foliage.js +821 -0
  452. package/dist/utility/serialization/scene/foliage.js.map +1 -0
  453. package/dist/utility/serialization/scene/hair.js +11 -4
  454. package/dist/utility/serialization/scene/hair.js.map +1 -1
  455. package/dist/utility/serialization/scene/light.js +115 -7
  456. package/dist/utility/serialization/scene/light.js.map +1 -1
  457. package/dist/utility/serialization/scene/material.js +388 -220
  458. package/dist/utility/serialization/scene/material.js.map +1 -1
  459. package/dist/utility/serialization/scene/mesh.js +69 -4
  460. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  461. package/dist/utility/serialization/scene/node.js +140 -5
  462. package/dist/utility/serialization/scene/node.js.map +1 -1
  463. package/dist/utility/serialization/scene/node_physics.js +1318 -0
  464. package/dist/utility/serialization/scene/node_physics.js.map +1 -0
  465. package/dist/utility/serialization/scene/particle.js +11 -4
  466. package/dist/utility/serialization/scene/particle.js.map +1 -1
  467. package/dist/utility/serialization/scene/physics.js +120 -0
  468. package/dist/utility/serialization/scene/physics.js.map +1 -0
  469. package/dist/utility/serialization/scene/primitive.js +124 -10
  470. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  471. package/dist/utility/serialization/scene/scene.js +1687 -51
  472. package/dist/utility/serialization/scene/scene.js.map +1 -1
  473. package/dist/utility/serialization/scene/sprite.js +11 -4
  474. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  475. package/dist/utility/serialization/scene/terrain.js +163 -33
  476. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  477. package/dist/utility/serialization/scene/text.js +11 -4
  478. package/dist/utility/serialization/scene/text.js.map +1 -1
  479. package/dist/utility/serialization/scene/water.js +1543 -264
  480. package/dist/utility/serialization/scene/water.js.map +1 -1
  481. package/dist/utility/serialization/types.js.map +1 -1
  482. package/dist/utility/shprojector.js +10 -22
  483. package/dist/utility/shprojector.js.map +1 -1
  484. package/dist/utility/textures/foam.js +170 -0
  485. package/dist/utility/textures/foam.js.map +1 -0
  486. package/dist/utility/textures/ggxlut.js +17 -43
  487. package/dist/utility/textures/ggxlut.js.map +1 -1
  488. package/dist/utility/textures/ltcdata.js +4 -4
  489. package/dist/utility/textures/ltcdata.js.map +1 -1
  490. package/dist/utility/textures/ltclut.js +16 -6
  491. package/dist/utility/textures/ltclut.js.map +1 -1
  492. package/dist/utility/unsupported.js +24 -0
  493. package/dist/utility/unsupported.js.map +1 -0
  494. package/dist/values.js +13 -1
  495. package/dist/values.js.map +1 -1
  496. package/package.json +25 -12
  497. package/src/asset/loaders/ktx2/basis/LICENSE +201 -0
  498. package/src/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  499. package/src/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  500. package/src/asset/meshoptimizer/LICENSE +21 -0
  501. package/dist/animation/joint_dynamics/convex_collider.js +0 -320
  502. package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
@@ -0,0 +1,342 @@
1
+ import { Quaternion, Vector3 } from '@zephyr3d/base';
2
+ import { BaseCameraController } from './base.js';
3
+
4
+ const defaultOptions = ()=>({
5
+ mode: 'free',
6
+ pivotOffset: new Vector3(0, 1.5, 0),
7
+ armLength: 4,
8
+ minArmLength: 1.5,
9
+ maxArmLength: 12,
10
+ minPitch: -1,
11
+ maxPitch: 1.3,
12
+ positionLag: 10,
13
+ forwardAxis: new Vector3(0, 0, 1),
14
+ chasePitch: 0.3,
15
+ chaseStiffness: 3,
16
+ recenterDelay: 1.5,
17
+ recenterMinSpeed: 1,
18
+ probeRadius: 0.15,
19
+ collisionMask: -1,
20
+ exclude: null,
21
+ zoomOutSpeed: 4,
22
+ mouseSensitivity: 0.005,
23
+ mouseButtons: [
24
+ 0,
25
+ 2
26
+ ],
27
+ fovBoost: null
28
+ });
29
+ const identity = Quaternion.identity();
30
+ /** Closest the camera comes to the pivot */ const MIN_DISTANCE = 0.05;
31
+ /** A sweep hit closer than this started inside something */ const START_OVERLAP = 1e-3;
32
+ /** Above this, a near plane is warned about as too far from the eye */ const LARGE_NEAR_RADIUS = 0.5;
33
+ /**
34
+ * Third-person camera on a spring arm.
35
+ *
36
+ * The camera orbits a pivot above its target at `armLength`, turned by look
37
+ * input. A sphere is swept from the pivot to the camera through the scene's
38
+ * physics world: an obstacle pulls the camera in at once, and it eases back out
39
+ * once clear. In `'chase'` mode it swings back behind a moving target when the
40
+ * player stops turning it, as driving games do.
41
+ *
42
+ * Its {@link FollowCameraController.updatePhase} is `'late'`: it is updated after
43
+ * physics, so it follows the pose of the target rendered this frame. Feed it look
44
+ * input from an action map, or let it read mouse drags through `camera.handleEvent`.
45
+ *
46
+ * The camera should have no parent; it is placed in world space.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const follow = new FollowCameraController(car, { mode: 'chase', armLength: 7 });
51
+ * camera.controller = follow;
52
+ * myApp.on('tick', () => {
53
+ * const look = driving.vector2('look');
54
+ * follow.addLookInput(look.x, look.y);
55
+ * });
56
+ * ```
57
+ *
58
+ * @public
59
+ */ class FollowCameraController extends BaseCameraController {
60
+ /** Options; may be changed at any time. */ options;
61
+ _target;
62
+ _yaw;
63
+ _pitch;
64
+ _pivot;
65
+ _lastTargetPos;
66
+ _distance;
67
+ _idleTime;
68
+ _speed;
69
+ _baseFovY;
70
+ _snap;
71
+ _blendTime;
72
+ _blendElapsed;
73
+ _blendEye;
74
+ _blendLookAt;
75
+ _eye;
76
+ _lookAt;
77
+ _dragging;
78
+ _lastX;
79
+ _lastY;
80
+ _warnedNear = false;
81
+ /**
82
+ * @param target - Node to follow.
83
+ * @param options - Options; unspecified ones take their defaults.
84
+ */ constructor(target, options){
85
+ super();
86
+ this.options = {
87
+ ...defaultOptions(),
88
+ ...options
89
+ };
90
+ this._target = target;
91
+ this._yaw = 0;
92
+ this._pitch = this.options.chasePitch;
93
+ this._pivot = new Vector3();
94
+ this._lastTargetPos = new Vector3();
95
+ this._distance = this.options.armLength;
96
+ this._idleTime = 0;
97
+ this._speed = 0;
98
+ this._baseFovY = 0;
99
+ this._snap = true;
100
+ this._blendTime = 0;
101
+ this._blendElapsed = 0;
102
+ this._blendEye = new Vector3();
103
+ this._blendLookAt = new Vector3();
104
+ this._eye = new Vector3();
105
+ this._lookAt = new Vector3();
106
+ this._dragging = false;
107
+ this._lastX = 0;
108
+ this._lastY = 0;
109
+ }
110
+ /** @override */ get updatePhase() {
111
+ return 'late';
112
+ }
113
+ /** The node being followed. */ get target() {
114
+ return this._target;
115
+ }
116
+ /** Horizontal angle of the arm. 0 puts the camera on the pivot's +Z side. */ get yaw() {
117
+ return this._yaw;
118
+ }
119
+ set yaw(val) {
120
+ this._yaw = val;
121
+ }
122
+ /** Vertical angle of the arm, clamped to the pitch limits. */ get pitch() {
123
+ return this._pitch;
124
+ }
125
+ set pitch(val) {
126
+ this._pitch = Math.min(Math.max(val, this.options.minPitch), this.options.maxPitch);
127
+ }
128
+ /** Current camera distance from the pivot, after collision. */ get distance() {
129
+ return this._distance;
130
+ }
131
+ /** Speed of the target in units per second, estimated from its movement. */ get targetSpeed() {
132
+ return this._speed;
133
+ }
134
+ /**
135
+ * Switches to another target, e.g. when the player gets into a vehicle.
136
+ *
137
+ * @param target - Node to follow.
138
+ * @param options - `blendTime`: seconds to ease from the current view to the new
139
+ * one, 0 to cut. `options`: options to change at the same time.
140
+ */ setTarget(target, options) {
141
+ const camera = this._getCamera();
142
+ this._blendTime = options?.blendTime ?? 0;
143
+ this._blendElapsed = 0;
144
+ if (camera && this._blendTime > 0 && !this._snap) {
145
+ this._blendEye.set(this._eye);
146
+ this._blendLookAt.set(this._lookAt);
147
+ } else {
148
+ this._blendTime = 0;
149
+ }
150
+ Object.assign(this.options, options?.options ?? {});
151
+ this._target = target;
152
+ this._snap = true;
153
+ }
154
+ /**
155
+ * Turns the camera. Call every frame with the frame's look input, such as the
156
+ * value of a look action.
157
+ *
158
+ * @param x - Radians to turn right.
159
+ * @param y - Radians to turn up.
160
+ */ addLookInput(x, y) {
161
+ if (x !== 0 || y !== 0) {
162
+ this._yaw -= x;
163
+ this.pitch = this._pitch - y;
164
+ this._idleTime = 0;
165
+ }
166
+ }
167
+ /**
168
+ * Zooms the camera. The arm length is scaled by `exp(amount)`: positive moves
169
+ * the camera out.
170
+ *
171
+ * @param amount - Zoom amount.
172
+ */ addZoomInput(amount) {
173
+ const o = this.options;
174
+ o.armLength = Math.min(Math.max(o.armLength * Math.exp(amount), o.minArmLength), o.maxArmLength);
175
+ }
176
+ /** Jumps to the wanted view on the next update, without lag or easing. */ snap() {
177
+ this._snap = true;
178
+ this._blendTime = 0;
179
+ }
180
+ /** @override */ reset() {
181
+ this._snap = true;
182
+ this._blendTime = 0;
183
+ }
184
+ /** @override */ _onMouseDown(evt) {
185
+ if (this.options.mouseButtons.includes(evt.button)) {
186
+ this._dragging = true;
187
+ this._lastX = evt.offsetX;
188
+ this._lastY = evt.offsetY;
189
+ return true;
190
+ }
191
+ return false;
192
+ }
193
+ /** @override */ _onMouseUp(evt) {
194
+ if (this._dragging && this.options.mouseButtons.includes(evt.button)) {
195
+ this._dragging = false;
196
+ return true;
197
+ }
198
+ return false;
199
+ }
200
+ /** @override */ _onMouseMove(evt) {
201
+ if (this._dragging) {
202
+ const s = this.options.mouseSensitivity;
203
+ this.addLookInput((evt.offsetX - this._lastX) * s, -(evt.offsetY - this._lastY) * s);
204
+ this._lastX = evt.offsetX;
205
+ this._lastY = evt.offsetY;
206
+ return true;
207
+ }
208
+ return false;
209
+ }
210
+ /** @override */ _onMouseWheel(evt) {
211
+ this.addZoomInput(evt.deltaY * 0.001);
212
+ return true;
213
+ }
214
+ /** @override */ _onUpdate(dt) {
215
+ const camera = this._getCamera();
216
+ const target = this._target;
217
+ if (!camera || !target) {
218
+ return;
219
+ }
220
+ const o = this.options;
221
+ const targetPos = target.getWorldPosition();
222
+ const wantedPivot = Vector3.add(targetPos, o.pivotOffset);
223
+ if (this._snap) {
224
+ this._pivot.set(wantedPivot);
225
+ this._lastTargetPos.set(targetPos);
226
+ this._speed = 0;
227
+ this._idleTime = o.recenterDelay;
228
+ if (o.mode === 'chase') {
229
+ this._yaw = this._chaseYaw(target);
230
+ this.pitch = o.chasePitch;
231
+ }
232
+ } else {
233
+ // Exponential approach: frame-rate independent
234
+ const t = o.positionLag > 0 ? 1 - Math.exp(-o.positionLag * dt) : 1;
235
+ this._pivot.combineBy(wantedPivot, 1 - t, t);
236
+ if (dt > 0) {
237
+ const speed = Vector3.distance(targetPos, this._lastTargetPos) / dt;
238
+ this._speed += (speed - this._speed) * (1 - Math.exp(-8 * dt));
239
+ }
240
+ this._lastTargetPos.set(targetPos);
241
+ this._idleTime += dt;
242
+ if (o.mode === 'chase' && this._idleTime >= o.recenterDelay && this._speed >= o.recenterMinSpeed) {
243
+ const t = 1 - Math.exp(-o.chaseStiffness * dt);
244
+ let diff = this._chaseYaw(target) - this._yaw;
245
+ // Shortest way round
246
+ diff = Math.atan2(Math.sin(diff), Math.cos(diff));
247
+ this._yaw += diff * t;
248
+ this.pitch = this._pitch + (o.chasePitch - this._pitch) * t;
249
+ }
250
+ }
251
+ // Spring arm: sweep from the pivot back along the view direction
252
+ const cosPitch = Math.cos(this._pitch);
253
+ const back = new Vector3(Math.sin(this._yaw) * cosPitch, Math.sin(this._pitch), Math.cos(this._yaw) * cosPitch);
254
+ const free = this._sweep(back, o.armLength);
255
+ if (this._snap || free < this._distance) {
256
+ this._distance = free;
257
+ } else {
258
+ this._distance = Math.min(free, this._distance + o.zoomOutSpeed * dt);
259
+ }
260
+ // Never on the pivot itself: looking at the point the eye is on has no direction
261
+ this._distance = Math.max(this._distance, MIN_DISTANCE);
262
+ this._lookAt.set(this._pivot);
263
+ Vector3.combine(this._pivot, back, 1, this._distance, this._eye);
264
+ let eye = this._eye;
265
+ let lookAt = this._lookAt;
266
+ if (this._blendTime > 0) {
267
+ this._blendElapsed += dt;
268
+ const x = Math.min(this._blendElapsed / this._blendTime, 1);
269
+ const s = x * x * (3 - 2 * x);
270
+ eye = Vector3.combine(this._blendEye, this._eye, 1 - s, s);
271
+ lookAt = Vector3.combine(this._blendLookAt, this._lookAt, 1 - s, s);
272
+ if (x >= 1) {
273
+ this._blendTime = 0;
274
+ }
275
+ }
276
+ camera.lookAt(eye, lookAt, Vector3.axisPY());
277
+ if (camera.isPerspective()) {
278
+ const perspective = camera;
279
+ if (o.fovBoost) {
280
+ // The field of view without boost is taken when boosting starts
281
+ if (!this._baseFovY) {
282
+ this._baseFovY = perspective.fovY;
283
+ }
284
+ const k = Math.min(this._speed / o.fovBoost.maxSpeed, 1);
285
+ perspective.fovY = this._baseFovY + o.fovBoost.maxBoost * k;
286
+ } else if (this._baseFovY) {
287
+ // Boost was turned off: restore once, then leave the field of view alone
288
+ perspective.fovY = this._baseFovY;
289
+ this._baseFovY = 0;
290
+ }
291
+ }
292
+ this._snap = false;
293
+ }
294
+ /** Yaw that puts the camera behind the target */ _chaseYaw(target) {
295
+ const fwd = target.worldMatrix.transformVectorAffine(this.options.forwardAxis, new Vector3());
296
+ if (fwd.x === 0 && fwd.z === 0) {
297
+ return this._yaw;
298
+ }
299
+ return Math.atan2(-fwd.x, -fwd.z);
300
+ }
301
+ /** How far the camera can go back from the pivot along `dir`, up to `length` */ _sweep(dir, length) {
302
+ const camera = this._getCamera();
303
+ const world = camera?.scene?.physicsWorld;
304
+ if (!world || length <= 0) {
305
+ return length;
306
+ }
307
+ const o = this.options;
308
+ let radius = o.probeRadius;
309
+ if (camera.isPerspective()) {
310
+ // The near plane's corners are this far from the eye: a smaller sphere
311
+ // lets them into a wall the sphere itself stopped short of
312
+ const p = camera;
313
+ const halfHeight = p.near * Math.tan(p.fovY / 2);
314
+ const nearRadius = Math.hypot(p.near, halfHeight, halfHeight * p.aspect);
315
+ if (nearRadius > LARGE_NEAR_RADIUS && !this._warnedNear) {
316
+ this._warnedNear = true;
317
+ console.warn(`FollowCameraController: the camera's near plane (${p.near}) is far from the eye, so ` + `the camera keeps ${nearRadius.toFixed(2)} away from walls and is pushed in close in ` + 'narrow places; set the near plane to about 0.1');
318
+ }
319
+ radius = Math.max(radius, nearRadius);
320
+ }
321
+ const options = {
322
+ layerMask: o.collisionMask,
323
+ exclude: o.exclude ?? this._target?.physics ?? null
324
+ };
325
+ let hit = world.shapeCast({
326
+ type: 'sphere',
327
+ radius
328
+ }, this._pivot, identity, dir, length, options);
329
+ if (hit && hit.distance <= START_OVERLAP && radius > o.probeRadius) {
330
+ // The sphere is already in a wall at the pivot: there is no room for the
331
+ // near plane anyway, so fall back to the small probe rather than the pivot
332
+ hit = world.shapeCast({
333
+ type: 'sphere',
334
+ radius: o.probeRadius
335
+ }, this._pivot, identity, dir, length, options);
336
+ }
337
+ return hit ? hit.distance : length;
338
+ }
339
+ }
340
+
341
+ export { FollowCameraController };
342
+ //# sourceMappingURL=follow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follow.js","sources":["../../src/camera/follow.ts"],"sourcesContent":["import type { Nullable } from '@zephyr3d/base';\r\nimport { Quaternion, Vector3 } from '@zephyr3d/base';\r\nimport type { IControllerMouseEvent, IControllerWheelEvent, CameraControllerUpdatePhase } from './base';\r\nimport { BaseCameraController } from './base';\r\nimport type { SceneNode } from '../scene/scene_node';\r\nimport type { NodePhysics } from '../physics/node_physics';\r\n\r\n/**\r\n * Options of {@link FollowCameraController}. Angles are in radians, distances in\r\n * world units, rates in 1/s.\r\n *\r\n * @public\r\n */\r\nexport interface FollowCameraOptions {\r\n /**\r\n * `'free'`: the player turns the camera; it stays where it was turned.\r\n * `'chase'`: as free, but after `recenterDelay` seconds without look input the\r\n * camera swings back behind the target while the target moves.\r\n */\r\n mode: 'free' | 'chase';\r\n /** World-space offset from the target's origin to the point the camera orbits and looks at. */\r\n pivotOffset: Vector3;\r\n /** Wanted distance from the pivot. Changed by zoom input within the limits below. */\r\n armLength: number;\r\n minArmLength: number;\r\n maxArmLength: number;\r\n /** Lowest and highest pitch. Positive pitch puts the camera above the pivot, looking down. */\r\n minPitch: number;\r\n maxPitch: number;\r\n /** How fast the pivot catches up with the target; 0 follows rigidly. */\r\n positionLag: number;\r\n /** Chase mode: the target's local forward axis. */\r\n forwardAxis: Vector3;\r\n /** Chase mode: pitch the camera returns to. */\r\n chasePitch: number;\r\n /** Chase mode: how fast the camera swings back behind the target. */\r\n chaseStiffness: number;\r\n /** Chase mode: seconds without look input before swinging back. */\r\n recenterDelay: number;\r\n /** Chase mode: the target must move at least this fast for the camera to swing back. */\r\n recenterMinSpeed: number;\r\n /**\r\n * Least radius of the sphere swept from the pivot to the camera. For a\r\n * perspective camera the sweep uses at least the distance from the eye to the\r\n * near plane's corners, or the near plane would cut into walls; keep the near\r\n * plane small (around 0.1) so that this stays small too.\r\n */\r\n probeRadius: number;\r\n /** Collider layers that block the camera, as bits `1 << layer`. */\r\n collisionMask: number;\r\n /** Physics object the sweep ignores. Defaults to the target's own `physics`. */\r\n exclude: Nullable<NodePhysics>;\r\n /** How fast the camera moves back out after an obstacle clears. Moving in is immediate. */\r\n zoomOutSpeed: number;\r\n /** Radians per pixel of mouse drag, for input through `camera.handleEvent`. */\r\n mouseSensitivity: number;\r\n /** Mouse buttons (as `MouseEvent.button`) that rotate the camera when dragged; empty for none. */\r\n mouseButtons: number[];\r\n /**\r\n * Widen the field of view with the target's speed: by `maxBoost` at `maxSpeed`\r\n * and above. Perspective cameras only; null disables it.\r\n */\r\n fovBoost: Nullable<{ maxBoost: number; maxSpeed: number }>;\r\n}\r\n\r\nconst defaultOptions = (): FollowCameraOptions => ({\r\n mode: 'free',\r\n pivotOffset: new Vector3(0, 1.5, 0),\r\n armLength: 4,\r\n minArmLength: 1.5,\r\n maxArmLength: 12,\r\n minPitch: -1.0,\r\n maxPitch: 1.3,\r\n positionLag: 10,\r\n forwardAxis: new Vector3(0, 0, 1),\r\n chasePitch: 0.3,\r\n chaseStiffness: 3,\r\n recenterDelay: 1.5,\r\n recenterMinSpeed: 1,\r\n probeRadius: 0.15,\r\n collisionMask: ~0,\r\n exclude: null,\r\n zoomOutSpeed: 4,\r\n mouseSensitivity: 0.005,\r\n mouseButtons: [0, 2],\r\n fovBoost: null\r\n});\r\n\r\nconst identity = Quaternion.identity();\r\n/** Closest the camera comes to the pivot */\r\nconst MIN_DISTANCE = 0.05;\r\n/** A sweep hit closer than this started inside something */\r\nconst START_OVERLAP = 1e-3;\r\n/** Above this, a near plane is warned about as too far from the eye */\r\nconst LARGE_NEAR_RADIUS = 0.5;\r\n\r\n/**\r\n * Third-person camera on a spring arm.\r\n *\r\n * The camera orbits a pivot above its target at `armLength`, turned by look\r\n * input. A sphere is swept from the pivot to the camera through the scene's\r\n * physics world: an obstacle pulls the camera in at once, and it eases back out\r\n * once clear. In `'chase'` mode it swings back behind a moving target when the\r\n * player stops turning it, as driving games do.\r\n *\r\n * Its {@link FollowCameraController.updatePhase} is `'late'`: it is updated after\r\n * physics, so it follows the pose of the target rendered this frame. Feed it look\r\n * input from an action map, or let it read mouse drags through `camera.handleEvent`.\r\n *\r\n * The camera should have no parent; it is placed in world space.\r\n *\r\n * @example\r\n * ```ts\r\n * const follow = new FollowCameraController(car, { mode: 'chase', armLength: 7 });\r\n * camera.controller = follow;\r\n * myApp.on('tick', () => {\r\n * const look = driving.vector2('look');\r\n * follow.addLookInput(look.x, look.y);\r\n * });\r\n * ```\r\n *\r\n * @public\r\n */\r\nexport class FollowCameraController extends BaseCameraController {\r\n /** Options; may be changed at any time. */\r\n readonly options: FollowCameraOptions;\r\n private _target: Nullable<SceneNode>;\r\n private _yaw: number;\r\n private _pitch: number;\r\n private readonly _pivot: Vector3;\r\n private readonly _lastTargetPos: Vector3;\r\n private _distance: number;\r\n private _idleTime: number;\r\n private _speed: number;\r\n private _baseFovY: number;\r\n private _snap: boolean;\r\n private _blendTime: number;\r\n private _blendElapsed: number;\r\n private readonly _blendEye: Vector3;\r\n private readonly _blendLookAt: Vector3;\r\n private readonly _eye: Vector3;\r\n private readonly _lookAt: Vector3;\r\n private _dragging: boolean;\r\n private _lastX: number;\r\n private _lastY: number;\r\n private _warnedNear = false;\r\n /**\r\n * @param target - Node to follow.\r\n * @param options - Options; unspecified ones take their defaults.\r\n */\r\n constructor(target: Nullable<SceneNode>, options?: Partial<FollowCameraOptions>) {\r\n super();\r\n this.options = { ...defaultOptions(), ...options };\r\n this._target = target;\r\n this._yaw = 0;\r\n this._pitch = this.options.chasePitch;\r\n this._pivot = new Vector3();\r\n this._lastTargetPos = new Vector3();\r\n this._distance = this.options.armLength;\r\n this._idleTime = 0;\r\n this._speed = 0;\r\n this._baseFovY = 0;\r\n this._snap = true;\r\n this._blendTime = 0;\r\n this._blendElapsed = 0;\r\n this._blendEye = new Vector3();\r\n this._blendLookAt = new Vector3();\r\n this._eye = new Vector3();\r\n this._lookAt = new Vector3();\r\n this._dragging = false;\r\n this._lastX = 0;\r\n this._lastY = 0;\r\n }\r\n /** @override */\r\n get updatePhase(): CameraControllerUpdatePhase {\r\n return 'late';\r\n }\r\n /** The node being followed. */\r\n get target() {\r\n return this._target;\r\n }\r\n /** Horizontal angle of the arm. 0 puts the camera on the pivot's +Z side. */\r\n get yaw() {\r\n return this._yaw;\r\n }\r\n set yaw(val: number) {\r\n this._yaw = val;\r\n }\r\n /** Vertical angle of the arm, clamped to the pitch limits. */\r\n get pitch() {\r\n return this._pitch;\r\n }\r\n set pitch(val: number) {\r\n this._pitch = Math.min(Math.max(val, this.options.minPitch), this.options.maxPitch);\r\n }\r\n /** Current camera distance from the pivot, after collision. */\r\n get distance() {\r\n return this._distance;\r\n }\r\n /** Speed of the target in units per second, estimated from its movement. */\r\n get targetSpeed() {\r\n return this._speed;\r\n }\r\n /**\r\n * Switches to another target, e.g. when the player gets into a vehicle.\r\n *\r\n * @param target - Node to follow.\r\n * @param options - `blendTime`: seconds to ease from the current view to the new\r\n * one, 0 to cut. `options`: options to change at the same time.\r\n */\r\n setTarget(\r\n target: Nullable<SceneNode>,\r\n options?: { blendTime?: number; options?: Partial<FollowCameraOptions> }\r\n ) {\r\n const camera = this._getCamera();\r\n this._blendTime = options?.blendTime ?? 0;\r\n this._blendElapsed = 0;\r\n if (camera && this._blendTime > 0 && !this._snap) {\r\n this._blendEye.set(this._eye);\r\n this._blendLookAt.set(this._lookAt);\r\n } else {\r\n this._blendTime = 0;\r\n }\r\n Object.assign(this.options, options?.options ?? {});\r\n this._target = target;\r\n this._snap = true;\r\n }\r\n /**\r\n * Turns the camera. Call every frame with the frame's look input, such as the\r\n * value of a look action.\r\n *\r\n * @param x - Radians to turn right.\r\n * @param y - Radians to turn up.\r\n */\r\n addLookInput(x: number, y: number) {\r\n if (x !== 0 || y !== 0) {\r\n this._yaw -= x;\r\n this.pitch = this._pitch - y;\r\n this._idleTime = 0;\r\n }\r\n }\r\n /**\r\n * Zooms the camera. The arm length is scaled by `exp(amount)`: positive moves\r\n * the camera out.\r\n *\r\n * @param amount - Zoom amount.\r\n */\r\n addZoomInput(amount: number) {\r\n const o = this.options;\r\n o.armLength = Math.min(Math.max(o.armLength * Math.exp(amount), o.minArmLength), o.maxArmLength);\r\n }\r\n /** Jumps to the wanted view on the next update, without lag or easing. */\r\n snap() {\r\n this._snap = true;\r\n this._blendTime = 0;\r\n }\r\n /** @override */\r\n reset() {\r\n this._snap = true;\r\n this._blendTime = 0;\r\n }\r\n /** @override */\r\n protected _onMouseDown(evt: IControllerMouseEvent): boolean {\r\n if (this.options.mouseButtons.includes(evt.button)) {\r\n this._dragging = true;\r\n this._lastX = evt.offsetX;\r\n this._lastY = evt.offsetY;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /** @override */\r\n protected _onMouseUp(evt: IControllerMouseEvent): boolean {\r\n if (this._dragging && this.options.mouseButtons.includes(evt.button)) {\r\n this._dragging = false;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /** @override */\r\n protected _onMouseMove(evt: IControllerMouseEvent): boolean {\r\n if (this._dragging) {\r\n const s = this.options.mouseSensitivity;\r\n this.addLookInput((evt.offsetX - this._lastX) * s, -(evt.offsetY - this._lastY) * s);\r\n this._lastX = evt.offsetX;\r\n this._lastY = evt.offsetY;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /** @override */\r\n protected _onMouseWheel(evt: IControllerWheelEvent): boolean {\r\n this.addZoomInput(evt.deltaY * 0.001);\r\n return true;\r\n }\r\n /** @override */\r\n protected _onUpdate(dt: number) {\r\n const camera = this._getCamera();\r\n const target = this._target;\r\n if (!camera || !target) {\r\n return;\r\n }\r\n const o = this.options;\r\n const targetPos = target.getWorldPosition();\r\n const wantedPivot = Vector3.add(targetPos, o.pivotOffset);\r\n if (this._snap) {\r\n this._pivot.set(wantedPivot);\r\n this._lastTargetPos.set(targetPos);\r\n this._speed = 0;\r\n this._idleTime = o.recenterDelay;\r\n if (o.mode === 'chase') {\r\n this._yaw = this._chaseYaw(target);\r\n this.pitch = o.chasePitch;\r\n }\r\n } else {\r\n // Exponential approach: frame-rate independent\r\n const t = o.positionLag > 0 ? 1 - Math.exp(-o.positionLag * dt) : 1;\r\n this._pivot.combineBy(wantedPivot, 1 - t, t);\r\n if (dt > 0) {\r\n const speed = Vector3.distance(targetPos, this._lastTargetPos) / dt;\r\n this._speed += (speed - this._speed) * (1 - Math.exp(-8 * dt));\r\n }\r\n this._lastTargetPos.set(targetPos);\r\n this._idleTime += dt;\r\n if (o.mode === 'chase' && this._idleTime >= o.recenterDelay && this._speed >= o.recenterMinSpeed) {\r\n const t = 1 - Math.exp(-o.chaseStiffness * dt);\r\n let diff = this._chaseYaw(target) - this._yaw;\r\n // Shortest way round\r\n diff = Math.atan2(Math.sin(diff), Math.cos(diff));\r\n this._yaw += diff * t;\r\n this.pitch = this._pitch + (o.chasePitch - this._pitch) * t;\r\n }\r\n }\r\n // Spring arm: sweep from the pivot back along the view direction\r\n const cosPitch = Math.cos(this._pitch);\r\n const back = new Vector3(\r\n Math.sin(this._yaw) * cosPitch,\r\n Math.sin(this._pitch),\r\n Math.cos(this._yaw) * cosPitch\r\n );\r\n const free = this._sweep(back, o.armLength);\r\n if (this._snap || free < this._distance) {\r\n this._distance = free;\r\n } else {\r\n this._distance = Math.min(free, this._distance + o.zoomOutSpeed * dt);\r\n }\r\n // Never on the pivot itself: looking at the point the eye is on has no direction\r\n this._distance = Math.max(this._distance, MIN_DISTANCE);\r\n this._lookAt.set(this._pivot);\r\n Vector3.combine(this._pivot, back, 1, this._distance, this._eye);\r\n let eye = this._eye;\r\n let lookAt = this._lookAt;\r\n if (this._blendTime > 0) {\r\n this._blendElapsed += dt;\r\n const x = Math.min(this._blendElapsed / this._blendTime, 1);\r\n const s = x * x * (3 - 2 * x);\r\n eye = Vector3.combine(this._blendEye, this._eye, 1 - s, s);\r\n lookAt = Vector3.combine(this._blendLookAt, this._lookAt, 1 - s, s);\r\n if (x >= 1) {\r\n this._blendTime = 0;\r\n }\r\n }\r\n camera.lookAt(eye, lookAt, Vector3.axisPY());\r\n if (camera.isPerspective()) {\r\n const perspective = camera as unknown as { fovY: number };\r\n if (o.fovBoost) {\r\n // The field of view without boost is taken when boosting starts\r\n if (!this._baseFovY) {\r\n this._baseFovY = perspective.fovY;\r\n }\r\n const k = Math.min(this._speed / o.fovBoost.maxSpeed, 1);\r\n perspective.fovY = this._baseFovY + o.fovBoost.maxBoost * k;\r\n } else if (this._baseFovY) {\r\n // Boost was turned off: restore once, then leave the field of view alone\r\n perspective.fovY = this._baseFovY;\r\n this._baseFovY = 0;\r\n }\r\n }\r\n this._snap = false;\r\n }\r\n /** Yaw that puts the camera behind the target */\r\n private _chaseYaw(target: SceneNode) {\r\n const fwd = target.worldMatrix.transformVectorAffine(this.options.forwardAxis, new Vector3());\r\n if (fwd.x === 0 && fwd.z === 0) {\r\n return this._yaw;\r\n }\r\n return Math.atan2(-fwd.x, -fwd.z);\r\n }\r\n /** How far the camera can go back from the pivot along `dir`, up to `length` */\r\n private _sweep(dir: Vector3, length: number) {\r\n const camera = this._getCamera();\r\n const world = camera?.scene?.physicsWorld;\r\n if (!world || length <= 0) {\r\n return length;\r\n }\r\n const o = this.options;\r\n let radius = o.probeRadius;\r\n if (camera!.isPerspective()) {\r\n // The near plane's corners are this far from the eye: a smaller sphere\r\n // lets them into a wall the sphere itself stopped short of\r\n const p = camera as unknown as { near: number; fovY: number; aspect: number };\r\n const halfHeight = p.near * Math.tan(p.fovY / 2);\r\n const nearRadius = Math.hypot(p.near, halfHeight, halfHeight * p.aspect);\r\n if (nearRadius > LARGE_NEAR_RADIUS && !this._warnedNear) {\r\n this._warnedNear = true;\r\n console.warn(\r\n `FollowCameraController: the camera's near plane (${p.near}) is far from the eye, so ` +\r\n `the camera keeps ${nearRadius.toFixed(2)} away from walls and is pushed in close in ` +\r\n 'narrow places; set the near plane to about 0.1'\r\n );\r\n }\r\n radius = Math.max(radius, nearRadius);\r\n }\r\n const options = { layerMask: o.collisionMask, exclude: o.exclude ?? this._target?.physics ?? null };\r\n let hit = world.shapeCast({ type: 'sphere', radius }, this._pivot, identity, dir, length, options);\r\n if (hit && hit.distance <= START_OVERLAP && radius > o.probeRadius) {\r\n // The sphere is already in a wall at the pivot: there is no room for the\r\n // near plane anyway, so fall back to the small probe rather than the pivot\r\n hit = world.shapeCast(\r\n { type: 'sphere', radius: o.probeRadius },\r\n this._pivot,\r\n identity,\r\n dir,\r\n length,\r\n options\r\n );\r\n }\r\n return hit ? hit.distance : length;\r\n }\r\n}\r\n"],"names":["defaultOptions","mode","pivotOffset","Vector3","armLength","minArmLength","maxArmLength","minPitch","maxPitch","positionLag","forwardAxis","chasePitch","chaseStiffness","recenterDelay","recenterMinSpeed","probeRadius","collisionMask","exclude","zoomOutSpeed","mouseSensitivity","mouseButtons","fovBoost","identity","Quaternion","MIN_DISTANCE","START_OVERLAP","LARGE_NEAR_RADIUS","FollowCameraController","BaseCameraController","_target","_yaw","_pitch","_pivot","_lastTargetPos","_distance","_idleTime","_speed","_baseFovY","_snap","_blendTime","_blendElapsed","_blendEye","_blendLookAt","_eye","_lookAt","_dragging","_lastX","_lastY","_warnedNear","target","options","updatePhase","yaw","val","pitch","Math","min","max","distance","targetSpeed","setTarget","camera","_getCamera","blendTime","set","Object","assign","addLookInput","x","y","addZoomInput","amount","o","exp","snap","reset","_onMouseDown","evt","includes","button","offsetX","offsetY","_onMouseUp","_onMouseMove","s","_onMouseWheel","deltaY","_onUpdate","dt","targetPos","getWorldPosition","wantedPivot","add","_chaseYaw","t","combineBy","speed","diff","atan2","sin","cos","cosPitch","back","free","_sweep","combine","eye","lookAt","axisPY","isPerspective","perspective","fovY","k","maxSpeed","maxBoost","fwd","worldMatrix","transformVectorAffine","z","dir","length","world","scene","physicsWorld","radius","p","halfHeight","near","tan","nearRadius","hypot","aspect","console","warn","toFixed","layerMask","physics","hit","shapeCast","type"],"mappings":"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"}
@@ -184,8 +184,10 @@ import { BaseCameraController } from './base.js';
184
184
  /**
185
185
  * {@inheritDoc BaseCameraController._onUpdate}
186
186
  * @override
187
- */ _onUpdate() {
187
+ */ _onUpdate(deltaTime) {
188
188
  const camera = this._getCamera();
189
+ // moveSpeed is per 60 Hz frame
190
+ const step = this.options.moveSpeed * deltaTime * 60;
189
191
  const x = camera.worldMatrix.getRow(0).xyz();
190
192
  x.y = 0;
191
193
  x.inplaceNormalize();
@@ -194,27 +196,27 @@ import { BaseCameraController } from './base.js';
194
196
  let changed = false;
195
197
  if (this.keyForward) {
196
198
  changed = true;
197
- move.subBy(Vector3.scale(z, this.options.moveSpeed));
199
+ move.subBy(Vector3.scale(z, step));
198
200
  }
199
201
  if (this.keyBackward) {
200
202
  changed = true;
201
- move.addBy(Vector3.scale(z, this.options.moveSpeed));
203
+ move.addBy(Vector3.scale(z, step));
202
204
  }
203
205
  if (this.keyUp) {
204
206
  changed = true;
205
- move.y += this.options.moveSpeed;
207
+ move.y += step;
206
208
  }
207
209
  if (this.keyDown) {
208
210
  changed = true;
209
- move.y -= this.options.moveSpeed;
211
+ move.y -= step;
210
212
  }
211
213
  if (this.keyLeft) {
212
214
  changed = true;
213
- move.subBy(Vector3.scale(x, this.options.moveSpeed));
215
+ move.subBy(Vector3.scale(x, step));
214
216
  }
215
217
  if (this.keyRight) {
216
218
  changed = true;
217
- move.addBy(Vector3.scale(x, this.options.moveSpeed));
219
+ move.addBy(Vector3.scale(x, step));
218
220
  }
219
221
  if (changed) {
220
222
  if (camera.parent) {
@@ -1 +1 @@
1
- {"version":3,"file":"fps.js","sources":["../../src/camera/fps.ts"],"sourcesContent":["import type { RequireOptionals } from '@zephyr3d/base';\r\nimport { Vector3, Quaternion, Matrix3x3, Matrix4x4 } from '@zephyr3d/base';\r\nimport type {\r\n IControllerKeydownEvent,\r\n IControllerKeyupEvent,\r\n IControllerPointerDownEvent,\r\n IControllerPointerMoveEvent,\r\n IControllerPointerUpEvent\r\n} from './base';\r\nimport { BaseCameraController } from './base';\r\n\r\n/**\r\n * Creation options for FPSCameraController\r\n * @public\r\n */\r\nexport interface FPSCameraControllerOptions {\r\n /** The control keys */\r\n controlKeys?: {\r\n up: string;\r\n down: string;\r\n forward: string;\r\n backward: string;\r\n left: string;\r\n right: string;\r\n };\r\n /** Moving speed */\r\n moveSpeed?: number;\r\n /** Rotating speed */\r\n rotateSpeed?: number;\r\n}\r\n\r\n/**\r\n * FPS camera controller\r\n * @public\r\n */\r\nexport class FPSCameraController extends BaseCameraController {\r\n /** @internal */\r\n private readonly options: RequireOptionals<FPSCameraControllerOptions>;\r\n /** @internal */\r\n private mouseDown!: boolean;\r\n /** @internal */\r\n private lastMouseX!: number;\r\n /** @internal */\r\n private lastMouseY!: number;\r\n /** @internal */\r\n private keyUp!: boolean;\r\n /** @internal */\r\n private keyDown!: boolean;\r\n /** @internal */\r\n private keyLeft!: boolean;\r\n /** @internal */\r\n private keyRight!: boolean;\r\n /** @internal */\r\n private keyForward!: boolean;\r\n /** @internal */\r\n private keyBackward!: boolean;\r\n /**\r\n * Creates an instance of FPSCameraController\r\n * @param options - The creation options\r\n */\r\n constructor(options?: FPSCameraControllerOptions) {\r\n super();\r\n this.options = Object.assign(\r\n {\r\n controlKeys: {\r\n up: 'KeyQ',\r\n down: 'KeyE',\r\n forward: 'KeyW',\r\n backward: 'KeyS',\r\n left: 'KeyA',\r\n right: 'KeyD'\r\n },\r\n moveSpeed: 0.2,\r\n rotateSpeed: 0.01\r\n },\r\n options || {}\r\n );\r\n this.reset();\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController.reset}\r\n * @override\r\n */\r\n reset() {\r\n this.mouseDown = false;\r\n this.lastMouseX = 0;\r\n this.lastMouseY = 0;\r\n this.keyUp = false;\r\n this.keyDown = false;\r\n this.keyLeft = false;\r\n this.keyRight = false;\r\n this.keyForward = false;\r\n this.keyBackward = false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onMouseDown}\r\n * @override\r\n */\r\n protected _onMouseDown(evt: IControllerPointerDownEvent) {\r\n if (evt.button === 0) {\r\n this.mouseDown = true;\r\n this.lastMouseX = evt.offsetX;\r\n this.lastMouseY = evt.offsetY;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onMouseUp}\r\n * @override\r\n */\r\n protected _onMouseUp(evt: IControllerPointerUpEvent) {\r\n if (evt.button === 0 && this.mouseDown) {\r\n this.mouseDown = false;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onMouseMove}\r\n * @override\r\n */\r\n protected _onMouseMove(evt: IControllerPointerMoveEvent) {\r\n const camera = this._getCamera()!;\r\n if (this.mouseDown) {\r\n const dx = evt.offsetX - this.lastMouseX;\r\n const dy = evt.offsetY - this.lastMouseY;\r\n this.lastMouseX = evt.offsetX;\r\n this.lastMouseY = evt.offsetY;\r\n const zAxis = camera.worldMatrix.getRow(2).xyz();\r\n const alpha = Math.atan2(zAxis.z, zAxis.x) + dx * this.options.rotateSpeed;\r\n const beta = Math.min(\r\n Math.PI / 2.1,\r\n Math.max(-Math.PI / 2.1, Math.asin(zAxis.y) + dy * this.options.rotateSpeed)\r\n );\r\n const newY = Math.sin(beta);\r\n const r = Math.sqrt(Math.max(0, 1 - newY * newY));\r\n const newZ = Math.sin(alpha) * r;\r\n const newX = Math.cos(alpha) * r;\r\n zAxis.setXYZ(newX, newY, newZ).inplaceNormalize();\r\n const XAxis = Vector3.cross(Vector3.axisPY(), zAxis).inplaceNormalize();\r\n const YAxis = Vector3.cross(zAxis, XAxis).inplaceNormalize();\r\n const rotation = Quaternion.fromRotationMatrix(\r\n new Matrix3x3([XAxis.x, XAxis.y, XAxis.z, YAxis.x, YAxis.y, YAxis.z, zAxis.x, zAxis.y, zAxis.z])\r\n );\r\n if (!camera.parent) {\r\n camera.rotation.set(rotation);\r\n } else {\r\n const pos = new Vector3();\r\n const scale = new Vector3();\r\n camera.worldMatrix.decompose(scale, null, pos);\r\n const newWorldMatrix = Matrix4x4.scaling(scale).rotateLeft(rotation).translateLeft(pos);\r\n const newLocalMatrix = camera.parent\r\n ? newWorldMatrix.multiplyLeftAffine(Matrix4x4.invertAffine(camera.parent.worldMatrix))\r\n : newWorldMatrix;\r\n newLocalMatrix.decompose(scale, rotation, pos);\r\n camera.position.set(pos);\r\n camera.scale.set(scale);\r\n camera.rotation.set(rotation);\r\n }\r\n return true;\r\n }\r\n return false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onKeyDown}\r\n * @override\r\n */\r\n protected _onKeyDown(evt: IControllerKeydownEvent) {\r\n switch (evt.code) {\r\n case this.options.controlKeys.up:\r\n this.keyUp = true;\r\n break;\r\n case this.options.controlKeys.down:\r\n this.keyDown = true;\r\n break;\r\n case this.options.controlKeys.left:\r\n this.keyLeft = true;\r\n break;\r\n case this.options.controlKeys.right:\r\n this.keyRight = true;\r\n break;\r\n case this.options.controlKeys.forward:\r\n this.keyForward = true;\r\n break;\r\n case this.options.controlKeys.backward:\r\n this.keyBackward = true;\r\n break;\r\n default:\r\n return false;\r\n }\r\n return true;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onKeyUp}\r\n * @override\r\n */\r\n protected _onKeyUp(evt: IControllerKeyupEvent) {\r\n switch (evt.code) {\r\n case this.options.controlKeys.up:\r\n this.keyUp = false;\r\n break;\r\n case this.options.controlKeys.down:\r\n this.keyDown = false;\r\n break;\r\n case this.options.controlKeys.left:\r\n this.keyLeft = false;\r\n break;\r\n case this.options.controlKeys.right:\r\n this.keyRight = false;\r\n break;\r\n case this.options.controlKeys.forward:\r\n this.keyForward = false;\r\n break;\r\n case this.options.controlKeys.backward:\r\n this.keyBackward = false;\r\n break;\r\n default:\r\n return false;\r\n }\r\n return true;\r\n }\r\n /**\r\n * Set options\r\n * @param opt - options\r\n */\r\n setOptions(opt?: FPSCameraControllerOptions) {\r\n Object.assign(this.options, opt ?? {});\r\n this.reset();\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onUpdate}\r\n * @override\r\n */\r\n protected _onUpdate() {\r\n const camera = this._getCamera()!;\r\n const x = camera.worldMatrix.getRow(0).xyz();\r\n x.y = 0;\r\n x.inplaceNormalize();\r\n const z = camera.worldMatrix.getRow(2).xyz().inplaceNormalize();\r\n const move = new Vector3(0, 0, 0);\r\n let changed = false;\r\n if (this.keyForward) {\r\n changed = true;\r\n move.subBy(Vector3.scale(z, this.options.moveSpeed));\r\n }\r\n if (this.keyBackward) {\r\n changed = true;\r\n move.addBy(Vector3.scale(z, this.options.moveSpeed));\r\n }\r\n if (this.keyUp) {\r\n changed = true;\r\n move.y += this.options.moveSpeed;\r\n }\r\n if (this.keyDown) {\r\n changed = true;\r\n move.y -= this.options.moveSpeed;\r\n }\r\n if (this.keyLeft) {\r\n changed = true;\r\n move.subBy(Vector3.scale(x, this.options.moveSpeed));\r\n }\r\n if (this.keyRight) {\r\n changed = true;\r\n move.addBy(Vector3.scale(x, this.options.moveSpeed));\r\n }\r\n if (changed) {\r\n if (camera.parent) {\r\n const pos = new Vector3();\r\n const scale = new Vector3();\r\n const rotation = new Quaternion();\r\n camera.worldMatrix.decompose(scale, rotation, pos);\r\n pos.addBy(move);\r\n const newWorldMatrix = Matrix4x4.scaling(scale).rotateLeft(rotation).translateLeft(pos);\r\n const newLocalMatrix = newWorldMatrix.multiplyLeftAffine(\r\n Matrix4x4.invertAffine(camera.parent.worldMatrix)\r\n );\r\n newLocalMatrix.decompose(scale, rotation, pos);\r\n camera.position.set(pos);\r\n camera.scale.set(scale);\r\n camera.rotation.set(rotation);\r\n } else {\r\n camera.moveBy(move);\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["FPSCameraController","BaseCameraController","options","Object","assign","controlKeys","up","down","forward","backward","left","right","moveSpeed","rotateSpeed","reset","mouseDown","lastMouseX","lastMouseY","keyUp","keyDown","keyLeft","keyRight","keyForward","keyBackward","_onMouseDown","evt","button","offsetX","offsetY","_onMouseUp","_onMouseMove","camera","_getCamera","dx","dy","zAxis","worldMatrix","getRow","xyz","alpha","Math","atan2","z","x","beta","min","PI","max","asin","y","newY","sin","r","sqrt","newZ","newX","cos","setXYZ","inplaceNormalize","XAxis","Vector3","cross","axisPY","YAxis","rotation","Quaternion","fromRotationMatrix","Matrix3x3","parent","set","pos","scale","decompose","newWorldMatrix","Matrix4x4","scaling","rotateLeft","translateLeft","newLocalMatrix","multiplyLeftAffine","invertAffine","position","_onKeyDown","code","_onKeyUp","setOptions","opt","move","changed","subBy","addBy","moveBy"],"mappings":"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"}
1
+ {"version":3,"file":"fps.js","sources":["../../src/camera/fps.ts"],"sourcesContent":["import type { RequireOptionals } from '@zephyr3d/base';\r\nimport { Vector3, Quaternion, Matrix3x3, Matrix4x4 } from '@zephyr3d/base';\r\nimport type { IControllerKeyboardEvent, IControllerMouseEvent } from './base';\r\nimport { BaseCameraController } from './base';\r\n\r\n/**\r\n * Creation options for FPSCameraController\r\n * @public\r\n */\r\nexport interface FPSCameraControllerOptions {\r\n /** The control keys */\r\n controlKeys?: {\r\n up: string;\r\n down: string;\r\n forward: string;\r\n backward: string;\r\n left: string;\r\n right: string;\r\n };\r\n /** Moving speed: world units per 1/60 s, independent of the actual frame rate. */\r\n moveSpeed?: number;\r\n /** Rotating speed */\r\n rotateSpeed?: number;\r\n}\r\n\r\n/**\r\n * FPS camera controller\r\n * @public\r\n */\r\nexport class FPSCameraController extends BaseCameraController {\r\n /** @internal */\r\n private readonly options: RequireOptionals<FPSCameraControllerOptions>;\r\n /** @internal */\r\n private mouseDown!: boolean;\r\n /** @internal */\r\n private lastMouseX!: number;\r\n /** @internal */\r\n private lastMouseY!: number;\r\n /** @internal */\r\n private keyUp!: boolean;\r\n /** @internal */\r\n private keyDown!: boolean;\r\n /** @internal */\r\n private keyLeft!: boolean;\r\n /** @internal */\r\n private keyRight!: boolean;\r\n /** @internal */\r\n private keyForward!: boolean;\r\n /** @internal */\r\n private keyBackward!: boolean;\r\n /**\r\n * Creates an instance of FPSCameraController\r\n * @param options - The creation options\r\n */\r\n constructor(options?: FPSCameraControllerOptions) {\r\n super();\r\n this.options = Object.assign(\r\n {\r\n controlKeys: {\r\n up: 'KeyQ',\r\n down: 'KeyE',\r\n forward: 'KeyW',\r\n backward: 'KeyS',\r\n left: 'KeyA',\r\n right: 'KeyD'\r\n },\r\n moveSpeed: 0.2,\r\n rotateSpeed: 0.01\r\n },\r\n options || {}\r\n );\r\n this.reset();\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController.reset}\r\n * @override\r\n */\r\n reset() {\r\n this.mouseDown = false;\r\n this.lastMouseX = 0;\r\n this.lastMouseY = 0;\r\n this.keyUp = false;\r\n this.keyDown = false;\r\n this.keyLeft = false;\r\n this.keyRight = false;\r\n this.keyForward = false;\r\n this.keyBackward = false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onMouseDown}\r\n * @override\r\n */\r\n protected _onMouseDown(evt: IControllerMouseEvent) {\r\n if (evt.button === 0) {\r\n this.mouseDown = true;\r\n this.lastMouseX = evt.offsetX;\r\n this.lastMouseY = evt.offsetY;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onMouseUp}\r\n * @override\r\n */\r\n protected _onMouseUp(evt: IControllerMouseEvent) {\r\n if (evt.button === 0 && this.mouseDown) {\r\n this.mouseDown = false;\r\n return true;\r\n }\r\n return false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onMouseMove}\r\n * @override\r\n */\r\n protected _onMouseMove(evt: IControllerMouseEvent) {\r\n const camera = this._getCamera()!;\r\n if (this.mouseDown) {\r\n const dx = evt.offsetX - this.lastMouseX;\r\n const dy = evt.offsetY - this.lastMouseY;\r\n this.lastMouseX = evt.offsetX;\r\n this.lastMouseY = evt.offsetY;\r\n const zAxis = camera.worldMatrix.getRow(2).xyz();\r\n const alpha = Math.atan2(zAxis.z, zAxis.x) + dx * this.options.rotateSpeed;\r\n const beta = Math.min(\r\n Math.PI / 2.1,\r\n Math.max(-Math.PI / 2.1, Math.asin(zAxis.y) + dy * this.options.rotateSpeed)\r\n );\r\n const newY = Math.sin(beta);\r\n const r = Math.sqrt(Math.max(0, 1 - newY * newY));\r\n const newZ = Math.sin(alpha) * r;\r\n const newX = Math.cos(alpha) * r;\r\n zAxis.setXYZ(newX, newY, newZ).inplaceNormalize();\r\n const XAxis = Vector3.cross(Vector3.axisPY(), zAxis).inplaceNormalize();\r\n const YAxis = Vector3.cross(zAxis, XAxis).inplaceNormalize();\r\n const rotation = Quaternion.fromRotationMatrix(\r\n new Matrix3x3([XAxis.x, XAxis.y, XAxis.z, YAxis.x, YAxis.y, YAxis.z, zAxis.x, zAxis.y, zAxis.z])\r\n );\r\n if (!camera.parent) {\r\n camera.rotation.set(rotation);\r\n } else {\r\n const pos = new Vector3();\r\n const scale = new Vector3();\r\n camera.worldMatrix.decompose(scale, null, pos);\r\n const newWorldMatrix = Matrix4x4.scaling(scale).rotateLeft(rotation).translateLeft(pos);\r\n const newLocalMatrix = camera.parent\r\n ? newWorldMatrix.multiplyLeftAffine(Matrix4x4.invertAffine(camera.parent.worldMatrix))\r\n : newWorldMatrix;\r\n newLocalMatrix.decompose(scale, rotation, pos);\r\n camera.position.set(pos);\r\n camera.scale.set(scale);\r\n camera.rotation.set(rotation);\r\n }\r\n return true;\r\n }\r\n return false;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onKeyDown}\r\n * @override\r\n */\r\n protected _onKeyDown(evt: IControllerKeyboardEvent) {\r\n switch (evt.code) {\r\n case this.options.controlKeys.up:\r\n this.keyUp = true;\r\n break;\r\n case this.options.controlKeys.down:\r\n this.keyDown = true;\r\n break;\r\n case this.options.controlKeys.left:\r\n this.keyLeft = true;\r\n break;\r\n case this.options.controlKeys.right:\r\n this.keyRight = true;\r\n break;\r\n case this.options.controlKeys.forward:\r\n this.keyForward = true;\r\n break;\r\n case this.options.controlKeys.backward:\r\n this.keyBackward = true;\r\n break;\r\n default:\r\n return false;\r\n }\r\n return true;\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onKeyUp}\r\n * @override\r\n */\r\n protected _onKeyUp(evt: IControllerKeyboardEvent) {\r\n switch (evt.code) {\r\n case this.options.controlKeys.up:\r\n this.keyUp = false;\r\n break;\r\n case this.options.controlKeys.down:\r\n this.keyDown = false;\r\n break;\r\n case this.options.controlKeys.left:\r\n this.keyLeft = false;\r\n break;\r\n case this.options.controlKeys.right:\r\n this.keyRight = false;\r\n break;\r\n case this.options.controlKeys.forward:\r\n this.keyForward = false;\r\n break;\r\n case this.options.controlKeys.backward:\r\n this.keyBackward = false;\r\n break;\r\n default:\r\n return false;\r\n }\r\n return true;\r\n }\r\n /**\r\n * Set options\r\n * @param opt - options\r\n */\r\n setOptions(opt?: FPSCameraControllerOptions) {\r\n Object.assign(this.options, opt ?? {});\r\n this.reset();\r\n }\r\n /**\r\n * {@inheritDoc BaseCameraController._onUpdate}\r\n * @override\r\n */\r\n protected _onUpdate(deltaTime: number) {\r\n const camera = this._getCamera()!;\r\n // moveSpeed is per 60 Hz frame\r\n const step = this.options.moveSpeed * deltaTime * 60;\r\n const x = camera.worldMatrix.getRow(0).xyz();\r\n x.y = 0;\r\n x.inplaceNormalize();\r\n const z = camera.worldMatrix.getRow(2).xyz().inplaceNormalize();\r\n const move = new Vector3(0, 0, 0);\r\n let changed = false;\r\n if (this.keyForward) {\r\n changed = true;\r\n move.subBy(Vector3.scale(z, step));\r\n }\r\n if (this.keyBackward) {\r\n changed = true;\r\n move.addBy(Vector3.scale(z, step));\r\n }\r\n if (this.keyUp) {\r\n changed = true;\r\n move.y += step;\r\n }\r\n if (this.keyDown) {\r\n changed = true;\r\n move.y -= step;\r\n }\r\n if (this.keyLeft) {\r\n changed = true;\r\n move.subBy(Vector3.scale(x, step));\r\n }\r\n if (this.keyRight) {\r\n changed = true;\r\n move.addBy(Vector3.scale(x, step));\r\n }\r\n if (changed) {\r\n if (camera.parent) {\r\n const pos = new Vector3();\r\n const scale = new Vector3();\r\n const rotation = new Quaternion();\r\n camera.worldMatrix.decompose(scale, rotation, pos);\r\n pos.addBy(move);\r\n const newWorldMatrix = Matrix4x4.scaling(scale).rotateLeft(rotation).translateLeft(pos);\r\n const newLocalMatrix = newWorldMatrix.multiplyLeftAffine(\r\n Matrix4x4.invertAffine(camera.parent.worldMatrix)\r\n );\r\n newLocalMatrix.decompose(scale, rotation, pos);\r\n camera.position.set(pos);\r\n camera.scale.set(scale);\r\n camera.rotation.set(rotation);\r\n } else {\r\n camera.moveBy(move);\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["FPSCameraController","BaseCameraController","options","Object","assign","controlKeys","up","down","forward","backward","left","right","moveSpeed","rotateSpeed","reset","mouseDown","lastMouseX","lastMouseY","keyUp","keyDown","keyLeft","keyRight","keyForward","keyBackward","_onMouseDown","evt","button","offsetX","offsetY","_onMouseUp","_onMouseMove","camera","_getCamera","dx","dy","zAxis","worldMatrix","getRow","xyz","alpha","Math","atan2","z","x","beta","min","PI","max","asin","y","newY","sin","r","sqrt","newZ","newX","cos","setXYZ","inplaceNormalize","XAxis","Vector3","cross","axisPY","YAxis","rotation","Quaternion","fromRotationMatrix","Matrix3x3","parent","set","pos","scale","decompose","newWorldMatrix","Matrix4x4","scaling","rotateLeft","translateLeft","newLocalMatrix","multiplyLeftAffine","invertAffine","position","_onKeyDown","code","_onKeyUp","setOptions","opt","_onUpdate","deltaTime","step","move","changed","subBy","addBy","moveBy"],"mappings":"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"}
@@ -28,7 +28,7 @@ import { BaseCameraController } from './base.js';
28
28
  damping: 1,
29
29
  rotateSpeed: 1,
30
30
  panSpeed: 1,
31
- zoomSpeed: 1,
31
+ zoomSpeed: 5,
32
32
  controls: {
33
33
  rotate: {
34
34
  button: 0,
@@ -139,7 +139,20 @@ import { BaseCameraController } from './base.js';
139
139
  * {@inheritDoc BaseCameraController._onMouseWheel}
140
140
  * @override
141
141
  */ _onMouseWheel(evt) {
142
- this.zoom(evt.deltaY);
142
+ // Same scroll handling as the editor camera (EditorCameraController._onMouseWheel)
143
+ let px = evt.deltaY;
144
+ if (evt.deltaMode === 1) {
145
+ px *= 16;
146
+ } else if (evt.deltaMode === 2) {
147
+ px *= window.innerHeight;
148
+ }
149
+ if (evt.ctrlKey) {
150
+ px *= 10;
151
+ }
152
+ if (evt.shiftKey) {
153
+ px *= 0.1;
154
+ }
155
+ this.zoom(Math.max(-100, Math.min(100, px)));
143
156
  return true;
144
157
  }
145
158
  /**
@@ -164,12 +177,18 @@ import { BaseCameraController } from './base.js';
164
177
  }
165
178
  return false;
166
179
  }
167
- zoom(dy) {
168
- const distance = Vector3.distance(this.eyePos, this.options.center);
169
- let t = dy > 0 ? this.options.zoomSpeed : dy < 0 ? -this.options.zoomSpeed : 0;
170
- t = Math.exp(t * 0.1);
171
- if (t > 1 || distance > 0.01) {
172
- this.eyePos.combineBy(this.options.center, t, 1 - t);
180
+ /**
181
+ * Moves the eye along the view direction by zoomSpeed per 100 pixels, away from the center for
182
+ * positive values; it stops short of the center instead of passing through it
183
+ */ zoom(px) {
184
+ const center = this.options.center;
185
+ const distance = Vector3.distance(this.eyePos, center);
186
+ if (distance < 1e-6 || px === 0) {
187
+ return;
188
+ }
189
+ const newDistance = Math.max(0.01, distance + this.options.zoomSpeed * px * 0.01);
190
+ if (newDistance !== distance) {
191
+ this.eyePos.combineBy(center, newDistance / distance, 1 - newDistance / distance);
173
192
  }
174
193
  }
175
194
  matchesControl(evt, control) {
@@ -204,18 +223,26 @@ import { BaseCameraController } from './base.js';
204
223
  /**
205
224
  * {@inheritDoc BaseCameraController._onUpdate}
206
225
  * @override
207
- */ _onUpdate() {
226
+ */ _onUpdate(deltaTime) {
208
227
  const camera = this._getCamera();
209
228
  const center = this.options.center;
229
+ // Velocities are per 60 Hz frame and decay by `damping` per frame. For `frames`
230
+ // such frames the velocity decays by `decay`, and the distance covered is the
231
+ // sum of the geometric series, `travel` times the current velocity. At 60 fps
232
+ // this is exactly one frame: travel 1, decay 1 - damping.
233
+ const frames = deltaTime * 60;
234
+ const damping = this.options.damping;
235
+ const decay = Math.pow(1 - damping, frames);
236
+ const travel = damping > 0 ? (1 - decay) / damping : frames;
210
237
  if (Math.abs(this.panVelocityX) > 0.0001 || Math.abs(this.panVelocityY) > 0.0001) {
211
238
  const right = this.xVector;
212
239
  const up = this.upVector;
213
- center.combineBy(right, 1, this.panVelocityX);
214
- center.combineBy(up, 1, this.panVelocityY);
215
- this.eyePos.combineBy(right, 1, this.panVelocityX);
216
- this.eyePos.combineBy(up, 1, this.panVelocityY);
217
- this.panVelocityX *= 1 - this.options.damping;
218
- this.panVelocityY *= 1 - this.options.damping;
240
+ center.combineBy(right, 1, this.panVelocityX * travel);
241
+ center.combineBy(up, 1, this.panVelocityY * travel);
242
+ this.eyePos.combineBy(right, 1, this.panVelocityX * travel);
243
+ this.eyePos.combineBy(up, 1, this.panVelocityY * travel);
244
+ this.panVelocityX *= decay;
245
+ this.panVelocityY *= decay;
219
246
  if (Math.abs(this.panVelocityX) < 0.0001) {
220
247
  this.panVelocityX = 0;
221
248
  }
@@ -224,16 +251,16 @@ import { BaseCameraController } from './base.js';
224
251
  }
225
252
  }
226
253
  if (Math.abs(this.rotateX) > 0.0001 || Math.abs(this.rotateY) > 0.0001) {
227
- Quaternion.fromAxisAngle(this.xVector, this.rotateX, this.quat);
254
+ Quaternion.fromAxisAngle(this.xVector, this.rotateX * travel, this.quat);
228
255
  this.quat.transform(this.eyePos.subBy(center), this.eyePos);
229
- Quaternion.fromEulerAngle(0, this.rotateY, 0, 'ZYX', this.quat);
256
+ Quaternion.fromEulerAngle(0, this.rotateY * travel, 0, 'ZYX', this.quat);
230
257
  this.quat.transform(this.eyePos, this.eyePos);
231
258
  this.quat.transform(this.xVector, this.xVector).inplaceNormalize();
232
259
  Vector3.normalize(this.eyePos, this.direction).inplaceNormalize();
233
260
  Vector3.cross(this.direction, this.xVector, this.upVector).inplaceNormalize();
234
261
  this.eyePos.addBy(center);
235
- this.rotateX *= 1 - this.options.damping;
236
- this.rotateY *= 1 - this.options.damping;
262
+ this.rotateX *= decay;
263
+ this.rotateY *= decay;
237
264
  if (Math.abs(this.rotateX) < 0.0001) {
238
265
  this.rotateX = 0;
239
266
  }