Skip to content

Commit

Permalink
Fix non-angle discontinuities
Browse files Browse the repository at this point in the history
Fixes #4
  • Loading branch information
hotgluebanjo committed Feb 4, 2024
1 parent ecb0094 commit cc02a35
Show file tree
Hide file tree
Showing 11 changed files with 518 additions and 380 deletions.
111 changes: 56 additions & 55 deletions extra/ReuleauxUserStandalone.dctl
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
// https://github.com/hotgluebanjo
// https://github.com/calvinsilly
//
// Concatenates the Reuleaux transforms with ReuleauxUser.

// 6 hue, 1 wrap, 2 anchor.
#define N_HUE_POINTS 9

// 6 hue, 1 wrap.
#define N_CORNER_POINTS 7
#define N_POINTS 9

#define EPS 1e-6f

Expand Down Expand Up @@ -49,28 +44,34 @@ __DEVICE__ inline float max3(float x, float y, float z) {
}

__DEVICE__ inline float spow(float x, float p) {
if (x > 0.0f) {
return _powf(x, p);
if (x < 0.0f) {
return -_powf(-x, p);
}
return x;
return _powf(x, p);
}

__DEVICE__ float interp_linear(__PRIVATE__ float2 *pts, int n_pts, float x) {
if (x <= pts[0].x) return pts[0].y;
if (x >= pts[n_pts - 1].x) return pts[n_pts - 1].y;

// Lower of the indices x is between.
int i = 0;
for (; i < n_pts - 1; i += 1) {
// x == x[i]. No need to interpolate.
if (_fabs(pts[i].x - x) < EPS) return pts[i].y;
if (x <= pts[0].x) {
return pts[0].y;
}

if (pts[i].x < x && x < pts[i + 1].x) break;
if (x >= pts[n_pts - 1].x) {
return pts[n_pts - 1].y;
}

float slope = (x - pts[i].x) / (pts[i + 1].x - pts[i].x);
int i = 0;
int upper = n_pts - 1;
while (i != upper - 1) {
int m = i + (upper - i) / 2;
if (x >= pts[m].x) {
i = m;
} else {
upper = m;
}
}

return _mix(pts[i].y, pts[i + 1].y, slope);
float t = (x - pts[i].x) / (pts[i + 1].x - pts[i].x);
return _mix(pts[i].y, pts[i + 1].y, t);
}

__DEVICE__ float3 rgb_to_reuleaux(float3 rgb) {
Expand Down Expand Up @@ -121,53 +122,53 @@ __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p
float sat = reuleaux.y;
float val = reuleaux.z;

float2 hue_curve[N_HUE_POINTS];

// Start and end anchors.
hue_curve[0] = make_float2(5.0f / 6.0f, MAG_HUE + 5.0f / 6.0f) - 1.0f;
hue_curve[8] = make_float2(1.0f / 6.0f, YEL_HUE + 1.0f / 6.0f) + 1.0f;

// Wrapping anchor.
hue_curve[1] = make_float2(0.0f, RED_HUE);
hue_curve[7] = make_float2(1.0f, RED_HUE + 1.0f);

hue_curve[2] = make_float2(1.0f / 6.0f, YEL_HUE + 1.0f / 6.0f);
hue_curve[3] = make_float2(2.0f / 6.0f, GRN_HUE + 2.0f / 6.0f);
hue_curve[4] = make_float2(3.0f / 6.0f, CYN_HUE + 3.0f / 6.0f);
hue_curve[5] = make_float2(4.0f / 6.0f, BLU_HUE + 4.0f / 6.0f);
hue_curve[6] = make_float2(5.0f / 6.0f, MAG_HUE + 5.0f / 6.0f);
float2 hue_curve[N_POINTS] = {
{5.0f / 6.0f - 1.0f, MAG_HUE + 5.0f / 6.0f - 1.0f},
{0.0f, RED_HUE},
{1.0f / 6.0f, YEL_HUE + 1.0f / 6.0f},
{2.0f / 6.0f, GRN_HUE + 2.0f / 6.0f},
{3.0f / 6.0f, CYN_HUE + 3.0f / 6.0f},
{4.0f / 6.0f, BLU_HUE + 4.0f / 6.0f},
{5.0f / 6.0f, MAG_HUE + 5.0f / 6.0f},
{1.0f, RED_HUE + 1.0f},
{1.0f / 6.0f + 1.0f, YEL_HUE + 1.0f / 6.0f + 1.0f}
};

if (INVERT) {
for (int i = 0; i < N_HUE_POINTS; i += 1) {
for (int i = 0; i < N_POINTS; i += 1) {
hue_curve[i] = make_float2(hue_curve[i].y, hue_curve[i].x);
}
}

float2 sat_curve[N_CORNER_POINTS] = {
{0.0f, RED_SAT},
{1.0f / 6.0f, YEL_SAT},
{2.0f / 6.0f, GRN_SAT},
{3.0f / 6.0f, CYN_SAT},
{4.0f / 6.0f, BLU_SAT},
{5.0f / 6.0f, MAG_SAT},
{1.0f, RED_SAT}
float2 sat_curve[N_POINTS] = {
{5.0f / 6.0f - 1.0f, MAG_SAT},
{0.0f, RED_SAT},
{1.0f / 6.0f, YEL_SAT},
{2.0f / 6.0f, GRN_SAT},
{3.0f / 6.0f, CYN_SAT},
{4.0f / 6.0f, BLU_SAT},
{5.0f / 6.0f, MAG_SAT},
{1.0f, RED_SAT},
{1.0f / 6.0f + 1.0f, YEL_SAT}
};

float2 val_curve[N_CORNER_POINTS] = {
{0.0f, RED_VAL},
{1.0f / 6.0f, YEL_VAL},
{2.0f / 6.0f, GRN_VAL},
{3.0f / 6.0f, CYN_VAL},
{4.0f / 6.0f, BLU_VAL},
{5.0f / 6.0f, MAG_VAL},
{1.0f, RED_VAL}
float2 val_curve[N_POINTS] = {
{5.0f / 6.0f - 1.0f, MAG_VAL},
{0.0f, RED_VAL},
{1.0f / 6.0f, YEL_VAL},
{2.0f / 6.0f, GRN_VAL},
{3.0f / 6.0f, CYN_VAL},
{4.0f / 6.0f, BLU_VAL},
{5.0f / 6.0f, MAG_VAL},
{1.0f, RED_VAL},
{1.0f / 6.0f + 1.0f, YEL_VAL}
};

float hue_result = interp_linear(hue_curve, N_HUE_POINTS, hue);
float hue_result = interp_linear(hue_curve, N_POINTS, hue);
float hue_switch = INVERT ? hue : hue_result;

float sat_factor = interp_linear(sat_curve, N_CORNER_POINTS, hue_switch) * OVERALL_SAT;
float val_factor = interp_linear(val_curve, N_CORNER_POINTS, hue_switch) + OVERALL_VAl;
float sat_factor = interp_linear(sat_curve, N_POINTS, hue_switch) * OVERALL_SAT;
float val_factor = interp_linear(val_curve, N_POINTS, hue_switch) + OVERALL_VAl;

if (!INVERT) {
sat_factor = 1.0f / sat_factor;
Expand Down
41 changes: 25 additions & 16 deletions nuke/tools/HueAtHue.blink
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ inline float lerp(float a, float b, float t) {
return (1.0f - t) * a + t * b;
}

float interp_linear(float2 *pts, int n_pts, float x) {
if (x <= pts[0].x) {
return pts[0].y;
}

if (x >= pts[n_pts - 1].x) {
return pts[n_pts - 1].y;
}

int i = 0;
int upper = n_pts - 1;
while (i != upper - 1) {
int m = i + (upper - i) / 2;
if (x >= pts[m].x) {
i = m;
} else {
upper = m;
}
}

float t = (x - pts[i].x) / (pts[i + 1].x - pts[i].x);
return lerp(pts[i].y, pts[i + 1].y, t);
}

kernel HueAtHue : ImageComputationKernel<ePixelWise> {
Image<eRead, eAccessPoint, eEdgeClamped> src;
Image<eWrite> dst;
Expand Down Expand Up @@ -74,22 +98,7 @@ kernel HueAtHue : ImageComputationKernel<ePixelWise> {
void process() {
SampleType(src) input = src();

float hue = input.x;
float result = 0.0f;

if (hue <= curve[0].x) {
result = curve[0].y;
} else if (hue >= curve[N_POINTS - 1].x) {
result = curve[N_POINTS - 1].y;
} else {
for (int i = 0; i < N_POINTS - 1; i += 1) {
if (curve[i].x <= hue && hue < curve[i + 1].x) {
float slope = (hue - curve[i].x) / (curve[i + 1].x - curve[i].x);
result = lerp(curve[i].y, curve[i + 1].y, slope);
break;
}
}
}
float result = interp_linear(curve, N_POINTS, input.x);

dst() = float4(result, input.y, input.z, input.w);
}
Expand Down
109 changes: 56 additions & 53 deletions nuke/tools/ReuleauxUser.blink
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,43 @@
// https://github.com/calvinsilly

// 6 hue, 1 wrap, 2 anchor.
#define N_HUE_POINTS 9

// 6 hue, 1 wrap.
#define N_CORNER_POINTS 7
#define N_POINTS 9

#define EPS 1e-6f

inline float spow(float x, float p) {
if (x > 0.0f) {
return pow(x, p);
if (x < 0.0f) {
return -pow(-x, p);
}
return x;
return pow(x, p);
}

inline float lerp(float a, float b, float t) {
return (1.0f - t) * a + t * b;
}

float interp_linear(float2 *pts, int n_pts, float x) {
if (x <= pts[0].x) return pts[0].y;
if (x >= pts[n_pts - 1].x) return pts[n_pts - 1].y;

// Lower of the indices x is between.
int i = 0;
for (; i < n_pts - 1; i += 1) {
// x == x[i]. No need to interpolate.
if (fabs(pts[i].x - x) < EPS) return pts[i].y;
if (x <= pts[0].x) {
return pts[0].y;
}

if (pts[i].x < x && x < pts[i + 1].x) break;
if (x >= pts[n_pts - 1].x) {
return pts[n_pts - 1].y;
}

float slope = (x - pts[i].x) / (pts[i + 1].x - pts[i].x);
int i = 0;
int upper = n_pts - 1;
while (i != upper - 1) {
int m = i + (upper - i) / 2;
if (x >= pts[m].x) {
i = m;
} else {
upper = m;
}
}

return lerp(pts[i].y, pts[i + 1].y, slope);
float t = (x - pts[i].x) / (pts[i + 1].x - pts[i].x);
return lerp(pts[i].y, pts[i + 1].y, t);
}

kernel ReuleauxUser : ImageComputationKernel<ePixelWise> {
Expand Down Expand Up @@ -111,53 +114,53 @@ kernel ReuleauxUser : ImageComputationKernel<ePixelWise> {
float sat = hsv.y;
float val = hsv.z;

float2 hue_curve[N_HUE_POINTS];

// Start and end anchors.
hue_curve[0] = float2(5.0f / 6.0f, mag_hue + 5.0f / 6.0f) - 1.0f;
hue_curve[8] = float2(1.0f / 6.0f, yel_hue + 1.0f / 6.0f) + 1.0f;

// Wrapping anchor.
hue_curve[1] = float2(0.0f, red_hue);
hue_curve[7] = float2(1.0f, red_hue + 1.0f);

hue_curve[2] = float2(1.0f / 6.0f, yel_hue + 1.0f / 6.0f);
hue_curve[3] = float2(2.0f / 6.0f, grn_hue + 2.0f / 6.0f);
hue_curve[4] = float2(3.0f / 6.0f, cyn_hue + 3.0f / 6.0f);
hue_curve[5] = float2(4.0f / 6.0f, blu_hue + 4.0f / 6.0f);
hue_curve[6] = float2(5.0f / 6.0f, mag_hue + 5.0f / 6.0f);
float2 hue_curve[N_POINTS] = {
{5.0f / 6.0f - 1.0f, mag_hue + 5.0f / 6.0f - 1.0f},
{0.0f, red_hue},
{1.0f / 6.0f, yel_hue + 1.0f / 6.0f},
{2.0f / 6.0f, grn_hue + 2.0f / 6.0f},
{3.0f / 6.0f, cyn_hue + 3.0f / 6.0f},
{4.0f / 6.0f, blu_hue + 4.0f / 6.0f},
{5.0f / 6.0f, mag_hue + 5.0f / 6.0f},
{1.0f, red_hue + 1.0f},
{1.0f / 6.0f + 1.0f, yel_hue + 1.0f / 6.0f + 1.0f}
};

if (invert) {
for (int i = 0; i < N_HUE_POINTS; i += 1) {
for (int i = 0; i < N_POINTS; i += 1) {
hue_curve[i] = float2(hue_curve[i].y, hue_curve[i].x);
}
}

float2 sat_curve[N_CORNER_POINTS] = {
{0.0f, red_sat},
{1.0f / 6.0f, yel_sat},
{2.0f / 6.0f, grn_sat},
{3.0f / 6.0f, cyn_sat},
{4.0f / 6.0f, blu_sat},
{5.0f / 6.0f, mag_sat},
{1.0f, red_sat}
float2 sat_curve[N_POINTS] = {
{5.0f / 6.0f - 1.0f, mag_sat},
{0.0f, red_sat},
{1.0f / 6.0f, yel_sat},
{2.0f / 6.0f, grn_sat},
{3.0f / 6.0f, cyn_sat},
{4.0f / 6.0f, blu_sat},
{5.0f / 6.0f, mag_sat},
{1.0f, red_sat},
{1.0f / 6.0f + 1.0f, yel_sat}
};

float2 val_curve[N_CORNER_POINTS] = {
{0.0f, red_val},
{1.0f / 6.0f, yel_val},
{2.0f / 6.0f, grn_val},
{3.0f / 6.0f, cyn_val},
{4.0f / 6.0f, blu_val},
{5.0f / 6.0f, mag_val},
{1.0f, red_val}
float2 val_curve[N_POINTS] = {
{5.0f / 6.0f - 1.0f, mag_val},
{0.0f, red_val},
{1.0f / 6.0f, yel_val},
{2.0f / 6.0f, grn_val},
{3.0f / 6.0f, cyn_val},
{4.0f / 6.0f, blu_val},
{5.0f / 6.0f, mag_val},
{1.0f, red_val},
{1.0f / 6.0f + 1.0f, yel_val}
};

float hue_result = interp_linear(hue_curve, N_HUE_POINTS, hue);
float hue_result = interp_linear(hue_curve, N_POINTS, hue);
float hue_switch = invert ? hue : hue_result;

float sat_factor = interp_linear(sat_curve, N_CORNER_POINTS, hue_switch) * overall_sat;
float val_factor = interp_linear(val_curve, N_CORNER_POINTS, hue_switch) + overall_val;
float sat_factor = interp_linear(sat_curve, N_POINTS, hue_switch) * overall_sat;
float val_factor = interp_linear(val_curve, N_POINTS, hue_switch) + overall_val;

if (!invert) {
sat_factor = 1.0f / sat_factor;
Expand Down
Loading

0 comments on commit cc02a35

Please sign in to comment.