@woosh/meep-engine 3.61.0 → 3.61.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 (170) hide show
  1. package/package.json +1 -1
  2. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  3. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
  4. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts +46 -2
  5. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
  6. package/src/engine/graphics/ecs/decal/v2/Decal.js +74 -5
  7. package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.d.ts.map +1 -1
  8. package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.js +13 -1
  9. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts +9 -0
  10. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.js +37 -0
  12. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/DecalSystem.js +462 -447
  14. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts +14 -0
  15. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts.map +1 -1
  16. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.js +53 -13
  17. package/src/engine/graphics3/decal/chunk_decal_record.d.ts +6 -1
  18. package/src/engine/graphics3/decal/chunk_decal_record.d.ts.map +1 -1
  19. package/src/engine/graphics3/decal/chunk_decal_record.js +28 -9
  20. package/src/engine/graphics3/decal/decal_gpu_records.d.ts +2 -1
  21. package/src/engine/graphics3/decal/decal_gpu_records.d.ts.map +1 -1
  22. package/src/engine/graphics3/decal/decal_gpu_records.js +26 -5
  23. package/src/engine/graphics3/decal/decal_material_samplers.d.ts +6 -0
  24. package/src/engine/graphics3/decal/decal_material_samplers.d.ts.map +1 -1
  25. package/src/engine/graphics3/decal/decal_material_samplers.js +13 -0
  26. package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +1 -1
  27. package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +1 -1
  28. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +5 -0
  29. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  30. package/src/engine/graphics3/decal/shader_decal_composite.js +69 -28
  31. package/src/engine/network/sim/SimActionExecutor.d.ts +4 -0
  32. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  33. package/src/engine/network/sim/SimActionExecutor.js +4 -0
  34. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -1
  35. package/src/generation/foliage/material/foliage_atlas_cutout.js +21 -5
  36. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts +8 -0
  37. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts.map +1 -1
  38. package/src/generation/foliage/mesh/tree_cluster_representatives.js +178 -78
  39. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  40. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +178 -97
  41. package/src/generation/foliage/skeleton/ShootLightField.d.ts +1 -0
  42. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -1
  43. package/src/generation/foliage/skeleton/ShootLightField.js +88 -17
  44. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts +8 -4
  45. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts.map +1 -1
  46. package/src/generation/foliage/skeleton/ShootWoodHash.js +216 -27
  47. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  48. package/src/shade/playground/probe_clipmap/main.js +4 -0
  49. package/src/shade/playground/probe_clipmap_box/README.md +55 -0
  50. package/src/shade/playground/probe_clipmap_box/index.html +185 -0
  51. package/src/shade/playground/probe_clipmap_box/main.d.ts +8 -0
  52. package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -0
  53. package/src/shade/playground/probe_clipmap_box/main.js +323 -0
  54. package/src/shade/playground/probe_clipmap_box/scene.d.ts +93 -0
  55. package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -0
  56. package/src/shade/playground/probe_clipmap_box/scene.js +256 -0
  57. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  58. package/src/shade/renderer/Renderer.js +6 -1
  59. package/src/shade/renderer/buffer/graph_read_buffer.d.ts +3 -1
  60. package/src/shade/renderer/buffer/graph_read_buffer.d.ts.map +1 -1
  61. package/src/shade/renderer/buffer/graph_read_buffer.js +9 -6
  62. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.d.ts +12 -0
  63. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.d.ts.map +1 -1
  64. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.js +49 -24
  65. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.d.ts +12 -0
  66. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.d.ts.map +1 -1
  67. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.js +50 -19
  68. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_sh3_compress.d.ts.map +1 -1
  69. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_sh3_compress.js +6 -2
  70. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +5 -1
  71. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  72. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +7 -3
  73. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +6 -4
  74. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  75. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +10 -9
  76. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +12 -0
  77. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  78. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +14 -0
  79. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +17 -22
  80. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  81. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +53 -65
  82. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +2 -3
  83. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -1
  84. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +9 -20
  85. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +2 -2
  86. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  87. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +14 -19
  88. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +1 -1
  89. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  90. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +8 -4
  91. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +1 -1
  92. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts +2 -1
  93. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts.map +1 -1
  94. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js +13 -18
  95. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.d.ts +1 -1
  96. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.js +4 -2
  98. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts.map +1 -1
  99. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.js +4 -6
  100. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -1
  101. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +4 -7
  102. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +4 -3
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +14 -13
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +3 -4
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +7 -15
  108. package/src/shade/renderer/light/environment/shader_downsample_environment_map.d.ts.map +1 -1
  109. package/src/shade/renderer/light/environment/shader_downsample_environment_map.js +5 -1
  110. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  111. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -7
  112. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +26 -8
  113. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  114. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +170 -142
  115. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts +1 -1
  116. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts.map +1 -1
  117. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.js +5 -8
  118. package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts.map +1 -1
  119. package/src/shade/renderer/restir/di/chunk_restir_resolve.js +91 -94
  120. package/src/shade/renderer/restir/reservoir/chunk_rtxdi_stream_sample.js +1 -1
  121. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts +14 -0
  122. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts.map +1 -1
  123. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.js +36 -21
  124. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts +22 -0
  125. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts.map +1 -0
  126. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.js +64 -0
  127. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +15 -4
  128. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -1
  129. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +33 -7
  130. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.d.ts.map +1 -1
  131. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.js +13 -18
  132. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.d.ts.map +1 -1
  133. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.js +28 -30
  134. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.d.ts.map +1 -1
  135. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.js +15 -16
  136. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts +0 -1
  137. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts.map +1 -1
  138. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.js +15 -18
  139. package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.d.ts +40 -0
  140. package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.d.ts.map +1 -0
  141. package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.js +75 -0
  142. package/src/shade/renderer/shader/chunk/noise/chunk_vdc_radical_inverse.d.ts.map +1 -1
  143. package/src/shade/renderer/shader/chunk/noise/chunk_vdc_radical_inverse.js +3 -1
  144. package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.d.ts +28 -0
  145. package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.d.ts.map +1 -0
  146. package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.js +41 -0
  147. package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.d.ts +12 -0
  148. package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.d.ts.map +1 -0
  149. package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.js +24 -0
  150. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +3 -2
  151. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -1
  152. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +4 -0
  153. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +2 -5
  154. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -1
  155. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +3 -20
  156. package/src/shade/renderer/water/chunk_water_gi.d.ts +1 -1
  157. package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -1
  158. package/src/shade/renderer/water/chunk_water_gi.js +6 -8
  159. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -1
  160. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  161. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +79 -35
  162. package/src/core/math/hash/squirrel3.d.ts +0 -17
  163. package/src/core/math/hash/squirrel3.d.ts.map +0 -1
  164. package/src/core/math/hash/squirrel3.js +0 -30
  165. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts +0 -2
  166. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts.map +0 -1
  167. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.js +0 -6
  168. package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.d.ts +0 -12
  169. package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.d.ts.map +0 -1
  170. package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.js +0 -30
@@ -6,6 +6,12 @@
6
6
  * ask, per pixel, whether a world position is inside the cube and where in the decal's texture it
7
7
  * lands. Deriving either from the other is a matrix inverse — cheap once on the CPU, and absurd per
8
8
  * pixel per decal inside the composite's loop.
9
+ *
10
+ * **Shaders read the record as `array<u32>`** and bitcast the float fields. The packed weights are
11
+ * bit patterns, not floats — a weight of one in a high half reads as a NaN — and neither WGSL nor a
12
+ * JavaScript `Float32Array` promises to keep a NaN's bits through a float load, so the words are only
13
+ * ever moved as integers and never read through a float view. The CPU writes them through a
14
+ * `Uint32Array` over the same memory.
9
15
  */
10
16
  export const DECAL_GPU_RECORD: WebGPUStruct;
11
17
  /**
@@ -44,6 +50,14 @@ export const DECAL_RECORD_OFFSET_EMISSIVE: number;
44
50
  * @type {number}
45
51
  */
46
52
  export const DECAL_RECORD_OFFSET_PARAMS: number;
53
+ /**
54
+ * @type {number}
55
+ */
56
+ export const DECAL_RECORD_OFFSET_WEIGHTS: number;
57
+ /**
58
+ * @type {number}
59
+ */
60
+ export const DECAL_RECORD_OFFSET_WEIGHT_EMISSIVE: number;
47
61
  /**
48
62
  * @type {number}
49
63
  */
@@ -1 +1 @@
1
- {"version":3,"file":"DECAL_GPU_RECORD.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/DECAL_GPU_RECORD.js"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,4CAsDyB;AAEzB;;GAEG;AACH,sCAFU,MAAM,CAEiD;AAEjE;;GAEG;AACH,4CAFU,MAAM,CAE+B;AAE/C;;GAEG;AACH,oDAFU,MAAM,CAEwC;AAExD;;GAEG;AACH,4CAFU,MAAM,CAEgC;AAEhD;;GAEG;AACH,4CAFU,MAAM,CAEgC;AAEhD;;GAEG;AACH,yCAFU,MAAM,CAE6B;AAE7C;;GAEG;AACH,wCAFU,MAAM,CAE4B;AAE5C;;GAEG;AACH,2CAFU,MAAM,CAE+B;AAE/C;;GAEG;AACH,yCAFU,MAAM,CAE6B;AAE7C;;GAEG;AACH,sCAFU,MAAM,CAE0B;6BAnHb,qDAAqD"}
1
+ {"version":3,"file":"DECAL_GPU_RECORD.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/DECAL_GPU_RECORD.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,4CAkEyB;AAczB;;GAEG;AACH,sCAFU,MAAM,CAEiD;AAEjE;;GAEG;AACH,4CAFU,MAAM,CAEsD;AAEtE;;GAEG;AACH,oDAFU,MAAM,CAEsE;AAEtF;;GAEG;AACH,4CAFU,MAAM,CAEsD;AAEtE;;GAEG;AACH,4CAFU,MAAM,CAEsD;AAEtE;;GAEG;AACH,yCAFU,MAAM,CAEgD;AAEhE;;GAEG;AACH,wCAFU,MAAM,CAE8C;AAE9D;;GAEG;AACH,2CAFU,MAAM,CAEoD;AAEpE;;GAEG;AACH,yCAFU,MAAM,CAEgD;AAEhE;;GAEG;AACH,0CAFU,MAAM,CAEkD;AAElE;;GAEG;AACH,kDAFU,MAAM,CAEkE;AAElF;;GAEG;AACH,sCAFU,MAAM,CAE0C;6BA3J7B,qDAAqD"}
@@ -1,4 +1,4 @@
1
- import { mat4x4f, vec4f } from "../../../shade/renderer/shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
1
+ import { mat4x4f, u32, vec2f, vec2u, vec3f, vec4f } from "../../../shade/renderer/shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
2
  import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.js";
3
3
 
4
4
  /**
@@ -9,6 +9,12 @@ import { WebGPUStruct } from "../../../shade/renderer/shader/type/WebGPUStruct.j
9
9
  * ask, per pixel, whether a world position is inside the cube and where in the decal's texture it
10
10
  * lands. Deriving either from the other is a matrix inverse — cheap once on the CPU, and absurd per
11
11
  * pixel per decal inside the composite's loop.
12
+ *
13
+ * **Shaders read the record as `array<u32>`** and bitcast the float fields. The packed weights are
14
+ * bit patterns, not floats — a weight of one in a high half reads as a NaN — and neither WGSL nor a
15
+ * JavaScript `Float32Array` promises to keep a NaN's bits through a float load, so the words are only
16
+ * ever moved as integers and never read through a float view. The CPU writes them through a
17
+ * `Uint32Array` over the same memory.
12
18
  */
13
19
  export const DECAL_GPU_RECORD = WebGPUStruct.from({
14
20
  /**
@@ -47,12 +53,24 @@ export const DECAL_GPU_RECORD = WebGPUStruct.from({
47
53
  * `emissive_color.rgb * emissive_intensity`. Zero for every decal that does not emit, which is
48
54
  * every decal the game authors today.
49
55
  */
50
- emissive: vec4f,
56
+ emissive: vec3f,
57
+
58
+ /**
59
+ * `pack2x16unorm(emissive_weight, 0)`.
60
+ */
61
+ weight_emissive: u32,
62
+
63
+ /**
64
+ * roughness, metalness.
65
+ */
66
+ params: vec2f,
51
67
 
52
68
  /**
53
- * roughness, metalness, and two spare.
69
+ * `pack2x16unorm(albedo_weight, normal_weight)`, `pack2x16unorm(roughness_weight, metalness_weight)`:
70
+ * how much of each channel the decal writes, each scaling the mask's coverage for that channel
71
+ * alone.
54
72
  */
55
- params: vec4f,
73
+ weights: vec2u,
56
74
 
57
75
  /**
58
76
  * The deepest mip level each of the three atlases may be sampled at for this decal — albedo,
@@ -66,6 +84,18 @@ export const DECAL_GPU_RECORD = WebGPUStruct.from({
66
84
  lod: vec4f,
67
85
  }, "DecalRecord").pack();
68
86
 
87
+ /**
88
+ * Where a field sits, in words. Derived from the struct, because {@link WebGPUStruct#pack} chooses the
89
+ * order, and an offset written by hand would go on agreeing with the shaders while disagreeing with the
90
+ * layout the record declares.
91
+ *
92
+ * @param {string} name
93
+ * @returns {number}
94
+ */
95
+ function word_offset(name) {
96
+ return DECAL_GPU_RECORD.get(name).offset / 4;
97
+ }
98
+
69
99
  /**
70
100
  * @type {number}
71
101
  */
@@ -74,44 +104,54 @@ export const DECAL_RECORD_WORD_COUNT = DECAL_GPU_RECORD.size / 4;
74
104
  /**
75
105
  * @type {number}
76
106
  */
77
- export const DECAL_RECORD_OFFSET_TRANSFORM = 0;
107
+ export const DECAL_RECORD_OFFSET_TRANSFORM = word_offset("transform");
108
+
109
+ /**
110
+ * @type {number}
111
+ */
112
+ export const DECAL_RECORD_OFFSET_TRANSFORM_INVERSE = word_offset("transform_inverse");
113
+
114
+ /**
115
+ * @type {number}
116
+ */
117
+ export const DECAL_RECORD_OFFSET_UV_ALBEDO = word_offset("uv_albedo");
78
118
 
79
119
  /**
80
120
  * @type {number}
81
121
  */
82
- export const DECAL_RECORD_OFFSET_TRANSFORM_INVERSE = 16;
122
+ export const DECAL_RECORD_OFFSET_UV_NORMAL = word_offset("uv_normal");
83
123
 
84
124
  /**
85
125
  * @type {number}
86
126
  */
87
- export const DECAL_RECORD_OFFSET_UV_ALBEDO = 32;
127
+ export const DECAL_RECORD_OFFSET_UV_ORM = word_offset("uv_orm");
88
128
 
89
129
  /**
90
130
  * @type {number}
91
131
  */
92
- export const DECAL_RECORD_OFFSET_UV_NORMAL = 36;
132
+ export const DECAL_RECORD_OFFSET_COLOR = word_offset("color");
93
133
 
94
134
  /**
95
135
  * @type {number}
96
136
  */
97
- export const DECAL_RECORD_OFFSET_UV_ORM = 40;
137
+ export const DECAL_RECORD_OFFSET_EMISSIVE = word_offset("emissive");
98
138
 
99
139
  /**
100
140
  * @type {number}
101
141
  */
102
- export const DECAL_RECORD_OFFSET_COLOR = 44;
142
+ export const DECAL_RECORD_OFFSET_PARAMS = word_offset("params");
103
143
 
104
144
  /**
105
145
  * @type {number}
106
146
  */
107
- export const DECAL_RECORD_OFFSET_EMISSIVE = 48;
147
+ export const DECAL_RECORD_OFFSET_WEIGHTS = word_offset("weights");
108
148
 
109
149
  /**
110
150
  * @type {number}
111
151
  */
112
- export const DECAL_RECORD_OFFSET_PARAMS = 52;
152
+ export const DECAL_RECORD_OFFSET_WEIGHT_EMISSIVE = word_offset("weight_emissive");
113
153
 
114
154
  /**
115
155
  * @type {number}
116
156
  */
117
- export const DECAL_RECORD_OFFSET_LOD = 56;
157
+ export const DECAL_RECORD_OFFSET_LOD = word_offset("lod");
@@ -1,7 +1,12 @@
1
1
  /**
2
- * Shared WGSL accessors for reading packed decal records (`array<f32>`) from a `decal_data` storage buffer.
2
+ * Shared WGSL accessors for reading packed decal records from a `decal_data` storage buffer bound as
3
+ * `array<u32>`. Float fields are bitcast out of their words; packed fields are read as the words
4
+ * they are (see {@link DECAL_GPU_RECORD}).
3
5
  *
4
6
  * ```wgsl
7
+ * fn decal_word(index: u32, field: u32) -> u32
8
+ * fn decal_vec2(index: u32, field: u32) -> vec2<f32>
9
+ * fn decal_vec3(index: u32, field: u32) -> vec3<f32>
5
10
  * fn decal_vec4(index: u32, field: u32) -> vec4<f32>
6
11
  * fn decal_matrix(index: u32, field: u32) -> mat4x4<f32>
7
12
  * fn decal_transform(index: u32) -> mat4x4<f32>
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_decal_record.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/chunk_decal_record.js"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,iCAFU,SAAS,CA+BjB;0BA3CwB,sDAAsD"}
1
+ {"version":3,"file":"chunk_decal_record.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/chunk_decal_record.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,iCAFU,SAAS,CA6CjB;0BA9DwB,sDAAsD"}
@@ -2,9 +2,14 @@ import { CodeChunk } from "../../../shade/renderer/shader/compiler/CodeChunk.js"
2
2
  import { DECAL_RECORD_OFFSET_TRANSFORM, DECAL_RECORD_WORD_COUNT } from "./DECAL_GPU_RECORD.js";
3
3
 
4
4
  /**
5
- * Shared WGSL accessors for reading packed decal records (`array<f32>`) from a `decal_data` storage buffer.
5
+ * Shared WGSL accessors for reading packed decal records from a `decal_data` storage buffer bound as
6
+ * `array<u32>`. Float fields are bitcast out of their words; packed fields are read as the words
7
+ * they are (see {@link DECAL_GPU_RECORD}).
6
8
  *
7
9
  * ```wgsl
10
+ * fn decal_word(index: u32, field: u32) -> u32
11
+ * fn decal_vec2(index: u32, field: u32) -> vec2<f32>
12
+ * fn decal_vec3(index: u32, field: u32) -> vec3<f32>
8
13
  * fn decal_vec4(index: u32, field: u32) -> vec4<f32>
9
14
  * fn decal_matrix(index: u32, field: u32) -> mat4x4<f32>
10
15
  * fn decal_transform(index: u32) -> mat4x4<f32>
@@ -18,22 +23,36 @@ export const chunk_decal_record = CodeChunk.from(
18
23
  const DECAL_RECORD_WORD_COUNT : u32 = ${DECAL_RECORD_WORD_COUNT}u;
19
24
  const DECAL_RECORD_OFFSET_TRANSFORM : u32 = ${DECAL_RECORD_OFFSET_TRANSFORM}u;
20
25
 
26
+ fn decal_word(index: u32, field: u32) -> u32 {
27
+ return decal_data[index * DECAL_RECORD_WORD_COUNT + field];
28
+ }
29
+
30
+ fn decal_vec2(index: u32, field: u32) -> vec2<f32> {
31
+ let base = index * DECAL_RECORD_WORD_COUNT + field;
32
+
33
+ return bitcast<vec2<f32>>(vec2<u32>(decal_data[base], decal_data[base + 1u]));
34
+ }
35
+
36
+ fn decal_vec3(index: u32, field: u32) -> vec3<f32> {
37
+ let base = index * DECAL_RECORD_WORD_COUNT + field;
38
+
39
+ return bitcast<vec3<f32>>(vec3<u32>(decal_data[base], decal_data[base + 1u], decal_data[base + 2u]));
40
+ }
41
+
21
42
  fn decal_vec4(index: u32, field: u32) -> vec4<f32> {
22
43
  let base = index * DECAL_RECORD_WORD_COUNT + field;
23
44
 
24
- return vec4<f32>(
45
+ return bitcast<vec4<f32>>(vec4<u32>(
25
46
  decal_data[base], decal_data[base + 1u], decal_data[base + 2u], decal_data[base + 3u]
26
- );
47
+ ));
27
48
  }
28
49
 
29
50
  fn decal_matrix(index: u32, field: u32) -> mat4x4<f32> {
30
- let base = index * DECAL_RECORD_WORD_COUNT + field;
31
-
32
51
  return mat4x4<f32>(
33
- vec4<f32>(decal_data[base + 0u], decal_data[base + 1u], decal_data[base + 2u], decal_data[base + 3u]),
34
- vec4<f32>(decal_data[base + 4u], decal_data[base + 5u], decal_data[base + 6u], decal_data[base + 7u]),
35
- vec4<f32>(decal_data[base + 8u], decal_data[base + 9u], decal_data[base + 10u], decal_data[base + 11u]),
36
- vec4<f32>(decal_data[base + 12u], decal_data[base + 13u], decal_data[base + 14u], decal_data[base + 15u])
52
+ decal_vec4(index, field),
53
+ decal_vec4(index, field + 4u),
54
+ decal_vec4(index, field + 8u),
55
+ decal_vec4(index, field + 12u)
37
56
  );
38
57
  }
39
58
 
@@ -2,13 +2,14 @@
2
2
  * Write one decal into the buffer every decal shader reads.
3
3
  *
4
4
  * @param {Float32Array} target
5
+ * @param {Uint32Array} target_words the same memory as `target`, for the fields that are bit patterns
5
6
  * @param {number} offset in words, a multiple of the record size
6
7
  * @param {Decal} decal
7
8
  * @param {Float32Array|number[]} matrix the entity's world transform, column-major
8
9
  * @param {{albedo: Rectangle, normal: Rectangle, orm: Rectangle}} uv atlas rectangles
9
10
  * @param {{albedo: number, normal: number, orm: number}} max_lod per atlas, from each patch's border
10
11
  */
11
- export function write_decal_record(target: Float32Array, offset: number, decal: Decal, matrix: Float32Array | number[], uv: {
12
+ export function write_decal_record(target: Float32Array, target_words: Uint32Array, offset: number, decal: Decal, matrix: Float32Array | number[], uv: {
12
13
  albedo: Rectangle;
13
14
  normal: Rectangle;
14
15
  orm: Rectangle;
@@ -1 +1 @@
1
- {"version":3,"file":"decal_gpu_records.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/decal_gpu_records.js"],"names":[],"mappings":"AA2BA;;;;;;;;;GASG;AACH,2CAPW,YAAY,UACZ,MAAM,wBAEN,YAAY,GAAC,MAAM,EAAE,MACrB;IAAC,MAAM,YAAY;IAAC,MAAM,YAAY;IAAC,GAAG,YAAW;CAAC,WACtD;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,QAmDvD;AAED;;;;;;;;;;;;GAYG;AACH,iDAHW,MAAM;IAAC,KAAK,QAAO;CAAC,CAAC,GACnB,MAAM;IAAC,KAAK,QAAO;CAAC,CAAC,CAoBjC"}
1
+ {"version":3,"file":"decal_gpu_records.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/decal_gpu_records.js"],"names":[],"mappings":"AA4CA;;;;;;;;;;GAUG;AACH,2CARW,YAAY,gBACZ,WAAW,UACX,MAAM,wBAEN,YAAY,GAAC,MAAM,EAAE,MACrB;IAAC,MAAM,YAAY;IAAC,MAAM,YAAY;IAAC,GAAG,YAAW;CAAC,WACtD;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,QAsDvD;AAED;;;;;;;;;;;;GAYG;AACH,iDAHW,MAAM;IAAC,KAAK,QAAO;CAAC,CAAC,GACnB,MAAM;IAAC,KAAK,QAAO;CAAC,CAAC,CAoBjC"}
@@ -1,6 +1,7 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
  import { m4_invert } from "../../../core/geom/3d/mat4/m4_invert.js";
3
3
  import { array_copy } from "../../../core/collection/array/array_copy.js";
4
+ import { clamp01 } from "../../../core/math/clamp01.js";
4
5
  import {
5
6
  DECAL_RECORD_OFFSET_COLOR,
6
7
  DECAL_RECORD_OFFSET_EMISSIVE,
@@ -10,9 +11,25 @@ import {
10
11
  DECAL_RECORD_OFFSET_TRANSFORM_INVERSE,
11
12
  DECAL_RECORD_OFFSET_UV_ALBEDO,
12
13
  DECAL_RECORD_OFFSET_UV_NORMAL,
13
- DECAL_RECORD_OFFSET_UV_ORM
14
+ DECAL_RECORD_OFFSET_UV_ORM,
15
+ DECAL_RECORD_OFFSET_WEIGHT_EMISSIVE,
16
+ DECAL_RECORD_OFFSET_WEIGHTS
14
17
  } from "./DECAL_GPU_RECORD.js";
15
18
 
19
+ /**
20
+ * WGSL's `pack2x16unorm`: `low` in bits 0..15, `high` in bits 16..31, each clamped to [0, 1].
21
+ *
22
+ * @param {number} low
23
+ * @param {number} high
24
+ * @returns {number} u32
25
+ */
26
+ function pack2x16unorm(low, high) {
27
+ const x = Math.round(clamp01(low) * 65535);
28
+ const y = Math.round(clamp01(high) * 65535);
29
+
30
+ return ((y << 16) | x) >>> 0;
31
+ }
32
+
16
33
  /**
17
34
  * @param {Float32Array} target
18
35
  * @param {number} offset in words
@@ -29,14 +46,17 @@ function write_uv(target, offset, uv) {
29
46
  * Write one decal into the buffer every decal shader reads.
30
47
  *
31
48
  * @param {Float32Array} target
49
+ * @param {Uint32Array} target_words the same memory as `target`, for the fields that are bit patterns
32
50
  * @param {number} offset in words, a multiple of the record size
33
51
  * @param {Decal} decal
34
52
  * @param {Float32Array|number[]} matrix the entity's world transform, column-major
35
53
  * @param {{albedo: Rectangle, normal: Rectangle, orm: Rectangle}} uv atlas rectangles
36
54
  * @param {{albedo: number, normal: number, orm: number}} max_lod per atlas, from each patch's border
37
55
  */
38
- export function write_decal_record(target, offset, decal, matrix, uv, max_lod) {
56
+ export function write_decal_record(target, target_words, offset, decal, matrix, uv, max_lod) {
39
57
  assert.defined(target, 'target');
58
+ assert.equal(target_words.buffer, target.buffer, 'target_words aliases target');
59
+ assert.equal(target_words.byteOffset, target.byteOffset, 'target_words.byteOffset === target.byteOffset');
40
60
  assert.defined(decal, 'decal');
41
61
  assert.defined(matrix, 'matrix');
42
62
 
@@ -73,12 +93,13 @@ export function write_decal_record(target, offset, decal, matrix, uv, max_lod) {
73
93
  target[offset + DECAL_RECORD_OFFSET_EMISSIVE] = emissive.r * intensity;
74
94
  target[offset + DECAL_RECORD_OFFSET_EMISSIVE + 1] = emissive.g * intensity;
75
95
  target[offset + DECAL_RECORD_OFFSET_EMISSIVE + 2] = emissive.b * intensity;
76
- target[offset + DECAL_RECORD_OFFSET_EMISSIVE + 3] = 0;
77
96
 
78
97
  target[offset + DECAL_RECORD_OFFSET_PARAMS] = decal.roughness;
79
98
  target[offset + DECAL_RECORD_OFFSET_PARAMS + 1] = decal.metalness;
80
- target[offset + DECAL_RECORD_OFFSET_PARAMS + 2] = 0;
81
- target[offset + DECAL_RECORD_OFFSET_PARAMS + 3] = 0;
99
+
100
+ target_words[offset + DECAL_RECORD_OFFSET_WEIGHTS] = pack2x16unorm(decal.albedo_weight, decal.normal_weight);
101
+ target_words[offset + DECAL_RECORD_OFFSET_WEIGHTS + 1] = pack2x16unorm(decal.roughness_weight, decal.metalness_weight);
102
+ target_words[offset + DECAL_RECORD_OFFSET_WEIGHT_EMISSIVE] = pack2x16unorm(decal.emissive_weight, 0);
82
103
 
83
104
  target[offset + DECAL_RECORD_OFFSET_LOD] = max_lod.albedo;
84
105
  target[offset + DECAL_RECORD_OFFSET_LOD + 1] = max_lod.normal;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Opaque white: a mask of one everywhere, and a colour that the tint alone decides.
3
+ *
4
+ * @returns {Sampler2D}
5
+ */
6
+ export function decal_identity_albedo(): Sampler2D;
1
7
  /**
2
8
  * A flat tangent-space normal: (0, 0, 1) encoded the way a normal map stores it.
3
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"decal_material_samplers.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/decal_material_samplers.js"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,yCAFa,SAAS,CAUrB;AAED;;;;;;;;;;;;;;GAcG;AACH,sCAFa,SAAS,CAWrB;AAED;;;;;;;;;;;;;GAaG;AACH,oCAJW,SAAS,GAAC,IAAI,YACd,SAAS,GAAC,IAAI,GACZ,SAAS,GAAC,IAAI,CAyC1B;0BA3GyB,6CAA6C"}
1
+ {"version":3,"file":"decal_material_samplers.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/decal_material_samplers.js"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,yCAFa,SAAS,CAQrB;AAED;;;;GAIG;AACH,yCAFa,SAAS,CAUrB;AAED;;;;;;;;;;;;;;GAcG;AACH,sCAFa,SAAS,CAWrB;AAED;;;;;;;;;;;;;GAaG;AACH,oCAJW,SAAS,GAAC,IAAI,YACd,SAAS,GAAC,IAAI,GACZ,SAAS,GAAC,IAAI,CAyC1B;0BAxHyB,6CAA6C"}
@@ -12,6 +12,19 @@ import { Sampler2D } from "../../graphics/texture/sampler/Sampler2D.js";
12
12
  */
13
13
  const IDENTITY_SIZE = 8;
14
14
 
15
+ /**
16
+ * Opaque white: a mask of one everywhere, and a colour that the tint alone decides.
17
+ *
18
+ * @returns {Sampler2D}
19
+ */
20
+ export function decal_identity_albedo() {
21
+ const sampler = Sampler2D.uint8(4, IDENTITY_SIZE, IDENTITY_SIZE);
22
+
23
+ sampler.data.fill(255);
24
+
25
+ return sampler;
26
+ }
27
+
15
28
  /**
16
29
  * A flat tangent-space normal: (0, 0, 1) encoded the way a normal map stores it.
17
30
  *
@@ -53,7 +53,7 @@ resources.createGroup()
53
53
  .addUniform("settings", DECAL_CLUSTER_ASSIGNMENT_SETTINGS);
54
54
 
55
55
  resources.createGroup()
56
- .addStorageBuffer("decal_data", WebGPUArray.f32);
56
+ .addStorageBuffer("decal_data", WebGPUArray.u32);
57
57
 
58
58
  const CLUSTER_DATA_STRUCT = WebGPUStruct.from({
59
59
  offset: atomic_u32,
@@ -34,7 +34,7 @@ resources.createGroup()
34
34
  .addUniform("settings", SETTINGS_STRUCT);
35
35
 
36
36
  resources.createGroup()
37
- .addStorageBuffer("decal_data", WebGPUArray.f32);
37
+ .addStorageBuffer("decal_data", WebGPUArray.u32);
38
38
 
39
39
  resources.createGroup()
40
40
  .addStorageBuffer("output", OUTPUT_STRUCT, true);
@@ -9,6 +9,11 @@ export const DECAL_COMPOSITE_SETTINGS: WebGPUStruct;
9
9
  * `shader_decal_tile_copy`'s copy of the same tiles, so only the covered part of the screen
10
10
  * is read and written twice, rather than all of it once.
11
11
  *
12
+ * **Each channel blends by the decal's mask times that channel's own weight**, so a decal may write
13
+ * any subset of albedo, normal, roughness, metalness and emission. A channel no decal over a pixel
14
+ * weights comes back with exactly the bits it had, and a decal skips the atlas samples only its
15
+ * unweighted channels would read.
16
+ *
12
17
  * The face normal is carried through untouched. A decal changes what a surface looks like, not which
13
18
  * way it is turned, and the face normal is what the fade and everything downstream reason about.
14
19
  *
@@ -1 +1 @@
1
- {"version":3,"file":"shader_decal_composite.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/shader_decal_composite.js"],"names":[],"mappings":"AAgEA,oDAKG;AAuRH;;;;;;;;;;;;;;GAcG;AACH,qCAFU,eAAe,CActB;6BAzU0B,qDAAqD;gCARlD,sBAAsB"}
1
+ {"version":3,"file":"shader_decal_composite.d.ts","sourceRoot":"","sources":["../../../../../src/engine/graphics3/decal/shader_decal_composite.js"],"names":[],"mappings":"AAkEA,oDAKG;AAyTH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qCAFU,eAAe,CActB;6BAlX0B,qDAAqD;gCARlD,sBAAsB"}
@@ -59,7 +59,9 @@ import {
59
59
  DECAL_RECORD_OFFSET_TRANSFORM_INVERSE,
60
60
  DECAL_RECORD_OFFSET_UV_ALBEDO,
61
61
  DECAL_RECORD_OFFSET_UV_NORMAL,
62
- DECAL_RECORD_OFFSET_UV_ORM
62
+ DECAL_RECORD_OFFSET_UV_ORM,
63
+ DECAL_RECORD_OFFSET_WEIGHT_EMISSIVE,
64
+ DECAL_RECORD_OFFSET_WEIGHTS
63
65
  } from "./DECAL_GPU_RECORD.js";
64
66
 
65
67
  export const DECAL_COMPOSITE_SETTINGS = WebGPUStruct.from({
@@ -91,7 +93,7 @@ resources.createGroup()
91
93
  .addTexture("scene_depth");
92
94
 
93
95
  resources.createGroup()
94
- .addStorageBuffer("decal_data", WebGPUArray.f32)
96
+ .addStorageBuffer("decal_data", WebGPUArray.u32)
95
97
  .addStorageBuffer("cluster_lookup", WebGPUArray.from(DECAL_CLUSTER_METADATA))
96
98
  .addStorageBuffer("cluster_data", WebGPUArray.u32)
97
99
  .addStorageBuffer("decal_tiles", WebGPUArray.u32);
@@ -227,6 +229,9 @@ fn main(
227
229
  var normal = shading_normal;
228
230
  var emissive = rgbe9995_decode(old_emissive);
229
231
 
232
+ var wrote_normal = false;
233
+ var wrote_emissive = false;
234
+
230
235
  let uv_bias = view_uv_derivative_bias(view.upscale_ratio);
231
236
 
232
237
  for (var i = 0u; i < metadata.count; i++) {
@@ -277,50 +282,81 @@ fn main(
277
282
  // coverage together and the fade scales both at once
278
283
  let source = albedo_sample * tint * fade;
279
284
 
285
+ // the mask: every channel blends by this, scaled by its own weight
280
286
  let coverage = source.a;
281
287
 
282
288
  if (coverage <= 0.0) {
283
289
  continue;
284
290
  }
285
291
 
286
- albedo = source.rgb + albedo * (1.0 - coverage);
292
+ let weights_albedo_normal = unpack2x16unorm(decal_word(decal_index, ${DECAL_RECORD_OFFSET_WEIGHTS}u));
293
+ let weights_roughness_metalness = unpack2x16unorm(decal_word(decal_index, ${DECAL_RECORD_OFFSET_WEIGHTS + 1}u));
294
+ let weight_emissive = unpack2x16unorm(decal_word(decal_index, ${DECAL_RECORD_OFFSET_WEIGHT_EMISSIVE}u)).x;
287
295
 
288
- let orm = textureSampleBarycentric(
289
- atlas_orm,
290
- atlas_orm_sampler,
291
- decal_sampling_info(local_uv, duv_dx, duv_dy, decal_vec4(decal_index, ${DECAL_RECORD_OFFSET_UV_ORM}u), lod.z, atlas_orm_size)
292
- );
296
+ let weight_albedo = weights_albedo_normal.x;
297
+ let weight_normal = weights_albedo_normal.y;
298
+ let weight_roughness = weights_roughness_metalness.x;
299
+ let weight_metalness = weights_roughness_metalness.y;
293
300
 
294
- let params = decal_vec4(decal_index, ${DECAL_RECORD_OFFSET_PARAMS}u);
301
+ // premultiplied, so the weight scales the colour and the coverage it replaces alike
302
+ albedo = source.rgb * weight_albedo + albedo * (1.0 - coverage * weight_albedo);
295
303
 
296
- // glTF packing, whose R channel is ambient occlusion and is deliberately unused
297
- roughness = mix(roughness, orm.g * params.x, coverage);
298
- metalness = mix(metalness, orm.b * params.y, coverage);
304
+ if (weight_roughness > 0.0 || weight_metalness > 0.0 || weight_emissive > 0.0) {
305
+ let orm = textureSampleBarycentric(
306
+ atlas_orm,
307
+ atlas_orm_sampler,
308
+ decal_sampling_info(local_uv, duv_dx, duv_dy, decal_vec4(decal_index, ${DECAL_RECORD_OFFSET_UV_ORM}u), lod.z, atlas_orm_size)
309
+ );
299
310
 
300
- let tangent_normal = textureSampleBarycentric(
301
- atlas_normal,
302
- atlas_normal_sampler,
303
- decal_sampling_info(local_uv, duv_dx, duv_dy, decal_vec4(decal_index, ${DECAL_RECORD_OFFSET_UV_NORMAL}u), lod.y, atlas_normal_size)
304
- ).rgb * 2.0 - 1.0;
311
+ let params = decal_vec2(decal_index, ${DECAL_RECORD_OFFSET_PARAMS}u);
305
312
 
306
- let decal_normal = normalize(
307
- tangent_normal.x * frame.tangent
308
- + tangent_normal.y * frame.bitangent
309
- + tangent_normal.z * frame.normal
310
- );
313
+ // glTF packing, whose R channel is ambient occlusion and is deliberately unused
314
+ roughness = mix(roughness, orm.g * params.x, coverage * weight_roughness);
315
+ metalness = mix(metalness, orm.b * params.y, coverage * weight_metalness);
316
+
317
+ if (weight_emissive > 0.0) {
318
+ let emission = decal_vec3(decal_index, ${DECAL_RECORD_OFFSET_EMISSIVE}u) * orm.a;
319
+
320
+ // lerp, not add: a decal is a surface override and occludes whatever was emitting beneath it
321
+ emissive = mix(emissive, emission, coverage * weight_emissive);
322
+
323
+ wrote_emissive = true;
324
+ }
325
+ }
326
+
327
+ if (weight_normal > 0.0) {
328
+ let tangent_normal = textureSampleBarycentric(
329
+ atlas_normal,
330
+ atlas_normal_sampler,
331
+ decal_sampling_info(local_uv, duv_dx, duv_dy, decal_vec4(decal_index, ${DECAL_RECORD_OFFSET_UV_NORMAL}u), lod.y, atlas_normal_size)
332
+ ).rgb * 2.0 - 1.0;
311
333
 
312
- normal = normalize(mix(normal, decal_normal, coverage));
334
+ let decal_normal = normalize(
335
+ tangent_normal.x * frame.tangent
336
+ + tangent_normal.y * frame.bitangent
337
+ + tangent_normal.z * frame.normal
338
+ );
313
339
 
314
- let emission = decal_vec4(decal_index, ${DECAL_RECORD_OFFSET_EMISSIVE}u).rgb * orm.a;
340
+ normal = normalize(mix(normal, decal_normal, coverage * weight_normal));
315
341
 
316
- // lerp, not add: a decal is a surface override and occludes whatever was emitting beneath it
317
- emissive = mix(emissive, emission, coverage);
342
+ wrote_normal = true;
343
+ }
318
344
  }
319
345
 
320
346
  out.albedo = vec4<f32>(albedo, old_albedo.a);
321
347
  out.pbr = vec2<f32>(metalness, roughness);
322
- out.normal = vec4<u32>(encode_g_buffer_normal(normal), old_normal.zw);
323
- out.emissive = rgbe9995_encode(emissive);
348
+
349
+ /*
350
+ The two encoded channels are re-encoded only when a decal wrote them: decoding and encoding
351
+ again is not exact, and a channel no decal weights must come back with the bits it had.
352
+ */
353
+ if (wrote_normal) {
354
+ out.normal = vec4<u32>(encode_g_buffer_normal(normal), old_normal.zw);
355
+ }
356
+
357
+ if (wrote_emissive) {
358
+ out.emissive = rgbe9995_encode(emissive);
359
+ }
324
360
 
325
361
  return out;
326
362
  }
@@ -356,6 +392,11 @@ fn main(
356
392
  * `shader_decal_tile_copy`'s copy of the same tiles, so only the covered part of the screen
357
393
  * is read and written twice, rather than all of it once.
358
394
  *
395
+ * **Each channel blends by the decal's mask times that channel's own weight**, so a decal may write
396
+ * any subset of albedo, normal, roughness, metalness and emission. A channel no decal over a pixel
397
+ * weights comes back with exactly the bits it had, and a decal skips the atlas samples only its
398
+ * unweighted channels would read.
399
+ *
359
400
  * The face normal is carried through untouched. A decal changes what a surface looks like, not which
360
401
  * way it is turned, and the face normal is what the fade and everything downstream reason about.
361
402
  *
@@ -224,6 +224,10 @@ export class SimActionExecutor {
224
224
  /**
225
225
  * Execute an action: capture prior state of affected components, apply, log.
226
226
  *
227
+ * Not re-entrant: calling `execute` or {@link record} from inside `affected_components`,
228
+ * {@link authorize}, `apply`, `announce` or {@link on_component_written} is illegal (the
229
+ * executor is passed to actions for `slot_table` / `current_sender_id` reads only).
230
+ *
227
231
  * @param {SimAction} action
228
232
  * @param {number} [sender_id] peer that originated this action.
229
233
  * Defaults to {@link SENDER_LOCAL} for locally-originated actions.
@@ -1 +1 @@
1
- {"version":3,"file":"SimActionExecutor.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/SimActionExecutor.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,2BAFU,MAAM,CAEiB;AAEjC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,6BAFU,MAAM,CAEmB;AAEnC;;;;;;;;;;GAUG;AACH,8BAFU,MAAM,CAEoB;AAEpC;;;;;;;;;;;;GAYG;AACH,+BAFU,MAAM,CAEqB;AAErC;;;;;;GAMG;AACH,0BAFU,MAAM,CAEgB;AAEhC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IA2EI;;;;;;;;;OASG;IACH,sGATW;QACV,KAAS,yBAAyB;QAClC,UAAc,YAAY;QAC1B,eAAmB,oBAAoB;QACvC,kBAAsB,8BAA8B;QACpD,UAAc,uBAAuB;QACrC,gBAAoB,CAAC,mBAAmB;KACrC,EAyFH;IAjKD;;;;;;;;;OASG;IACH,gBAFU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAEP;IAEtB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,WAFU,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,KAAK,OAAO,CAAC,GAAG,IAAI,CAEtE;IAEjB;;;;;;;;;;;;;;;OAeG;IACH,UAFU,OAAO,CAEA;IAEjB;;;;;;;OAOG;IACH,sBAFU,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,UAAU,KAAK,IAAI,CAAC,GAAG,IAAI,CAE7C;IAaxB;;OAEG;IACH,8BAAkB;IAElB;;OAEG;IACH,sBAA4B;IAE5B;;OAEG;IACH,mCAAsC;IAEtC;;OAEG;IACH,gDAA4C;IAE5C;;;;OAIG;IACH,iCAA4B;IAE5B;;;;;;;;;;;OAWG;IACH,kBAFU,mBAAiB,IAAI,CAES;IA4BxC;;;;;;;OAOG;IACH,mBAFU,MAAM,CAEqB;IAErC;;;;;;;OAOG;IACH,kBAFU,MAAM,CAEoB;IAGxC;;;;;;;;;;OAUG;IACH,uCAPW,MAAM,GAGJ,OAAO,CA0KnB;IAkCD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,gCAwCC;IAED;;;;;;;;;;;;;OAaG;IACH,4BAFW,MAAM,QAqChB;IAED;;;;;;;;OAQG;IACH,sBAJW,UAAU,UACV,MAAM,UACN,MAAM,QAchB;;CACJ;mBA7mBkB,uCAAuC"}
1
+ {"version":3,"file":"SimActionExecutor.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/sim/SimActionExecutor.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,2BAFU,MAAM,CAEiB;AAEjC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,6BAFU,MAAM,CAEmB;AAEnC;;;;;;;;;;GAUG;AACH,8BAFU,MAAM,CAEoB;AAEpC;;;;;;;;;;;;GAYG;AACH,+BAFU,MAAM,CAEqB;AAErC;;;;;;GAMG;AACH,0BAFU,MAAM,CAEgB;AAEhC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IA2EI;;;;;;;;;OASG;IACH,sGATW;QACV,KAAS,yBAAyB;QAClC,UAAc,YAAY;QAC1B,eAAmB,oBAAoB;QACvC,kBAAsB,8BAA8B;QACpD,UAAc,uBAAuB;QACrC,gBAAoB,CAAC,mBAAmB;KACrC,EAyFH;IAjKD;;;;;;;;;OASG;IACH,gBAFU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAEP;IAEtB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,WAFU,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,KAAK,OAAO,CAAC,GAAG,IAAI,CAEtE;IAEjB;;;;;;;;;;;;;;;OAeG;IACH,UAFU,OAAO,CAEA;IAEjB;;;;;;;OAOG;IACH,sBAFU,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,UAAU,KAAK,IAAI,CAAC,GAAG,IAAI,CAE7C;IAaxB;;OAEG;IACH,8BAAkB;IAElB;;OAEG;IACH,sBAA4B;IAE5B;;OAEG;IACH,mCAAsC;IAEtC;;OAEG;IACH,gDAA4C;IAE5C;;;;OAIG;IACH,iCAA4B;IAE5B;;;;;;;;;;;OAWG;IACH,kBAFU,mBAAiB,IAAI,CAES;IA4BxC;;;;;;;OAOG;IACH,mBAFU,MAAM,CAEqB;IAErC;;;;;;;OAOG;IACH,kBAFU,MAAM,CAEoB;IAGxC;;;;;;;;;;;;;;OAcG;IACH,uCAPW,MAAM,GAGJ,OAAO,CA0KnB;IAkCD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,gCAwCC;IAED;;;;;;;;;;;;;OAaG;IACH,4BAFW,MAAM,QAqChB;IAED;;;;;;;;OAQG;IACH,sBAJW,UAAU,UACV,MAAM,UACN,MAAM,QAchB;;CACJ;mBAjnBkB,uCAAuC"}
@@ -274,6 +274,10 @@ export class SimActionExecutor {
274
274
  /**
275
275
  * Execute an action: capture prior state of affected components, apply, log.
276
276
  *
277
+ * Not re-entrant: calling `execute` or {@link record} from inside `affected_components`,
278
+ * {@link authorize}, `apply`, `announce` or {@link on_component_written} is illegal (the
279
+ * executor is passed to actions for `slot_table` / `current_sender_id` reads only).
280
+ *
277
281
  * @param {SimAction} action
278
282
  * @param {number} [sender_id] peer that originated this action.
279
283
  * Defaults to {@link SENDER_LOCAL} for locally-originated actions.
@@ -1 +1 @@
1
- {"version":3,"file":"foliage_atlas_cutout.d.ts","sourceRoot":"","sources":["../../../../../src/generation/foliage/material/foliage_atlas_cutout.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;GAYG;AACH,mDARW,kBAAkB,WAClB,MAAM,WACN,UAAU,WACV,UAAU,gBACV,MAAM,SACN,MAAM,WACN,MAAM,QAiHhB;AAED;;;;;;;;GAQG;AACH,oDANW,kBAAkB,WAClB,MAAM,SACN,YAAY,SACZ,MAAM,WACN,MAAM,QAkBhB;AAED;;;;;;;;GAQG;AACH,8CAJW,OAAO,gCAAgC,EAAE,iBAAiB,QAC1D,kBAAkB,GAChB,kBAAkB,CAU9B;mCA7K4D,yBAAyB"}
1
+ {"version":3,"file":"foliage_atlas_cutout.d.ts","sourceRoot":"","sources":["../../../../../src/generation/foliage/material/foliage_atlas_cutout.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;GAYG;AACH,mDARW,kBAAkB,WAClB,MAAM,WACN,UAAU,WACV,UAAU,gBACV,MAAM,SACN,MAAM,WACN,MAAM,QAiHhB;AAED;;;;;;;;GAQG;AACH,oDANW,kBAAkB,WAClB,MAAM,SACN,YAAY,SACZ,MAAM,WACN,MAAM,QAkBhB;AAED;;;;;;;;GAQG;AACH,8CAJW,OAAO,gCAAgC,EAAE,iBAAiB,QAC1D,kBAAkB,GAChB,kBAAkB,CAqB9B;mCA3L4D,yBAAyB"}