1- DEFINE_UI_PARAMS(threshold_r , threshold r , DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
2- DEFINE_UI_PARAMS(threshold_g , threshold g , DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
3- DEFINE_UI_PARAMS(threshold_b , threshold b , DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
1+ DEFINE_UI_PARAMS(threshold_c , threshold c , DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
2+ DEFINE_UI_PARAMS(threshold_m , threshold m , DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
3+ DEFINE_UI_PARAMS(threshold_y , threshold y , DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
44DEFINE_UI_PARAMS(power, power, DCTLUI_SLIDER_FLOAT, 1.2f, 1.0f, 3.0f, 1.0f);
5- DEFINE_UI_PARAMS(shd_rolloff, shd rolloff, DCTLUI_SLIDER_FLOAT, 0.03f , 0.0f, 0.1f , 0.0f);
5+ DEFINE_UI_PARAMS(shd_rolloff, shd rolloff, DCTLUI_SLIDER_FLOAT, 0.0f , 0.0f, 0.03f , 0.0f);
66DEFINE_UI_PARAMS(cyan, cyan, DCTLUI_SLIDER_FLOAT, 0.09f, 0.0f, 1.0f, 0.0f);
77DEFINE_UI_PARAMS(magenta, magenta, DCTLUI_SLIDER_FLOAT, 0.24f, 0.0f, 1.0f, 0.0f);
88DEFINE_UI_PARAMS(yellow, yellow, DCTLUI_SLIDER_FLOAT, 0.12f, 0.0f, 1.0f, 0.0f);
9- DEFINE_UI_PARAMS(hexagonal, hexagonal, DCTLUI_CHECK_BOX, 0);
109DEFINE_UI_PARAMS(working_colorspace, working space, DCTLUI_COMBO_BOX, 0, {acescct, acescc, acescg}, {acescct, acescc, acescg});
1110DEFINE_UI_PARAMS(invert, invert, DCTLUI_CHECK_BOX, 0);
1211
1312
14- // Convert acescg to acescct
13+ // convert acescg to acescct
1514__DEVICE__ float lin_to_acescct(float in) {
1615 if (in <= 0.0078125f) {
1716 return 10.5402377416545f * in + 0.0729055341958355f;
@@ -20,7 +19,7 @@ __DEVICE__ float lin_to_acescct(float in) {
2019 }
2120}
2221
23- // Convert acescct to acescg
22+ // convert acescct to acescg
2423__DEVICE__ float acescct_to_lin(float in) {
2524 if (in > 0.155251141552511f) {
2625 return _powf( 2.0f, in*17.52f - 9.72f);
@@ -29,7 +28,7 @@ __DEVICE__ float acescct_to_lin(float in) {
2928 }
3029}
3130
32- // Convert acescg to acescc
31+ // convert acescg to acescc
3332__DEVICE__ float lin_to_acescc(float in) {
3433 if (in <= 0.0f) {
3534 return -0.3584474886f;
@@ -40,7 +39,7 @@ __DEVICE__ float lin_to_acescc(float in) {
4039 }
4140}
4241
43- // Convert acescc to acescg
42+ // convert acescc to acescg
4443__DEVICE__ float acescc_to_lin(float in) {
4544 if (in < -0.3013698630f) {
4645 return (_powf( 2.0f, in * 17.52f - 9.72f) - _powf( 2.0f, -16.0f)) * 2.0f;
@@ -94,9 +93,9 @@ __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p
9493
9594 // thr is the percentage of the core gamut to protect: the complement of threshold.
9695 float3 thr = make_float3(
97- 1.0f-_fmaxf(0.00001, threshold_r ),
98- 1.0f-_fmaxf(0.00001, threshold_g ),
99- 1.0f-_fmaxf(0.00001, threshold_b ));
96+ 1.0f-_fmaxf(0.00001, threshold_c ),
97+ 1.0f-_fmaxf(0.00001, threshold_m ),
98+ 1.0f-_fmaxf(0.00001, threshold_y ));
10099
101100 // lim is the distance beyond the gamut boundary that will be compressed to the gamut boundary.
102101 // lim = 0.2 will compress from a distance of 1.2 from achromatic to 1.0 (the gamut boundary).
@@ -106,9 +105,19 @@ __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p
106105 // achromatic axis
107106 float ach = _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z));
108107
109- // achromatic with shadow rolloff below shd_rolloff threshold
110- float ach_shd = 1.0f-((1.0f-ach)<(1.0f-shd_rolloff)?(1.0f-ach):(1.0f-shd_rolloff)+shd_rolloff*_tanhf((((1.0f-ach)-(1.0f-shd_rolloff))/shd_rolloff)));
111-
108+ // achromatic shadow rolloff
109+ float ach_shd;
110+ if (shd_rolloff < 0.004f) {
111+ // disable shadow rolloff functionality.
112+ // values below 0.004 cause strange behavior, actually increasing distance in some cases.
113+ // if ach < 0.0 and shd_rolloff is disabled, take absolute value. This preserves negative components after compression.
114+ ach_shd = _fabs(ach);
115+ } else {
116+ // lift ach below threshold using a tanh compression function.
117+ // this reduces large distance values in shadow grain, which can cause differences when inverting.
118+ ach_shd = 1.0f-((1.0f-ach)<(1.0f-shd_rolloff)?(1.0f-ach):(1.0f-shd_rolloff)+shd_rolloff*_tanhf((((1.0f-ach)-(1.0f-shd_rolloff))/shd_rolloff)));
119+ }
120+
112121 // distance from the achromatic axis for each color component aka inverse rgb ratios
113122 // distance is normalized by achromatic, so that 1.0f is at gamut boundary. avoid 0 div
114123 float3 dist;
@@ -117,26 +126,10 @@ __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p
117126 dist.z = ach_shd == 0.0f ? 0.0f : (ach-rgb.z)/ach_shd;
118127
119128 // compress distance with user controlled parameterized shaper function
120- float sat;
121- float3 csat, cdist;
122- if (hexagonal) {
123- // Based on Nick Shaw's variation on the gamut mapping algorithm
124- // https://community.acescentral.com/t/a-variation-on-jeds-rgb-gamut-mapper/3060
125- sat = _fmaxf(dist.x, _fmaxf(dist.y, dist.z));
126- csat = make_float3(
127- compress(sat, lim.x, thr.x, power, invert),
128- compress(sat, lim.y, thr.y, power, invert),
129- compress(sat, lim.z, thr.z, power, invert));
130- cdist = sat == 0.0f ? dist : make_float3(
131- dist.x * csat.x / sat,
132- dist.y * csat.y / sat,
133- dist.z * csat.z / sat);
134- } else {
135- cdist = make_float3(
136- compress(dist.x, lim.x, thr.x, power, invert),
137- compress(dist.y, lim.y, thr.y, power, invert),
138- compress(dist.z, lim.z, thr.z, power, invert));
139- }
129+ float3 cdist = make_float3(
130+ compress(dist.x, lim.x, thr.x, power, invert),
131+ compress(dist.y, lim.y, thr.y, power, invert),
132+ compress(dist.z, lim.z, thr.z, power, invert));
140133
141134 // recalculate rgb from compressed distance and achromatic
142135 // effectively this scales each color component relative to achromatic axis by the compressed distance
0 commit comments