@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
@@ -1,7 +1,7 @@
1
1
  import { m3_rgb_to_xyz_from_primaries } from "../../../../core/color/xyz/m3_rgb_to_xyz_from_primaries.js";
2
2
  import { m3_invert } from "../../../../core/geom/mat3/m3_invert.js";
3
3
  import { m3_multiply } from "../../../../core/geom/mat3/m3_multiply.js";
4
- import { f32, vec3f } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
4
+ import { vec3f } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
5
5
  import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
6
6
 
7
7
  // chromaticities of red, green and blue; every space here has a D65 white, so none needs chromatic adaptation
@@ -48,26 +48,21 @@ function write_columns(c0, c1, c2, from, to) {
48
48
  }
49
49
 
50
50
  /**
51
- * The immediate data every tonemap pass reads: the colour space the canvas actually shows, and the display's peak.
51
+ * What the tone mapper is told about the display: the colour space the canvas actually shows, and the display's peak.
52
52
  *
53
- * A pass's immediate struct names only the members it reads. The GT7 passes leave the operator in Rec.2020 and read
54
- * `display_from_rec2020_*`; the others work in Rec.709 and read `display_from_rec709_*`; only the HDR passes read
55
- * `peak_nits`. So one instance serves whichever pass is current.
53
+ * The apply passes read the matrix from linear Rec.2020, the LUT's output, to the canvas's linear primaries, as
54
+ * {@link TONEMAP_SETTINGS}. The peak is what an HDR LUT is baked for.
56
55
  *
57
- * Each matrix is three columns, not a `mat3x3f`: a `mat3x3f` pads each column to 16 bytes and the immediate
56
+ * The matrix is three columns, not a `mat3x3f`: a `mat3x3f` pads each column to 16 bytes and the immediate
58
57
  * serialiser writes its nine floats end to end.
59
58
  */
60
59
  export class TonemapDisplaySettings {
61
- display_from_rec709_c0 = new Float32Array([1, 0, 0]);
62
- display_from_rec709_c1 = new Float32Array([0, 1, 0]);
63
- display_from_rec709_c2 = new Float32Array([0, 0, 1]);
64
-
65
60
  display_from_rec2020_c0 = new Float32Array(3);
66
61
  display_from_rec2020_c1 = new Float32Array(3);
67
62
  display_from_rec2020_c2 = new Float32Array(3);
68
63
 
69
64
  /**
70
- * The display's peak, cd/m². Read by the HDR passes only.
65
+ * The display's peak, cd/m². An HDR LUT is baked for it.
71
66
  * @type {number}
72
67
  */
73
68
  peak_nits = 1000;
@@ -89,10 +84,6 @@ export class TonemapDisplaySettings {
89
84
  throw new Error(`Canvas colorSpace '${color_space}' is not one the tonemap passes can write`);
90
85
  }
91
86
 
92
- write_columns(
93
- this.display_from_rec709_c0, this.display_from_rec709_c1, this.display_from_rec709_c2,
94
- PRIMARIES_REC709, display
95
- );
96
87
  write_columns(
97
88
  this.display_from_rec2020_c0, this.display_from_rec2020_c1, this.display_from_rec2020_c2,
98
89
  PRIMARIES_REC2020, display
@@ -100,43 +91,12 @@ export class TonemapDisplaySettings {
100
91
  }
101
92
  }
102
93
 
103
- const display_from_rec709 = {
104
- /** column 0 of the matrix from linear Rec.709 to the canvas's linear primaries */
105
- display_from_rec709_c0: vec3f,
106
- display_from_rec709_c1: vec3f,
107
- display_from_rec709_c2: vec3f,
108
- };
109
-
110
- const display_from_rec2020 = {
94
+ /**
95
+ * Immediate data of the tone mapper's apply passes. Filled by {@link TonemapDisplaySettings}.
96
+ */
97
+ export const TONEMAP_SETTINGS = WebGPUStruct.from({
111
98
  /** column 0 of the matrix from linear Rec.2020 to the canvas's linear primaries */
112
99
  display_from_rec2020_c0: vec3f,
113
100
  display_from_rec2020_c1: vec3f,
114
101
  display_from_rec2020_c2: vec3f,
115
- };
116
-
117
- /**
118
- * The display's peak, cd/m². The paper white is not a setting: it is PAPER_WHITE_NITS on both outputs.
119
- */
120
- const peak = { peak_nits: f32 };
121
-
122
- /**
123
- * Immediate data of a pass that works in Rec.709. Filled by {@link TonemapDisplaySettings}.
124
- */
125
- export const TONEMAP_SETTINGS_REC709 = WebGPUStruct.from({ ...display_from_rec709 });
126
-
127
- /**
128
- * Immediate data of a pass that works in Rec.709 and is told the display's peak. Filled by {@link
129
- * TonemapDisplaySettings}.
130
- */
131
- export const TONEMAP_SETTINGS_REC709_PEAK = WebGPUStruct.from({ ...display_from_rec709, ...peak });
132
-
133
- /**
134
- * Immediate data of a pass that works in Rec.2020. Filled by {@link TonemapDisplaySettings}.
135
- */
136
- export const TONEMAP_SETTINGS_REC2020 = WebGPUStruct.from({ ...display_from_rec2020 });
137
-
138
- /**
139
- * Immediate data of a pass that works in Rec.2020 and is told the display's peak. Filled by {@link
140
- * TonemapDisplaySettings}.
141
- */
142
- export const TONEMAP_SETTINGS_REC2020_PEAK = WebGPUStruct.from({ ...display_from_rec2020, ...peak });
102
+ });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Unreal's temperature white balance (`WhiteBalance` in `TonemapCommon.ush`, the default "White Balance" mode) on
3
+ * linear Rec.709, as a matrix. Light from a white at `temperature` K, moved along its isotherm by `tint`, becomes
4
+ * neutral: a lower temperature cools the picture.
5
+ *
6
+ * The source white is on the Planckian locus below 4000 K and on the CIE daylight locus from there, as Unreal's is,
7
+ * and the adaptation to D65 is Bradford. At 6500 K and no tint, where Unreal skips the stage, the matrix is the
8
+ * identity.
9
+ *
10
+ * @param {Float32Array|Float64Array|number[]} out 9 elements, row-major
11
+ * @param {number} temperature K
12
+ * @param {number} tint offset along the isotherm, in units of 0.05 in CIE 1960 uv; Unreal's range is -1 to 1
13
+ */
14
+ export function m3_white_balance_rec709(out: Float32Array | Float64Array | number[], temperature: number, tint: number): void;
15
+ /**
16
+ * The temperature white balance is neutral at these, and Unreal skips it there.
17
+ */
18
+ export const WHITE_BALANCE_NEUTRAL_TEMPERATURE: 6500;
19
+ export const WHITE_BALANCE_NEUTRAL_TINT: 0;
20
+ //# sourceMappingURL=m3_white_balance_rec709.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"m3_white_balance_rec709.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/m3_white_balance_rec709.js"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;GAYG;AACH,6CAJW,YAAY,GAAC,YAAY,GAAC,MAAM,EAAE,eAClC,MAAM,QACN,MAAM,QAsDhB;AAxFD;;GAEG;AACH,qDAAsD;AACtD,2CAA4C"}
@@ -0,0 +1,103 @@
1
+ import { m3_chromatic_adaptation_bradford } from "../../../../core/color/xyz/m3_chromatic_adaptation_bradford.js";
2
+ import { m3_rgb_to_xyz_from_primaries } from "../../../../core/color/xyz/m3_rgb_to_xyz_from_primaries.js";
3
+ import { m3_invert } from "../../../../core/geom/mat3/m3_invert.js";
4
+ import { m3_multiply } from "../../../../core/geom/mat3/m3_multiply.js";
5
+
6
+ const D65_X = 0.3127;
7
+ const D65_Y = 0.3290;
8
+
9
+ const REC709_TO_XYZ = new Float64Array(9);
10
+ m3_rgb_to_xyz_from_primaries(REC709_TO_XYZ, [0.640, 0.330, 0.300, 0.600, 0.150, 0.060], D65_X, D65_Y);
11
+
12
+ const XYZ_TO_REC709 = new Float64Array(9);
13
+ m3_invert(XYZ_TO_REC709, REC709_TO_XYZ);
14
+
15
+ /**
16
+ * The temperature white balance is neutral at these, and Unreal skips it there.
17
+ */
18
+ export const WHITE_BALANCE_NEUTRAL_TEMPERATURE = 6500;
19
+ export const WHITE_BALANCE_NEUTRAL_TINT = 0;
20
+
21
+ /**
22
+ * Chromaticity of the Planckian locus at `temperature` K, Krystek's rational fit in CIE 1960 uv, as Unreal's
23
+ * `PlanckianLocusChromaticity`.
24
+ *
25
+ * @param {number[]} out [x, y]
26
+ * @param {number} temperature
27
+ */
28
+ function planckian_locus_uv(out, temperature) {
29
+ const t = temperature;
30
+ out[0] = (0.860117757 + 1.54118254e-4 * t + 1.28641212e-7 * t * t) / (1 + 8.42420235e-4 * t + 7.08145163e-7 * t * t);
31
+ out[1] = (0.317398726 + 4.22806245e-5 * t + 4.20481691e-8 * t * t) / (1 - 2.89741816e-5 * t + 1.61456053e-7 * t * t);
32
+ }
33
+
34
+ const scratch_uv = [0, 0];
35
+ const scratch_cat = new Float64Array(9);
36
+ const scratch_m = new Float64Array(9);
37
+
38
+ /**
39
+ * Unreal's temperature white balance (`WhiteBalance` in `TonemapCommon.ush`, the default "White Balance" mode) on
40
+ * linear Rec.709, as a matrix. Light from a white at `temperature` K, moved along its isotherm by `tint`, becomes
41
+ * neutral: a lower temperature cools the picture.
42
+ *
43
+ * The source white is on the Planckian locus below 4000 K and on the CIE daylight locus from there, as Unreal's is,
44
+ * and the adaptation to D65 is Bradford. At 6500 K and no tint, where Unreal skips the stage, the matrix is the
45
+ * identity.
46
+ *
47
+ * @param {Float32Array|Float64Array|number[]} out 9 elements, row-major
48
+ * @param {number} temperature K
49
+ * @param {number} tint offset along the isotherm, in units of 0.05 in CIE 1960 uv; Unreal's range is -1 to 1
50
+ */
51
+ export function m3_white_balance_rec709(out, temperature, tint) {
52
+ if (temperature === WHITE_BALANCE_NEUTRAL_TEMPERATURE && tint === WHITE_BALANCE_NEUTRAL_TINT) {
53
+ out.fill(0);
54
+ out[0] = 1;
55
+ out[4] = 1;
56
+ out[8] = 1;
57
+ return;
58
+ }
59
+
60
+ let x, y;
61
+
62
+ if (temperature < 4000) {
63
+ planckian_locus_uv(scratch_uv, temperature);
64
+ const [u, v] = scratch_uv;
65
+ const d = 2 * u - 8 * v + 4;
66
+ x = 3 * u / d;
67
+ y = 2 * v / d;
68
+ } else {
69
+ // the CIE daylight locus, with the temperature corrected for the revision of Planck's c2, so 6500 is D65
70
+ const t = temperature * 1.4388 / 1.438;
71
+ const r = 1 / t;
72
+
73
+ x = t <= 7000
74
+ ? 0.244063 + (0.09911e3 + (2.9678e6 - 4.6070e9 * r) * r) * r
75
+ : 0.237040 + (0.24748e3 + (1.9018e6 - 2.0064e9 * r) * r) * r;
76
+ y = -3 * x * x + 2.87 * x - 0.275;
77
+ }
78
+
79
+ {
80
+ // along the isotherm, the normal to the Planckian locus in uv, by the tint
81
+ const t = temperature;
82
+ planckian_locus_uv(scratch_uv, t);
83
+ const [u, v] = scratch_uv;
84
+
85
+ const ud = (-1.13758118e9 - 1.91615621e6 * t - 1.53177 * t * t) / ((1.41213984e6 + 1189.62 * t + t * t) ** 2);
86
+ const vd = (1.97471536e9 - 705674.0 * t - 308.607 * t * t) / ((6.19363586e6 - 179.456 * t + t * t) ** 2);
87
+ const length = Math.hypot(ud, vd);
88
+
89
+ const iu = u + vd / length * tint * 0.05;
90
+ const iv = v - ud / length * tint * 0.05;
91
+
92
+ const d0 = 2 * u - 8 * v + 4;
93
+ const d1 = 2 * iu - 8 * iv + 4;
94
+
95
+ x += 3 * iu / d1 - 3 * u / d0;
96
+ y += 2 * iv / d1 - 2 * v / d0;
97
+ }
98
+
99
+ m3_chromatic_adaptation_bradford(scratch_cat, x, y, D65_X, D65_Y);
100
+
101
+ m3_multiply(scratch_m, scratch_cat, REC709_TO_XYZ);
102
+ m3_multiply(out, XYZ_TO_REC709, scratch_m);
103
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The HDR output of {@link ToneMapper}: exposure, then the HDR LUT, written in the canvas's primaries, extended, where
3
+ * 1.0 is SDR white.
4
+ *
5
+ * @type {ImageShader}
6
+ */
7
+ export const shader_tonemap_HDR_lut: ImageShader;
8
+ import { ImageShader } from "../../shader/ImageShader.js";
9
+ //# sourceMappingURL=shader_tonemap_HDR_lut.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_tonemap_HDR_lut.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.js"],"names":[],"mappings":"AAmDA;;;;;GAKG;AACH,qCAFU,WAAW,CAclB;4BAlEyB,6BAA6B"}
@@ -1,16 +1,21 @@
1
- import { F32_CONTAINER_STRUCT } from "../../shader/type/F32_CONTAINER_STRUCT.js";
2
- import { TONEMAP_SETTINGS_REC709 } from "./TonemapDisplaySettings.js";
3
1
  import { chunk_sRGBTransferOETF } from "../../shader/chunk/color/sRGB/chunk_sRGBTransferOETF.js";
2
+ import { chunk_tonemap_lut } from "../../shader/chunk/color/tonemap/chunk_tonemap_lut.js";
4
3
  import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
5
4
  import { ImageShader } from "../../shader/ImageShader.js";
6
5
  import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
7
6
  import { ShaderDescriptor } from "../../shader/ShaderDescriptor.js";
7
+ import { F32_CONTAINER_STRUCT } from "../../shader/type/F32_CONTAINER_STRUCT.js";
8
+ import { SAMPLER_TONEMAP_LUT } from "./SAMPLER_TONEMAP_LUT.js";
9
+ import { TONEMAP_SETTINGS } from "./TonemapDisplaySettings.js";
8
10
 
9
11
  const resources = new ShaderResourceSetDescriptor();
10
- resources.setImmediate("settings", TONEMAP_SETTINGS_REC709);
12
+
13
+ resources.setImmediate("settings", TONEMAP_SETTINGS);
11
14
  resources.createGroup()
12
15
  .addTexture("input_color", "float")
13
16
  .addUniform("exposure", F32_CONTAINER_STRUCT)
17
+ .addTexture("lut", "float", "3d")
18
+ .addSampler("lut_sampler", "filtering", SAMPLER_TONEMAP_LUT)
14
19
 
15
20
  const body = CodeChunk.from(
16
21
  //language=WGSL
@@ -21,39 +26,38 @@ fn main(
21
26
  ) -> @location(0) vec4<f32> {
22
27
 
23
28
  // scene color in linear Rec. 709
24
- var color = textureLoad(input_color, vec2i(coord.xy), 0).rgb;
29
+ let color = textureLoad(input_color, vec2i(coord.xy), 0).rgb * exposure.value;
25
30
 
26
- color *= exposure.value;
31
+ let uvw = tonemap_lut_coordinate(color, f32(textureDimensions(lut).x));
32
+ let color_2020 = tonemap_lut_pq_decode(textureSampleLevel(lut, lut_sampler, uvw, 0.0).rgb);
27
33
 
28
- // no tone mapping: 1.0 is SDR white, and what lies above it is shown as far as the display reaches
34
+ // into the primaries the canvas reports it was configured with (Renderer#configure_context)
35
+ let color_display = mat3x3<f32>(
36
+ settings.display_from_rec2020_c0,
37
+ settings.display_from_rec2020_c1,
38
+ settings.display_from_rec2020_c2
39
+ ) * color_2020;
29
40
 
30
41
  // NOTE: no dithering, colorspace is wide
31
42
 
32
- // into the primaries the canvas reports it was configured with (Renderer#configure_context): Display P3, or
33
- // sRGB where the browser would not configure P3
34
- let color_display = mat3x3<f32>(
35
- settings.display_from_rec709_c0,
36
- settings.display_from_rec709_c1,
37
- settings.display_from_rec709_c2
38
- ) * color;
39
-
40
43
  // apply gamma. Note that gamma is the same for "Display P3" and "sRGB"
41
44
  return vec4(sRGBTransferOETF(color_display), 1.0);
42
45
  }
43
46
  `, [
47
+ chunk_tonemap_lut,
44
48
  chunk_sRGBTransferOETF,
45
49
  ]
46
50
  );
47
51
 
48
52
  /**
49
- * The HDR output with {@link ShadeToneMappingMode.NONE}: exposure and the canvas's primaries, extended, where 1.0 is
50
- * SDR white, and nothing in between.
53
+ * The HDR output of {@link ToneMapper}: exposure, then the HDR LUT, written in the canvas's primaries, extended, where
54
+ * 1.0 is SDR white.
51
55
  *
52
56
  * @type {ImageShader}
53
57
  */
54
- export const shader_tonemap_HDR_none = new ImageShader({
58
+ export const shader_tonemap_HDR_lut = new ImageShader({
55
59
  descriptor: ShaderDescriptor.from({
56
- label: "Tonemap/HDR/none",
60
+ label: "Tonemap/HDR",
57
61
  resources,
58
62
  body
59
63
  }),
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The SDR output of {@link ToneMapper}: exposure, then the SDR LUT, the canvas's primaries, the sRGB transfer curve
3
+ * and an 8-bit dither. The 8-bit target clips anything the LUT puts past SDR white.
4
+ *
5
+ * @type {ImageShader}
6
+ */
7
+ export const shader_tonemap_LDR_lut: ImageShader;
8
+ import { ImageShader } from "../../shader/ImageShader.js";
9
+ //# sourceMappingURL=shader_tonemap_LDR_lut.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_tonemap_LDR_lut.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.js"],"names":[],"mappings":"AA0DA;;;;;GAKG;AACH,qCAFU,WAAW,CAclB;4BAtEyB,6BAA6B"}
@@ -1,7 +1,5 @@
1
- import { F32_CONTAINER_STRUCT } from "../../shader/type/F32_CONTAINER_STRUCT.js";
2
- import { TONEMAP_SETTINGS_REC709 } from "./TonemapDisplaySettings.js";
3
1
  import { chunk_sRGBTransferOETF } from "../../shader/chunk/color/sRGB/chunk_sRGBTransferOETF.js";
4
- import { chunk_tonemap_ue_filmic } from "../../shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js";
2
+ import { chunk_tonemap_lut } from "../../shader/chunk/color/tonemap/chunk_tonemap_lut.js";
5
3
  import {
6
4
  chunk_dither_color_8bit_triangle_noise
7
5
  } from "../../shader/chunk/texture/dither/chunk_dither_color_8bit_triangle_noise.js";
@@ -9,12 +7,18 @@ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
9
7
  import { ImageShader } from "../../shader/ImageShader.js";
10
8
  import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
11
9
  import { ShaderDescriptor } from "../../shader/ShaderDescriptor.js";
10
+ import { F32_CONTAINER_STRUCT } from "../../shader/type/F32_CONTAINER_STRUCT.js";
11
+ import { SAMPLER_TONEMAP_LUT } from "./SAMPLER_TONEMAP_LUT.js";
12
+ import { TONEMAP_SETTINGS } from "./TonemapDisplaySettings.js";
12
13
 
13
14
  const resources = new ShaderResourceSetDescriptor();
14
- resources.setImmediate("settings", TONEMAP_SETTINGS_REC709);
15
+
16
+ resources.setImmediate("settings", TONEMAP_SETTINGS);
15
17
  resources.createGroup()
16
18
  .addTexture("input_color", "float")
17
19
  .addUniform("exposure", F32_CONTAINER_STRUCT)
20
+ .addTexture("lut", "float", "3d")
21
+ .addSampler("lut_sampler", "filtering", SAMPLER_TONEMAP_LUT)
18
22
 
19
23
  const body = CodeChunk.from(
20
24
  //language=WGSL
@@ -25,46 +29,42 @@ fn main(
25
29
  ) -> @location(0) vec4<f32> {
26
30
 
27
31
  // scene color in linear Rec. 709
28
- var color = textureLoad(input_color, vec2i(coord.xy), 0).rgb;
29
-
30
- color *= exposure.value;
32
+ let color = textureLoad(input_color, vec2i(coord.xy), 0).rgb * exposure.value;
31
33
 
32
- // Unreal's default SDR rendering, in Rec.709 and within it
33
- color = tonemap_ue_filmic(color);
34
+ let uvw = tonemap_lut_coordinate(color, f32(textureDimensions(lut).x));
35
+ let color_2020 = tonemap_lut_pq_decode(textureSampleLevel(lut, lut_sampler, uvw, 0.0).rgb);
34
36
 
35
- // into the primaries the canvas reports it was configured with (Renderer#configure_context): Display P3, or
36
- // sRGB where the browser would not configure P3. A Rec.709 colour sits inside both.
37
+ // into the primaries the canvas reports it was configured with (Renderer#configure_context)
37
38
  let color_display = mat3x3<f32>(
38
- settings.display_from_rec709_c0,
39
- settings.display_from_rec709_c1,
40
- settings.display_from_rec709_c2
41
- ) * color;
39
+ settings.display_from_rec2020_c0,
40
+ settings.display_from_rec2020_c1,
41
+ settings.display_from_rec2020_c2
42
+ ) * color_2020;
42
43
 
43
44
  // apply gamma. Note that gamma is the same for "Display P3" and "sRGB"
44
- color = sRGBTransferOETF(color_display);
45
+ var color_gamma = sRGBTransferOETF(color_display);
45
46
 
46
47
  // apply dither to remove color banding
47
- color += dither_color_8bit_triangle_noise(coord.xy);
48
+ color_gamma += dither_color_8bit_triangle_noise(coord.xy);
48
49
 
49
- return vec4(color, 1.0);
50
+ return vec4(color_gamma, 1.0);
50
51
  }
51
52
  `, [
52
- chunk_tonemap_ue_filmic,
53
+ chunk_tonemap_lut,
53
54
  chunk_dither_color_8bit_triangle_noise,
54
55
  chunk_sRGBTransferOETF,
55
56
  ]
56
57
  );
57
58
 
58
59
  /**
59
- * The SDR output with {@link ShadeToneMappingMode.ACES}: exposure, Unreal Engine's default "Filmic" tone mapping, the
60
- * canvas's primaries, the sRGB transfer curve and an 8-bit dither. {@link shader_tonemap_HDR_aces} expands the same
61
- * picture into an HDR display's headroom.
60
+ * The SDR output of {@link ToneMapper}: exposure, then the SDR LUT, the canvas's primaries, the sRGB transfer curve
61
+ * and an 8-bit dither. The 8-bit target clips anything the LUT puts past SDR white.
62
62
  *
63
63
  * @type {ImageShader}
64
64
  */
65
- export const shader_tonemap_LDR_aces = new ImageShader({
65
+ export const shader_tonemap_LDR_lut = new ImageShader({
66
66
  descriptor: ShaderDescriptor.from({
67
- label: "Tonemap/LDR/aces",
67
+ label: "Tonemap/LDR",
68
68
  resources,
69
69
  body
70
70
  }),
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The compute shader that bakes `operator` into a LUT, `lut`, one texel a thread: the texel's PQ signal decoded to
3
+ * exposed scene colour, through the colour grade and the operator, and encoded again, as {@link chunk_tonemap_lut}
4
+ * describes. The grade is `grade`, a {@link COLOR_GRADE_STRUCT}, and `grade_keys`, its curves' keyframes; see
5
+ * `ColorGrade#pack`. Built on first use and kept for the operator.
6
+ *
7
+ * Dispatch `ceil(resolution / TONEMAP_LUT_BAKE_GROUP)` workgroups along each axis.
8
+ *
9
+ * @param {ToneMapOperator} operator
10
+ * @returns {ComputeShader}
11
+ */
12
+ export function shader_tonemap_lut_bake(operator: ToneMapOperator): ComputeShader;
13
+ /**
14
+ * Immediate data of a bake: the peak the operator is evaluated for, `PAPER_WHITE_NITS` for an SDR LUT.
15
+ */
16
+ export const TONEMAP_LUT_BAKE_SETTINGS: WebGPUStruct;
17
+ /**
18
+ * Edge of the cube of LUT texels one workgroup bakes.
19
+ */
20
+ export const TONEMAP_LUT_BAKE_GROUP: 4;
21
+ import { ComputeShader } from "../../shader/ComputeShader.js";
22
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
23
+ //# sourceMappingURL=shader_tonemap_lut_bake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_tonemap_lut_bake.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/shader_tonemap_lut_bake.js"],"names":[],"mappings":"AA2BA;;;;;;;;;;GAUG;AACH,oEAFa,aAAa,CAuDzB;AA/ED;;GAEG;AACH,qDAA+E;AAE/E;;GAEG;AACH,uCAAwC;8BAfV,+BAA+B;6BAIhC,mCAAmC"}
@@ -0,0 +1,92 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { ANIMATION_CURVE_KEYFRAME_STRUCT } from "../../animation/ANIMATION_CURVE_KEYFRAME_STRUCT.js";
3
+ import { chunk_color_grade } from "../../shader/chunk/color/grade/chunk_color_grade.js";
4
+ import { chunk_tonemap_lut } from "../../shader/chunk/color/tonemap/chunk_tonemap_lut.js";
5
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
6
+ import { ComputeShader } from "../../shader/ComputeShader.js";
7
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
8
+ import { f32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
9
+ import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
10
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
11
+ import { COLOR_GRADE_STRUCT } from "./ColorGrade.js";
12
+
13
+ /**
14
+ * Immediate data of a bake: the peak the operator is evaluated for, `PAPER_WHITE_NITS` for an SDR LUT.
15
+ */
16
+ export const TONEMAP_LUT_BAKE_SETTINGS = WebGPUStruct.from({ peak_nits: f32 });
17
+
18
+ /**
19
+ * Edge of the cube of LUT texels one workgroup bakes.
20
+ */
21
+ export const TONEMAP_LUT_BAKE_GROUP = 4;
22
+
23
+ /**
24
+ * @type {WeakMap<ToneMapOperator, ComputeShader>}
25
+ */
26
+ const shaders = new WeakMap();
27
+
28
+ /**
29
+ * The compute shader that bakes `operator` into a LUT, `lut`, one texel a thread: the texel's PQ signal decoded to
30
+ * exposed scene colour, through the colour grade and the operator, and encoded again, as {@link chunk_tonemap_lut}
31
+ * describes. The grade is `grade`, a {@link COLOR_GRADE_STRUCT}, and `grade_keys`, its curves' keyframes; see
32
+ * `ColorGrade#pack`. Built on first use and kept for the operator.
33
+ *
34
+ * Dispatch `ceil(resolution / TONEMAP_LUT_BAKE_GROUP)` workgroups along each axis.
35
+ *
36
+ * @param {ToneMapOperator} operator
37
+ * @returns {ComputeShader}
38
+ */
39
+ export function shader_tonemap_lut_bake(operator) {
40
+ assert.defined(operator, 'operator');
41
+
42
+ let shader = shaders.get(operator);
43
+
44
+ if (shader !== undefined) {
45
+ return shader;
46
+ }
47
+
48
+ const resources = new ShaderResourceSetDescriptor();
49
+
50
+ resources.setImmediate("settings", TONEMAP_LUT_BAKE_SETTINGS);
51
+
52
+ const group = resources.createGroup()
53
+ .addStorageTexture("lut", "rgba16float", "3d", "write-only")
54
+ .addUniform("grade", COLOR_GRADE_STRUCT)
55
+ .addStorageBuffer("grade_keys", WebGPUArray.from(ANIMATION_CURVE_KEYFRAME_STRUCT));
56
+
57
+ operator.declare(group);
58
+
59
+ const body = CodeChunk.from(
60
+ //language=WGSL
61
+ `
62
+ @compute @workgroup_size(${TONEMAP_LUT_BAKE_GROUP}, ${TONEMAP_LUT_BAKE_GROUP}, ${TONEMAP_LUT_BAKE_GROUP})
63
+ fn main(@builtin(global_invocation_id) texel: vec3<u32>) {
64
+ let size = textureDimensions(lut);
65
+
66
+ if (any(texel >= size)) {
67
+ return;
68
+ }
69
+
70
+ let scene = tonemap_lut_pq_decode(vec3<f32>(texel) / vec3<f32>(size - 1u));
71
+
72
+ let display = tone_map_operator(color_grade(scene, grade, &grade_keys), settings.peak_nits);
73
+
74
+ textureStore(lut, texel, vec4<f32>(tonemap_lut_pq_encode(display), 1.0));
75
+ }
76
+ `, [
77
+ chunk_tonemap_lut,
78
+ chunk_color_grade,
79
+ operator.chunk,
80
+ ]
81
+ );
82
+
83
+ shader = ComputeShader.from({
84
+ label: `Tonemap/LUT bake/${operator.label}`,
85
+ body,
86
+ resources,
87
+ });
88
+
89
+ shaders.set(operator, shader);
90
+
91
+ return shader;
92
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Immediate data of {@link shader_tonemap_lut_sdr_from_hdr}: the peak the HDR LUT was graded for, cd/m².
3
+ */
4
+ export const TONEMAP_LUT_SDR_FROM_HDR_SETTINGS: WebGPUStruct;
5
+ /**
6
+ * An SDR LUT from an HDR one of the same resolution: each texel through the BT.2390 EETF, from the HDR LUT's graded
7
+ * peak down to the paper white. The EETF maps the brightest channel's signal and the three channels scale by the
8
+ * same ratio of light, so the hue holds and no channel passes SDR white. Below the EETF's knee a texel is unchanged.
9
+ *
10
+ * @type {ComputeShader}
11
+ */
12
+ export const shader_tonemap_lut_sdr_from_hdr: ComputeShader;
13
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
14
+ import { ComputeShader } from "../../shader/ComputeShader.js";
15
+ //# sourceMappingURL=shader_tonemap_lut_sdr_from_hdr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_tonemap_lut_sdr_from_hdr.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/deferred/tonemap/shader_tonemap_lut_sdr_from_hdr.js"],"names":[],"mappings":"AAUA;;GAEG;AACH,6DAA8F;AAgD9F;;;;;;GAMG;AACH,8CAFU,aAAa,CAMpB;6BAjE0B,mCAAmC;8BAHlC,+BAA+B"}
@@ -0,0 +1,73 @@
1
+ import { chunk_bt2390_eetf } from "../../shader/chunk/color/tonemap/chunk_bt2390_eetf.js";
2
+ import { chunk_PAPER_WHITE_NITS } from "../../shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js";
3
+ import { chunk_tonemap_lut } from "../../shader/chunk/color/tonemap/chunk_tonemap_lut.js";
4
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
5
+ import { ComputeShader } from "../../shader/ComputeShader.js";
6
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
7
+ import { f32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
8
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
9
+ import { TONEMAP_LUT_BAKE_GROUP } from "./shader_tonemap_lut_bake.js";
10
+
11
+ /**
12
+ * Immediate data of {@link shader_tonemap_lut_sdr_from_hdr}: the peak the HDR LUT was graded for, cd/m².
13
+ */
14
+ export const TONEMAP_LUT_SDR_FROM_HDR_SETTINGS = WebGPUStruct.from({ source_peak_nits: f32 });
15
+
16
+ const resources = new ShaderResourceSetDescriptor();
17
+
18
+ resources.setImmediate("settings", TONEMAP_LUT_SDR_FROM_HDR_SETTINGS);
19
+ resources.createGroup()
20
+ .addTexture("hdr_lut", "unfilterable-float", "3d")
21
+ .addStorageTexture("sdr_lut", "rgba16float", "3d", "write-only");
22
+
23
+ const body = CodeChunk.from(
24
+ //language=WGSL
25
+ `
26
+ @compute @workgroup_size(${TONEMAP_LUT_BAKE_GROUP}, ${TONEMAP_LUT_BAKE_GROUP}, ${TONEMAP_LUT_BAKE_GROUP})
27
+ fn main(@builtin(global_invocation_id) texel: vec3<u32>) {
28
+ let size = textureDimensions(sdr_lut);
29
+
30
+ if (any(texel >= size)) {
31
+ return;
32
+ }
33
+
34
+ let signal = textureLoad(hdr_lut, texel, 0).rgb;
35
+
36
+ // the brightest channel's signal; the other two follow it by the same ratio of light, which keeps the hue
37
+ let brightest = max(signal.r, max(signal.g, signal.b));
38
+
39
+ let source_peak = tonemap_lut_pq_encode(vec3<f32>(settings.source_peak_nits / PAPER_WHITE_NITS)).x;
40
+ let target_peak = tonemap_lut_pq_encode(vec3<f32>(1.0)).x;
41
+
42
+ let mapped = bt2390_eetf(brightest, source_peak, target_peak);
43
+
44
+ let light = tonemap_lut_pq_decode(signal);
45
+ let before = tonemap_lut_pq_decode(vec3<f32>(brightest)).x;
46
+ let after = tonemap_lut_pq_decode(vec3<f32>(mapped)).x;
47
+
48
+ var scale = 1.0;
49
+ if (before > 0.0) {
50
+ scale = after / before;
51
+ }
52
+
53
+ textureStore(sdr_lut, texel, vec4<f32>(tonemap_lut_pq_encode(light * scale), 1.0));
54
+ }
55
+ `, [
56
+ chunk_tonemap_lut,
57
+ chunk_bt2390_eetf,
58
+ chunk_PAPER_WHITE_NITS,
59
+ ]
60
+ );
61
+
62
+ /**
63
+ * An SDR LUT from an HDR one of the same resolution: each texel through the BT.2390 EETF, from the HDR LUT's graded
64
+ * peak down to the paper white. The EETF maps the brightest channel's signal and the three channels scale by the
65
+ * same ratio of light, so the hue holds and no channel passes SDR white. Below the EETF's knee a texel is unchanged.
66
+ *
67
+ * @type {ComputeShader}
68
+ */
69
+ export const shader_tonemap_lut_sdr_from_hdr = ComputeShader.from({
70
+ label: "Tonemap/LUT SDR from HDR",
71
+ body,
72
+ resources,
73
+ });