@woosh/meep-engine 3.14.0 → 3.14.2

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 (220) hide show
  1. package/README.md +33 -64
  2. package/package.json +1 -1
  3. package/src/avif/native/DECISIONS.md +544 -536
  4. package/src/avif/native/heif/parse_avif_file.d.ts.map +1 -1
  5. package/src/avif/native/heif/parse_avif_file.js +384 -383
  6. package/src/avif/native/heif/parse_image_grid.d.ts.map +1 -1
  7. package/src/avif/native/heif/parse_image_grid.js +49 -48
  8. package/src/basis/BasisBitReader.d.ts +77 -0
  9. package/src/basis/BasisBitReader.d.ts.map +1 -0
  10. package/src/basis/BasisBitReader.js +231 -0
  11. package/src/basis/BasisHuffmanTable.d.ts +53 -0
  12. package/src/basis/BasisHuffmanTable.d.ts.map +1 -0
  13. package/src/basis/BasisHuffmanTable.js +263 -0
  14. package/src/basis/basis_read_huffman_table.d.ts +20 -0
  15. package/src/basis/basis_read_huffman_table.d.ts.map +1 -0
  16. package/src/basis/basis_read_huffman_table.js +187 -0
  17. package/src/basis/etc1s/Etc1sSelectorHistory.d.ts +50 -0
  18. package/src/basis/etc1s/Etc1sSelectorHistory.d.ts.map +1 -0
  19. package/src/basis/etc1s/Etc1sSelectorHistory.js +89 -0
  20. package/src/basis/etc1s/etc1s_block_colors.d.ts +14 -0
  21. package/src/basis/etc1s/etc1s_block_colors.d.ts.map +1 -0
  22. package/src/basis/etc1s/etc1s_block_colors.js +75 -0
  23. package/src/basis/etc1s/etc1s_decode_slice.d.ts +57 -0
  24. package/src/basis/etc1s/etc1s_decode_slice.d.ts.map +1 -0
  25. package/src/basis/etc1s/etc1s_decode_slice.js +258 -0
  26. package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts +48 -0
  27. package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts.map +1 -0
  28. package/src/basis/etc1s/etc1s_read_endpoint_codebook.js +111 -0
  29. package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts +42 -0
  30. package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts.map +1 -0
  31. package/src/basis/etc1s/etc1s_read_selector_codebook.js +127 -0
  32. package/src/basis/etc1s/etc1s_read_slice_tables.d.ts +54 -0
  33. package/src/basis/etc1s/etc1s_read_slice_tables.d.ts.map +1 -0
  34. package/src/basis/etc1s/etc1s_read_slice_tables.js +47 -0
  35. package/src/basis/transcode/build_range_plan.js +54 -0
  36. package/src/basis/transcode/etc1s_to_bc1.d.ts +24 -0
  37. package/src/basis/transcode/etc1s_to_bc1.d.ts.map +1 -0
  38. package/src/basis/transcode/etc1s_to_bc1.js +205 -0
  39. package/src/basis/transcode/etc1s_to_bc7.d.ts +30 -0
  40. package/src/basis/transcode/etc1s_to_bc7.d.ts.map +1 -0
  41. package/src/basis/transcode/etc1s_to_bc7.js +496 -0
  42. package/src/basis/transcode/fit_endpoints.d.ts +59 -0
  43. package/src/basis/transcode/fit_endpoints.d.ts.map +1 -0
  44. package/src/basis/transcode/fit_endpoints.js +226 -0
  45. package/src/{avif/native/isobmff → core/binary}/ByteCursor.d.ts +19 -6
  46. package/src/core/binary/ByteCursor.d.ts.map +1 -0
  47. package/src/{avif/native/isobmff → core/binary}/ByteCursor.js +41 -14
  48. package/src/engine/EngineHarness.js +1 -1
  49. package/src/engine/asset/codec/Codec.d.ts.map +1 -0
  50. package/src/engine/asset/codec/CodecWithFallback.d.ts.map +1 -0
  51. package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.js +2 -2
  52. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +4 -4
  53. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
  54. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  55. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +1 -1
  56. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts +1 -1
  57. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts.map +1 -1
  58. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +1 -1
  59. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts +1 -1
  60. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts.map +1 -1
  61. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +1 -1
  62. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  63. package/src/engine/graphics/texture/atlas/TextureAtlas.js +13 -0
  64. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  65. package/src/engine/physics/broadphase/generate_pairs.js +7 -1
  66. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  67. package/src/ktx2/KTX2_IDENTIFIER.d.ts +14 -0
  68. package/src/ktx2/KTX2_IDENTIFIER.d.ts.map +1 -0
  69. package/src/ktx2/KTX2_IDENTIFIER.js +15 -0
  70. package/src/ktx2/KhrDfModel.d.ts +35 -0
  71. package/src/ktx2/KhrDfModel.d.ts.map +1 -0
  72. package/src/ktx2/KhrDfModel.js +49 -0
  73. package/src/ktx2/SupercompressionScheme.d.ts +16 -0
  74. package/src/ktx2/SupercompressionScheme.d.ts.map +1 -0
  75. package/src/ktx2/SupercompressionScheme.js +23 -0
  76. package/src/ktx2/ktx2_read.d.ts +71 -0
  77. package/src/ktx2/ktx2_read.d.ts.map +1 -0
  78. package/src/ktx2/ktx2_read.js +581 -0
  79. package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts +27 -0
  80. package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts.map +1 -0
  81. package/src/ktx2/ktx2_read_basis_lz_global_data.js +189 -0
  82. package/src/ktx2/vk_format_to_texture_format.d.ts +55 -0
  83. package/src/ktx2/vk_format_to_texture_format.d.ts.map +1 -0
  84. package/src/ktx2/vk_format_to_texture_format.js +290 -0
  85. package/src/shade/descriptor/GPUTextureUsage.d.ts +23 -0
  86. package/src/shade/descriptor/GPUTextureUsage.d.ts.map +1 -0
  87. package/src/shade/descriptor/GPUTextureUsage.js +24 -0
  88. package/src/shade/descriptor/WebGPUExtensionType.d.ts +3 -0
  89. package/src/shade/descriptor/WebGPUExtensionType.js +26 -0
  90. package/src/shade/descriptor/texture/TextureDescriptor.d.ts +2 -6
  91. package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
  92. package/src/shade/descriptor/texture/TextureDescriptor.js +24 -40
  93. package/src/shade/descriptor/texture/format/TextureFormat.d.ts +125 -0
  94. package/src/shade/descriptor/texture/format/TextureFormat.d.ts.map +1 -0
  95. package/src/shade/descriptor/texture/format/TextureFormat.js +146 -0
  96. package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts +60 -0
  97. package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts.map +1 -1
  98. package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +102 -0
  99. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  100. package/src/shade/device/graph/TextureResourceDescriptor.js +160 -155
  101. package/src/shade/device/mock/SoftwareGPUQueue.d.ts +11 -4
  102. package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
  103. package/src/shade/device/mock/SoftwareGPUQueue.js +31 -37
  104. package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
  105. package/src/shade/device/mock/SoftwareGPUTexture.js +8 -4
  106. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -1
  107. package/src/shade/device/timing/profile/frame_graph_extract_topology.js +164 -174
  108. package/src/shade/playground/ground_seam/README.md +235 -0
  109. package/src/shade/playground/ground_seam/capture_scene_color.d.ts +45 -0
  110. package/src/shade/playground/ground_seam/capture_scene_color.d.ts.map +1 -0
  111. package/src/shade/playground/ground_seam/capture_scene_color.js +242 -0
  112. package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts +11 -0
  113. package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts.map +1 -0
  114. package/src/shade/playground/ground_seam/depth_step_across_seam.js +185 -0
  115. package/src/shade/playground/ground_seam/index.html +195 -0
  116. package/src/shade/playground/ground_seam/main.d.ts +2 -0
  117. package/src/shade/playground/ground_seam/main.d.ts.map +1 -0
  118. package/src/shade/playground/ground_seam/main.js +879 -0
  119. package/src/shade/playground/ground_seam/make_grid_texture.d.ts +29 -0
  120. package/src/shade/playground/ground_seam/make_grid_texture.d.ts.map +1 -0
  121. package/src/shade/playground/ground_seam/make_grid_texture.js +105 -0
  122. package/src/shade/playground/ground_seam/make_ground.d.ts +70 -0
  123. package/src/shade/playground/ground_seam/make_ground.d.ts.map +1 -0
  124. package/src/shade/playground/ground_seam/make_ground.js +161 -0
  125. package/src/shade/playground/ground_seam/measure_flicker.d.ts +71 -0
  126. package/src/shade/playground/ground_seam/measure_flicker.d.ts.map +1 -0
  127. package/src/shade/playground/ground_seam/measure_flicker.js +531 -0
  128. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  129. package/src/shade/renderer/Renderer.js +2519 -2511
  130. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  131. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +275 -274
  132. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  133. package/src/shade/renderer/light/GPULightCollection.js +323 -314
  134. package/src/shade/renderer/lightmap/GPULightMap.js +336 -336
  135. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  136. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +12 -2
  137. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  138. package/src/shade/renderer/material/standard/fragment_gbuffer.js +3 -1
  139. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
  140. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  141. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +3 -1
  142. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  143. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  144. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.js +3 -1
  145. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  146. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.js +3 -1
  147. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts +28 -0
  148. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts.map +1 -0
  149. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.js +39 -0
  150. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts +45 -0
  151. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts.map +1 -1
  152. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.js +94 -61
  153. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts +24 -0
  154. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts.map +1 -0
  155. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.js +43 -0
  156. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +1462 -0
  157. package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
  158. package/src/shade/renderer/texture/TextureManager.js +20 -8
  159. package/src/shade/renderer/texture/TextureRole.d.ts +19 -0
  160. package/src/shade/renderer/texture/TextureRole.d.ts.map +1 -0
  161. package/src/shade/renderer/texture/TextureRole.js +26 -0
  162. package/src/shade/renderer/texture/TextureVariantSet.d.ts +71 -0
  163. package/src/shade/renderer/texture/TextureVariantSet.d.ts.map +1 -0
  164. package/src/shade/renderer/texture/TextureVariantSet.js +105 -0
  165. package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
  166. package/src/shade/renderer/texture/download_texture_data.js +22 -0
  167. package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts +15 -0
  168. package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts.map +1 -0
  169. package/src/shade/renderer/texture/format/gpu_texture_compression_support.js +50 -0
  170. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts +27 -0
  171. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts.map +1 -0
  172. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.js +65 -0
  173. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts +11 -0
  174. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -0
  175. package/src/shade/renderer/texture/format/infer_format_from_parameters.js +88 -0
  176. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +24 -0
  177. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -0
  178. package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +71 -0
  179. package/src/shade/renderer/texture/format/texture_format_preference.d.ts +22 -0
  180. package/src/shade/renderer/texture/format/texture_format_preference.d.ts.map +1 -0
  181. package/src/shade/renderer/texture/format/texture_format_preference.js +89 -0
  182. package/src/shade/renderer/texture/format/texture_variant_select.d.ts +24 -0
  183. package/src/shade/renderer/texture/format/texture_variant_select.d.ts.map +1 -0
  184. package/src/shade/renderer/texture/format/texture_variant_select.js +38 -0
  185. package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts +9 -1
  186. package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts.map +1 -1
  187. package/src/shade/renderer/texture/shade_texture_might_have_alpha.js +73 -8
  188. package/src/shade/renderer/texture/source/AlphaMode.d.ts +27 -0
  189. package/src/shade/renderer/texture/source/AlphaMode.d.ts.map +1 -0
  190. package/src/shade/renderer/texture/source/AlphaMode.js +52 -0
  191. package/src/shade/renderer/texture/source/ShadeImage.d.ts +33 -0
  192. package/src/shade/renderer/texture/source/ShadeImage.d.ts.map +1 -1
  193. package/src/shade/renderer/texture/source/ShadeImage.js +74 -0
  194. package/src/shade/renderer/texture/source/ShadeTexelData.d.ts +78 -0
  195. package/src/shade/renderer/texture/source/ShadeTexelData.d.ts.map +1 -0
  196. package/src/shade/renderer/texture/source/ShadeTexelData.js +158 -0
  197. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts +0 -10
  198. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts.map +1 -1
  199. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -175
  200. package/src/shade/renderer/texture/texture_write_level.d.ts +32 -0
  201. package/src/shade/renderer/texture/texture_write_level.d.ts.map +1 -0
  202. package/src/shade/renderer/texture/texture_write_level.js +77 -0
  203. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts +8 -1
  204. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
  205. package/src/shade/renderer/texture/texture_write_to_gpu.js +62 -37
  206. package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts +8 -0
  207. package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts.map +1 -1
  208. package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +8 -0
  209. package/src/shade/util/texture_mip_extent.d.ts +49 -0
  210. package/src/shade/util/texture_mip_extent.d.ts.map +1 -0
  211. package/src/shade/util/texture_mip_extent.js +87 -0
  212. package/src/avif/native/isobmff/ByteCursor.d.ts.map +0 -1
  213. package/src/engine/asset/loaders/image/codec/Codec.d.ts.map +0 -1
  214. package/src/engine/asset/loaders/image/codec/CodecWithFallback.d.ts.map +0 -1
  215. package/src/shade/util/compute_max_mip_count.d.ts +0 -8
  216. package/src/shade/util/compute_max_mip_count.d.ts.map +0 -1
  217. package/src/shade/util/compute_max_mip_count.js +0 -27
  218. /package/src/engine/asset/{loaders/image/codec → codec}/Codec.d.ts +0 -0
  219. /package/src/engine/asset/{loaders/image/codec → codec}/Codec.js +0 -0
  220. /package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.d.ts +0 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The albedo the ground plane wears.
3
+ *
4
+ * A grid rather than a photograph, because what is being measured is a *per-texel* instability: the
5
+ * signal only exists if the texture carries energy at the texel scale, and a smooth image would
6
+ * hide a mip level or an anisotropy ratio that moved by a fraction. A one-texel line on a flat
7
+ * field is the highest-contrast thing a 256² texture can hold at its own Nyquist limit, so it is
8
+ * the loudest possible witness to a sampler that is not landing in the same place twice.
9
+ *
10
+ * Every filter stays {@link TextureFilterType.Linear} deliberately —
11
+ * `sampler_descriptor_from_shade_texture` grants 16× anisotropy only when min, mag *and* mip are
12
+ * all linear, and the anisotropic path is one of the quantities under suspicion. Dropping any one
13
+ * of them to Nearest would quietly take the sampler down to 1× and change what is being observed.
14
+ *
15
+ * An `ImageBitmap` rather than the raw `ImageData` buffer: it is the path every glTF albedo takes,
16
+ * so the decode, the premultiplication rule and the `rgba8unorm-srgb` format selection are the ones
17
+ * a real asset gets rather than a second set reached only from here.
18
+ *
19
+ * @param {number} [size] edge length in texels; a power of two so the mip chain reaches 1×1 exactly
20
+ * @param {boolean} [anisotropic] when false, the mip filter drops to Nearest, which is the only
21
+ * handle {@link ShadeTexture} offers on anisotropy — `sampler_descriptor_from_shade_texture`
22
+ * grants 16× only while min, mag *and* mip are all Linear, and 1× otherwise. Not a
23
+ * single-variable control, and the trilinear blend goes with it; what it is good for is asking
24
+ * whether a difference depends on the gradient-derived footprint at all.
25
+ * @returns {Promise<ShadeTexture>}
26
+ */
27
+ export function make_grid_texture(size?: number, anisotropic?: boolean): Promise<ShadeTexture>;
28
+ import { ShadeTexture } from "../../renderer/texture/ShadeTexture.js";
29
+ //# sourceMappingURL=make_grid_texture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make_grid_texture.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/ground_seam/make_grid_texture.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,yCARW,MAAM,gBACN,OAAO,GAKL,QAAQ,YAAY,CAAC,CA0EjC;6BAvG4B,wCAAwC"}
@@ -0,0 +1,105 @@
1
+ import { ColorSpace } from "../../renderer/texture/ColorSpace.js";
2
+ import { ShadeTexture } from "../../renderer/texture/ShadeTexture.js";
3
+ import { ShadeImage } from "../../renderer/texture/source/ShadeImage.js";
4
+ import { TextureFilterType } from "../../renderer/texture/TextureFilterType.js";
5
+ import { TextureWrapType } from "../../renderer/texture/TextureWrapType.js";
6
+
7
+ /**
8
+ * The albedo the ground plane wears.
9
+ *
10
+ * A grid rather than a photograph, because what is being measured is a *per-texel* instability: the
11
+ * signal only exists if the texture carries energy at the texel scale, and a smooth image would
12
+ * hide a mip level or an anisotropy ratio that moved by a fraction. A one-texel line on a flat
13
+ * field is the highest-contrast thing a 256² texture can hold at its own Nyquist limit, so it is
14
+ * the loudest possible witness to a sampler that is not landing in the same place twice.
15
+ *
16
+ * Every filter stays {@link TextureFilterType.Linear} deliberately —
17
+ * `sampler_descriptor_from_shade_texture` grants 16× anisotropy only when min, mag *and* mip are
18
+ * all linear, and the anisotropic path is one of the quantities under suspicion. Dropping any one
19
+ * of them to Nearest would quietly take the sampler down to 1× and change what is being observed.
20
+ *
21
+ * An `ImageBitmap` rather than the raw `ImageData` buffer: it is the path every glTF albedo takes,
22
+ * so the decode, the premultiplication rule and the `rgba8unorm-srgb` format selection are the ones
23
+ * a real asset gets rather than a second set reached only from here.
24
+ *
25
+ * @param {number} [size] edge length in texels; a power of two so the mip chain reaches 1×1 exactly
26
+ * @param {boolean} [anisotropic] when false, the mip filter drops to Nearest, which is the only
27
+ * handle {@link ShadeTexture} offers on anisotropy — `sampler_descriptor_from_shade_texture`
28
+ * grants 16× only while min, mag *and* mip are all Linear, and 1× otherwise. Not a
29
+ * single-variable control, and the trilinear blend goes with it; what it is good for is asking
30
+ * whether a difference depends on the gradient-derived footprint at all.
31
+ * @returns {Promise<ShadeTexture>}
32
+ */
33
+ export async function make_grid_texture(size = 256, anisotropic = true) {
34
+ const canvas = document.createElement('canvas');
35
+
36
+ canvas.width = size;
37
+ canvas.height = size;
38
+
39
+ const ctx = canvas.getContext('2d');
40
+
41
+ // olive base — dark enough that the grid is the only high-frequency content in the image
42
+ ctx.fillStyle = '#3c4838';
43
+ ctx.fillRect(0, 0, size, size);
44
+
45
+ /**
46
+ * Cell pitch, in texels. 32 divides 256 exactly, so the pattern is continuous across the wrap
47
+ * seam and a tile boundary is not itself a feature.
48
+ */
49
+ const CELL = 32;
50
+
51
+ ctx.strokeStyle = '#ffffff';
52
+
53
+ /**
54
+ * A half-texel offset puts a 1px stroke on a texel centre rather than straddling two, which
55
+ * keeps the line a genuine one-texel impulse instead of a two-texel ramp.
56
+ *
57
+ * @param {number} width
58
+ * @param {number} pitch
59
+ */
60
+ function rule(width, pitch) {
61
+ ctx.lineWidth = width;
62
+
63
+ for (let i = 0; i <= size; i += pitch) {
64
+ ctx.beginPath();
65
+ ctx.moveTo(i + 0.5, 0);
66
+ ctx.lineTo(i + 0.5, size);
67
+ ctx.stroke();
68
+
69
+ ctx.beginPath();
70
+ ctx.moveTo(0, i + 0.5);
71
+ ctx.lineTo(size, i + 0.5);
72
+ ctx.stroke();
73
+ }
74
+ }
75
+
76
+ rule(1, CELL);
77
+
78
+ // every fourth cell is heavier, so the pattern has structure at two scales and a mip slip reads
79
+ // as a change in which of the two dominates rather than as uniform blur
80
+ rule(1.5, CELL * 4);
81
+
82
+ const bitmap = await createImageBitmap(canvas, {
83
+ // premultiplication happens during texture upload
84
+ premultiplyAlpha: 'none'
85
+ });
86
+
87
+ const image = ShadeImage.fromImageBitmap(bitmap);
88
+
89
+ // assigned after construction, exactly as `gltf_create_material` does it — this is what selects
90
+ // `rgba8unorm-srgb` and therefore the free sRGB decode on sample
91
+ image.color_space = ColorSpace.SRGB;
92
+
93
+ const texture = ShadeTexture.from(image);
94
+
95
+ texture.label = 'ground_seam/grid';
96
+
97
+ texture.wrapS = TextureWrapType.Repeat;
98
+ texture.wrapT = TextureWrapType.Repeat;
99
+
100
+ texture.minFilter = TextureFilterType.Linear;
101
+ texture.magFilter = TextureFilterType.Linear;
102
+ texture.mipmapFilter = anisotropic ? TextureFilterType.Linear : TextureFilterType.Nearest;
103
+
104
+ return texture;
105
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * How many times the grid texture repeats across the quad.
3
+ *
4
+ * extent/16 — one texture tile every 16 world units, which puts the 256² grid somewhere around one
5
+ * texel per screen pixel in the middle distance of the view this page sets up. That is the band
6
+ * where mip selection and anisotropy actually have to make a decision, and therefore the band where
7
+ * an unstable decision is visible.
8
+ *
9
+ * @param {number} extent
10
+ * @returns {number}
11
+ */
12
+ export function uv_scale_for(extent: number): number;
13
+ /**
14
+ * The ground plane, and nothing else — the brief's scene reproduces with this alone.
15
+ *
16
+ * @param {object} options
17
+ * @param {ShadeTexture} options.albedo
18
+ * @param {number} [options.extent] edge length of the quad in world units. Bigger is worse
19
+ * conditioned: at a fixed camera height a wider quad puts its far corner closer to the eye
20
+ * plane, so |w| there shrinks and everything derived from it grows. The UV scale is derived
21
+ * from the extent, so world-space texel density — and therefore the image in the middle
22
+ * distance — is the same at every size, which is what makes two extents comparable at all.
23
+ * @param {number} [options.segments] subdivision per axis; 1 is the default two-triangle quad
24
+ * @param {number[]} [options.indices] index buffer override, only meaningful when `segments === 1`
25
+ * @param {number} [options.yaw_degrees] rotation about +Y, applied after the quad is laid flat
26
+ * @param {number} [options.roughness]
27
+ * @param {number} [options.metallic]
28
+ * @returns {Mesh}
29
+ */
30
+ export function make_ground({ albedo, segments, indices, extent, yaw_degrees, roughness, metallic, }: {
31
+ albedo: ShadeTexture;
32
+ extent?: number;
33
+ segments?: number;
34
+ indices?: number[];
35
+ yaw_degrees?: number;
36
+ roughness?: number;
37
+ metallic?: number;
38
+ }): Mesh;
39
+ /**
40
+ * Edge length of the ground quad, in world units.
41
+ * @type {number}
42
+ */
43
+ export const GROUND_EXTENT: number;
44
+ /**
45
+ * How `make_plane_geometry` triangulates its default 1×1 quad, and the other way it could have.
46
+ *
47
+ * The vertices it emits, in the plane's own XY (before the −90° X rotation that lays it flat):
48
+ *
49
+ * ```
50
+ * v0 (−212.5, +212.5) v1 (+212.5, +212.5)
51
+ * v2 (−212.5, −212.5) v3 (+212.5, −212.5)
52
+ * ```
53
+ *
54
+ * The default is `(0,2,1)` and `(2,3,1)`, whose shared edge is v2→v1 — the diagonal that becomes
55
+ * the world line **x = −z** once the quad is laid flat. {@link GROUND_TRIANGULATION.flipped } is the
56
+ * same four vertices, the same UVs and the same winding across the *other* diagonal, v0→v3, which
57
+ * is the world line **x = z**.
58
+ *
59
+ * Both windings were checked by hand: every triangle in both lists has a positive Z cross product
60
+ * in plane-local XY, so nothing here changes which face is front.
61
+ */
62
+ export type GROUND_TRIANGULATION = number[];
63
+ export namespace GROUND_TRIANGULATION {
64
+ let _default: number[];
65
+ export { _default as default };
66
+ export let flipped: number[];
67
+ export let rotated: number[];
68
+ }
69
+ import { Mesh } from "../../renderer/scene/Mesh.js";
70
+ //# sourceMappingURL=make_ground.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make_ground.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/ground_seam/make_ground.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AACH,qCAHW,MAAM,GACJ,MAAM,CAIlB;AAyCD;;;;;;;;;;;;;;;;GAgBG;AACH;IAbiC,MAAM;IACX,MAAM,GAAvB,MAAM;IAKW,QAAQ,GAAzB,MAAM;IACa,OAAO,GAA1B,MAAM,EAAE;IACS,WAAW,GAA5B,MAAM;IACW,SAAS,GAA1B,MAAM;IACW,QAAQ,GAAzB,MAAM;IACJ,IAAI,CA2EhB;AAtJD;;;GAGG;AACH,4BAFU,MAAM,CAEiB;;;;;;;;;;;;;;;;;;;mCAmCvB,MAAM,EAAE;;;;;;;qBAzCG,8BAA8B"}
@@ -0,0 +1,161 @@
1
+ import Quaternion from "../../../core/geom/Quaternion.js";
2
+ import Vector3 from "../../../core/geom/Vector3.js";
3
+ import { Attribute } from "../../renderer/geometry/Attribute.js";
4
+ import { meshlet_geometry_build_from_geometry } from "../../renderer/geometry/meshlet_geometry_build_from_geometry.js";
5
+ import { MeshletGeometry } from "../../renderer/geometry/MeshletGeometry.js";
6
+ import { make_plane_geometry } from "../../renderer/geometry/primitives/make_plane_geometry.js";
7
+ import { StandardAttributes } from "../../renderer/geometry/StandardAttributes.js";
8
+ import { StandardShadeMaterial } from "../../renderer/material/StandardShadeMaterial.js";
9
+ import { Mesh } from "../../renderer/scene/Mesh.js";
10
+
11
+ /**
12
+ * Edge length of the ground quad, in world units.
13
+ * @type {number}
14
+ */
15
+ export const GROUND_EXTENT = 425;
16
+
17
+ /**
18
+ * How many times the grid texture repeats across the quad.
19
+ *
20
+ * extent/16 — one texture tile every 16 world units, which puts the 256² grid somewhere around one
21
+ * texel per screen pixel in the middle distance of the view this page sets up. That is the band
22
+ * where mip selection and anisotropy actually have to make a decision, and therefore the band where
23
+ * an unstable decision is visible.
24
+ *
25
+ * @param {number} extent
26
+ * @returns {number}
27
+ */
28
+ export function uv_scale_for(extent) {
29
+ return extent / 16;
30
+ }
31
+
32
+ /**
33
+ * How `make_plane_geometry` triangulates its default 1×1 quad, and the other way it could have.
34
+ *
35
+ * The vertices it emits, in the plane's own XY (before the −90° X rotation that lays it flat):
36
+ *
37
+ * ```
38
+ * v0 (−212.5, +212.5) v1 (+212.5, +212.5)
39
+ * v2 (−212.5, −212.5) v3 (+212.5, −212.5)
40
+ * ```
41
+ *
42
+ * The default is `(0,2,1)` and `(2,3,1)`, whose shared edge is v2→v1 — the diagonal that becomes
43
+ * the world line **x = −z** once the quad is laid flat. {@link GROUND_TRIANGULATION.flipped} is the
44
+ * same four vertices, the same UVs and the same winding across the *other* diagonal, v0→v3, which
45
+ * is the world line **x = z**.
46
+ *
47
+ * Both windings were checked by hand: every triangle in both lists has a positive Z cross product
48
+ * in plane-local XY, so nothing here changes which face is front.
49
+ *
50
+ * @enum {number[]}
51
+ */
52
+ export const GROUND_TRIANGULATION = {
53
+ default: [0, 2, 1, 2, 3, 1],
54
+ flipped: [0, 2, 3, 0, 3, 1],
55
+
56
+ /**
57
+ * The **same two triangles** as `default`, each cyclically rotated so a different corner is
58
+ * first. Same diagonal, same winding, same three vertices per face — only which one the
59
+ * reconstruction anchors on changes.
60
+ *
61
+ * `chunk_barycentric_full` builds every pixel's barycentric from `pixel - ndc0` and divides by
62
+ * `determinant(mat2x2(ndc2 - ndc1, ndc0 - ndc1))`, so vertex 0 is the origin the whole
63
+ * reconstruction is measured from and the other two set the scale. In exact arithmetic a
64
+ * rotation changes nothing. In f32 it changes which differences are formed and therefore how
65
+ * they round — which is exactly the quantity a per-triangle instability would be made of, and
66
+ * the one thing that can be varied without varying the geometry, the UVs or the coverage.
67
+ */
68
+ rotated: [2, 1, 0, 3, 1, 2],
69
+ };
70
+
71
+ /**
72
+ * The ground plane, and nothing else — the brief's scene reproduces with this alone.
73
+ *
74
+ * @param {object} options
75
+ * @param {ShadeTexture} options.albedo
76
+ * @param {number} [options.extent] edge length of the quad in world units. Bigger is worse
77
+ * conditioned: at a fixed camera height a wider quad puts its far corner closer to the eye
78
+ * plane, so |w| there shrinks and everything derived from it grows. The UV scale is derived
79
+ * from the extent, so world-space texel density — and therefore the image in the middle
80
+ * distance — is the same at every size, which is what makes two extents comparable at all.
81
+ * @param {number} [options.segments] subdivision per axis; 1 is the default two-triangle quad
82
+ * @param {number[]} [options.indices] index buffer override, only meaningful when `segments === 1`
83
+ * @param {number} [options.yaw_degrees] rotation about +Y, applied after the quad is laid flat
84
+ * @param {number} [options.roughness]
85
+ * @param {number} [options.metallic]
86
+ * @returns {Mesh}
87
+ */
88
+ export function make_ground({
89
+ albedo,
90
+ segments = 1,
91
+ indices = GROUND_TRIANGULATION.default,
92
+ extent = GROUND_EXTENT,
93
+ yaw_degrees = 0,
94
+ roughness = 0.95,
95
+ metallic = 0,
96
+ }) {
97
+
98
+ const geometry = make_plane_geometry(extent, extent, segments, segments);
99
+
100
+ // The texture has to tile, and it has to tile by exactly the same amount however the quad is
101
+ // cut up — a subdivided plane that sampled the texture differently would confound "subdivision
102
+ // fixes it" with "subdivision changed the shading".
103
+ const uv = geometry.getAttribute(StandardAttributes.TextureCoordinates0);
104
+
105
+ for (let i = 0; i < uv.data.length; i++) {
106
+ uv.data[i] *= uv_scale_for(extent);
107
+ }
108
+
109
+ if (segments === 1) {
110
+ /*
111
+ Same vertices, same UVs, same winding. Which pairs of corners are joined is the A/B the
112
+ brief calls its first positive result; which corner comes first within a face is the
113
+ finer one, and both are just this index buffer.
114
+ */
115
+ geometry.index = Attribute.from(new Uint32Array(indices), 1, StandardAttributes.Index);
116
+ }
117
+
118
+ const mesh = new Mesh();
119
+
120
+ mesh.name = 'ground';
121
+ mesh.geometry = new MeshletGeometry();
122
+
123
+ meshlet_geometry_build_from_geometry(geometry, mesh.geometry);
124
+
125
+ const material = new StandardShadeMaterial();
126
+
127
+ material.texture_albedo = albedo;
128
+ material.roughness_factor = roughness;
129
+ material.metallic_factor = metallic;
130
+
131
+ mesh.material = material;
132
+
133
+ /*
134
+ −90° about X lays the plane flat with its normal pointing at +Y.
135
+
136
+ A yaw on top of that is the control that separates *which diagonal the seam lies on* from
137
+ *which of the two triangles is which*. 180° is a symmetry of both the quad and the shared edge
138
+ — the world line x = −z maps to itself — but it exchanges the triangles' corners: the one whose
139
+ odd vertex sat behind the eye plane now has two there, and the other way round. So the seam
140
+ stays exactly where it was on screen while the two triangles swap roles, which is the one
141
+ experiment that can tell a property of the *edge* from a property of a *triangle*.
142
+
143
+ `Transform64` keeps its matrix by hand, so the write is only real after `updateMatrix`, and the
144
+ world bounds the `meshes` table publishes only exist after `updateMatrices` — a mesh added on
145
+ its own is never reached by the scene's hierarchy walk.
146
+ */
147
+ const rotation = Quaternion.fromAxisAngle(Vector3.right, -Math.PI / 2);
148
+
149
+ if (yaw_degrees !== 0) {
150
+ const yaw = Quaternion.fromAxisAngle(Vector3.up, yaw_degrees * Math.PI / 180);
151
+
152
+ rotation.multiplyQuaternions(yaw, rotation);
153
+ rotation.normalize();
154
+ }
155
+
156
+ mesh.transform_local.setRotation(rotation.x, rotation.y, rotation.z, rotation.w);
157
+ mesh.transform_local.updateMatrix();
158
+ mesh.updateMatrices();
159
+
160
+ return mesh;
161
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Which of the ground quad's two triangles covers each pixel, and where on the plane it lands.
3
+ *
4
+ * The classification is `sign(x + z)`: the default triangulation's shared edge is the world line
5
+ * `x = −z` (v2→v1 of `make_plane_geometry`'s 1×1 quad, laid flat by the −90° X rotation), so the
6
+ * two triangles are exactly the two sides of `x + z = 0`. For the flipped index buffer the shared
7
+ * edge is `x = z` instead, so `side_flipped` carries `sign(x − z)` alongside it and a caller can
8
+ * ask about whichever diagonal is currently in the mesh.
9
+ *
10
+ * @param {PerspectiveCamera} camera must already have had `update_matrices` run for this frame
11
+ * @param {number} width in pixels
12
+ * @param {number} height in pixels
13
+ * @param {number} [extent] half-width of the quad; pixels outside it are not ground
14
+ * @returns {{side: Int8Array, side_flipped: Int8Array, round_trip_error_px: number, covered: number}}
15
+ * `side` is −1, +1 or 0 (not ground). `round_trip_error_px` is the worst error, in pixels, from
16
+ * projecting a recovered world point back through the forward matrix — a sanity check on the whole
17
+ * convention, which should be a small fraction of a pixel.
18
+ */
19
+ export function classify_ground(camera: PerspectiveCamera, width: number, height: number, extent?: number): {
20
+ side: Int8Array;
21
+ side_flipped: Int8Array;
22
+ round_trip_error_px: number;
23
+ covered: number;
24
+ };
25
+ /**
26
+ * Owns the render target, the readback buffer, and the frame-driving loop.
27
+ *
28
+ * @param {object} context
29
+ * @param {Renderer} context.renderer
30
+ * @param {Scene} context.scene
31
+ * @param {PerspectiveCamera} context.camera
32
+ */
33
+ export function attach_measurement({ renderer, scene, camera }: {
34
+ renderer: Renderer;
35
+ scene: Scene;
36
+ camera: PerspectiveCamera;
37
+ }): {
38
+ frame: (time_delta_s?: number) => void;
39
+ settle: (n: number) => Promise<void>;
40
+ burst: ({ settle_frames, frames }?: {
41
+ settle_frames?: number;
42
+ frames?: number;
43
+ }) => Promise<{
44
+ spread: Float32Array;
45
+ mean: Float32Array;
46
+ width: number;
47
+ height: number;
48
+ }>;
49
+ read_depth: () => Promise<{
50
+ depth: Float32Array;
51
+ width: number;
52
+ height: number;
53
+ }>;
54
+ readonly capture: any;
55
+ };
56
+ /**
57
+ * Where a world-space line on the ground plane lands on screen, as a signed-distance function.
58
+ *
59
+ * A projective map takes a straight line to a straight line, so two projected points are the whole
60
+ * of it. This exists so a profile can be taken *across* the seam in pixels: the half-plane means a
61
+ * split reports cannot tell a step at the boundary from a smooth gradient over the whole frame, and
62
+ * that is exactly the difference between "a seam" and "one half of the view is more oblique".
63
+ *
64
+ * @param {PerspectiveCamera} camera
65
+ * @param {number} width
66
+ * @param {number} height
67
+ * @param {number[]} direction unit direction of the line in the XZ plane
68
+ * @returns {function(number, number): number} pixel → signed perpendicular distance, in pixels
69
+ */
70
+ export function screen_line_distance(camera: PerspectiveCamera, width: number, height: number, direction: number[]): (arg0: number, arg1: number) => number;
71
+ //# sourceMappingURL=measure_flicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure_flicker.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/ground_seam/measure_flicker.js"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;;;;;GAiBG;AACH,kEARW,MAAM,UACN,MAAM,WACN,MAAM;UACG,SAAS;kBAAgB,SAAS;yBAAuB,MAAM;aAAW,MAAM;EAmHnG;AAED;;;;;;;GAOG;AACH;IAJ6B,QAAQ;IACX,KAAK;IACO,MAAM;;2BAqE7B,MAAM;gBAQN,MAAM;;QAoFW,aAAa,GAA9B,MAAM;QACW,MAAM,GAAvB,MAAM;;gBACa,YAAY;cAAQ,YAAY;eAAS,MAAM;gBAAU,MAAM;;;eA4DhE,YAAY;eAAS,MAAM;gBAAU,MAAM;;;EAkE3E;AAED;;;;;;;;;;;;;GAaG;AACH,uEALW,MAAM,UACN,MAAM,aACN,MAAM,EAAE,UACG,MAAM,QAAE,MAAM,KAAG,MAAM,CAyC5C"}