@woosh/meep-engine 3.50.0 → 3.52.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.
- package/package.json +1 -1
- package/src/engine/graphics3/make_default_environment.d.ts.map +1 -1
- package/src/engine/graphics3/make_default_environment.js +11 -5
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/particle_ecs/moonlit_environment.d.ts.map +1 -1
- package/src/shade/playground/particle_ecs/moonlit_environment.js +11 -5
- package/src/shade/playground/sh_exponential/sh_exp_playground_shaders.d.ts.map +1 -1
- package/src/shade/playground/sh_exponential/sh_exp_playground_shaders.js +3 -1
- package/src/shade/playground/tonemap_sdr/README.md +5 -3
- package/src/shade/renderer/Renderer.d.ts +1 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +43 -15
- package/src/shade/renderer/ShadeToneMappingMode.d.ts +3 -2
- package/src/shade/renderer/ShadeToneMappingMode.js +15 -4
- package/src/shade/renderer/atmosphere/chunk_sample_environment_color.d.ts +3 -0
- package/src/shade/renderer/atmosphere/chunk_sample_environment_color.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/chunk_sample_environment_color.js +11 -8
- package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts +6 -0
- package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +227 -215
- package/src/shade/renderer/deferred/SHADING_LIGHT_RESOURCE_GROUP.d.ts.map +1 -1
- package/src/shade/renderer/deferred/SHADING_LIGHT_RESOURCE_GROUP.js +2 -0
- package/src/shade/renderer/deferred/indirect/chunk_get_ibl_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/deferred/indirect/chunk_get_ibl_irradiance.js +4 -2
- package/src/shade/renderer/deferred/indirect/chunk_get_ibl_radiance.d.ts.map +1 -1
- package/src/shade/renderer/deferred/indirect/chunk_get_ibl_radiance.js +4 -2
- package/src/shade/renderer/deferred/shader_background.d.ts.map +1 -1
- package/src/shade/renderer/deferred/shader_background.js +4 -2
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts +38 -0
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js +97 -0
- package/src/shade/renderer/deferred/{TonemapDisplaySettings.d.ts → tonemap/TonemapDisplaySettings.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{TonemapDisplaySettings.js → tonemap/TonemapDisplaySettings.js} +5 -5
- package/src/shade/renderer/deferred/{shader_tonemap_HDR.d.ts → tonemap/shader_tonemap_HDR.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR.js → tonemap/shader_tonemap_HDR.js} +9 -9
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts +17 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.js +101 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_none.d.ts → tonemap/shader_tonemap_HDR_none.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_none.js → tonemap/shader_tonemap_HDR_none.js} +6 -6
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_pbr_neutral.d.ts → tonemap/shader_tonemap_HDR_pbr_neutral.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_pbr_neutral.js → tonemap/shader_tonemap_HDR_pbr_neutral.js} +8 -8
- package/src/shade/renderer/deferred/{shader_tonemap_LDR.d.ts → tonemap/shader_tonemap_LDR.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR.js → tonemap/shader_tonemap_LDR.js} +10 -10
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts +10 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.js +77 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_none.d.ts → tonemap/shader_tonemap_LDR_none.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_none.js → tonemap/shader_tonemap_LDR_none.js} +7 -7
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_pbr_neutral.d.ts → tonemap/shader_tonemap_LDR_pbr_neutral.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_pbr_neutral.js → tonemap/shader_tonemap_LDR_pbr_neutral.js} +8 -8
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.js +3 -1
- package/src/shade/renderer/global_illumination/ibl/shader_diffuse_IBL.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/ibl/shader_diffuse_IBL.js +3 -1
- package/src/shade/renderer/global_illumination/ibl/shader_specular_IBL.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/ibl/shader_specular_IBL.js +3 -1
- package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.js +3 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/shader_lpv_build_gbuffer.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/shader_lpv_build_gbuffer.js +4 -2
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +44 -0
- package/src/shade/renderer/light/environment/ENVIRONMENT_MAP_RESOURCE.d.ts +2 -1
- package/src/shade/renderer/light/environment/ENVIRONMENT_MAP_RESOURCE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/ENVIRONMENT_MAP_RESOURCE.js +3 -2
- package/src/shade/renderer/light/environment/ENVIRONMENT_MAP_SAMPLER_RESOURCE.d.ts +14 -0
- package/src/shade/renderer/light/environment/ENVIRONMENT_MAP_SAMPLER_RESOURCE.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/ENVIRONMENT_MAP_SAMPLER_RESOURCE.js +25 -0
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/execute_filter_environment_map.js +3 -4
- package/src/shade/renderer/light/environment/octahedral_skirt_matches.d.ts +19 -0
- package/src/shade/renderer/light/environment/octahedral_skirt_matches.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/octahedral_skirt_matches.js +67 -0
- package/src/shade/renderer/light/environment/octahedral_skirt_source_texel.d.ts +16 -0
- package/src/shade/renderer/light/environment/octahedral_skirt_source_texel.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/octahedral_skirt_source_texel.js +35 -0
- package/src/shade/renderer/light/environment/resample_cube_to_octahedral.d.ts +7 -2
- package/src/shade/renderer/light/environment/resample_cube_to_octahedral.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +23 -7
- package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.d.ts +8 -2
- package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.js +24 -7
- package/src/shade/renderer/light/environment/sampler2d_octahedral_skirt_fill.d.ts +12 -0
- package/src/shade/renderer/light/environment/sampler2d_octahedral_skirt_fill.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/sampler2d_octahedral_skirt_fill.js +54 -0
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_environment_cells.d.ts +2 -2
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_environment_cells.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/sh_exponential/shader_sh_exp_environment_cells.js +5 -4
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map.js +13 -9
- package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/shader_project_environment_sh.js +3 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.js +3 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.js +3 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.js +3 -1
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +3 -1
- package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.js +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +3 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.d.ts +0 -5
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_CONSTANTS.js +0 -6
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_counts_to_extinction.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_counts_to_extinction.js +4 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +3 -0
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +3 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +160 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +5 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +15 -5
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/aces2_transform_block.d.ts +41 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/aces2_transform_block.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/aces2_transform_block.js +692 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.js +446 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.js +68 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts +32 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js +163 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts +10 -3
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js +12 -4
- package/src/shade/renderer/shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_texel_uv.d.ts +15 -0
- package/src/shade/renderer/shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_texel_uv.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_texel_uv.js +27 -0
- package/src/shade/renderer/shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_uv.d.ts +18 -0
- package/src/shade/renderer/shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_uv.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_uv.js +24 -0
- package/src/shade/renderer/shader/chunk/texture/sample/chunk_sample_environment_map.d.ts +18 -1
- package/src/shade/renderer/shader/chunk/texture/sample/chunk_sample_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/texture/sample/chunk_sample_environment_map.js +45 -27
- package/src/shade/renderer/view/GPUViewSkyContext.js +169 -169
- package/src/shade/renderer/volumetrics/NOTES.md +209 -0
- package/src/shade/renderer/volumetrics/VOLUMETRICS_METADATA_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/VOLUMETRICS_METADATA_STRUCT.js +1 -1
- package/src/shade/renderer/volumetrics/chunk_volumetrics_media_group_list.d.ts +36 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_media_group_list.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_media_group_list.js +129 -0
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +75 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_bin_participating_media.d.ts +26 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_bin_participating_media.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_bin_participating_media.js +110 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +38 -14
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +9 -4
- package/src/shade/renderer/volumetrics/shader_volumetrics_split_participating_media.d.ts +31 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_split_participating_media.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_split_participating_media.js +139 -0
- package/src/shade/renderer/deferred/TonemapDisplaySettings.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR_none.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR_none.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.d.ts.map +0 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ACES 2.0 output transform, forward and inverse, for a display whose parameters and gamut tables sit in
|
|
3
|
+
* `aces2_tables` from float `block` on, as {@link aces2_transform_block_write} lays them out.
|
|
4
|
+
*
|
|
5
|
+
* This is OpenColorIO v2.6.0's `ACES_OUTPUT_TRANSFORM_20` (ops/fixedfunction/ACES2/Transform.cpp), which implements the
|
|
6
|
+
* Academy's reference, with what OCIO's builtin output transforms put around it: a clamp of the input to the AP1
|
|
7
|
+
* gamut and to the tone scale's reach, and a clamp of the output to the display's peak. Units on the display side are
|
|
8
|
+
* 100 cd/m² to 1.0.
|
|
9
|
+
*
|
|
10
|
+
* - `aces2_forward(block, aces)`: ACES2065-1 (AP0) in, display-linear RGB in the block's limiting primaries out.
|
|
11
|
+
* - `aces2_inverse(block, rgb)`: the way back, which needs the same block.
|
|
12
|
+
*
|
|
13
|
+
* One difference from OCIO, where OCIO produces a NaN: the gamut boundary's power is taken of a base clamped at zero.
|
|
14
|
+
* A colour at the display's peak white can put the J intersection a rounding error past the upper hull, and OCIO's
|
|
15
|
+
* `powf` of the negative base returns NaN there.
|
|
16
|
+
*
|
|
17
|
+
* Reads a storage binding `aces2_tables: array<f32>`, declared by the pass.
|
|
18
|
+
*
|
|
19
|
+
* @see https://github.com/ampas/aces-core
|
|
20
|
+
* @see https://github.com/AcademySoftwareFoundation/OpenColorIO/tree/main/src/OpenColorIO/ops/fixedfunction/ACES2
|
|
21
|
+
* @type {CodeChunk}
|
|
22
|
+
*/
|
|
23
|
+
export const chunk_aces2_output_transform: CodeChunk;
|
|
24
|
+
import { CodeChunk } from "../../../../compiler/CodeChunk.js";
|
|
25
|
+
//# sourceMappingURL=chunk_aces2_output_transform.d.ts.map
|
package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_aces2_output_transform.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.js"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,2CAFU,SAAS,CA2ZjB;0BA7bwB,mCAAmC"}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { CodeChunk } from "../../../../compiler/CodeChunk.js";
|
|
2
|
+
import {
|
|
3
|
+
ACES2_AAB_TO_CONE,
|
|
4
|
+
ACES2_CONE_TO_AAB,
|
|
5
|
+
ACES2_CUSP_TABLE,
|
|
6
|
+
ACES2_IN_CAM_TO_RGB,
|
|
7
|
+
ACES2_IN_RGB_TO_CAM,
|
|
8
|
+
ACES2_OUT_CAM_TO_RGB,
|
|
9
|
+
ACES2_OUT_RGB_TO_CAM,
|
|
10
|
+
ACES2_REACH_TABLE,
|
|
11
|
+
ACES2_SCALARS
|
|
12
|
+
} from "./aces2_transform_block.js";
|
|
13
|
+
import { chunk_aces_ue_matrices } from "./chunk_aces_ue_matrices.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The ACES 2.0 output transform, forward and inverse, for a display whose parameters and gamut tables sit in
|
|
17
|
+
* `aces2_tables` from float `block` on, as {@link aces2_transform_block_write} lays them out.
|
|
18
|
+
*
|
|
19
|
+
* This is OpenColorIO v2.6.0's `ACES_OUTPUT_TRANSFORM_20` (ops/fixedfunction/ACES2/Transform.cpp), which implements the
|
|
20
|
+
* Academy's reference, with what OCIO's builtin output transforms put around it: a clamp of the input to the AP1
|
|
21
|
+
* gamut and to the tone scale's reach, and a clamp of the output to the display's peak. Units on the display side are
|
|
22
|
+
* 100 cd/m² to 1.0.
|
|
23
|
+
*
|
|
24
|
+
* - `aces2_forward(block, aces)`: ACES2065-1 (AP0) in, display-linear RGB in the block's limiting primaries out.
|
|
25
|
+
* - `aces2_inverse(block, rgb)`: the way back, which needs the same block.
|
|
26
|
+
*
|
|
27
|
+
* One difference from OCIO, where OCIO produces a NaN: the gamut boundary's power is taken of a base clamped at zero.
|
|
28
|
+
* A colour at the display's peak white can put the J intersection a rounding error past the upper hull, and OCIO's
|
|
29
|
+
* `powf` of the negative base returns NaN there.
|
|
30
|
+
*
|
|
31
|
+
* Reads a storage binding `aces2_tables: array<f32>`, declared by the pass.
|
|
32
|
+
*
|
|
33
|
+
* @see https://github.com/ampas/aces-core
|
|
34
|
+
* @see https://github.com/AcademySoftwareFoundation/OpenColorIO/tree/main/src/OpenColorIO/ops/fixedfunction/ACES2
|
|
35
|
+
* @type {CodeChunk}
|
|
36
|
+
*/
|
|
37
|
+
export const chunk_aces2_output_transform = CodeChunk.from(
|
|
38
|
+
//language=WGSL
|
|
39
|
+
`
|
|
40
|
+
const ACES2_CAM_NL_OFFSET: f32 = 27.13;
|
|
41
|
+
const ACES2_J_SCALE: f32 = 100.0;
|
|
42
|
+
const ACES2_SMOOTH_CUSPS: f32 = 0.12;
|
|
43
|
+
const ACES2_CUSP_MID_BLEND: f32 = 1.3;
|
|
44
|
+
const ACES2_FOCUS_GAIN_BLEND: f32 = 0.3;
|
|
45
|
+
const ACES2_COMPRESSION_THRESHOLD: f32 = 0.75;
|
|
46
|
+
const ACES2_DEGREES_PER_RADIAN: f32 = 57.29577951308232;
|
|
47
|
+
// how far below the peak's J the inverse starts fading out its gamut decompression; see aces2_gamut_compress
|
|
48
|
+
const ACES2_INVERSE_FADE_J: f32 = 1.0;
|
|
49
|
+
// the most the inverse's gamut decompression multiplies colourfulness by; see aces2_gamut_compress
|
|
50
|
+
const ACES2_INVERSE_GAIN_LIMIT: f32 = 5.0;
|
|
51
|
+
|
|
52
|
+
fn aces2_scalar(block: u32, index: u32) -> f32 {
|
|
53
|
+
return aces2_tables[block + ${ACES2_SCALARS}u + index];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fn aces2_matrix(at: u32) -> mat3x3<f32> {
|
|
57
|
+
return mat3x3<f32>(
|
|
58
|
+
vec3<f32>(aces2_tables[at], aces2_tables[at + 1u], aces2_tables[at + 2u]),
|
|
59
|
+
vec3<f32>(aces2_tables[at + 3u], aces2_tables[at + 4u], aces2_tables[at + 5u]),
|
|
60
|
+
vec3<f32>(aces2_tables[at + 6u], aces2_tables[at + 7u], aces2_tables[at + 8u])
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// post-adaptation cone response compression, odd in its argument
|
|
65
|
+
fn aces2_compress_cone(v: vec3<f32>) -> vec3<f32> {
|
|
66
|
+
let F = pow(abs(v), vec3<f32>(0.42));
|
|
67
|
+
return sign(v) * F / (ACES2_CAM_NL_OFFSET + F);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn aces2_compress_cone_inverse(v: vec3<f32>) -> vec3<f32> {
|
|
71
|
+
let a = min(abs(v), vec3<f32>(0.99));
|
|
72
|
+
let F = ACES2_CAM_NL_OFFSET * a / (1.0 - a);
|
|
73
|
+
return sign(v) * pow(F, vec3<f32>(1.0 / 0.42));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fn aces2_compress_cone_scalar(v: f32) -> f32 {
|
|
77
|
+
let F = pow(abs(v), 0.42);
|
|
78
|
+
return sign(v) * F / (ACES2_CAM_NL_OFFSET + F);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn aces2_compress_cone_inverse_scalar(v: f32) -> f32 {
|
|
82
|
+
let a = min(abs(v), 0.99);
|
|
83
|
+
return sign(v) * pow(ACES2_CAM_NL_OFFSET * a / (1.0 - a), 1.0 / 0.42);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// RGB to (A, a, b), through the given primaries' adapted cone space
|
|
87
|
+
fn aces2_rgb_to_Aab(block: u32, rgb_to_cam: u32, rgb: vec3<f32>) -> vec3<f32> {
|
|
88
|
+
let cone = aces2_matrix(block + rgb_to_cam) * rgb;
|
|
89
|
+
return aces2_matrix(block + ${ACES2_CONE_TO_AAB}u) * aces2_compress_cone(cone);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fn aces2_Aab_to_rgb(block: u32, cam_to_rgb: u32, Aab: vec3<f32>) -> vec3<f32> {
|
|
93
|
+
let cone = aces2_matrix(block + ${ACES2_AAB_TO_CONE}u) * Aab;
|
|
94
|
+
return aces2_matrix(block + cam_to_rgb) * aces2_compress_cone_inverse(cone);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn aces2_Aab_to_JMh(block: u32, Aab: vec3<f32>) -> vec3<f32> {
|
|
98
|
+
if (Aab.x <= 0.0) {
|
|
99
|
+
return vec3<f32>(0.0);
|
|
100
|
+
}
|
|
101
|
+
let J = ACES2_J_SCALE * pow(Aab.x, aces2_scalar(block, 18u));
|
|
102
|
+
let M = length(Aab.yz);
|
|
103
|
+
var h = atan2(Aab.z, Aab.y) * ACES2_DEGREES_PER_RADIAN;
|
|
104
|
+
if (h < 0.0) {
|
|
105
|
+
h += 360.0;
|
|
106
|
+
}
|
|
107
|
+
return vec3<f32>(J, M, h);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fn aces2_J_to_A(block: u32, J: f32) -> f32 {
|
|
111
|
+
return pow(J / ACES2_J_SCALE, aces2_scalar(block, 19u));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// achromatic response to luminance, and luminance to lightness J, for the AP0 input
|
|
115
|
+
fn aces2_A_to_Y(block: u32, A: f32) -> f32 {
|
|
116
|
+
return aces2_compress_cone_inverse_scalar(aces2_scalar(block, 20u) * A) / aces2_scalar(block, 17u);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fn aces2_Y_to_J(block: u32, Y: f32) -> f32 {
|
|
120
|
+
let Ra = aces2_compress_cone_scalar(Y * aces2_scalar(block, 17u));
|
|
121
|
+
return ACES2_J_SCALE * pow(Ra * aces2_scalar(block, 21u), aces2_scalar(block, 18u));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// the tone scale, in luminance, 1.0 = 100 cd/m² on the way out
|
|
125
|
+
fn aces2_tonescale(block: u32, Y: f32) -> f32 {
|
|
126
|
+
let s_2 = aces2_scalar(block, 5u);
|
|
127
|
+
let m_2 = aces2_scalar(block, 6u);
|
|
128
|
+
let g = aces2_scalar(block, 7u);
|
|
129
|
+
let t_1 = aces2_scalar(block, 8u);
|
|
130
|
+
let n_r = aces2_scalar(block, 9u);
|
|
131
|
+
|
|
132
|
+
let f = m_2 * pow(Y / (Y + s_2), g);
|
|
133
|
+
return max(0.0, f * f / (f + t_1)) * n_r;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fn aces2_tonescale_inverse(block: u32, Y: f32) -> f32 {
|
|
137
|
+
let s_2 = aces2_scalar(block, 5u);
|
|
138
|
+
let m_2 = aces2_scalar(block, 6u);
|
|
139
|
+
let g = aces2_scalar(block, 7u);
|
|
140
|
+
let t_1 = aces2_scalar(block, 8u);
|
|
141
|
+
let inverse_limit = aces2_scalar(block, 10u);
|
|
142
|
+
|
|
143
|
+
let Z = clamp(Y / 100.0, 0.0, inverse_limit);
|
|
144
|
+
let f = (Z + sqrt(Z * (4.0 * t_1 + Z))) / 2.0;
|
|
145
|
+
return s_2 / (pow(m_2 / f, 1.0 / g) - 1.0);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fn aces2_chroma_compress_norm(cos_h: f32, sin_h: f32, scale: f32) -> f32 {
|
|
149
|
+
let cos_h2 = 2.0 * cos_h * cos_h - 1.0;
|
|
150
|
+
let sin_h2 = 2.0 * cos_h * sin_h;
|
|
151
|
+
let cos_h3 = 4.0 * cos_h * cos_h * cos_h - 3.0 * cos_h;
|
|
152
|
+
let sin_h3 = 3.0 * sin_h - 4.0 * sin_h * sin_h * sin_h;
|
|
153
|
+
|
|
154
|
+
let M = 11.34072 * cos_h + 16.46899 * cos_h2 + 7.88380 * cos_h3
|
|
155
|
+
+ 14.66441 * sin_h - 6.37224 * sin_h2 + 9.19364 * sin_h3
|
|
156
|
+
+ 77.12896;
|
|
157
|
+
|
|
158
|
+
return M * scale;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
fn aces2_toe(x: f32, limit: f32, k1_in: f32, k2_in: f32) -> f32 {
|
|
162
|
+
if (x > limit) {
|
|
163
|
+
return x;
|
|
164
|
+
}
|
|
165
|
+
let k2 = max(k2_in, 0.001);
|
|
166
|
+
let k1 = sqrt(k1_in * k1_in + k2 * k2);
|
|
167
|
+
let k3 = (limit + k1) / (limit + k2);
|
|
168
|
+
let minus_b = k3 * x - k1;
|
|
169
|
+
let minus_ac = k2 * k3 * x;
|
|
170
|
+
return 0.5 * (minus_b + sqrt(minus_b * minus_b + 4.0 * minus_ac));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fn aces2_toe_inverse(x: f32, limit: f32, k1_in: f32, k2_in: f32) -> f32 {
|
|
174
|
+
if (x > limit) {
|
|
175
|
+
return x;
|
|
176
|
+
}
|
|
177
|
+
let k2 = max(k2_in, 0.001);
|
|
178
|
+
let k1 = sqrt(k1_in * k1_in + k2 * k2);
|
|
179
|
+
let k3 = (limit + k1) / (limit + k2);
|
|
180
|
+
return (x * x + k1 * x) / (k3 * (x + k2));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// M of the reach gamut at limit_J_max, one table entry a degree
|
|
184
|
+
fn aces2_reach_M(block: u32, h: f32) -> f32 {
|
|
185
|
+
let base = u32(h);
|
|
186
|
+
let t = h - f32(base);
|
|
187
|
+
let at = block + ${ACES2_REACH_TABLE}u + 1u + base;
|
|
188
|
+
return mix(aces2_tables[at], aces2_tables[at + 1u], t);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fn aces2_cusp_entry(block: u32, i: i32) -> vec4<f32> {
|
|
192
|
+
let at = block + ${ACES2_CUSP_TABLE}u + u32(i) * 4u;
|
|
193
|
+
return vec4<f32>(aces2_tables[at], aces2_tables[at + 1u], aces2_tables[at + 2u], aces2_tables[at + 3u]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// (cusp J, cusp M, upper hull 1 / gamma) at hue h, from the non-uniform hue table
|
|
197
|
+
fn aces2_cusp(block: u32, h: f32) -> vec3<f32> {
|
|
198
|
+
var i = 1 + i32(h);
|
|
199
|
+
var i_lo = max(0, i + i32(aces2_scalar(block, 22u)));
|
|
200
|
+
var i_hi = min(361, i + i32(aces2_scalar(block, 23u)));
|
|
201
|
+
|
|
202
|
+
// a handful of steps: the table strays from one entry a degree by a few entries at most, and 9 halvings cover
|
|
203
|
+
// all 363
|
|
204
|
+
for (var step = 0; step < 9; step++) {
|
|
205
|
+
if (i_lo + 1 >= i_hi) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
if (h > aces2_cusp_entry(block, i).x) {
|
|
209
|
+
i_lo = i;
|
|
210
|
+
} else {
|
|
211
|
+
i_hi = i;
|
|
212
|
+
}
|
|
213
|
+
i = (i_lo + i_hi) / 2;
|
|
214
|
+
}
|
|
215
|
+
i_hi = max(1, i_hi);
|
|
216
|
+
|
|
217
|
+
let lower = aces2_cusp_entry(block, i_hi - 1);
|
|
218
|
+
let upper = aces2_cusp_entry(block, i_hi);
|
|
219
|
+
let t = (h - lower.x) / (upper.x - lower.x);
|
|
220
|
+
return mix(lower.yzw, upper.yzw, t);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fn aces2_focus_gain(J: f32, threshold: f32, J_max: f32, focus_dist: f32) -> f32 {
|
|
224
|
+
var gain = J_max * focus_dist;
|
|
225
|
+
if (J > threshold) {
|
|
226
|
+
let adjustment = log2((J_max - threshold) / max(0.0001, J_max - J)) * 0.30102999566398120;
|
|
227
|
+
gain *= adjustment * adjustment + 1.0;
|
|
228
|
+
}
|
|
229
|
+
return gain;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
fn aces2_solve_J_intersect(J: f32, M: f32, focusJ: f32, J_max: f32, slope_gain: f32) -> f32 {
|
|
233
|
+
let M_scaled = M / slope_gain;
|
|
234
|
+
let a = M_scaled / focusJ;
|
|
235
|
+
if (J < focusJ) {
|
|
236
|
+
let b = 1.0 - M_scaled;
|
|
237
|
+
let c = -J;
|
|
238
|
+
return -2.0 * c / (b + sqrt(b * b - 4.0 * a * c));
|
|
239
|
+
}
|
|
240
|
+
let b = -(1.0 + M_scaled + J_max * a);
|
|
241
|
+
let c = J_max * M_scaled + J;
|
|
242
|
+
return -2.0 * c / (b - sqrt(b * b - 4.0 * a * c));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
fn aces2_line_boundary_M(J_axis_intersect: f32, slope: f32, inv_gamma: f32, J_max: f32, M_max: f32, J_reference: f32) -> f32 {
|
|
246
|
+
let shifted = J_reference * pow(max(J_axis_intersect / J_reference, 0.0), inv_gamma);
|
|
247
|
+
return shifted * M_max / (J_max - slope * M_max);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
fn aces2_remap_M(M: f32, gamut_M: f32, reach_M: f32, inverse: bool) -> f32 {
|
|
251
|
+
let proportion = max(gamut_M / reach_M, ACES2_COMPRESSION_THRESHOLD);
|
|
252
|
+
let threshold = proportion * gamut_M;
|
|
253
|
+
if (M <= threshold || proportion >= 1.0) {
|
|
254
|
+
return M;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let m_offset = M - threshold;
|
|
258
|
+
let gamut_offset = gamut_M - threshold;
|
|
259
|
+
let reach_offset = reach_M - threshold;
|
|
260
|
+
let scale = reach_offset / ((reach_offset / gamut_offset) - 1.0);
|
|
261
|
+
let nd = m_offset / scale;
|
|
262
|
+
|
|
263
|
+
if (inverse) {
|
|
264
|
+
if (nd >= 1.0) {
|
|
265
|
+
return threshold + scale;
|
|
266
|
+
}
|
|
267
|
+
return threshold + scale * -(nd / (nd - 1.0));
|
|
268
|
+
}
|
|
269
|
+
return threshold + scale * nd / (1.0 + nd);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// compressGamut: pulls (J, M) toward the focus point onto the display's gamut, or back out of it
|
|
273
|
+
fn aces2_gamut_compress(block: u32, JMh: vec3<f32>, Jx: f32, reach_M: f32, cusp: vec3<f32>, inverse: bool) -> vec3<f32> {
|
|
274
|
+
let J_max = aces2_scalar(block, 0u);
|
|
275
|
+
let model_gamma_inv = aces2_scalar(block, 1u);
|
|
276
|
+
let mid_J = aces2_scalar(block, 2u);
|
|
277
|
+
let focus_dist = aces2_scalar(block, 3u);
|
|
278
|
+
let gamma_bottom_inv = aces2_scalar(block, 4u);
|
|
279
|
+
|
|
280
|
+
let focusJ = mix(cusp.x, mid_J, min(1.0, ACES2_CUSP_MID_BLEND - cusp.x / J_max));
|
|
281
|
+
let threshold = mix(cusp.x, J_max, ACES2_FOCUS_GAIN_BLEND);
|
|
282
|
+
|
|
283
|
+
let slope_gain = aces2_focus_gain(Jx, threshold, J_max, focus_dist);
|
|
284
|
+
let J_intersect_source = aces2_solve_J_intersect(JMh.x, JMh.y, focusJ, J_max, slope_gain);
|
|
285
|
+
let direction = select(J_max - J_intersect_source, J_intersect_source, J_intersect_source < focusJ);
|
|
286
|
+
let slope = direction * (J_intersect_source - focusJ) / (focusJ * slope_gain);
|
|
287
|
+
let J_intersect_cusp = aces2_solve_J_intersect(cusp.x, cusp.y, focusJ, J_max, slope_gain);
|
|
288
|
+
|
|
289
|
+
// find_gamut_boundary_intersection: the lower hull, and the upper one flipped about J_max, smoothly minimised
|
|
290
|
+
let lower = aces2_line_boundary_M(J_intersect_source, slope, gamma_bottom_inv, cusp.x, cusp.y, J_intersect_cusp);
|
|
291
|
+
let upper = aces2_line_boundary_M(J_max - J_intersect_source, -slope, cusp.z, J_max - cusp.x, cusp.y, J_max - J_intersect_cusp);
|
|
292
|
+
let s = ACES2_SMOOTH_CUSPS * cusp.y;
|
|
293
|
+
let k = max(s - abs(lower - upper), 0.0) / s;
|
|
294
|
+
let gamut_M = min(lower, upper) - k * k * k * s * (1.0 / 6.0);
|
|
295
|
+
|
|
296
|
+
if (gamut_M <= 0.0) {
|
|
297
|
+
return vec3<f32>(JMh.x, 0.0, JMh.z);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
let reach_boundary_M = aces2_line_boundary_M(J_intersect_source, slope, model_gamma_inv, J_max, reach_M, J_max);
|
|
301
|
+
|
|
302
|
+
// Going back, a colour past the estimated gamut boundary is one the forward transform never writes: the estimate
|
|
303
|
+
// lies inside the display's real gamut, and OCIO's inverse extrapolates from there toward infinity, then snaps.
|
|
304
|
+
// Clamped at the boundary it comes back as the reach boundary, which the forward transform takes to it.
|
|
305
|
+
var M_source = JMh.y;
|
|
306
|
+
if (inverse) {
|
|
307
|
+
M_source = min(M_source, gamut_M);
|
|
308
|
+
}
|
|
309
|
+
var M = aces2_remap_M(M_source, gamut_M, reach_boundary_M, inverse);
|
|
310
|
+
|
|
311
|
+
// In the last unit of J before the peak, the display's gamut closes on white while the reach does not, so the
|
|
312
|
+
// inverse multiplies colourfulness by hundreds to thousands, where everywhere below that unit it multiplies by
|
|
313
|
+
// under 4.9 (3,000 Filmic outputs), and white itself, past J_max, comes back neutral. So the gain is held to what
|
|
314
|
+
// the rest of the gamut sees, which keeps float32 rounding from being multiplied a thousandfold, and fades out
|
|
315
|
+
// over that unit, which takes a near-white colour continuously to the neutral that white goes to.
|
|
316
|
+
if (inverse) {
|
|
317
|
+
M = min(M, ACES2_INVERSE_GAIN_LIMIT * M_source);
|
|
318
|
+
M = mix(M, M_source, smoothstep(J_max - ACES2_INVERSE_FADE_J, J_max, JMh.x));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return vec3<f32>(J_intersect_source + M * slope, M, JMh.z);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
fn aces2_clamp_to_ap1(block: u32, aces: vec3<f32>) -> vec3<f32> {
|
|
325
|
+
let upper_bound = aces2_scalar(block, 11u);
|
|
326
|
+
return UE_AP1_TO_AP0 * clamp(UE_AP0_TO_AP1 * aces, vec3<f32>(0.0), vec3<f32>(upper_bound));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
fn aces2_forward(block: u32, aces_in: vec3<f32>) -> vec3<f32> {
|
|
330
|
+
let J_max = aces2_scalar(block, 0u);
|
|
331
|
+
let model_gamma_inv = aces2_scalar(block, 1u);
|
|
332
|
+
|
|
333
|
+
let aces = aces2_clamp_to_ap1(block, aces_in);
|
|
334
|
+
|
|
335
|
+
let Aab = aces2_rgb_to_Aab(block, ${ACES2_IN_RGB_TO_CAM}u, aces);
|
|
336
|
+
let JMh = aces2_Aab_to_JMh(block, Aab);
|
|
337
|
+
let h = JMh.z;
|
|
338
|
+
|
|
339
|
+
let reach_M = aces2_reach_M(block, h);
|
|
340
|
+
let h_rad = h / ACES2_DEGREES_PER_RADIAN;
|
|
341
|
+
let cos_h = cos(h_rad);
|
|
342
|
+
let sin_h = sin(h_rad);
|
|
343
|
+
let M_norm = aces2_chroma_compress_norm(cos_h, sin_h, aces2_scalar(block, 15u));
|
|
344
|
+
|
|
345
|
+
// the tone scale, applied to the achromatic response's luminance. A response at or under zero comes out at zero,
|
|
346
|
+
// which is where OCIO's max(0, NaN) lands it
|
|
347
|
+
var Y_ts = 0.0;
|
|
348
|
+
if (Aab.x > 0.0) {
|
|
349
|
+
Y_ts = aces2_tonescale(block, aces2_A_to_Y(block, Aab.x));
|
|
350
|
+
}
|
|
351
|
+
let J_ts = aces2_Y_to_J(block, Y_ts);
|
|
352
|
+
|
|
353
|
+
// chroma compression
|
|
354
|
+
var M = JMh.y;
|
|
355
|
+
if (M != 0.0) {
|
|
356
|
+
let sat = aces2_scalar(block, 12u);
|
|
357
|
+
let sat_thr = aces2_scalar(block, 13u);
|
|
358
|
+
let compr = aces2_scalar(block, 14u);
|
|
359
|
+
|
|
360
|
+
let nJ = J_ts / J_max;
|
|
361
|
+
let snJ = max(0.0, 1.0 - nJ);
|
|
362
|
+
let limit = pow(nJ, model_gamma_inv) * reach_M / M_norm;
|
|
363
|
+
|
|
364
|
+
M = M * pow(J_ts / JMh.x, model_gamma_inv) / M_norm;
|
|
365
|
+
M = limit - aces2_toe(limit - M, limit - 0.001, snJ * sat, sqrt(nJ * nJ + sat_thr));
|
|
366
|
+
M = aces2_toe(M, limit, nJ * compr, snJ);
|
|
367
|
+
M = M * M_norm;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// gamut compression
|
|
371
|
+
var compressed = vec3<f32>(J_ts, M, h);
|
|
372
|
+
if (J_ts <= 0.0) {
|
|
373
|
+
compressed = vec3<f32>(0.0, 0.0, h);
|
|
374
|
+
} else if (M <= 0.0 || J_ts > J_max) {
|
|
375
|
+
compressed = vec3<f32>(J_ts, 0.0, h);
|
|
376
|
+
} else {
|
|
377
|
+
compressed = aces2_gamut_compress(block, compressed, J_ts, reach_M, aces2_cusp(block, h), false);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
let Aab_out = vec3<f32>(aces2_J_to_A(block, compressed.x), compressed.y * cos_h, compressed.y * sin_h);
|
|
381
|
+
let rgb = aces2_Aab_to_rgb(block, ${ACES2_OUT_CAM_TO_RGB}u, Aab_out);
|
|
382
|
+
|
|
383
|
+
return clamp(rgb, vec3<f32>(0.0), vec3<f32>(aces2_scalar(block, 16u)));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
fn aces2_inverse(block: u32, rgb_in: vec3<f32>) -> vec3<f32> {
|
|
387
|
+
let J_max = aces2_scalar(block, 0u);
|
|
388
|
+
let model_gamma_inv = aces2_scalar(block, 1u);
|
|
389
|
+
|
|
390
|
+
let rgb = clamp(rgb_in, vec3<f32>(0.0), vec3<f32>(aces2_scalar(block, 16u)));
|
|
391
|
+
|
|
392
|
+
let JMh = aces2_Aab_to_JMh(block, aces2_rgb_to_Aab(block, ${ACES2_OUT_RGB_TO_CAM}u, rgb));
|
|
393
|
+
let h = JMh.z;
|
|
394
|
+
|
|
395
|
+
let reach_M = aces2_reach_M(block, h);
|
|
396
|
+
let h_rad = h / ACES2_DEGREES_PER_RADIAN;
|
|
397
|
+
let cos_h = cos(h_rad);
|
|
398
|
+
let sin_h = sin(h_rad);
|
|
399
|
+
let M_norm = aces2_chroma_compress_norm(cos_h, sin_h, aces2_scalar(block, 15u));
|
|
400
|
+
|
|
401
|
+
// gamut compression, undone; above the analytical threshold J itself is estimated by one compression first
|
|
402
|
+
var tonemapped = JMh;
|
|
403
|
+
if (JMh.x <= 0.0) {
|
|
404
|
+
tonemapped = vec3<f32>(0.0, 0.0, h);
|
|
405
|
+
} else if (JMh.y <= 0.0 || JMh.x > J_max) {
|
|
406
|
+
tonemapped = vec3<f32>(JMh.x, 0.0, h);
|
|
407
|
+
} else {
|
|
408
|
+
let cusp = aces2_cusp(block, h);
|
|
409
|
+
let threshold = mix(cusp.x, J_max, ACES2_FOCUS_GAIN_BLEND);
|
|
410
|
+
var Jx = JMh.x;
|
|
411
|
+
if (Jx > threshold) {
|
|
412
|
+
Jx = aces2_gamut_compress(block, JMh, Jx, reach_M, cusp, true).x;
|
|
413
|
+
}
|
|
414
|
+
tonemapped = aces2_gamut_compress(block, JMh, Jx, reach_M, cusp, true);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// the tone scale, undone
|
|
418
|
+
let J_ts = tonemapped.x;
|
|
419
|
+
let Y_in = aces2_A_to_Y(block, aces2_J_to_A(block, abs(J_ts)));
|
|
420
|
+
let J = sign(J_ts) * aces2_Y_to_J(block, aces2_tonescale_inverse(block, Y_in));
|
|
421
|
+
|
|
422
|
+
// chroma compression, undone
|
|
423
|
+
var M = tonemapped.y;
|
|
424
|
+
if (M != 0.0) {
|
|
425
|
+
let sat = aces2_scalar(block, 12u);
|
|
426
|
+
let sat_thr = aces2_scalar(block, 13u);
|
|
427
|
+
let compr = aces2_scalar(block, 14u);
|
|
428
|
+
|
|
429
|
+
let nJ = J_ts / J_max;
|
|
430
|
+
let snJ = max(0.0, 1.0 - nJ);
|
|
431
|
+
let limit = pow(nJ, model_gamma_inv) * reach_M / M_norm;
|
|
432
|
+
|
|
433
|
+
M = M / M_norm;
|
|
434
|
+
M = aces2_toe_inverse(M, limit, nJ * compr, snJ);
|
|
435
|
+
M = limit - aces2_toe_inverse(limit - M, limit - 0.001, snJ * sat, sqrt(nJ * nJ + sat_thr));
|
|
436
|
+
M = M * M_norm * pow(J_ts / J, -model_gamma_inv);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
let Aab = vec3<f32>(aces2_J_to_A(block, J), M * cos_h, M * sin_h);
|
|
440
|
+
let aces = aces2_Aab_to_rgb(block, ${ACES2_IN_CAM_TO_RGB}u, Aab);
|
|
441
|
+
|
|
442
|
+
return aces2_clamp_to_ap1(block, aces);
|
|
443
|
+
}
|
|
444
|
+
`,
|
|
445
|
+
[chunk_aces_ue_matrices]
|
|
446
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The colour matrices of Unreal Engine 5.4's default tone mapping, each the product UE forms from the constants in
|
|
3
|
+
* `Engine/Shaders/Private/ACES.ush`, taken in float64 and written out. `M * v` here is UE's `mul(M, v)`.
|
|
4
|
+
*
|
|
5
|
+
* - `UE_REC709_TO_AP1`, `UE_AP1_TO_REC709`: UE's default working space (sRGB primaries, D65) to ACEScg and back,
|
|
6
|
+
* through XYZ with UE's Bradford D65/D60 adaptation (`XYZ_2_AP1_MAT · D65_2_D60_CAT · sRGB_2_XYZ_MAT`).
|
|
7
|
+
* - `UE_AP1_TO_AP0`, `UE_AP0_TO_AP1`: `AP1_2_AP0_MAT` and `AP0_2_AP1_MAT` as UE spells them.
|
|
8
|
+
* - `UE_EXPAND_GAMUT`: PostProcessCombineLUTs.usf's `ExpandMat`, from sRGB toward the "wide" primaries the file
|
|
9
|
+
* lists, `(XYZ_2_AP1_MAT · Wide_2_XYZ_MAT) · AP1_2_sRGB`. UE applies no adaptation on the wide side, and nor does
|
|
10
|
+
* this.
|
|
11
|
+
* - `UE_BLUE_CORRECT`, `UE_BLUE_CORRECT_INVERSE`: the file's `BlueCorrect` and `BlueCorrectInv`, both defined on
|
|
12
|
+
* AP0, conjugated into AP1 (`AP0_2_AP1 · BlueCorrect · AP1_2_AP0`).
|
|
13
|
+
*
|
|
14
|
+
* `UE_AP1_LUMINANCE` is `AP1_RGB2Y`, the Y row of `AP1_2_XYZ_MAT`.
|
|
15
|
+
*
|
|
16
|
+
* @see chunk_tonemap_ue_filmic
|
|
17
|
+
* @see chunk_aces2_output_transform
|
|
18
|
+
* @type {CodeChunk}
|
|
19
|
+
*/
|
|
20
|
+
export const chunk_aces_ue_matrices: CodeChunk;
|
|
21
|
+
import { CodeChunk } from "../../../../compiler/CodeChunk.js";
|
|
22
|
+
//# sourceMappingURL=chunk_aces_ue_matrices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_aces_ue_matrices.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,qCAFU,SAAS,CAgDjB;0BAnEwB,mCAAmC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { CodeChunk } from "../../../../compiler/CodeChunk.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The colour matrices of Unreal Engine 5.4's default tone mapping, each the product UE forms from the constants in
|
|
5
|
+
* `Engine/Shaders/Private/ACES.ush`, taken in float64 and written out. `M * v` here is UE's `mul(M, v)`.
|
|
6
|
+
*
|
|
7
|
+
* - `UE_REC709_TO_AP1`, `UE_AP1_TO_REC709`: UE's default working space (sRGB primaries, D65) to ACEScg and back,
|
|
8
|
+
* through XYZ with UE's Bradford D65/D60 adaptation (`XYZ_2_AP1_MAT · D65_2_D60_CAT · sRGB_2_XYZ_MAT`).
|
|
9
|
+
* - `UE_AP1_TO_AP0`, `UE_AP0_TO_AP1`: `AP1_2_AP0_MAT` and `AP0_2_AP1_MAT` as UE spells them.
|
|
10
|
+
* - `UE_EXPAND_GAMUT`: PostProcessCombineLUTs.usf's `ExpandMat`, from sRGB toward the "wide" primaries the file
|
|
11
|
+
* lists, `(XYZ_2_AP1_MAT · Wide_2_XYZ_MAT) · AP1_2_sRGB`. UE applies no adaptation on the wide side, and nor does
|
|
12
|
+
* this.
|
|
13
|
+
* - `UE_BLUE_CORRECT`, `UE_BLUE_CORRECT_INVERSE`: the file's `BlueCorrect` and `BlueCorrectInv`, both defined on
|
|
14
|
+
* AP0, conjugated into AP1 (`AP0_2_AP1 · BlueCorrect · AP1_2_AP0`).
|
|
15
|
+
*
|
|
16
|
+
* `UE_AP1_LUMINANCE` is `AP1_RGB2Y`, the Y row of `AP1_2_XYZ_MAT`.
|
|
17
|
+
*
|
|
18
|
+
* @see chunk_tonemap_ue_filmic
|
|
19
|
+
* @see chunk_aces2_output_transform
|
|
20
|
+
* @type {CodeChunk}
|
|
21
|
+
*/
|
|
22
|
+
export const chunk_aces_ue_matrices = CodeChunk.from(
|
|
23
|
+
//language=WGSL
|
|
24
|
+
`
|
|
25
|
+
const UE_AP1_LUMINANCE = vec3<f32>(0.2722287168, 0.6740817658, 0.0536895174);
|
|
26
|
+
|
|
27
|
+
const UE_REC709_TO_AP1 = mat3x3<f32>(
|
|
28
|
+
vec3<f32>( 0.6130974024, 0.0701937225, 0.0206155929),
|
|
29
|
+
vec3<f32>( 0.3395231461, 0.9163538791, 0.1095697729),
|
|
30
|
+
vec3<f32>( 0.0473794514, 0.0134523986, 0.8698146341)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const UE_AP1_TO_REC709 = mat3x3<f32>(
|
|
34
|
+
vec3<f32>( 1.7050509926, -0.1302564175, -0.0240033568),
|
|
35
|
+
vec3<f32>(-0.6217921205, 1.1408047365, -0.1289689761),
|
|
36
|
+
vec3<f32>(-0.0832588722, -0.0105483190, 1.1529723328)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const UE_AP1_TO_AP0 = mat3x3<f32>(
|
|
40
|
+
vec3<f32>( 0.6954522414, 0.0447945634, -0.0055258826),
|
|
41
|
+
vec3<f32>( 0.1406786965, 0.8596711185, 0.0040252103),
|
|
42
|
+
vec3<f32>( 0.1638690622, 0.0955343182, 1.0015006723)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const UE_AP0_TO_AP1 = mat3x3<f32>(
|
|
46
|
+
vec3<f32>( 1.4514393161, -0.0765537734, 0.0083161484),
|
|
47
|
+
vec3<f32>(-0.2365107469, 1.1762296998, -0.0060324498),
|
|
48
|
+
vec3<f32>(-0.2149285693, -0.0996759264, 0.9977163014)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const UE_EXPAND_GAMUT = mat3x3<f32>(
|
|
52
|
+
vec3<f32>( 1.3704123718, -0.0834334917, -0.0257933209),
|
|
53
|
+
vec3<f32>(-0.3292921877, 1.0970927480, -0.0986257988),
|
|
54
|
+
vec3<f32>(-0.0636831194, -0.0108613795, 1.2036949526)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const UE_BLUE_CORRECT = mat3x3<f32>(
|
|
58
|
+
vec3<f32>( 0.9386393778, 0.0000000001, 0.0000000000),
|
|
59
|
+
vec3<f32>( 0.0000000001, 0.8307941329, 0.0000000000),
|
|
60
|
+
vec3<f32>( 0.0613606221, 0.1692058671, 1.0000000000)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const UE_BLUE_CORRECT_INVERSE = mat3x3<f32>(
|
|
64
|
+
vec3<f32>( 1.0653748754, -0.0000003455, 0.0000000199),
|
|
65
|
+
vec3<f32>( 0.0000014468, 1.2036635244, 0.0000000212),
|
|
66
|
+
vec3<f32>(-0.0653710053, -0.2036677199, 0.9999996001)
|
|
67
|
+
);`
|
|
68
|
+
);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unreal Engine's default SDR tone mapping, "Filmic", with every setting at its default.
|
|
3
|
+
*
|
|
4
|
+
* A line-for-line port of UE 5.4's `CombineLUTsCommon` (PostProcessCombineLUTs.usf) for the sRGB output device and
|
|
5
|
+
* `FilmToneMap` (TonemapCommon.ush), as UE evaluates them into its colour grading LUT, here evaluated per pixel:
|
|
6
|
+
*
|
|
7
|
+
* 1. into ACEScg (AP1) from UE's default sRGB working space;
|
|
8
|
+
* 2. Expand Gamut at its default 1.0, which pushes bright saturated colours toward wider primaries;
|
|
9
|
+
* 3. the colour corrections at their defaults, which only clamp AP1 at zero;
|
|
10
|
+
* 4. Blue Correction at its default 0.6, a matrix that turns bright blue toward cyan rather than violet, before the
|
|
11
|
+
* curve, and its inverse after;
|
|
12
|
+
* 5. `FilmToneMap` with Slope 0.88, Toe 0.55, Shoulder 0.26, Black Clip 0 and White Clip 0.04 (`FPostProcessSettings`'
|
|
13
|
+
* defaults, Scene.cpp). It is the ACES reference rendering's glow and red modifier and its 0.96 desaturation, then a
|
|
14
|
+
* parametric toe-straight-shoulder curve on log10 of each AP1 channel, solved so that 0.18 comes out at 0.18, then a
|
|
15
|
+
* 0.93 desaturation;
|
|
16
|
+
* 6. back to the working space, clamped at zero, and clipped at 1 as the sRGB target clips it.
|
|
17
|
+
*
|
|
18
|
+
* UE 5.8 keeps Filmic as its default method and its SDR output unchanged. What it does on an HDR display is in
|
|
19
|
+
* shader_tonemap_HDR_aces.
|
|
20
|
+
*
|
|
21
|
+
* Where UE divides 0 by 0 (gamut expansion of black) or takes log10(0), this takes the limit, so black stays black.
|
|
22
|
+
* UE's LUT also limits its input to 43.7, the top of its log encoding; this does not, which moves a few saturated
|
|
23
|
+
* highlights over 43.7 by a few codes.
|
|
24
|
+
*
|
|
25
|
+
* Input: exposed linear Rec.709. Output: display-linear Rec.709 in [0, 1].
|
|
26
|
+
*
|
|
27
|
+
* @see "Color Grading and the Filmic Tonemapper in Unreal Engine", Epic Games
|
|
28
|
+
* @type {CodeChunk}
|
|
29
|
+
*/
|
|
30
|
+
export const chunk_tonemap_ue_filmic: CodeChunk;
|
|
31
|
+
import { CodeChunk } from "../../../../compiler/CodeChunk.js";
|
|
32
|
+
//# sourceMappingURL=chunk_tonemap_ue_filmic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_tonemap_ue_filmic.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,sCAFU,SAAS,CAoIjB;0BAlKwB,mCAAmC"}
|