Skip to content

Commit

Permalink
bugfix to preserve negative color components. rename threshold rgb to…
Browse files Browse the repository at this point in the history
… cmy. default shadow rolloff to 0.0.
  • Loading branch information
Jed Smith committed Aug 31, 2020
1 parent 2f495a2 commit ace29c1
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 86 deletions.
16 changes: 13 additions & 3 deletions GamutCompress.blink
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,19 @@ kernel GamutCompression : public ImageComputationKernel<ePixelWise> {
// achromatic axis
float ach = max(rgb.x, max(rgb.y, rgb.z));

// achromatic with shadow rolloff below shd_rolloff threshold
float ach_shd = 1.0f-( (1.0f-ach)<(1.0f-shd_rolloff)?(1.0f-ach):(1.0f-shd_rolloff)+shd_rolloff*tanh((((1.0f-ach)-(1.0f-shd_rolloff))/shd_rolloff)));

// achromatic shadow rolloff
float ach_shd;
if (shd_rolloff < 0.004f) {
// disable shadow rolloff functionality.
// values below 0.004 cause strange behavior, actually increasing distance in some cases.
// if ach < 0.0 and shd_rolloff is disabled, take absolute value. This preserves negative components after compression.
ach_shd = fabs(ach);
} else {
// lift ach below threshold using a tanh compression function.
// this reduces large distance values in shadow grain, which can cause differences when inverting.
ach_shd = 1.0f-((1.0f-ach)<(1.0f-shd_rolloff)?(1.0f-ach):(1.0f-shd_rolloff)+shd_rolloff*tanh((((1.0f-ach)-(1.0f-shd_rolloff))/shd_rolloff)));
}

// distance from the achromatic axis for each color component aka inverse rgb ratios
// distance is normalized by achromatic, so that 1.0f is at gamut boundary, avoid 0 div
float3 dist = ach_shd == 0 ? float3(0.0f, 0.0f, 0.0f) : (ach-rgb)/ach_shd;
Expand Down
30 changes: 20 additions & 10 deletions GamutCompress.dctl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
DEFINE_UI_PARAMS(threshold_r, threshold r, DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
DEFINE_UI_PARAMS(threshold_g, threshold g, DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
DEFINE_UI_PARAMS(threshold_b, threshold b, DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
DEFINE_UI_PARAMS(threshold_c, threshold c, DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
DEFINE_UI_PARAMS(threshold_m, threshold m, DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
DEFINE_UI_PARAMS(threshold_y, threshold y, DCTLUI_SLIDER_FLOAT, 0.2f, 0.0f, 0.6f, 0.0f);
DEFINE_UI_PARAMS(power, power, DCTLUI_SLIDER_FLOAT, 1.2f, 1.0f, 3.0f, 1.0f);
DEFINE_UI_PARAMS(shd_rolloff, shd rolloff, DCTLUI_SLIDER_FLOAT, 0.03f, 0.0f, 0.1f, 0.0f);
DEFINE_UI_PARAMS(shd_rolloff, shd rolloff, DCTLUI_SLIDER_FLOAT, 0.0f, 0.0f, 0.03f, 0.0f);
DEFINE_UI_PARAMS(cyan, cyan, DCTLUI_SLIDER_FLOAT, 0.09f, 0.0f, 1.0f, 0.0f);
DEFINE_UI_PARAMS(magenta, magenta, DCTLUI_SLIDER_FLOAT, 0.24f, 0.0f, 1.0f, 0.0f);
DEFINE_UI_PARAMS(yellow, yellow, DCTLUI_SLIDER_FLOAT, 0.12f, 0.0f, 1.0f, 0.0f);
Expand Down Expand Up @@ -224,9 +224,9 @@ __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p

// thr is the percentage of the core gamut to protect: the complement of threshold.
float3 thr = make_float3(
1.0f-_fmaxf(0.00001, threshold_r),
1.0f-_fmaxf(0.00001, threshold_g),
1.0f-_fmaxf(0.00001, threshold_b));
1.0f-_fmaxf(0.00001, threshold_c),
1.0f-_fmaxf(0.00001, threshold_m),
1.0f-_fmaxf(0.00001, threshold_y));

// lim is the max distance from the gamut boundary that will be compressed
// 0 is a no-op, 1 will compress colors from a distance of 2.0 from achromatic to the gamut boundary
Expand All @@ -249,9 +249,19 @@ __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p
// achromatic axis
float ach = _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z));

// achromatic with shadow rolloff below shd_rolloff threshold
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)));

// achromatic shadow rolloff
float ach_shd;
if (shd_rolloff < 0.004f) {
// disable shadow rolloff functionality.
// values below 0.004 cause strange behavior, actually increasing distance in some cases.
// if ach < 0.0 and shd_rolloff is disabled, take absolute value. This preserves negative components after compression.
ach_shd = _fabs(ach);
} else {
// lift ach below threshold using a tanh compression function.
// this reduces large distance values in shadow grain, which can cause differences when inverting.
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)));
}

// distance from the achromatic axis for each color component aka inverse rgb ratios
float3 dist;
dist.x = ach_shd == 0.0f ? 0.0f : (ach-rgb.x)/ach_shd;
Expand Down
42 changes: 26 additions & 16 deletions GamutCompress.fuse
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,23 @@ function Create()
INP_Default = 0.0,
})

InThresholdR = self:AddInput("threshold_r", "threshold_r", {
InThresholdR = self:AddInput("threshold_c", "threshold_c", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 0.2,
INP_MinAllowed = 0.0001,
INP_MaxScale = 0.6,
})

InThresholdG = self:AddInput("threshold_g", "threshold_g", {
InThresholdG = self:AddInput("threshold_m", "threshold_m", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 0.2,
INP_MinAllowed = 0.0001,
INP_MaxScale = 0.6,
})

InThresholdB = self:AddInput("threshold_b", "threshold_b", {
InThresholdB = self:AddInput("threshold_y", "threshold_y", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 0.2,
Expand All @@ -141,9 +141,9 @@ function Create()
InShdRolloff = self:AddInput("shd rolloff", "shd rolloff", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 0.03,
INP_Default = 0.0,
INP_MinAllowed = 0.0,
INP_MaxScale = 0.1,
INP_MaxScale = 0.03,
})

self:BeginControlNest("distance limits", "distance limits", true, {})
Expand Down Expand Up @@ -204,9 +204,9 @@ function Process(req)

params.method = InMethod:GetValue(req).Value
params.hexagonal = InHexagonal:GetValue(req).Value
params.threshold_r = InThresholdR:GetValue(req).Value
params.threshold_g = InThresholdG:GetValue(req).Value
params.threshold_b = InThresholdB:GetValue(req).Value
params.threshold_c = InThresholdR:GetValue(req).Value
params.threshold_m = InThresholdG:GetValue(req).Value
params.threshold_y = InThresholdB:GetValue(req).Value
params.power = InPower:GetValue(req).Value
params.shd_rolloff = InShdRolloff:GetValue(req).Value
params.cyan = InCyan:GetValue(req).Value
Expand Down Expand Up @@ -235,9 +235,9 @@ end
SolidParams = [[
int method;
int hexagonal;
float threshold_r;
float threshold_g;
float threshold_b;
float threshold_c;
float threshold_m;
float threshold_y;
float power;
float shd_rolloff;
float cyan;
Expand Down Expand Up @@ -410,9 +410,9 @@ SolidKernel = [[

// thr is the percentage of the core gamut to protect: the complement of threshold.
float3 thr = make_float3(
1.0f-_fmaxf(0.0001f, params->threshold_r),
1.0f-_fmaxf(0.0001f, params->threshold_g),
1.0f-_fmaxf(0.0001f, params->threshold_b));
1.0f-_fmaxf(0.0001f, params->threshold_c),
1.0f-_fmaxf(0.0001f, params->threshold_m),
1.0f-_fmaxf(0.0001f, params->threshold_y));

// lim is the max distance from the gamut boundary that will be compressed
// 0 is a no-op, 1 will compress colors from a distance of 2.0 from achromatic to the gamut boundary
Expand All @@ -435,8 +435,18 @@ SolidKernel = [[
// achromatic axis
float ach = _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z));

// achromatic with shadow rolloff below shd_rolloff threshold
float ach_shd = 1.0f-( (1.0f-ach)<(1.0f-params->shd_rolloff)?(1.0f-ach):(1.0f-params->shd_rolloff)+params->shd_rolloff*_tanhf((((1.0f-ach)-(1.0f-params->shd_rolloff))/params->shd_rolloff)));
// achromatic shadow rolloff
float ach_shd;
if (params->shd_rolloff < 0.004f) {
// disable shadow rolloff functionality.
// values below 0.004 cause strange behavior, actually increasing distance in some cases.
// if ach < 0.0 and shd_rolloff is disabled, take absolute value. This preserves negative components after compression.
ach_shd = _fabs(ach);
} else {
// lift ach below threshold using a tanh compression function.
// this reduces large distance values in shadow grain, which can cause differences when inverting.
ach_shd = 1.0f-((1.0f-ach)<(1.0f-params->shd_rolloff)?(1.0f-ach):(1.0f-params->shd_rolloff)+params->shd_rolloff*_tanhf((((1.0f-ach)-(1.0f-params->shd_rolloff))/params->shd_rolloff)));
}

// distance from the achromatic axis for each color component aka inverse rgb ratios
float3 dist;
Expand Down
14 changes: 12 additions & 2 deletions GamutCompress.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,18 @@ void main() {
// achromatic axis
float ach = max(rgb.x, max(rgb.y, rgb.z));

// achromatic with shadow rolloff below shd_rolloff threshold
float ach_shd = 1.0-((1.0-ach)<(1.0-shd_rolloff)?(1.0-ach):(1.0-shd_rolloff)+shd_rolloff*tanh((((1.0-ach)-(1.0-shd_rolloff))/shd_rolloff)));
// achromatic shadow rolloff
float ach_shd;
if (shd_rolloff < 0.004) {
// disable shadow rolloff functionality.
// values below 0.004 cause strange behavior, actually increasing distance in some cases.
// if ach < 0.0 and shd_rolloff is disabled, take absolute value. This preserves negative components after compression.
ach_shd = abs(ach);
} else {
// lift ach below threshold using a tanh compression function.
// this reduces large distance values in shadow grain, which can cause differences when inverting.
ach_shd = 1.0-((1.0-ach)<(1.0-shd_rolloff)?(1.0-ach):(1.0-shd_rolloff)+shd_rolloff*tanh((((1.0-ach)-(1.0-shd_rolloff))/shd_rolloff)));
}

// distance from the achromatic axis for each color component aka inverse rgb ratios
vec3 dist;
Expand Down
Loading

0 comments on commit ace29c1

Please sign in to comment.