@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
@@ -1,4 +1,4 @@
1
- import { AABB, Vector3, Disposable, Matrix4x4, ClipState, Vector2 } from '@zephyr3d/base';
1
+ import { AABB, Vector3, BoxSide, Disposable, Matrix4x4, ClipState, Vector2 } from '@zephyr3d/base';
2
2
  import { Primitive } from './primitive.js';
3
3
  import { getVertexAttributeIndex, VERTEX_ATTRIB_POSITION, VERTEX_ATTRIB_TEXCOORD0, getVertexAttributeFormat } from '@zephyr3d/device';
4
4
 
@@ -10,6 +10,10 @@ const rotationValues = [
10
10
  Math.PI * 0.5,
11
11
  Math.PI
12
12
  ];
13
+ /**
14
+ * Frustum plane mask covering everything but the far plane, for a clipmap that
15
+ * reaches past it. @internal
16
+ */ const ALL_PLANES_EXCEPT_FAR = 0b111111 & ~(1 << BoxSide.BACK);
13
17
  /** @internal */ class Clipmap extends Disposable {
14
18
  _instanceDataPool;
15
19
  _instanceDataPoolSize;
@@ -37,6 +41,8 @@ const rotationValues = [
37
41
  _seamMesh;
38
42
  _seamMeshLines;
39
43
  _seamMeshAABB;
44
+ _skirtMesh;
45
+ _skirtMeshLines;
40
46
  _wireframe;
41
47
  constructor(resolution, extraInstanceBuffers, maxMipLevels = 64){
42
48
  super();
@@ -60,6 +66,7 @@ const rotationValues = [
60
66
  this.generateSeamMesh();
61
67
  this.generateTileMesh();
62
68
  this.generateTrimMesh();
69
+ this.generateSkirtMesh();
63
70
  }
64
71
  get wireframe() {
65
72
  return this._wireframe;
@@ -78,6 +85,7 @@ const rotationValues = [
78
85
  this.generateSeamMesh();
79
86
  this.generateTileMesh();
80
87
  this.generateTrimMesh();
88
+ this.generateSkirtMesh();
81
89
  }
82
90
  }
83
91
  allocInstanceBuffer() {
@@ -533,6 +541,112 @@ const rotationValues = [
533
541
  this._seamMeshLines.indexCount = indicesLines.length;
534
542
  this._seamMeshLines.primitiveType = 'line-list';
535
543
  }
544
+ /**
545
+ * Ring of quads welded to the outer boundary of the outermost level, whose
546
+ * outer edge the vertex shader is expected to push towards the horizon.
547
+ *
548
+ * The inner edge has to land on exactly the vertices the outermost tiles end
549
+ * on, or a displaced surface tears along the join: both sides evaluate the
550
+ * same wave function, so identical world positions are what keeps them
551
+ * identical. That boundary runs from `-2 * tileResolution` to
552
+ * `2 * tileResolution + 1` in the level's local units - the asymmetry is the
553
+ * `fillX`/`fillY` shift `gather` applies to the far tiles - which is
554
+ * `clipmapVertResolution` vertices a side, the same density the seam mesh
555
+ * uses.
556
+ *
557
+ * Outer vertices are flagged with `position.z = 1`. Every other clipmap mesh
558
+ * leaves z at 0 and the shader's clipmap matrix only reads xy, so the
559
+ * component is free to carry the flag without a second vertex stream.
560
+ */ generateSkirtMesh() {
561
+ const clipmapVertResolution = this._tileResolution * 4 + 2;
562
+ const lo = -2 * this._tileResolution;
563
+ const hi = 2 * this._tileResolution + 1;
564
+ // Unique positions around the perimeter: each side contributes all but its
565
+ // last vertex, which is the next side's first, so the loop closes without
566
+ // doubling the corners.
567
+ const perSide = clipmapVertResolution - 1;
568
+ const ringCount = perSide * 4;
569
+ const vertices = new Float32Array(ringCount * 2 * 3);
570
+ // Placeholder extent for the outer ring. The vertex shader relocates these
571
+ // vertices, so this only has to be outside the inner ring and finite.
572
+ const outerFactor = 8;
573
+ const centre = (lo + hi) * 0.5;
574
+ let n = 0;
575
+ const putRing = (index, x, y, outer)=>{
576
+ const px = outer ? centre + (x - centre) * outerFactor : x;
577
+ const py = outer ? centre + (y - centre) * outerFactor : y;
578
+ const base = (index + (outer ? ringCount : 0)) * 3;
579
+ vertices[base + 0] = px;
580
+ vertices[base + 1] = py;
581
+ vertices[base + 2] = outer ? 1 : 0;
582
+ };
583
+ for(let i = 0; i < perSide; i++){
584
+ putRing(n, lo + i, lo, false);
585
+ putRing(n, lo + i, lo, true);
586
+ n++;
587
+ }
588
+ for(let i = 0; i < perSide; i++){
589
+ putRing(n, hi, lo + i, false);
590
+ putRing(n, hi, lo + i, true);
591
+ n++;
592
+ }
593
+ for(let i = 0; i < perSide; i++){
594
+ putRing(n, hi - i, hi, false);
595
+ putRing(n, hi - i, hi, true);
596
+ n++;
597
+ }
598
+ for(let i = 0; i < perSide; i++){
599
+ putRing(n, lo, hi - i, false);
600
+ putRing(n, lo, hi - i, true);
601
+ n++;
602
+ }
603
+ const indices = new Uint16Array(ringCount * 6);
604
+ n = 0;
605
+ for(let k = 0; k < ringCount; k++){
606
+ const j = (k + 1) % ringCount;
607
+ indices[n++] = k;
608
+ indices[n++] = j;
609
+ indices[n++] = ringCount + j;
610
+ indices[n++] = k;
611
+ indices[n++] = ringCount + j;
612
+ indices[n++] = ringCount + k;
613
+ }
614
+ this._skirtMesh?.dispose();
615
+ this._skirtMesh = new Primitive();
616
+ this._skirtMesh.createAndSetVertexBuffer('position_f32x3', vertices);
617
+ this._skirtMesh.createAndSetVertexBuffer('tex0_f32x4', this.allocNonInstanceBuffer(0, 0, 0, 0), 'instance');
618
+ this._nonInstanceDataPoolSize++;
619
+ for (const fmt of this._extraInstanceBuffers){
620
+ this._skirtMesh.createAndSetVertexBuffer(fmt, this.allocNonInstanceBuffer(0, 0, 0, 0), 'instance');
621
+ this._nonInstanceDataPoolSize++;
622
+ }
623
+ this._skirtMesh.createAndSetIndexBuffer(indices);
624
+ this._skirtMesh.indexStart = 0;
625
+ this._skirtMesh.indexCount = indices.length;
626
+ this._skirtMesh.primitiveType = 'triangle-list';
627
+ const indicesLines = new Uint16Array(indices.length * 2);
628
+ for(let i = 0; i < indices.length / 3; i++){
629
+ indicesLines[i * 6 + 0] = indices[i * 3 + 0];
630
+ indicesLines[i * 6 + 1] = indices[i * 3 + 1];
631
+ indicesLines[i * 6 + 2] = indices[i * 3 + 1];
632
+ indicesLines[i * 6 + 3] = indices[i * 3 + 2];
633
+ indicesLines[i * 6 + 4] = indices[i * 3 + 2];
634
+ indicesLines[i * 6 + 5] = indices[i * 3 + 0];
635
+ }
636
+ this._skirtMeshLines?.dispose();
637
+ this._skirtMeshLines = new Primitive();
638
+ this._skirtMeshLines.setVertexBuffer(this._skirtMesh.getVertexBuffer('position'));
639
+ this._skirtMeshLines.createAndSetVertexBuffer('tex0_f32x4', this.allocNonInstanceBuffer(0, 0, 0, 0), 'instance');
640
+ this._nonInstanceDataPoolSize++;
641
+ for (const fmt of this._extraInstanceBuffers){
642
+ this._skirtMeshLines.createAndSetVertexBuffer(fmt, this.allocNonInstanceBuffer(0, 0, 0, 0), 'instance');
643
+ this._nonInstanceDataPoolSize++;
644
+ }
645
+ this._skirtMeshLines.createAndSetIndexBuffer(indicesLines);
646
+ this._skirtMeshLines.indexStart = 0;
647
+ this._skirtMeshLines.indexCount = indicesLines.length;
648
+ this._skirtMeshLines.primitiveType = 'line-list';
649
+ }
536
650
  intervalsOverlap(a0, a1, b0, b1) {
537
651
  return a0 <= b1 && b0 <= a1;
538
652
  }
@@ -572,6 +686,14 @@ const rotationValues = [
572
686
  const minZ = (tmpAABB.minPoint.y * scale + offset.y) * gridScale;
573
687
  const maxZ = (tmpAABB.maxPoint.y * scale + offset.y) * gridScale;
574
688
  ctx.calcAABB(ctx.userData, minX, maxX, minZ, maxZ, tmpAABB, level);
689
+ if (ctx.skirt) {
690
+ // Every plane except the far one. A skirted clipmap deliberately reaches
691
+ // past the far plane and pins the depth of whatever lands beyond it, so
692
+ // culling against that plane here would throw away exactly the tiles the
693
+ // skirt is there to lead up to - leaving a gap between the last surviving
694
+ // tile and the ring, with the sky showing through it.
695
+ return tmpAABB.getClipStateWithFrustumMask(camera.frustum, ALL_PLANES_EXCEPT_FAR) !== ClipState.NOT_CLIPPED;
696
+ }
575
697
  return tmpAABB.getClipStateWithFrustum(camera.frustum) !== ClipState.NOT_CLIPPED;
576
698
  }
577
699
  calcLevelAABB(camera, minMaxWorldPos, gridScale) {
@@ -627,11 +749,16 @@ const rotationValues = [
627
749
  }
628
750
  return outAABB;
629
751
  }
630
- calcMipLevels(camera, minMaxWorldPos, gridScale) {
752
+ calcMipLevels(camera, minMaxWorldPos, gridScale, viewDistance) {
631
753
  camera.getWorldPosition(tmpV3);
632
754
  const distX = Math.max(Math.abs(tmpV3.x - minMaxWorldPos.x), Math.abs(tmpV3.x - minMaxWorldPos.z));
633
755
  const distY = Math.max(Math.abs(tmpV3.z - minMaxWorldPos.y), Math.abs(tmpV3.z - minMaxWorldPos.w));
634
- const maxDist = Math.min(Math.max(distX, distY), camera.getFarPlane());
756
+ // The reach is the caller's when it supplies one; the far plane is only the
757
+ // default. An infinite water surface draws its horizon ring beyond the far
758
+ // plane and clamps the depth in the vertex shader, so capping the levels
759
+ // here would starve it of the very tiles it needs.
760
+ const maxReach = viewDistance && viewDistance > 0 ? viewDistance : camera.getFarPlane();
761
+ const maxDist = Math.min(Math.max(distX, distY), maxReach);
635
762
  return Math.min(Math.max(Math.ceil(Math.log2(maxDist / (this._tileResolution * gridScale))), 0) + 1, this._maxMipLevels);
636
763
  }
637
764
  addInstance(info, rotation, offsetX, offsetY, scale, mipLevel) {
@@ -649,7 +776,7 @@ const rotationValues = [
649
776
  this._nonInstanceDataPoolSize = this._nonInstanceDataPool.length;
650
777
  this._nonInstanceMipLevelDataPoolSize = this._nonInstanceMipLevelDataPool.length;
651
778
  const renderData = [];
652
- const mipLevels = this.calcMipLevels(context.camera, context.minMaxWorldPos, context.gridScale);
779
+ const mipLevels = this.calcMipLevels(context.camera, context.minMaxWorldPos, context.gridScale, context.viewDistance);
653
780
  context.camera.getWorldPosition(tmpV3);
654
781
  const snappedPos = new Vector2();
655
782
  const tileSize = new Vector2();
@@ -711,7 +838,13 @@ const rotationValues = [
711
838
  const fillX = x >= 2 ? scale : 0;
712
839
  const fillY = y >= 2 ? scale : 0;
713
840
  offset.setXY(base.x + x * tileSize.x + fillX, base.y + y * tileSize.y + fillY);
714
- if (this.intervalsOverlap(offset.x * context.gridScale, (offset.x + tileSize.x) * context.gridScale, context.minMaxWorldPos.x, context.minMaxWorldPos.z) && this.intervalsOverlap(offset.y * context.gridScale, (offset.y + tileSize.y) * context.gridScale, context.minMaxWorldPos.y, context.minMaxWorldPos.w)) {
841
+ if (// An unbounded surface has no rectangle to keep tiles inside of.
842
+ // Passing a very large one instead does not work: the clipmap's
843
+ // outermost level reaches 2 * tileResolution << (levels - 1), which
844
+ // at a raised camera is tens of kilometres and outgrows any sentinel
845
+ // rectangle - dropping the outer tiles and opening a band of sky
846
+ // between the last one drawn and the horizon skirt.
847
+ context.skirt || this.intervalsOverlap(offset.x * context.gridScale, (offset.x + tileSize.x) * context.gridScale, context.minMaxWorldPos.x, context.minMaxWorldPos.z) && this.intervalsOverlap(offset.y * context.gridScale, (offset.y + tileSize.y) * context.gridScale, context.minMaxWorldPos.y, context.minMaxWorldPos.w)) {
715
848
  if (!context.frustumCulling || this.visible(context, this._tileMeshBBox, context.camera, null, offset, scale, context.gridScale, l)) {
716
849
  this.addInstance(tilePrimitives, rotationValues[0], offset.x, offset.y, scale, l);
717
850
  }
@@ -753,6 +886,22 @@ const rotationValues = [
753
886
  if (seamPrimitives.numInstances > 0) {
754
887
  renderData.push(seamPrimitives);
755
888
  }
889
+ if (context.skirt) {
890
+ // Welded to the outer boundary of the outermost level, so it carries that
891
+ // level's scale and snapped origin. Never frustum-culled: the ring spans
892
+ // the whole horizon, and its outer edge is relocated by the vertex shader,
893
+ // so the AABB tested here would not describe where it actually lands.
894
+ const outerLevel = mipLevels - 1;
895
+ const outerScale = 1 << outerLevel;
896
+ snappedPos.setXY(Math.floor(posX / outerScale) * outerScale, Math.floor(posY / outerScale) * outerScale);
897
+ renderData.push({
898
+ primitive: this._wireframe ? this._skirtMeshLines : this._skirtMesh,
899
+ numInstances: 1,
900
+ instanceDatas: this.allocNonInstanceBuffer(rotationValues[0], outerScale, snappedPos.x, snappedPos.y),
901
+ mipLevels: this.allocNonInstanceMipLevelBuffer(outerLevel),
902
+ maxMiplevel: outerLevel
903
+ });
904
+ }
756
905
  for (const info of renderData){
757
906
  info.primitive.getVertexBuffer('texCoord0').bufferSubData(0, info.instanceDatas, 0, info.numInstances * 4);
758
907
  }
@@ -770,6 +919,8 @@ const rotationValues = [
770
919
  this._trimMeshLines.dispose();
771
920
  this._tileMesh.dispose();
772
921
  this._tileMeshLines.dispose();
922
+ this._skirtMesh.dispose();
923
+ this._skirtMeshLines.dispose();
773
924
  }
774
925
  }
775
926