@woosh/meep-engine 3.14.6 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/package.json +1 -1
  2. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +48 -0
  3. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  4. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +246 -3
  5. package/src/shade/RENDERER_CONTRACT.md +584 -580
  6. package/src/shade/playground/avboit/README.md +117 -0
  7. package/src/shade/playground/avboit/index.html +215 -0
  8. package/src/shade/playground/avboit/main.d.ts +2 -0
  9. package/src/shade/playground/avboit/main.d.ts.map +1 -0
  10. package/src/shade/playground/avboit/main.js +875 -0
  11. package/src/shade/renderer/Renderer.d.ts +16 -0
  12. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  13. package/src/shade/renderer/Renderer.js +29 -28
  14. package/src/shade/renderer/ShadeTransparencyMode.d.ts +13 -0
  15. package/src/shade/renderer/ShadeTransparencyMode.d.ts.map +1 -0
  16. package/src/shade/renderer/ShadeTransparencyMode.js +30 -0
  17. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts +9 -0
  18. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts.map +1 -1
  19. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +26 -0
  20. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts +7 -2
  21. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  22. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -1
  23. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.js +1 -1
  24. package/src/shade/renderer/rasterize/forward/FORWARD_VERTEX_SHADER_STRUCT.d.ts +3 -0
  25. package/src/shade/renderer/rasterize/forward/FORWARD_VERTEX_SHADER_STRUCT.d.ts.map +1 -0
  26. package/src/shade/renderer/rasterize/{native/oit → forward}/FORWARD_VERTEX_SHADER_STRUCT.js +4 -4
  27. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts +3 -0
  28. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts.map +1 -0
  29. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.js +17 -0
  30. package/src/shade/renderer/rasterize/{native/oit → forward}/chunk_forward_shade_standard_fragment_brick4.d.ts +1 -1
  31. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -0
  32. package/src/shade/renderer/rasterize/{native/oit → forward}/chunk_forward_shade_standard_fragment_brick4.js +16 -16
  33. package/src/shade/renderer/rasterize/{native/oit → forward}/chunk_forward_shade_standard_fragment_ibl.d.ts +1 -1
  34. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -0
  35. package/src/shade/renderer/rasterize/{native/oit → forward}/chunk_forward_shade_standard_fragment_ibl.js +17 -17
  36. package/src/shade/renderer/rasterize/{native/oit → forward}/chunk_material_side_should_draw.d.ts +1 -1
  37. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts.map +1 -0
  38. package/src/shade/renderer/rasterize/{native/oit → forward}/chunk_material_side_should_draw.js +2 -2
  39. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts +3 -0
  40. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -0
  41. package/src/shade/renderer/rasterize/{native/oit → forward}/vertex_shader_chunk.js +4 -4
  42. package/src/shade/renderer/rasterize/native/avboit/AVBOITSettings.d.ts +27 -0
  43. package/src/shade/renderer/rasterize/native/avboit/AVBOITSettings.d.ts.map +1 -0
  44. package/src/shade/renderer/rasterize/native/avboit/AVBOITSettings.js +27 -0
  45. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.d.ts +107 -0
  46. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.d.ts.map +1 -0
  47. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.js +120 -0
  48. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +463 -0
  49. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +509 -0
  50. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_WARP_STRUCT.d.ts +15 -0
  51. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_WARP_STRUCT.d.ts.map +1 -0
  52. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_WARP_STRUCT.js +33 -0
  53. package/src/shade/renderer/rasterize/native/avboit/avboit_build_depth_curve.d.ts +20 -0
  54. package/src/shade/renderer/rasterize/native/avboit/avboit_build_depth_curve.d.ts.map +1 -0
  55. package/src/shade/renderer/rasterize/native/avboit/avboit_build_depth_curve.js +38 -0
  56. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.d.ts +38 -0
  57. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.d.ts.map +1 -0
  58. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +130 -0
  59. package/src/shade/renderer/rasterize/native/avboit/avboit_spec_support.d.ts +37 -0
  60. package/src/shade/renderer/rasterize/native/avboit/avboit_spec_support.d.ts.map +1 -0
  61. package/src/shade/renderer/rasterize/native/avboit/avboit_spec_support.js +73 -0
  62. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_counts_to_extinction.d.ts +9 -0
  63. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_counts_to_extinction.d.ts.map +1 -0
  64. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_counts_to_extinction.js +17 -0
  65. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_dilate_word.d.ts +11 -0
  66. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_dilate_word.d.ts.map +1 -0
  67. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_dilate_word.js +18 -0
  68. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_extinction_to_counts.d.ts +9 -0
  69. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_extinction_to_counts.d.ts.map +1 -0
  70. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_extinction_to_counts.js +17 -0
  71. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_extinction_to_transmittance.d.ts +9 -0
  72. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_extinction_to_transmittance.d.ts.map +1 -0
  73. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_extinction_to_transmittance.js +17 -0
  74. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts +15 -0
  75. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts.map +1 -0
  76. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.js +25 -0
  77. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_integral_depth_coordinate.d.ts +17 -0
  78. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_integral_depth_coordinate.d.ts.map +1 -0
  79. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_integral_depth_coordinate.js +35 -0
  80. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_range.d.ts +11 -0
  81. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_range.d.ts.map +1 -0
  82. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_range.js +21 -0
  83. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_word_mask.d.ts +9 -0
  84. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_word_mask.d.ts.map +1 -0
  85. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_word_mask.js +26 -0
  86. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_overflows.d.ts +11 -0
  87. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_overflows.d.ts.map +1 -0
  88. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_overflows.js +22 -0
  89. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_pack_counts.d.ts +10 -0
  90. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_pack_counts.d.ts.map +1 -0
  91. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_pack_counts.js +21 -0
  92. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_sample_transmittance.d.ts +10 -0
  93. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_sample_transmittance.d.ts.map +1 -0
  94. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_sample_transmittance.js +32 -0
  95. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_transmission_tint.d.ts +20 -0
  96. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_transmission_tint.d.ts.map +1 -0
  97. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_transmission_tint.js +27 -0
  98. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_transmittance_to_extinction.d.ts +10 -0
  99. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_transmittance_to_extinction.d.ts.map +1 -0
  100. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_transmittance_to_extinction.js +18 -0
  101. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_unpack_counts.d.ts +9 -0
  102. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_unpack_counts.d.ts.map +1 -0
  103. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_unpack_counts.js +21 -0
  104. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_view_depth_to_physical.d.ts +9 -0
  105. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_view_depth_to_physical.d.ts.map +1 -0
  106. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_view_depth_to_physical.js +23 -0
  107. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_view_depth_to_virtual.d.ts +13 -0
  108. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_view_depth_to_virtual.d.ts.map +1 -0
  109. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_view_depth_to_virtual.js +27 -0
  110. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp.d.ts +22 -0
  111. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp.d.ts.map +1 -0
  112. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_warp.js +38 -0
  113. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +117 -0
  114. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -0
  115. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +935 -0
  116. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_build_warp.d.ts +8 -0
  117. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_build_warp.d.ts.map +1 -0
  118. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_build_warp.js +135 -0
  119. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts +3 -0
  120. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts.map +1 -0
  121. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.js +101 -0
  122. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts +3 -0
  123. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts.map +1 -0
  124. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.js +96 -0
  125. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts +3 -0
  126. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -0
  127. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +83 -0
  128. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.d.ts +9 -0
  129. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.d.ts.map +1 -0
  130. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.js +119 -0
  131. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts +3 -0
  132. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts.map +1 -0
  133. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js +81 -0
  134. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts +15 -0
  135. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts.map +1 -0
  136. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +237 -0
  137. package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts +22 -0
  138. package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts.map +1 -0
  139. package/src/shade/renderer/rasterize/native/material_draw_indirect.js +69 -0
  140. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  141. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +665 -722
  142. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +3 -3
  143. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +4 -4
  144. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +4 -4
  145. package/src/shade/renderer/rasterize/native/oit/FORWARD_VERTEX_SHADER_STRUCT.d.ts +0 -3
  146. package/src/shade/renderer/rasterize/native/oit/FORWARD_VERTEX_SHADER_STRUCT.d.ts.map +0 -1
  147. package/src/shade/renderer/rasterize/native/oit/SHADING_SCENE_RESOURCE_GROUP.d.ts +0 -3
  148. package/src/shade/renderer/rasterize/native/oit/SHADING_SCENE_RESOURCE_GROUP.d.ts.map +0 -1
  149. package/src/shade/renderer/rasterize/native/oit/SHADING_SCENE_RESOURCE_GROUP.js +0 -17
  150. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.d.ts.map +0 -1
  151. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.d.ts.map +0 -1
  152. package/src/shade/renderer/rasterize/native/oit/chunk_material_side_should_draw.d.ts.map +0 -1
  153. package/src/shade/renderer/rasterize/native/oit/vertex_shader_chunk.d.ts +0 -3
  154. package/src/shade/renderer/rasterize/native/oit/vertex_shader_chunk.d.ts.map +0 -1
@@ -0,0 +1,935 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import { SamplerDescriptor } from "../../../../descriptor/texture/SamplerDescriptor.js";
3
+ import { BufferResourceDescriptor } from "../../../../device/graph/BufferResourceDescriptor.js";
4
+ import { TextureResourceDescriptor } from "../../../../device/graph/TextureResourceDescriptor.js";
5
+ import { rp_rewrite_for_primitive_state } from "../../../../device/pipeline/rp_rewrite_for_primitive_state.js";
6
+ import { BindGroupDescriptor } from "../../../binding/BindGroupDescriptor.js";
7
+ import { SHADING_LIGHT_RESOURCE_GROUP } from "../../../deferred/SHADING_LIGHT_RESOURCE_GROUP.js";
8
+ import { ShadeDrawMode } from "../../../material/ShadeDrawMode.js";
9
+ import { ShadeDrawSide } from "../../../material/ShadeDrawSide.js";
10
+ import { TransparencyMode } from "../../../material/TransparencyMode.js";
11
+ import { ShadeIndirectLightingMode } from "../../../ShadeIndirectLightingMode.js";
12
+ import { graph_compute_pass } from "../../../shader/graph/compute/graph_compute_pass.js";
13
+ import { graph_image_pass } from "../../../shader/graph/graph_image_pass.js";
14
+ import { graph_import_buffer } from "../../../shader/graph/graph_import_buffer.js";
15
+ import { graph_import_texture } from "../../../shader/graph/graph_import_texture.js";
16
+ import {
17
+ SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR
18
+ } from "../../../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
19
+ import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../../../STATIC_GRAPHICS_ENGINE_ASSETS.js";
20
+ import { rasterization_material_bucket } from "../../expand/bucket/chunk_rasterization_material_bucket.js";
21
+ import { construct_primitive_state } from "../../bucket/construct_primitive_state.js";
22
+ import { filter_materials_by_bucket } from "../../bucket/filter_materials_by_bucket.js";
23
+ import {
24
+ graph_prepare_meshlet_draw_commands_by_material
25
+ } from "../../bucket/prepare_meshlet_draw_commands_by_material.js";
26
+ import { SHADING_SCENE_RESOURCE_GROUP } from "../../forward/SHADING_SCENE_RESOURCE_GROUP.js";
27
+ import {
28
+ RASTERIZATION_SHADER_BIND_GROUP_SCENE,
29
+ RASTERIZATION_SHADER_BIND_GROUP_VIEW
30
+ } from "../alpha_tested_pass_resources.js";
31
+ import { material_draw_indirect } from "../material_draw_indirect.js";
32
+ import {
33
+ AVBOIT_INTEGRAL_FORMAT,
34
+ AVBOIT_INTEGRATE_WORKGROUP_SIZE,
35
+ AVBOIT_OCCUPANCY_WORDS,
36
+ AVBOIT_PHYSICAL_SLICES,
37
+ AVBOIT_VOXEL_DOWNSCALE
38
+ } from "./AVBOIT_CONSTANTS.js";
39
+ import { avboit_build_depth_curve } from "./avboit_build_depth_curve.js";
40
+ import { AVBOITSettings } from "./AVBOITSettings.js";
41
+ import { AVBOIT_WARP_STRUCT } from "./AVBOIT_WARP_STRUCT.js";
42
+ import { AVBOIT_BUILD_WARP_SETTINGS_STRUCT, shader_avboit_build_warp } from "./shader_avboit_build_warp.js";
43
+ import { shader_avboit_draw_brick4 } from "./shader_avboit_draw_brick4.js";
44
+ import { shader_avboit_draw_ibl } from "./shader_avboit_draw_ibl.js";
45
+ import { shader_avboit_integrate } from "./shader_avboit_integrate.js";
46
+ import { AVBOIT_OCCUPANCY_SETTINGS_STRUCT, shader_avboit_occupancy } from "./shader_avboit_occupancy.js";
47
+ import { shader_avboit_resolve } from "./shader_avboit_resolve.js";
48
+ import {
49
+ AVBOIT_SPLAT_BIND_GROUP_VOLUME,
50
+ AVBOIT_SPLAT_DUMMY_FORMAT,
51
+ shader_avboit_splat
52
+ } from "./shader_avboit_splat.js";
53
+
54
+ const BIND_GROUP_LAYOUT_SCENE = SHADING_SCENE_RESOURCE_GROUP.generateBindGroupLayoutDescriptor(GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX);
55
+ const BIND_GROUP_LAYOUT_LIGHT = SHADING_LIGHT_RESOURCE_GROUP.generateBindGroupLayoutDescriptor(GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX);
56
+
57
+ const WARP_BUFFER_SIZE = AVBOIT_WARP_STRUCT.size;
58
+
59
+ /**
60
+ * What a caller that passes no settings gets: every switch at its documented default.
61
+ * @type {AVBOITSettings}
62
+ */
63
+ const DEFAULT_SETTINGS = new AVBOITSettings();
64
+
65
+ /**
66
+ * Extinction volume XY resolution for an internal resolution.
67
+ *
68
+ * @param {ArrayLike<number>} resolution
69
+ * @returns {number[]}
70
+ */
71
+ export function avboit_voxel_resolution(resolution) {
72
+ return [
73
+ Math.max(1, Math.ceil(resolution[0] / AVBOIT_VOXEL_DOWNSCALE)),
74
+ Math.max(1, Math.ceil(resolution[1] / AVBOIT_VOXEL_DOWNSCALE)),
75
+ ];
76
+ }
77
+
78
+ /**
79
+ * Occupancy prepass over one bucket's HZB-filtered meshlets (plan §3.3).
80
+ *
81
+ * @param {FrameGraph} graph
82
+ * @param {GPUSceneContext} scene
83
+ * @param {number} camera resource ID
84
+ * @param {ArrayLike<number>} cluster_parameters the depth curve, see avboit_build_depth_curve
85
+ * @param {number} meshlet_collection resource ID, `MESHLET_COLLECTION_STRUCT` with its count header
86
+ * @param {number} meshlet_iterator_command resource ID, indirect dispatch over the collection
87
+ * @param {number} [occupancy] resource ID of an existing occupancy buffer to add to; created when -1
88
+ * @returns {number} resource ID of the occupancy bits
89
+ */
90
+ export function graph_avboit_occupancy({
91
+ graph,
92
+ scene,
93
+ camera,
94
+ cluster_parameters,
95
+ meshlet_collection,
96
+ meshlet_iterator_command,
97
+ occupancy = -1,
98
+ }) {
99
+
100
+ assert.isNonNegativeInteger(camera, 'camera');
101
+ assert.isArrayLike(cluster_parameters, 'cluster_parameters');
102
+ assert.isNonNegativeInteger(meshlet_collection, 'meshlet_collection');
103
+ assert.isNonNegativeInteger(meshlet_iterator_command, 'meshlet_iterator_command');
104
+
105
+ const settings = { cluster_parameters };
106
+
107
+ /**
108
+ *
109
+ * @param data
110
+ * @param {FramePassResources} resources
111
+ * @param {GraphicsExecutionContext} context
112
+ */
113
+ function execute(data, resources, context) {
114
+ const encoder = context.encoder;
115
+
116
+ shader_avboit_occupancy.dispatchIndirect({
117
+ encoder,
118
+ command: resources.get(data.command),
119
+ bindings: {
120
+ camera: resources.get(data.camera),
121
+ settings: encoder.allocateTransientValueBuffer(AVBOIT_OCCUPANCY_SETTINGS_STRUCT, settings, GPUBufferUsage.UNIFORM),
122
+ scene_database: scene.scene_database_buffer,
123
+ meshlet_metadata: scene.geometries.meshlets.buffer_metadata,
124
+ input: resources.get(data.input),
125
+ occupancy: resources.get(data.occupancy),
126
+ }
127
+ });
128
+ }
129
+
130
+ const pass_data = {};
131
+ const pass = graph.add("AVBOIT/occupancy", pass_data, execute);
132
+
133
+ pass_data.camera = pass.read(camera);
134
+ pass_data.input = pass.read(meshlet_collection);
135
+ pass_data.command = pass.read(meshlet_iterator_command);
136
+
137
+ if (occupancy !== -1) {
138
+ pass.read(occupancy);
139
+ pass_data.occupancy = pass.write(occupancy);
140
+ } else {
141
+ pass_data.occupancy = pass.create("AVBOIT occupancy", BufferResourceDescriptor.empty(
142
+ AVBOIT_OCCUPANCY_WORDS * 4,
143
+ GPUBufferUsage.STORAGE
144
+ ));
145
+ }
146
+
147
+ return pass_data.occupancy;
148
+ }
149
+
150
+ /**
151
+ * The depth-warp LUT from the occupancy bits (plan §3.4).
152
+ *
153
+ * @param {FrameGraph} graph
154
+ * @param {number} occupancy resource ID
155
+ * @param {number[]} voxel_resolution
156
+ * @param {ArrayLike<number>} cluster_parameters the depth curve, see avboit_build_depth_curve
157
+ * @param {AVBOITSettings} [avboit] the renderer's switches, carried into the header
158
+ * @returns {number} resource ID of the `AVBOIT_WARP_STRUCT` buffer
159
+ */
160
+ export function graph_avboit_build_warp({
161
+ graph,
162
+ occupancy,
163
+ voxel_resolution,
164
+ cluster_parameters,
165
+ avboit = DEFAULT_SETTINGS,
166
+ }) {
167
+
168
+ assert.isNonNegativeInteger(occupancy, 'occupancy');
169
+ assert.isArrayLike(cluster_parameters, 'cluster_parameters');
170
+
171
+ const settings = {
172
+ physical_count: AVBOIT_PHYSICAL_SLICES,
173
+ voxel_width: voxel_resolution[0],
174
+ voxel_height: voxel_resolution[1],
175
+ tint_from_base_color: avboit.transmission_tint_from_base_color ? 1 : 0,
176
+ cluster_parameters,
177
+ };
178
+
179
+ /**
180
+ *
181
+ * @param data
182
+ * @param {FramePassResources} resources
183
+ * @param {GraphicsExecutionContext} context
184
+ */
185
+ function execute(data, resources, context) {
186
+ const encoder = context.encoder;
187
+
188
+ shader_avboit_build_warp.dispatch({
189
+ encoder,
190
+ bindings: {
191
+ // a few words per frame: a transient uniform, serialized from the plain object
192
+ settings: encoder.allocateTransientValueBuffer(AVBOIT_BUILD_WARP_SETTINGS_STRUCT, settings, GPUBufferUsage.UNIFORM),
193
+ occupancy: resources.get(data.occupancy),
194
+ warp: resources.get(data.warp),
195
+ },
196
+ group_count_x: 1,
197
+ group_count_y: 1,
198
+ group_count_z: 1,
199
+ });
200
+ }
201
+
202
+ // Recorded by hand rather than through graph_compute_pass: the warp is a read_write storage
203
+ // buffer, which that helper treats as a managed input and will not create from a descriptor.
204
+ const pass_data = {};
205
+ const pass = graph.add("AVBOIT/build warp", pass_data, execute);
206
+
207
+ pass_data.occupancy = pass.read(occupancy);
208
+ // every entry that can be read is written; no clear
209
+ pass_data.warp = pass.create("AVBOIT warp", BufferResourceDescriptor.from(WARP_BUFFER_SIZE, GPUBufferUsage.STORAGE));
210
+
211
+ return pass_data.warp;
212
+ }
213
+
214
+ /**
215
+ * Splat one bucket's transparent draws into the extinction volume (plan §3.5).
216
+ *
217
+ * @param {FrameGraph} graph
218
+ * @param {GPUViewContext} view_ctx
219
+ * @param {number} material_count
220
+ * @param {ShadeMaterial[]} materials
221
+ * @param {number} draw_commands resource ID
222
+ * @param {number} meshlets resource ID
223
+ * @param {number} camera resource ID
224
+ * @param {number} warp resource ID
225
+ * @param {number[]} voxel_resolution
226
+ * @param {PrimitiveState} primitive
227
+ * @param {{extinction: number, overflow: number, dummy: number}} [volume] existing resources to add to
228
+ * @returns {{extinction: number, overflow: number, dummy: number}}
229
+ */
230
+ export function graph_avboit_splat({
231
+ graph,
232
+ view_ctx,
233
+ material_count,
234
+ materials,
235
+ draw_commands,
236
+ meshlets,
237
+ camera,
238
+ warp,
239
+ voxel_resolution,
240
+ primitive,
241
+ volume,
242
+ }) {
243
+
244
+ assert.isNonNegativeInteger(material_count, 'material_count');
245
+ assert.isNonNegativeInteger(draw_commands, 'draw_commands');
246
+ assert.isNonNegativeInteger(meshlets, 'meshlets');
247
+ assert.isNonNegativeInteger(warp, 'warp');
248
+
249
+ const scene_ctx = view_ctx.scene;
250
+
251
+ /**
252
+ *
253
+ * @param data
254
+ * @param {FramePassResources} resources
255
+ * @param {GraphicsExecutionContext} context
256
+ */
257
+ function execute(data, resources, context) {
258
+
259
+ assert.ok(context.graphics.device.features.has("indirect-first-instance"), '"indirect-first-instance" feature needs to be enabled for non-zero firstInstance values to be used.')
260
+
261
+ const command_buffer_draw = resources.get(data.draw_commands);
262
+ const meshlet_buffer = resources.get(data.meshlets);
263
+
264
+ const camera_buffer = resources.get(data.camera);
265
+ const warp_buffer = resources.get(data.warp);
266
+ const extinction_buffer = resources.get(data.extinction);
267
+ const overflow_buffer = resources.get(data.overflow);
268
+ const t_dummy = resources.get(data.dummy);
269
+
270
+ const encoder = context.encoder;
271
+ const graphics = context.graphics;
272
+ const bind_manager = graphics.bind_groups;
273
+
274
+ const scene_bindings = bind_manager.obtain(BindGroupDescriptor.from(
275
+ BIND_GROUP_LAYOUT_SCENE,
276
+ [
277
+ { buffer: meshlet_buffer },
278
+ { buffer: scene_ctx.geometries.meshlets.buffer_metadata },
279
+ { buffer: scene_ctx.geometries.meshlets.buffer_data },
280
+ { buffer: scene_ctx.scene_database_buffer },
281
+ { buffer: scene_ctx.geometries.buffer_metadata },
282
+ ]
283
+ ));
284
+
285
+ const render_pass_descriptor = shader_avboit_splat;
286
+ const layouts = render_pass_descriptor.pipeline.layout.bindGroupLayouts;
287
+
288
+ const view_bindings = bind_manager.obtain(BindGroupDescriptor.from(
289
+ layouts[RASTERIZATION_SHADER_BIND_GROUP_VIEW],
290
+ [
291
+ { buffer: camera_buffer },
292
+ { buffer: warp_buffer },
293
+ ]
294
+ ));
295
+
296
+ const volume_bindings = bind_manager.obtain(BindGroupDescriptor.from(
297
+ layouts[AVBOIT_SPLAT_BIND_GROUP_VOLUME],
298
+ [
299
+ { buffer: extinction_buffer },
300
+ { buffer: overflow_buffer },
301
+ ]
302
+ ));
303
+
304
+ // the dummy target is never written; it only sizes the raster
305
+ const pass_encoder = encoder.beginRenderPass(render_pass_descriptor.toGPU({
306
+ colorTargets: [t_dummy],
307
+ colorLoadOp: "clear",
308
+ colorStoreOp: "discard",
309
+ }));
310
+
311
+ const pipeline_descriptor = rp_rewrite_for_primitive_state(render_pass_descriptor.pipeline, primitive);
312
+ const pipeline = graphics.render_pipelines.obtain(pipeline_descriptor);
313
+ pass_encoder.setPipeline(pipeline);
314
+
315
+ pass_encoder.setBindGroup(RASTERIZATION_SHADER_BIND_GROUP_SCENE, scene_bindings);
316
+ pass_encoder.setBindGroup(RASTERIZATION_SHADER_BIND_GROUP_VIEW, view_bindings);
317
+ pass_encoder.setBindGroup(AVBOIT_SPLAT_BIND_GROUP_VOLUME, volume_bindings);
318
+
319
+ material_draw_indirect(
320
+ scene_ctx.materials,
321
+ material_count,
322
+ materials,
323
+ render_pass_descriptor,
324
+ bind_manager,
325
+ pass_encoder,
326
+ command_buffer_draw
327
+ );
328
+
329
+ pass_encoder.end();
330
+ }
331
+
332
+ const pass_data = {};
333
+ const pass = graph.add("AVBOIT/splat", pass_data, execute);
334
+
335
+ pass_data.draw_commands = pass.read(draw_commands);
336
+ pass_data.meshlets = pass.read(meshlets);
337
+ pass_data.camera = pass.read(camera);
338
+ pass_data.warp = pass.read(warp);
339
+
340
+ if (volume !== undefined) {
341
+ pass.read(volume.extinction);
342
+ pass_data.extinction = pass.write(volume.extinction);
343
+ pass.read(volume.overflow);
344
+ pass_data.overflow = pass.write(volume.overflow);
345
+ pass.read(volume.dummy);
346
+ pass_data.dummy = pass.write(volume.dummy);
347
+ } else {
348
+ const texel_count = voxel_resolution[0] * voxel_resolution[1];
349
+
350
+ // one packed u32 per voxel, column-major with the slice fastest; zeroed every frame
351
+ pass_data.extinction = pass.create("AVBOIT extinction", BufferResourceDescriptor.empty(
352
+ texel_count * AVBOIT_PHYSICAL_SLICES * 4,
353
+ GPUBufferUsage.STORAGE
354
+ ));
355
+
356
+ // three inverted first-overflow marks per texel; zero is "none"
357
+ pass_data.overflow = pass.create("AVBOIT overflow", BufferResourceDescriptor.empty(
358
+ texel_count * 3 * 4,
359
+ GPUBufferUsage.STORAGE
360
+ ));
361
+
362
+ pass_data.dummy = pass.create("AVBOIT splat target", TextureResourceDescriptor.from({
363
+ resolution: voxel_resolution,
364
+ format: AVBOIT_SPLAT_DUMMY_FORMAT,
365
+ usage: GPUTextureUsage.RENDER_ATTACHMENT
366
+ }));
367
+ }
368
+
369
+ return {
370
+ extinction: pass_data.extinction,
371
+ overflow: pass_data.overflow,
372
+ dummy: pass_data.dummy,
373
+ };
374
+ }
375
+
376
+ /**
377
+ * Integrate the extinction volume into the 3D transmittance-integral texture (plan §3.6).
378
+ *
379
+ * @param {FrameGraph} graph
380
+ * @param {number} warp resource ID
381
+ * @param {number} extinction resource ID
382
+ * @param {number} overflow resource ID
383
+ * @param {number[]} voxel_resolution
384
+ * @returns {number} resource ID of the integral texture, `P + 1` slices deep
385
+ */
386
+ export function graph_avboit_integrate({
387
+ graph,
388
+ warp,
389
+ extinction,
390
+ overflow,
391
+ voxel_resolution,
392
+ }) {
393
+
394
+ assert.isNonNegativeInteger(warp, 'warp');
395
+ assert.isNonNegativeInteger(extinction, 'extinction');
396
+ assert.isNonNegativeInteger(overflow, 'overflow');
397
+
398
+ const { integral } = graph_compute_pass({
399
+ graph,
400
+ shader: shader_avboit_integrate,
401
+ bindings: {
402
+ warp,
403
+ extinction_volume: extinction,
404
+ overflow_slice: overflow,
405
+ integral: TextureResourceDescriptor.from({
406
+ resolution: [voxel_resolution[0], voxel_resolution[1], AVBOIT_PHYSICAL_SLICES + 1],
407
+ dimension: "3d",
408
+ format: AVBOIT_INTEGRAL_FORMAT,
409
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
410
+ }),
411
+ },
412
+ group_count: [
413
+ Math.ceil(voxel_resolution[0] / AVBOIT_INTEGRATE_WORKGROUP_SIZE),
414
+ Math.ceil(voxel_resolution[1] / AVBOIT_INTEGRATE_WORKGROUP_SIZE),
415
+ 1,
416
+ ],
417
+ });
418
+
419
+ return integral;
420
+ }
421
+
422
+ /**
423
+ * Draw one bucket's transparent materials with full shading into the three accumulators (plan §3.8).
424
+ *
425
+ * @param {FrameGraph} graph
426
+ * @param {GPUViewContext} view_ctx
427
+ * @param {number} material_count
428
+ * @param {ShadeMaterial[]} materials
429
+ * @param {number} draw_commands resource ID
430
+ * @param {number} meshlets resource ID
431
+ * @param {number} depth_texture resource ID
432
+ * @param {number} warp resource ID
433
+ * @param {number} integral resource ID
434
+ * @param {PrimitiveState} primitive
435
+ * @param {number} light_cluster_parameters
436
+ * @param {number} light_cluster_lookup
437
+ * @param {number} light_cluster_data
438
+ * @param {number} shadowmap_atlas
439
+ * @param {number} volumetrics_lut
440
+ * @param {number} volumetrics_metadata
441
+ * @param {{color: number, norm: number, extinction: number}} [accumulators] existing targets to add to
442
+ * @param {ShadeIndirectLightingMode} indirect_lighting_mode
443
+ * @returns {{color: number, norm: number, extinction: number}}
444
+ */
445
+ export function graph_avboit_draw({
446
+ graph,
447
+ view_ctx,
448
+ material_count,
449
+ materials,
450
+ draw_commands,
451
+ meshlets,
452
+ depth_texture,
453
+ warp,
454
+ integral,
455
+ primitive,
456
+ light_cluster_parameters,
457
+ light_cluster_lookup,
458
+ light_cluster_data,
459
+ shadowmap_atlas,
460
+ volumetrics_lut,
461
+ volumetrics_metadata,
462
+ accumulators,
463
+ indirect_lighting_mode = ShadeIndirectLightingMode.IBL,
464
+ }) {
465
+
466
+ assert.isNonNegativeInteger(material_count, 'material_count');
467
+ assert.isNonNegativeInteger(draw_commands, 'draw_commands');
468
+ assert.isNonNegativeInteger(meshlets, 'meshlets');
469
+ assert.isNonNegativeInteger(warp, 'warp');
470
+ assert.isNonNegativeInteger(integral, 'integral');
471
+
472
+ const scene_ctx = view_ctx.scene;
473
+
474
+ /**
475
+ *
476
+ * @param data
477
+ * @param {FramePassResources} resources
478
+ * @param {GraphicsExecutionContext} context
479
+ */
480
+ function execute(data, resources, context) {
481
+
482
+ assert.ok(context.graphics.device.features.has("indirect-first-instance"), '"indirect-first-instance" feature needs to be enabled for non-zero firstInstance values to be used.')
483
+
484
+ const command_buffer_draw = resources.get(data.draw_commands);
485
+ const meshlet_buffer = resources.get(data.meshlets);
486
+
487
+ const t_depth = resources.get(data.depth);
488
+ const t_color = resources.get(data.color);
489
+ const t_norm = resources.get(data.norm);
490
+ const t_extinction = resources.get(data.extinction);
491
+
492
+ const warp_buffer = resources.get(data.warp);
493
+ const t_integral = resources.get(data.integral);
494
+
495
+ const light_cluster_parameters = resources.get(data.light_cluster_parameters);
496
+ const light_cluster_lookup = resources.get(data.light_cluster_lookup);
497
+ const light_cluster_data = resources.get(data.light_cluster_data);
498
+
499
+ const shadowmap_atlas = resources.get(data.shadowmap_atlas);
500
+
501
+ const t_volumetrics_lut = resources.get(data.volumetrics_lut);
502
+ const volumetrics_metadata = resources.get(data.volumetrics_metadata);
503
+
504
+ const encoder = context.encoder;
505
+ const graphics = context.graphics;
506
+ const bind_manager = graphics.bind_groups;
507
+
508
+ const scene_bindings = bind_manager.obtain(BindGroupDescriptor.from(
509
+ BIND_GROUP_LAYOUT_SCENE,
510
+ [
511
+ { buffer: meshlet_buffer },
512
+ { buffer: scene_ctx.geometries.meshlets.buffer_metadata },
513
+ { buffer: scene_ctx.geometries.meshlets.buffer_data },
514
+ { buffer: scene_ctx.scene_database_buffer },
515
+ { buffer: scene_ctx.geometries.buffer_metadata },
516
+ ]
517
+ ));
518
+
519
+ const sampler_shadowmap = graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
520
+
521
+ const light_bindings = bind_manager.obtain(BindGroupDescriptor.from(
522
+ BIND_GROUP_LAYOUT_LIGHT,
523
+ [
524
+ { buffer: view_ctx.scene.lights.buffer_data },
525
+ view_ctx.scene.lights.environment.obtainView(),
526
+ //
527
+ { buffer: light_cluster_parameters },
528
+ { buffer: light_cluster_lookup },
529
+ { buffer: light_cluster_data },
530
+ //
531
+ shadowmap_atlas.obtainView(),
532
+ sampler_shadowmap,
533
+ ]
534
+ ));
535
+
536
+ const use_brick4 = data.indirect_lighting_mode === ShadeIndirectLightingMode.Brick4;
537
+ const render_pass_descriptor = use_brick4
538
+ ? shader_avboit_draw_brick4
539
+ : shader_avboit_draw_ibl;
540
+
541
+ const pass_encoder = encoder.beginRenderPass(render_pass_descriptor.toGPU({
542
+ colorTargets: [t_color, t_norm, t_extinction],
543
+ depthTarget: t_depth,
544
+ colorLoadOp: data.clear_targets ? "clear" : "load",
545
+ // depth is only tested, never written
546
+ depthLoadOp: "load",
547
+ storeOp: "store",
548
+ }));
549
+
550
+ const pipeline_descriptor = rp_rewrite_for_primitive_state(render_pass_descriptor.pipeline, primitive);
551
+ const pipeline = graphics.render_pipelines.obtain(pipeline_descriptor);
552
+ pass_encoder.setPipeline(pipeline);
553
+
554
+ pass_encoder.setBindGroup(RASTERIZATION_SHADER_BIND_GROUP_SCENE, scene_bindings);
555
+ pass_encoder.setBindGroup(3, light_bindings);
556
+
557
+ // linear and clamped on every axis: serves the split-sum LUT and the integral texture alike
558
+ const sampler_linear = graphics.samplers.obtain(SamplerDescriptor.from({
559
+ magFilter: "linear",
560
+ }));
561
+
562
+ const t_split_sum_lut = graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.split_sum);
563
+ const stbn_vec3 = graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
564
+
565
+ // Entry order matches the view group declared in shader_avboit_draw_ibl / _brick4; the
566
+ // Brick4 variant carries its lightmap buffer right after the integral texture.
567
+ const view_bind_entries = use_brick4
568
+ ? [
569
+ { buffer: view_ctx.camera.buffer.buffer },
570
+ { buffer: view_ctx.uniform_buffer.buffer },
571
+ { buffer: warp_buffer },
572
+ t_integral.obtainView(),
573
+ { buffer: view_ctx.scene.volumetric_light_map.buffer },
574
+ t_split_sum_lut.obtainView(),
575
+ sampler_linear,
576
+ // volumetrics
577
+ { buffer: volumetrics_metadata },
578
+ t_volumetrics_lut.obtainView(),
579
+ stbn_vec3.obtainView(),
580
+ ]
581
+ : [
582
+ { buffer: view_ctx.camera.buffer.buffer },
583
+ { buffer: view_ctx.uniform_buffer.buffer },
584
+ { buffer: warp_buffer },
585
+ t_integral.obtainView(),
586
+ t_split_sum_lut.obtainView(),
587
+ sampler_linear,
588
+ // volumetrics
589
+ { buffer: volumetrics_metadata },
590
+ t_volumetrics_lut.obtainView(),
591
+ stbn_vec3.obtainView(),
592
+ ];
593
+
594
+ const view_bindings = bind_manager.obtain(BindGroupDescriptor.from(
595
+ render_pass_descriptor.pipeline.layout.bindGroupLayouts[RASTERIZATION_SHADER_BIND_GROUP_VIEW],
596
+ view_bind_entries
597
+ ));
598
+
599
+ pass_encoder.setBindGroup(RASTERIZATION_SHADER_BIND_GROUP_VIEW, view_bindings);
600
+
601
+ material_draw_indirect(
602
+ scene_ctx.materials,
603
+ material_count,
604
+ materials,
605
+ render_pass_descriptor,
606
+ bind_manager,
607
+ pass_encoder,
608
+ command_buffer_draw
609
+ );
610
+
611
+ pass_encoder.end();
612
+ }
613
+
614
+ const pass_data = {
615
+ indirect_lighting_mode,
616
+ clear_targets: accumulators === undefined,
617
+ };
618
+ const pass = graph.add("AVBOIT/draw", pass_data, execute);
619
+
620
+ pass_data.draw_commands = pass.read(draw_commands);
621
+ pass_data.meshlets = pass.read(meshlets);
622
+ pass_data.depth = pass.read(depth_texture);
623
+ pass_data.warp = pass.read(warp);
624
+ pass_data.integral = pass.read(integral);
625
+
626
+ if (accumulators !== undefined) {
627
+ pass.read(accumulators.color);
628
+ pass_data.color = pass.write(accumulators.color);
629
+ pass.read(accumulators.norm);
630
+ pass_data.norm = pass.write(accumulators.norm);
631
+ pass.read(accumulators.extinction);
632
+ pass_data.extinction = pass.write(accumulators.extinction);
633
+ } else {
634
+ const make = label => pass.create(label, TextureResourceDescriptor.from({
635
+ resolution: view_ctx.resolution,
636
+ format: 'rgba16float',
637
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
638
+ }));
639
+
640
+ pass_data.color = make("AVBOIT accumulated color");
641
+ pass_data.norm = make("AVBOIT accumulated normalization");
642
+ pass_data.extinction = make("AVBOIT accumulated extinction");
643
+ }
644
+
645
+ pass_data.light_cluster_parameters = pass.read(light_cluster_parameters);
646
+ pass_data.light_cluster_lookup = pass.read(light_cluster_lookup);
647
+ pass_data.light_cluster_data = pass.read(light_cluster_data);
648
+
649
+ pass_data.shadowmap_atlas = pass.read(shadowmap_atlas);
650
+
651
+ pass_data.volumetrics_lut = pass.read(volumetrics_lut);
652
+ pass_data.volumetrics_metadata = pass.read(volumetrics_metadata);
653
+
654
+ return {
655
+ color: pass_data.color,
656
+ norm: pass_data.norm,
657
+ extinction: pass_data.extinction,
658
+ };
659
+ }
660
+
661
+ /**
662
+ * Adaptive voxel-based order-independent transparency (Drobot, SIGGRAPH 2025). Does not write depth.
663
+ *
664
+ * Same argument object and same return as `graph_rasterize_meshes_transparent_oit`, so `Renderer`
665
+ * selects between the two with `transparency_mode` alone. The passes it records are listed in
666
+ * `AVBOIT_PLAN_2026_09_03.md` §3.1.
667
+ *
668
+ * @param {FrameGraph} graph
669
+ * @param {number} buckets
670
+ * @param {GPUViewContext} view_ctx
671
+ * @param {number[]} viewport
672
+ * @param {number} color_texture resource ID
673
+ * @param {number} depth_texture resource ID
674
+ * @param {GPUCollectionLimits} limits
675
+ * @param {number} light_cluster_parameters
676
+ * @param {number} light_cluster_lookup
677
+ * @param {number} light_cluster_data
678
+ * @param {number} shadowmap_atlas
679
+ * @param {number} volumetrics_lut
680
+ * @param {number} volumetrics_metadata
681
+ * @param {ShadeIndirectLightingMode} indirect_lighting_mode
682
+ * @param {AVBOITSettings} [avboit] `Renderer.avboit`; the MBOIT orchestrator ignores it
683
+ * @returns {number} resource ID of the composited color texture
684
+ */
685
+ export function graph_rasterize_meshes_transparent_avboit({
686
+ graph,
687
+ buckets,
688
+ view_ctx,
689
+ viewport,
690
+ depth_texture,
691
+ color_texture,
692
+ limits,
693
+ light_cluster_parameters,
694
+ light_cluster_lookup,
695
+ light_cluster_data,
696
+
697
+ shadowmap_atlas,
698
+
699
+ volumetrics_lut,
700
+ volumetrics_metadata,
701
+
702
+ indirect_lighting_mode = ShadeIndirectLightingMode.IBL,
703
+ avboit = DEFAULT_SETTINGS,
704
+ }) {
705
+
706
+ assert.isNonNegativeInteger(buckets, 'buckets');
707
+ assert.isNonNegativeInteger(color_texture, 'color_texture');
708
+ assert.isNonNegativeInteger(depth_texture, 'depth_texture');
709
+
710
+ assert.isNonNegativeInteger(light_cluster_parameters, 'light_cluster_parameters');
711
+ assert.isNonNegativeInteger(light_cluster_lookup, 'light_cluster_lookup');
712
+ assert.isNonNegativeInteger(light_cluster_data, 'light_cluster_data');
713
+
714
+ assert.isNonNegativeInteger(shadowmap_atlas, 'shadowmap_atlas');
715
+
716
+ assert.equal(view_ctx.isGPUViewContext, true, 'view_ctx.isGPUViewContext !== true');
717
+
718
+ const scene_ctx = view_ctx.scene;
719
+
720
+ /**
721
+ * @type {ShadeMaterial[]}
722
+ */
723
+ const materials_front = [];
724
+ /**
725
+ * @type {ShadeMaterial[]}
726
+ */
727
+ const materials_double = [];
728
+
729
+ const scene_materials = scene_ctx.scene.instances.materials;
730
+
731
+ // Front-sided and double-sided materials need different pipeline states, so every raster pass
732
+ // below runs twice. `ShadeDrawSide.Back` is not drawn, the same as under MBOIT (plan §7).
733
+ const material_count_front = filter_materials_by_bucket(
734
+ materials_front, 0,
735
+ TransparencyMode.Transparent,
736
+ ShadeDrawMode.Triangles,
737
+ ShadeDrawSide.Front,
738
+ scene_materials,
739
+ scene_materials.length
740
+ );
741
+
742
+ const material_count_double = filter_materials_by_bucket(
743
+ materials_double, 0,
744
+ TransparencyMode.Transparent,
745
+ ShadeDrawMode.Triangles,
746
+ ShadeDrawSide.Double,
747
+ scene_materials,
748
+ scene_materials.length
749
+ );
750
+
751
+ if ((material_count_front + material_count_double) === 0) {
752
+ // nothing to do
753
+ return color_texture;
754
+ }
755
+
756
+ const bucket_index_front = rasterization_material_bucket(
757
+ TransparencyMode.Transparent, ShadeDrawMode.Triangles, ShadeDrawSide.Front
758
+ );
759
+
760
+ const bucket_index_double = rasterization_material_bucket(
761
+ TransparencyMode.Transparent, ShadeDrawMode.Triangles, ShadeDrawSide.Double
762
+ );
763
+
764
+ const primitive_front = construct_primitive_state(ShadeDrawMode.Triangles, ShadeDrawSide.Front);
765
+ const primitive_double = construct_primitive_state(ShadeDrawMode.Triangles, ShadeDrawSide.Double);
766
+
767
+ const gr_hzb = graph_import_texture(graph, view_ctx.hierarchical_z_buffer.texture);
768
+ const gr_camera = graph_import_buffer(graph, view_ctx.camera.buffer.buffer);
769
+
770
+ const voxel_resolution = avboit_voxel_resolution(view_ctx.resolution);
771
+
772
+ // the depth curve for this camera, shared by the occupancy prepass and, through the warp
773
+ // header, by every pass after it
774
+ const camera = view_ctx.camera.camera;
775
+ const cluster_parameters = avboit_build_depth_curve(camera.near, camera.far);
776
+
777
+ // Draw artifacts (shared with MBOIT)
778
+ // ======
779
+
780
+ const prep_front = graph_prepare_meshlet_draw_commands_by_material({
781
+ graph,
782
+ materials: materials_front,
783
+ bucket_id: bucket_index_front,
784
+ limits,
785
+ buckets,
786
+ scene: scene_ctx,
787
+ camera: gr_camera,
788
+ hzb: gr_hzb,
789
+ resolution: [viewport[2], viewport[3]],
790
+ label: `${view_ctx.label}/AVBOIT-front`,
791
+ });
792
+
793
+ const prep_double = graph_prepare_meshlet_draw_commands_by_material({
794
+ graph,
795
+ materials: materials_double,
796
+ bucket_id: bucket_index_double,
797
+ limits,
798
+ buckets,
799
+ scene: scene_ctx,
800
+ camera: gr_camera,
801
+ hzb: gr_hzb,
802
+ resolution: [viewport[2], viewport[3]],
803
+ label: `${view_ctx.label}/AVBOIT-double`,
804
+ });
805
+
806
+ // Occupancy and warp
807
+ // ======
808
+
809
+ let occupancy = graph_avboit_occupancy({
810
+ graph,
811
+ scene: scene_ctx,
812
+ camera: gr_camera,
813
+ cluster_parameters,
814
+ meshlet_collection: prep_front.meshlet_collection,
815
+ meshlet_iterator_command: prep_front.meshlet_iterator_command,
816
+ });
817
+
818
+ occupancy = graph_avboit_occupancy({
819
+ graph,
820
+ scene: scene_ctx,
821
+ camera: gr_camera,
822
+ cluster_parameters,
823
+ meshlet_collection: prep_double.meshlet_collection,
824
+ meshlet_iterator_command: prep_double.meshlet_iterator_command,
825
+ occupancy,
826
+ });
827
+
828
+ const warp = graph_avboit_build_warp({
829
+ graph,
830
+ occupancy,
831
+ voxel_resolution,
832
+ cluster_parameters,
833
+ avboit,
834
+ });
835
+
836
+ // Splat
837
+ // ======
838
+
839
+ let volume = graph_avboit_splat({
840
+ graph,
841
+ view_ctx,
842
+ material_count: material_count_front,
843
+ materials: materials_front,
844
+ draw_commands: prep_front.draw_commands,
845
+ meshlets: prep_front.meshlets,
846
+ camera: gr_camera,
847
+ warp,
848
+ voxel_resolution,
849
+ primitive: primitive_front,
850
+ });
851
+
852
+ volume = graph_avboit_splat({
853
+ graph,
854
+ view_ctx,
855
+ material_count: material_count_double,
856
+ materials: materials_double,
857
+ draw_commands: prep_double.draw_commands,
858
+ meshlets: prep_double.meshlets,
859
+ camera: gr_camera,
860
+ warp,
861
+ voxel_resolution,
862
+ primitive: primitive_double,
863
+ volume,
864
+ });
865
+
866
+ // Integrate
867
+ // ======
868
+
869
+ const integral = graph_avboit_integrate({
870
+ graph,
871
+ warp,
872
+ extinction: volume.extinction,
873
+ overflow: volume.overflow,
874
+ voxel_resolution,
875
+ });
876
+
877
+ // Draw
878
+ // ======
879
+
880
+ const lighting = {
881
+ light_cluster_parameters,
882
+ light_cluster_lookup,
883
+ light_cluster_data,
884
+ shadowmap_atlas,
885
+ volumetrics_lut,
886
+ volumetrics_metadata,
887
+ indirect_lighting_mode,
888
+ };
889
+
890
+ let accumulators = graph_avboit_draw({
891
+ graph,
892
+ view_ctx,
893
+ material_count: material_count_front,
894
+ materials: materials_front,
895
+ draw_commands: prep_front.draw_commands,
896
+ meshlets: prep_front.meshlets,
897
+ depth_texture,
898
+ warp,
899
+ integral,
900
+ primitive: primitive_front,
901
+ ...lighting,
902
+ });
903
+
904
+ accumulators = graph_avboit_draw({
905
+ graph,
906
+ view_ctx,
907
+ material_count: material_count_double,
908
+ materials: materials_double,
909
+ draw_commands: prep_double.draw_commands,
910
+ meshlets: prep_double.meshlets,
911
+ depth_texture,
912
+ warp,
913
+ integral,
914
+ primitive: primitive_double,
915
+ accumulators,
916
+ ...lighting,
917
+ });
918
+
919
+ // Resolve
920
+ // ======
921
+
922
+ const [composited] = graph_image_pass({
923
+ graph,
924
+ shader: shader_avboit_resolve,
925
+ output_resolution: view_ctx.resolution,
926
+ inputs: {
927
+ tScene: color_texture,
928
+ tColor: accumulators.color,
929
+ tNorm: accumulators.norm,
930
+ tExtinction: accumulators.extinction,
931
+ }
932
+ });
933
+
934
+ return composited;
935
+ }