Skip to content

Commit 7527d9f

Browse files
committed
feat(shaders): add AdaptiveD65 gamut compression
1 parent 0b0ee12 commit 7527d9f

1 file changed

Lines changed: 161 additions & 0 deletions

File tree

src/shaders/color/gamut.hlsl

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,167 @@ float3 GamutCompressWeightedLMSCoreRGBBoundFromAdaptiveWeightedInputPrecise(
523523
strength);
524524
}
525525

526+
float ComputeGamutCompressionScaleWeightedLMSCoreRGBBoundFromWeightedInput(
527+
float3 lms_weighted_input,
528+
float2 bound_r,
529+
float2 bound_g,
530+
float2 bound_b,
531+
float strength) {
532+
float3 lms_weighted_clamped = ClampWeightedLMSToCIE1702(max(lms_weighted_input, 0));
533+
float3 mb = renodx::color::macleod_boynton::from::WeightedLMS(lms_weighted_clamped);
534+
float y_mb = mb.z;
535+
float2 ls = mb.xy;
536+
if (!(y_mb > EPSILON)) {
537+
return 1.f;
538+
}
539+
540+
float2 mb_white = CIE1702WhiteChromaticity();
541+
float2 direction = ls - mb_white;
542+
if (dot(direction, direction) <= MB_NEAR_WHITE_EPSILON) {
543+
return 1.f;
544+
}
545+
546+
bool has_peak = false;
547+
float t_peak = RayMaxT_RGBTriangleInMB(
548+
mb_white, direction, bound_r, bound_g, bound_b, has_peak);
549+
float t_clip = RayExitTCIE1702D(direction);
550+
if (!has_peak) {
551+
t_peak = t_clip;
552+
}
553+
554+
float t_hard = saturate(t_peak);
555+
float t_soft = NeutwoScaleFromRayT(min(t_peak, t_clip), t_clip);
556+
float soft_mix = saturate(strength) * SoftCompressionActivationFromRayT(t_peak);
557+
return lerp(t_hard, t_soft, soft_mix);
558+
}
559+
560+
float ComputeGamutCompressionScaleWeightedLMSCoreRGBBoundFromWeightedInput(
561+
float3 lms_weighted_input,
562+
float3x3 bound_rgb_to_lms_weighted_mat,
563+
float strength) {
564+
float2 bound_r;
565+
float2 bound_g;
566+
float2 bound_b;
567+
MakeRGBTriangleInMBWeighted(bound_rgb_to_lms_weighted_mat, bound_r, bound_g, bound_b);
568+
return ComputeGamutCompressionScaleWeightedLMSCoreRGBBoundFromWeightedInput(
569+
lms_weighted_input,
570+
bound_r,
571+
bound_g,
572+
bound_b,
573+
strength);
574+
}
575+
576+
float ComputeGamutCompressionScaleWeightedLMSCoreRGBBoundFromAdaptiveWeightedInput(
577+
float3 lms_weighted_input,
578+
float3 current_adaptive_state_lms,
579+
float3x3 bound_rgb_to_lms_weighted_mat,
580+
float strength) {
581+
float2 bound_r;
582+
float2 bound_g;
583+
float2 bound_b;
584+
MakeRGBTriangleInMBAdaptiveWeighted(
585+
bound_rgb_to_lms_weighted_mat,
586+
current_adaptive_state_lms,
587+
bound_r,
588+
bound_g,
589+
bound_b);
590+
return ComputeGamutCompressionScaleWeightedLMSCoreRGBBoundFromWeightedInput(
591+
lms_weighted_input,
592+
bound_r,
593+
bound_g,
594+
bound_b,
595+
strength);
596+
}
597+
598+
float3 CompressWeightedLMSFromCIE1702White(float3 lms_weighted_input, float compression_scale) {
599+
float3 lms_weighted_clamped = ClampWeightedLMSToCIE1702(max(lms_weighted_input, 0));
600+
float3 mb = renodx::color::macleod_boynton::from::WeightedLMS(lms_weighted_clamped);
601+
float y_mb = mb.z;
602+
float2 ls = mb.xy;
603+
if (!(y_mb > EPSILON)) {
604+
return float3(lms_weighted_clamped.x, lms_weighted_clamped.y, 0.f);
605+
}
606+
607+
float2 mb_white = CIE1702WhiteChromaticity();
608+
float2 direction = ls - mb_white;
609+
if (dot(direction, direction) <= MB_NEAR_WHITE_EPSILON) {
610+
return lms_weighted_clamped;
611+
}
612+
613+
float2 ls_out = mb_white + saturate(compression_scale) * direction;
614+
return renodx::color::macleod_boynton::WeightedLMSFromMacleodBoynton(ls_out, y_mb);
615+
}
616+
617+
float3 DecompressWeightedLMSFromCIE1702White(float3 lms_weighted_input, float compression_scale) {
618+
float3 lms_weighted_clamped = max(lms_weighted_input, 0);
619+
float3 mb = renodx::color::macleod_boynton::from::WeightedLMS(lms_weighted_clamped);
620+
float y_mb = mb.z;
621+
float2 ls = mb.xy;
622+
if (!(y_mb > EPSILON)) {
623+
return float3(lms_weighted_clamped.x, lms_weighted_clamped.y, 0.f);
624+
}
625+
626+
float2 mb_white = CIE1702WhiteChromaticity();
627+
float2 direction = ls - mb_white;
628+
if (dot(direction, direction) <= MB_NEAR_WHITE_EPSILON) {
629+
return lms_weighted_clamped;
630+
}
631+
632+
float safe_scale = max(compression_scale, 1e-6f);
633+
float2 ls_out = mb_white + direction * rcp(safe_scale);
634+
return renodx::color::macleod_boynton::WeightedLMSFromMacleodBoynton(ls_out, y_mb);
635+
}
636+
637+
float ComputeGamutCompressionScaleBT709AdaptiveD65(
638+
float3 bt709_input,
639+
float3 current_adaptive_state_lms,
640+
float strength = 1.f) {
641+
float3 lms_input = renodx::color::lms::from::BT709(bt709_input);
642+
float3 lms_weighted_relative = renodx::math::DivideSafe(
643+
renodx::color::macleod_boynton::WeighLMS(lms_input),
644+
current_adaptive_state_lms,
645+
0.f);
646+
return ComputeGamutCompressionScaleWeightedLMSCoreRGBBoundFromAdaptiveWeightedInput(
647+
lms_weighted_relative,
648+
current_adaptive_state_lms,
649+
renodx::color::macleod_boynton::BT709_TO_LMS_WEIGHTED_MAT,
650+
strength);
651+
}
652+
653+
float3 GamutCompressBT709AdaptiveD65(
654+
float3 bt709_input,
655+
float3 current_adaptive_state_lms,
656+
float compression_scale) {
657+
float3 lms_input = renodx::color::lms::from::BT709(bt709_input);
658+
float3 lms_weighted_relative = renodx::math::DivideSafe(
659+
renodx::color::macleod_boynton::WeighLMS(lms_input),
660+
current_adaptive_state_lms,
661+
0.f);
662+
float3 lms_weighted_relative_out = CompressWeightedLMSFromCIE1702White(
663+
lms_weighted_relative,
664+
compression_scale);
665+
return renodx::color::bt709::from::LMS(
666+
renodx::color::macleod_boynton::UnweighLMS(
667+
lms_weighted_relative_out * max(current_adaptive_state_lms, 1e-6f)));
668+
}
669+
670+
float3 GamutDecompressBT709AdaptiveD65(
671+
float3 bt709_input,
672+
float3 current_adaptive_state_lms,
673+
float compression_scale) {
674+
float3 lms_input = renodx::color::lms::from::BT709(bt709_input);
675+
float3 lms_weighted_relative = renodx::math::DivideSafe(
676+
renodx::color::macleod_boynton::WeighLMS(lms_input),
677+
current_adaptive_state_lms,
678+
0.f);
679+
float3 lms_weighted_relative_out = DecompressWeightedLMSFromCIE1702White(
680+
lms_weighted_relative,
681+
compression_scale);
682+
return renodx::color::bt709::from::LMS(
683+
renodx::color::macleod_boynton::UnweighLMS(
684+
lms_weighted_relative_out * max(current_adaptive_state_lms, 1e-6f)));
685+
}
686+
526687
float3 GamutCompressLMS(float3 lms_input, float strength = 1.f) {
527688
float3 lms_weighted_input = renodx::color::macleod_boynton::WeighLMS(lms_input);
528689
float3 lms_weighted_clamped = max(lms_weighted_input, 0);

0 commit comments

Comments
 (0)