@woosh/meep-engine 3.63.2 → 3.64.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 (148) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +1 -1
  3. package/src/core/color/xyz/m3_chromatic_adaptation_bradford.d.ts +14 -0
  4. package/src/core/color/xyz/m3_chromatic_adaptation_bradford.d.ts.map +1 -0
  5. package/src/core/color/xyz/m3_chromatic_adaptation_bradford.js +51 -0
  6. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts +2 -1
  7. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts.map +1 -1
  8. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +51 -70
  9. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts.map +1 -1
  10. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.js +8 -64
  11. package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.d.ts +17 -0
  12. package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.d.ts.map +1 -0
  13. package/src/core/math/linalg/eigen/matrix_symmetric_jacobi_rotate_in_place.js +64 -0
  14. package/src/core/math/linalg/solve_box_constrained_qp.d.ts +30 -0
  15. package/src/core/math/linalg/solve_box_constrained_qp.d.ts.map +1 -0
  16. package/src/core/math/linalg/solve_box_constrained_qp.js +205 -0
  17. package/src/engine/physics/constraint/soft_spring_coefficients.d.ts +24 -0
  18. package/src/engine/physics/constraint/soft_spring_coefficients.d.ts.map +1 -0
  19. package/src/engine/physics/constraint/soft_spring_coefficients.js +38 -0
  20. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  21. package/src/engine/physics/constraint/solve_constraints.js +16 -8
  22. package/src/engine/physics/ecs/PhysicsSystem.d.ts +54 -0
  23. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  24. package/src/engine/physics/ecs/PhysicsSystem.js +192 -7
  25. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  26. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +3 -5
  27. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  28. package/src/engine/physics/inertia/world_inverse_inertia.js +3 -5
  29. package/src/engine/physics/vehicle/RaycastVehicle.d.ts +183 -12
  30. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  31. package/src/engine/physics/vehicle/RaycastVehicle.js +1046 -121
  32. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +17 -0
  33. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
  34. package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +46 -0
  35. package/src/shade/playground/tonemap_sdr/README.md +11 -8
  36. package/src/shade/playground/tonemap_sdr/ToneMapCompare.js +2 -2
  37. package/src/shade/renderer/Renderer.d.ts +5 -6
  38. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  39. package/src/shade/renderer/Renderer.js +15 -88
  40. package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.d.ts +14 -0
  41. package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.d.ts.map +1 -0
  42. package/src/shade/renderer/animation/chunk_animation_curve_evaluate_keys.js +62 -0
  43. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +12 -0
  44. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  45. package/src/shade/renderer/buffer/table/GPUDatabase.js +85 -0
  46. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts +2 -1
  47. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts.map +1 -1
  48. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.js +2 -1
  49. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts +158 -0
  50. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts.map +1 -0
  51. package/src/shade/renderer/deferred/tonemap/ColorGrade.js +337 -0
  52. package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.d.ts +9 -0
  53. package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.d.ts.map +1 -0
  54. package/src/shade/renderer/deferred/tonemap/SAMPLER_TONEMAP_LUT.js +15 -0
  55. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.d.ts +6 -0
  56. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.d.ts.map +1 -0
  57. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_ACES.js +84 -0
  58. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.d.ts +10 -0
  59. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.d.ts.map +1 -0
  60. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_GT7.js +25 -0
  61. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.d.ts +9 -0
  62. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.d.ts.map +1 -0
  63. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_NONE.js +20 -0
  64. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.d.ts +14 -0
  65. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.d.ts.map +1 -0
  66. package/src/shade/renderer/deferred/tonemap/TONE_MAP_OPERATOR_PBR_NEUTRAL.js +30 -0
  67. package/src/shade/renderer/deferred/tonemap/ToneMapOperator.d.ts +54 -0
  68. package/src/shade/renderer/deferred/tonemap/ToneMapOperator.d.ts.map +1 -0
  69. package/src/shade/renderer/deferred/tonemap/ToneMapOperator.js +63 -0
  70. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts +106 -0
  71. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts.map +1 -0
  72. package/src/shade/renderer/deferred/tonemap/ToneMapper.js +474 -0
  73. package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts +5 -13
  74. package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts.map +1 -1
  75. package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js +5 -44
  76. package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts +7 -25
  77. package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts.map +1 -1
  78. package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.js +11 -51
  79. package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.d.ts +20 -0
  80. package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.d.ts.map +1 -0
  81. package/src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.js +103 -0
  82. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts +9 -0
  83. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts.map +1 -0
  84. package/src/shade/renderer/deferred/tonemap/{shader_tonemap_HDR_none.js → shader_tonemap_HDR_lut.js} +22 -18
  85. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts +9 -0
  86. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts.map +1 -0
  87. package/src/shade/renderer/deferred/tonemap/{shader_tonemap_LDR_aces.js → shader_tonemap_LDR_lut.js} +24 -24
  88. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.d.ts +23 -0
  89. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.d.ts.map +1 -0
  90. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.js +92 -0
  91. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.d.ts +15 -0
  92. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.d.ts.map +1 -0
  93. package/src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.js +73 -0
  94. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  95. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  96. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  97. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  98. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  99. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +1 -1
  100. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  101. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  102. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts +22 -0
  103. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts.map +1 -0
  104. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.js +62 -0
  105. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts +13 -0
  106. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts.map +1 -0
  107. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.js +140 -0
  108. package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.d.ts +11 -0
  109. package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.d.ts.map +1 -0
  110. package/src/shade/renderer/shader/chunk/color/oklab/chunk_oklab_compute_max_saturation.js +65 -0
  111. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.d.ts +14 -0
  112. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.d.ts.map +1 -0
  113. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_bt2390_eetf.js +38 -0
  114. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.d.ts +16 -0
  115. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.d.ts.map +1 -0
  116. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_lut.js +41 -0
  117. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  118. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -8
  119. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  120. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
  121. package/src/shade/renderer/ShadeToneMappingMode.d.ts +0 -15
  122. package/src/shade/renderer/ShadeToneMappingMode.d.ts.map +0 -1
  123. package/src/shade/renderer/ShadeToneMappingMode.js +0 -41
  124. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts +0 -9
  125. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts.map +0 -1
  126. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.js +0 -79
  127. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts +0 -17
  128. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts.map +0 -1
  129. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.js +0 -101
  130. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts +0 -9
  131. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts.map +0 -1
  132. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts +0 -10
  133. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts.map +0 -1
  134. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.js +0 -80
  135. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts +0 -9
  136. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts.map +0 -1
  137. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.js +0 -80
  138. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts +0 -10
  139. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts.map +0 -1
  140. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts +0 -9
  141. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts.map +0 -1
  142. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.js +0 -71
  143. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts +0 -10
  144. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts.map +0 -1
  145. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.js +0 -76
  146. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.d.ts +0 -3
  147. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.d.ts.map +0 -1
  148. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_hdr_bt2390.js +0 -44
@@ -0,0 +1,474 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { PAPER_WHITE_NITS } from "../../shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js";
3
+ import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
4
+ import { graph_image_pass } from "../../shader/graph/graph_image_pass.js";
5
+ import { graph_import_raw_buffer } from "../../shader/graph/graph_import_raw_buffer.js";
6
+ import { graph_import_texture } from "../../shader/graph/graph_import_texture.js";
7
+ import { GPUTextureContext } from "../../texture/GPUTextureContext.js";
8
+ import { COLOR_GRADE_HEADER_FLOATS, ColorGrade } from "./ColorGrade.js";
9
+ import { shader_tonemap_HDR_lut } from "./shader_tonemap_HDR_lut.js";
10
+ import { shader_tonemap_LDR_lut } from "./shader_tonemap_LDR_lut.js";
11
+ import { shader_tonemap_lut_bake, TONEMAP_LUT_BAKE_GROUP } from "./shader_tonemap_lut_bake.js";
12
+ import { shader_tonemap_lut_sdr_from_hdr } from "./shader_tonemap_lut_sdr_from_hdr.js";
13
+ import { TONE_MAP_OPERATOR_ACES } from "./TONE_MAP_OPERATOR_ACES.js";
14
+ import { TonemapDisplaySettings } from "./TonemapDisplaySettings.js";
15
+
16
+ /**
17
+ * @typedef {import("./ToneMapOperator.js").ToneMapOperator} ToneMapOperator
18
+ * @typedef {import("../../../device/pipeline/PipelineEnquiry.js").PipelineEnquiry} PipelineEnquiry
19
+ * @typedef {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} FrameGraph
20
+ */
21
+
22
+ /**
23
+ * The pass that writes the canvas, for an SDR or an HDR output.
24
+ *
25
+ * @param {boolean} hdr
26
+ */
27
+ function apply_shader(hdr) {
28
+ return hdr ? shader_tonemap_HDR_lut : shader_tonemap_LDR_lut;
29
+ }
30
+
31
+ /**
32
+ * One LUT the tone mapper draws with, and what it holds.
33
+ */
34
+ class ToneMapLut {
35
+ /**
36
+ * @param {GPUDevice} device
37
+ * @param {string} label
38
+ */
39
+ constructor(device, label) {
40
+ /**
41
+ * @readonly
42
+ * @type {GPUTextureContext}
43
+ */
44
+ this.texture = new GPUTextureContext(device);
45
+ this.texture.descriptor.label = label;
46
+ this.texture.descriptor.dimension = "3d";
47
+ this.texture.descriptor.format = "rgba16float";
48
+ this.texture.descriptor.usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING
49
+ | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC;
50
+
51
+ /**
52
+ * Whether the user supplied this LUT, rather than the tone mapper baking it from its operator.
53
+ * @type {boolean}
54
+ */
55
+ this.user = false;
56
+
57
+ /**
58
+ * The operator, resolution and peak this LUT was baked for; `null` operator when it holds no bake.
59
+ * @type {ToneMapOperator|null}
60
+ */
61
+ this.baked_operator = null;
62
+ this.baked_resolution = 0;
63
+ this.baked_peak_nits = NaN;
64
+
65
+ /**
66
+ * The packed grade this LUT was baked with, its bits compared with the grade's each frame.
67
+ * @type {Uint32Array}
68
+ */
69
+ this.baked_grade = new Uint32Array(0);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * @param {Uint32Array} a
75
+ * @param {Uint32Array} b
76
+ * @returns {boolean} whether the two hold the same bits
77
+ */
78
+ function same_words(a, b) {
79
+ const length = a.length;
80
+
81
+ if (length !== b.length) {
82
+ return false;
83
+ }
84
+
85
+ for (let i = 0; i < length; i++) {
86
+ if (a[i] !== b[i]) {
87
+ return false;
88
+ }
89
+ }
90
+
91
+ return true;
92
+ }
93
+
94
+ /**
95
+ * Turns the exposed scene colour into the canvas's colour, through a 3D LUT for each output.
96
+ *
97
+ * Each LUT maps exposed scene-linear Rec.709 to linear Rec.2020 display light, both as PQ (ST 2084) signals with 1 at
98
+ * the paper white, `PAPER_WHITE_NITS`; see `chunk_tonemap_lut`. Texel i of a LUT of N³ holds the scene signal
99
+ * i / (N - 1) along each axis, red fastest. Scene colour past 10000 cd/m², 49.3 × the paper white, reads the last
100
+ * texel. The apply passes take the LUT's output to the canvas's primaries and transfer curve.
101
+ *
102
+ * A LUT comes from {@link grade} and {@link operator}, baked at {@link lut_resolution} and baked again when any of them
103
+ * changes or, for the HDR LUT, when the display's peak does; or from the user, by {@link set_lut_sdr} and
104
+ * {@link set_lut_hdr}, which takes the place of the bake for that output until cleared. A user's LUT is not graded.
105
+ */
106
+ export class ToneMapper {
107
+ /**
108
+ * The tone-mapping function the LUTs are baked from. Unreal's default look unless set. Read every frame.
109
+ * @type {ToneMapOperator}
110
+ */
111
+ operator = TONE_MAP_OPERATOR_ACES;
112
+
113
+ /**
114
+ * Texels along each edge of a baked LUT. At least 2, and at most the device's `maxTextureDimension3D`. Read every
115
+ * frame.
116
+ * @type {number}
117
+ */
118
+ lut_resolution = 32;
119
+
120
+ /**
121
+ * The colour grade ahead of {@link operator}, neutral unless changed. Read every frame; a change bakes again.
122
+ * @readonly
123
+ * @type {ColorGrade}
124
+ */
125
+ grade = new ColorGrade();
126
+
127
+ /**
128
+ * The canvas's primaries and the display's peak, which the Renderer writes.
129
+ * @readonly
130
+ * @type {TonemapDisplaySettings}
131
+ */
132
+ display = new TonemapDisplaySettings();
133
+
134
+ /**
135
+ * @type {GPUDevice}
136
+ */
137
+ #device;
138
+
139
+ /**
140
+ * @type {ToneMapLut}
141
+ */
142
+ #sdr;
143
+
144
+ /**
145
+ * @type {ToneMapLut}
146
+ */
147
+ #hdr;
148
+
149
+ /**
150
+ * The peak the user's HDR LUT was graded for, cd/m².
151
+ * @type {number}
152
+ */
153
+ #hdr_graded_peak_nits = NaN;
154
+
155
+ /**
156
+ * Whether the next {@link render} builds the SDR LUT from the HDR one.
157
+ * @type {boolean}
158
+ */
159
+ #sdr_from_hdr_pending = false;
160
+
161
+ /**
162
+ * {@link grade} as this frame packed it.
163
+ * @type {Float32Array}
164
+ */
165
+ #grade_data = new Float32Array(0);
166
+
167
+ /**
168
+ * {@link #grade_data}'s words.
169
+ * @type {Uint32Array}
170
+ */
171
+ #grade_words = new Uint32Array(0);
172
+
173
+ /**
174
+ * @param {GPUDevice} device
175
+ */
176
+ constructor(device) {
177
+ assert.defined(device, 'device');
178
+
179
+ this.#device = device;
180
+ this.#sdr = new ToneMapLut(device, "Tonemap / SDR LUT");
181
+ this.#hdr = new ToneMapLut(device, "Tonemap / HDR LUT");
182
+ }
183
+
184
+ /**
185
+ * Supply the SDR LUT, in place of the one baked from {@link operator}.
186
+ *
187
+ * @param {number} resolution texels along each edge
188
+ * @param {Float32Array} data resolution³ RGB triples, red fastest, as the class describes
189
+ */
190
+ set_lut_sdr(resolution, data) {
191
+ this.#upload(this.#sdr, resolution, data);
192
+ this.#sdr_from_hdr_pending = false;
193
+ }
194
+
195
+ /**
196
+ * Supply the HDR LUT, in place of the one baked from {@link operator}. It shows as graded: a display under
197
+ * `peak_nits` clips what it cannot reach.
198
+ *
199
+ * @param {number} resolution texels along each edge
200
+ * @param {Float32Array} data resolution³ RGB triples, red fastest, as the class describes
201
+ * @param {number} peak_nits the peak the LUT was graded for, cd/m²
202
+ */
203
+ set_lut_hdr(resolution, data, peak_nits) {
204
+ assert.isNumber(peak_nits, 'peak_nits');
205
+ assert.greaterThan(peak_nits, 0, 'peak_nits');
206
+
207
+ this.#upload(this.#hdr, resolution, data);
208
+ this.#hdr_graded_peak_nits = peak_nits;
209
+ }
210
+
211
+ /**
212
+ * Go back to the SDR LUT baked from {@link operator}.
213
+ */
214
+ clear_lut_sdr() {
215
+ this.#sdr.user = false;
216
+ this.#sdr.baked_operator = null;
217
+ this.#sdr_from_hdr_pending = false;
218
+ }
219
+
220
+ /**
221
+ * Go back to the HDR LUT baked from {@link operator}.
222
+ */
223
+ clear_lut_hdr() {
224
+ this.#hdr.user = false;
225
+ this.#hdr.baked_operator = null;
226
+ }
227
+
228
+ /**
229
+ * Make the SDR LUT from the HDR LUT supplied by {@link set_lut_hdr}, at its resolution: each texel through the
230
+ * BT.2390 EETF from the HDR LUT's graded peak down to the paper white, which keeps the hue and never passes SDR
231
+ * white. Built on the GPU in the next {@link render}, from the HDR LUT as it is then. Stays until
232
+ * {@link set_lut_sdr} or {@link clear_lut_sdr}.
233
+ */
234
+ build_lut_sdr_from_hdr() {
235
+ assert.equal(this.#hdr.user, true, 'build_lut_sdr_from_hdr needs an HDR LUT from set_lut_hdr');
236
+
237
+ const resolution = this.#hdr.texture.width;
238
+
239
+ this.#sdr.texture.resize(resolution, resolution, resolution);
240
+ this.#sdr.user = true;
241
+ this.#sdr.baked_operator = null;
242
+ this.#sdr_from_hdr_pending = true;
243
+ }
244
+
245
+ /**
246
+ * Offer the pipelines the next frame on this output needs.
247
+ *
248
+ * @param {PipelineEnquiry} enquiry
249
+ * @param {boolean} hdr
250
+ * @param {GPUTextureFormat} format the canvas's
251
+ */
252
+ enquire_pipelines(enquiry, hdr, format) {
253
+ enquiry.render.push(apply_shader(hdr).pipeline_for([format]));
254
+ enquiry.compute.push(shader_tonemap_lut_bake(this.operator).pipeline);
255
+ }
256
+
257
+ /**
258
+ * Record the tone mapping of a frame: any LUT work it needs first, then the pass writing `target`.
259
+ *
260
+ * @param {Object} options
261
+ * @param {FrameGraph} options.graph
262
+ * @param {number} options.input_color the scene colour, linear Rec.709
263
+ * @param {number} options.exposure the exposure multiplier, a uniform
264
+ * @param {boolean} options.hdr whether the output is HDR
265
+ * @param {number} options.target the texture to write
266
+ * @returns {number} `target`, written
267
+ */
268
+ render({ graph, input_color, exposure, hdr, target }) {
269
+ assert.isBoolean(hdr, 'hdr');
270
+
271
+ const lut = hdr ? this.#hdr : this.#sdr;
272
+ const peak_nits = hdr ? this.display.peak_nits : PAPER_WHITE_NITS;
273
+
274
+ let bake = false;
275
+
276
+ if (!lut.user) {
277
+ this.#pack_grade();
278
+ bake = this.#bake_is_stale(lut, peak_nits);
279
+ }
280
+
281
+ if (bake) {
282
+ // sized before it is imported, so the import describes the texture the bake writes
283
+ const resolution = this.lut_resolution;
284
+
285
+ this.#check_resolution(resolution);
286
+ lut.texture.resize(resolution, resolution, resolution);
287
+ }
288
+
289
+ const pending = this.#sdr_from_hdr_pending;
290
+
291
+ let gr_hdr = -1;
292
+ let gr_sdr = -1;
293
+
294
+ if (hdr || pending) {
295
+ gr_hdr = graph_import_texture(graph, this.#hdr.texture, "tonemap/HDR LUT");
296
+ }
297
+
298
+ if (!hdr || pending) {
299
+ gr_sdr = graph_import_texture(graph, this.#sdr.texture, "tonemap/SDR LUT");
300
+ }
301
+
302
+ if (pending) {
303
+ // a pass writing an imported texture never culls, so this runs whichever output draws
304
+ const groups = Math.ceil(this.#sdr.texture.width / TONEMAP_LUT_BAKE_GROUP);
305
+
306
+ gr_sdr = graph_compute_pass({
307
+ graph,
308
+ shader: shader_tonemap_lut_sdr_from_hdr,
309
+ bindings: {
310
+ settings: { source_peak_nits: this.#hdr_graded_peak_nits },
311
+ hdr_lut: gr_hdr,
312
+ sdr_lut: gr_sdr,
313
+ },
314
+ group_count: [groups, groups, groups],
315
+ }).sdr_lut;
316
+
317
+ this.#sdr_from_hdr_pending = false;
318
+ }
319
+
320
+ let gr_lut = hdr ? gr_hdr : gr_sdr;
321
+
322
+ if (bake) {
323
+ gr_lut = this.#bake(graph, lut, peak_nits, gr_lut);
324
+ }
325
+
326
+ const [written] = graph_image_pass({
327
+ graph,
328
+ shader: apply_shader(hdr),
329
+ inputs: {
330
+ input_color,
331
+ exposure,
332
+ settings: this.display,
333
+ lut: gr_lut,
334
+ },
335
+ output: [target]
336
+ });
337
+
338
+ return written;
339
+ }
340
+
341
+ destroy() {
342
+ this.#sdr.texture.destroy();
343
+ this.#hdr.texture.destroy();
344
+ }
345
+
346
+ /**
347
+ * @param {ToneMapLut} lut
348
+ * @param {number} peak_nits
349
+ * @returns {boolean}
350
+ */
351
+ #bake_is_stale(lut, peak_nits) {
352
+ return lut.baked_operator !== this.operator
353
+ || lut.baked_resolution !== this.lut_resolution
354
+ || lut.baked_peak_nits !== peak_nits
355
+ || !same_words(lut.baked_grade, this.#grade_words);
356
+ }
357
+
358
+ #pack_grade() {
359
+ const data = this.grade.pack();
360
+
361
+ if (data !== this.#grade_data) {
362
+ this.#grade_data = data;
363
+ this.#grade_words = new Uint32Array(data.buffer, data.byteOffset, data.length);
364
+ }
365
+ }
366
+
367
+ /**
368
+ * @param {FrameGraph} graph
369
+ * @param {ToneMapLut} lut
370
+ * @param {number} peak_nits
371
+ * @param {number} gr_lut the LUT's texture, sized for {@link lut_resolution} and imported into `graph`
372
+ * @returns {number} the LUT, written
373
+ */
374
+ #bake(graph, lut, peak_nits, gr_lut) {
375
+ const operator = this.operator;
376
+ const resolution = this.lut_resolution;
377
+
378
+ const grade = this.#grade_data;
379
+ const header_bytes = COLOR_GRADE_HEADER_FLOATS * 4;
380
+
381
+ const bindings = {
382
+ settings: { peak_nits },
383
+ lut: gr_lut,
384
+ grade: graph_import_raw_buffer({
385
+ graph,
386
+ value: grade.buffer,
387
+ offset: grade.byteOffset,
388
+ size: header_bytes,
389
+ label: "tonemap/grade",
390
+ usage: GPUBufferUsage.UNIFORM,
391
+ }),
392
+ grade_keys: graph_import_raw_buffer({
393
+ graph,
394
+ value: grade.buffer,
395
+ offset: grade.byteOffset + header_bytes,
396
+ size: grade.byteLength - header_bytes,
397
+ label: "tonemap/grade keys",
398
+ usage: GPUBufferUsage.STORAGE,
399
+ }),
400
+ };
401
+
402
+ operator.bind(graph, peak_nits, bindings);
403
+
404
+ const groups = Math.ceil(resolution / TONEMAP_LUT_BAKE_GROUP);
405
+
406
+ const written = graph_compute_pass({
407
+ graph,
408
+ shader: shader_tonemap_lut_bake(operator),
409
+ bindings,
410
+ group_count: [groups, groups, groups],
411
+ }).lut;
412
+
413
+ lut.baked_operator = operator;
414
+ lut.baked_resolution = resolution;
415
+ lut.baked_peak_nits = peak_nits;
416
+
417
+ if (lut.baked_grade.length !== this.#grade_words.length) {
418
+ lut.baked_grade = new Uint32Array(this.#grade_words.length);
419
+ }
420
+
421
+ lut.baked_grade.set(this.#grade_words);
422
+
423
+ return written;
424
+ }
425
+
426
+ /**
427
+ * @param {ToneMapLut} lut
428
+ * @param {number} resolution
429
+ * @param {Float32Array} data
430
+ */
431
+ #upload(lut, resolution, data) {
432
+ this.#check_resolution(resolution);
433
+ assert.isInstanceOf(data, Float32Array, 'data');
434
+ assert.equal(data.length, resolution * resolution * resolution * 3, 'data.length !== resolution³ × 3');
435
+
436
+ const texel_count = resolution * resolution * resolution;
437
+ const texels = new Float16Array(texel_count * 4);
438
+
439
+ for (let i = 0; i < texel_count; i++) {
440
+ texels[i * 4] = data[i * 3];
441
+ texels[i * 4 + 1] = data[i * 3 + 1];
442
+ texels[i * 4 + 2] = data[i * 3 + 2];
443
+ texels[i * 4 + 3] = 1;
444
+ }
445
+
446
+ const texture = lut.texture;
447
+
448
+ texture.resize(resolution, resolution, resolution);
449
+
450
+ this.#device.queue.writeTexture(
451
+ { texture: texture.gpu_texture },
452
+ texels,
453
+ { bytesPerRow: resolution * 8, rowsPerImage: resolution },
454
+ [resolution, resolution, resolution]
455
+ );
456
+
457
+ lut.user = true;
458
+ lut.baked_operator = null;
459
+ }
460
+
461
+ /**
462
+ * @param {number} resolution
463
+ */
464
+ #check_resolution(resolution) {
465
+ assert.isNonNegativeInteger(resolution, 'resolution');
466
+ assert.greaterThanOrEqual(resolution, 2, 'resolution');
467
+
468
+ const limit = this.#device.limits.maxTextureDimension3D;
469
+
470
+ if (resolution > limit) {
471
+ throw new Error(`A tone-mapping LUT of ${resolution}³ exceeds the device's maxTextureDimension3D, ${limit}`);
472
+ }
473
+ }
474
+ }
@@ -1,16 +1,16 @@
1
1
  /**
2
- * What {@link shader_tonemap_HDR_aces} binds as `aces2_tables`: two ACES 2.0 output transforms, each its parameters and
2
+ * What the ACES tone-map operator binds as `aces2_tables`: two ACES 2.0 output transforms, each its parameters and
3
3
  * gamut tables, both limited to Rec.709, the gamut of the SDR picture they expand.
4
4
  *
5
- * 1. An SDR display, 100 cd/m². The pass runs it backwards, from the SDR picture to the scene.
5
+ * 1. An SDR display, 100 cd/m². The operator runs it backwards, from the SDR picture to the scene.
6
6
  * 2. This display: the peak over the paper white, times 100 cd/m². A display at or under the paper white gets
7
- * 100 cd/m², which the pass does not read.
7
+ * 100 cd/m², which the operator does not read.
8
8
  *
9
9
  * Both take SDR white for 100 cd/m², ACES 2.0's reference, so an SDR picture expanded for a display keeps SDR white
10
10
  * where the paper white puts it.
11
11
  *
12
- * Building one transform takes 7 to 13 ms, so the tables are built on the first {@link update} rather than with the
13
- * renderer, and again only when the display's peak changes.
12
+ * Building one transform takes 7 to 13 ms, so the tables are built on the first {@link update}, and again only when
13
+ * the display's peak changes.
14
14
  */
15
15
  export class TonemapAces2Tables {
16
16
  /**
@@ -25,14 +25,6 @@ export class TonemapAces2Tables {
25
25
  * @returns {boolean} whether {@link data} changed
26
26
  */
27
27
  update(peak_nits: number): boolean;
28
- /**
29
- * The tables on the device, written if they changed since the last call.
30
- *
31
- * @param {GPUDevice} device
32
- * @returns {GPUBuffer}
33
- */
34
- gpu_buffer(device: GPUDevice): GPUBuffer;
35
- destroy(): void;
36
28
  #private;
37
29
  }
38
30
  //# sourceMappingURL=TonemapAces2Tables.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TonemapAces2Tables.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;GAaG;AACH;IACI;;;OAGG;IACH,MAFU,YAAY,CAE0B;IAWhD;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,OAAO,CAsBnB;IAED;;;;;OAKG;IACH,yCAgBC;IAED,gBAKC;;CACJ"}
1
+ {"version":3,"file":"TonemapAces2Tables.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;GAaG;AACH;IACI;;;OAGG;IACH,MAFU,YAAY,CAE0B;IAIhD;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,OAAO,CAqBnB;;CACJ"}
@@ -7,18 +7,18 @@ import {
7
7
  import { PAPER_WHITE_NITS } from "../../shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js";
8
8
 
9
9
  /**
10
- * What {@link shader_tonemap_HDR_aces} binds as `aces2_tables`: two ACES 2.0 output transforms, each its parameters and
10
+ * What the ACES tone-map operator binds as `aces2_tables`: two ACES 2.0 output transforms, each its parameters and
11
11
  * gamut tables, both limited to Rec.709, the gamut of the SDR picture they expand.
12
12
  *
13
- * 1. An SDR display, 100 cd/m². The pass runs it backwards, from the SDR picture to the scene.
13
+ * 1. An SDR display, 100 cd/m². The operator runs it backwards, from the SDR picture to the scene.
14
14
  * 2. This display: the peak over the paper white, times 100 cd/m². A display at or under the paper white gets
15
- * 100 cd/m², which the pass does not read.
15
+ * 100 cd/m², which the operator does not read.
16
16
  *
17
17
  * Both take SDR white for 100 cd/m², ACES 2.0's reference, so an SDR picture expanded for a display keeps SDR white
18
18
  * where the paper white puts it.
19
19
  *
20
- * Building one transform takes 7 to 13 ms, so the tables are built on the first {@link update} rather than with the
21
- * renderer, and again only when the display's peak changes.
20
+ * Building one transform takes 7 to 13 ms, so the tables are built on the first {@link update}, and again only when
21
+ * the display's peak changes.
22
22
  */
23
23
  export class TonemapAces2Tables {
24
24
  /**
@@ -29,13 +29,6 @@ export class TonemapAces2Tables {
29
29
 
30
30
  #peak_nits = NaN;
31
31
 
32
- /**
33
- * @type {GPUBuffer|null}
34
- */
35
- #buffer = null;
36
-
37
- #uploaded = false;
38
-
39
32
  /**
40
33
  * Build the tables for a display, if they are not built for it already.
41
34
  *
@@ -59,39 +52,7 @@ export class TonemapAces2Tables {
59
52
  aces2_transform_block_write(this.data, ACES2_BLOCK_FLOATS, 100 * headroom, ACES2_LIMITING_REC709);
60
53
 
61
54
  this.#peak_nits = peak_nits;
62
- this.#uploaded = false;
63
55
 
64
56
  return true;
65
57
  }
66
-
67
- /**
68
- * The tables on the device, written if they changed since the last call.
69
- *
70
- * @param {GPUDevice} device
71
- * @returns {GPUBuffer}
72
- */
73
- gpu_buffer(device) {
74
- if (this.#buffer === null) {
75
- this.#buffer = device.createBuffer({
76
- label: "tonemap/aces2 tables",
77
- size: this.data.byteLength,
78
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
79
- });
80
- this.#uploaded = false;
81
- }
82
-
83
- if (!this.#uploaded) {
84
- device.queue.writeBuffer(this.#buffer, 0, this.data);
85
- this.#uploaded = true;
86
- }
87
-
88
- return this.#buffer;
89
- }
90
-
91
- destroy() {
92
- if (this.#buffer !== null) {
93
- this.#buffer.destroy();
94
- this.#buffer = null;
95
- }
96
- }
97
58
  }
@@ -1,22 +1,18 @@
1
1
  /**
2
- * The immediate data every tonemap pass reads: the colour space the canvas actually shows, and the display's peak.
2
+ * What the tone mapper is told about the display: the colour space the canvas actually shows, and the display's peak.
3
3
  *
4
- * A pass's immediate struct names only the members it reads. The GT7 passes leave the operator in Rec.2020 and read
5
- * `display_from_rec2020_*`; the others work in Rec.709 and read `display_from_rec709_*`; only the HDR passes read
6
- * `peak_nits`. So one instance serves whichever pass is current.
4
+ * The apply passes read the matrix from linear Rec.2020, the LUT's output, to the canvas's linear primaries, as
5
+ * {@link TONEMAP_SETTINGS}. The peak is what an HDR LUT is baked for.
7
6
  *
8
- * Each matrix is three columns, not a `mat3x3f`: a `mat3x3f` pads each column to 16 bytes and the immediate
7
+ * The matrix is three columns, not a `mat3x3f`: a `mat3x3f` pads each column to 16 bytes and the immediate
9
8
  * serialiser writes its nine floats end to end.
10
9
  */
11
10
  export class TonemapDisplaySettings {
12
- display_from_rec709_c0: Float32Array;
13
- display_from_rec709_c1: Float32Array;
14
- display_from_rec709_c2: Float32Array;
15
11
  display_from_rec2020_c0: Float32Array;
16
12
  display_from_rec2020_c1: Float32Array;
17
13
  display_from_rec2020_c2: Float32Array;
18
14
  /**
19
- * The display's peak, cd/m². Read by the HDR passes only.
15
+ * The display's peak, cd/m². An HDR LUT is baked for it.
20
16
  * @type {number}
21
17
  */
22
18
  peak_nits: number;
@@ -29,22 +25,8 @@ export class TonemapDisplaySettings {
29
25
  set_canvas_color_space(color_space: PredefinedColorSpace | string): void;
30
26
  }
31
27
  /**
32
- * Immediate data of a pass that works in Rec.709. Filled by {@link TonemapDisplaySettings}.
28
+ * Immediate data of the tone mapper's apply passes. Filled by {@link TonemapDisplaySettings}.
33
29
  */
34
- export const TONEMAP_SETTINGS_REC709: WebGPUStruct;
35
- /**
36
- * Immediate data of a pass that works in Rec.709 and is told the display's peak. Filled by {@link
37
- * TonemapDisplaySettings}.
38
- */
39
- export const TONEMAP_SETTINGS_REC709_PEAK: WebGPUStruct;
40
- /**
41
- * Immediate data of a pass that works in Rec.2020. Filled by {@link TonemapDisplaySettings}.
42
- */
43
- export const TONEMAP_SETTINGS_REC2020: WebGPUStruct;
44
- /**
45
- * Immediate data of a pass that works in Rec.2020 and is told the display's peak. Filled by {@link
46
- * TonemapDisplaySettings}.
47
- */
48
- export const TONEMAP_SETTINGS_REC2020_PEAK: WebGPUStruct;
30
+ export const TONEMAP_SETTINGS: WebGPUStruct;
49
31
  import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
50
32
  //# sourceMappingURL=TonemapDisplaySettings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TonemapDisplaySettings.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.js"],"names":[],"mappings":"AAiDA;;;;;;;;;GASG;AACH;IACI,qCAAqD;IACrD,qCAAqD;IACrD,qCAAqD;IAErD,sCAA8C;IAC9C,sCAA8C;IAC9C,sCAA8C;IAE9C;;;OAGG;IACH,WAFU,MAAM,CAEC;IAMjB;;;;;OAKG;IACH,oCAHW,oBAAoB,GAAC,MAAM,QAkBrC;CACJ;AAqBD;;GAEG;AACH,mDAAqF;AAErF;;;GAGG;AACH,wDAAmG;AAEnG;;GAEG;AACH,oDAAuF;AAEvF;;;GAGG;AACH,yDAAqG;6BAzIxE,mCAAmC"}
1
+ {"version":3,"file":"TonemapDisplaySettings.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.js"],"names":[],"mappings":"AAiDA;;;;;;;;GAQG;AACH;IACI,sCAA8C;IAC9C,sCAA8C;IAC9C,sCAA8C;IAE9C;;;OAGG;IACH,WAFU,MAAM,CAEC;IAMjB;;;;;OAKG;IACH,oCAHW,oBAAoB,GAAC,MAAM,QAcrC;CACJ;AAED;;GAEG;AACH,4CAKG;6BAjG0B,mCAAmC"}