uniform sampler2D tex; float lin_interp(float x, float domain_low, float domain_hi, float range_low, float range_hi) { if ((x >= domain_low) && (x <= domain_hi)) { x = (x - domain_low) / (domain_hi - domain_low); x = range_low + x * (range_hi - range_low); } return x; } float pvp_adjust_3(float x) { // red x = lin_interp(x, 0.00, 0.125, -0.050, 0.090); // orange x = lin_interp(x, 0.125, 0.25, 0.090, 0.167); // yellow x = lin_interp(x, 0.25, 0.375, 0.167, 0.253); // chartreuse x = lin_interp(x, 0.375, 0.50, 0.253, 0.383); // green x = lin_interp(x, 0.50, 0.625, 0.383, 0.500); // teal x = lin_interp(x, 0.625, 0.75, 0.500, 0.667); // blue x = lin_interp(x, 0.75, 0.875, 0.667, 0.800); // purple x = lin_interp(x, 0.875, 1.00, 0.800, 0.950); return(x); } vec3 hsv2rgb(float h, float s, float v) { float i, f, p, q, t, r, g, b; int ii; if (s == 0.0) { // Ignore hue r = v; g = v; b = v; } else { /* Apply physiological mapping: red, yellow, green and blue should be equidistant. */ h = pvp_adjust_3(h); h = h - floor(h); h = h * 6.0; i = floor(h); ii = int(i); f = h - i; p = v*(1.0 - s); // The "low-flat" curve q = v*(1.0 - (s*f)); // The "falling" curve t = v*(1.0 - (s*(1.0 - f))); // The "rising" curve switch(ii) { case 0: // red point r = v; g = t; b = p; // RED max, GRN rising, BLU min break; case 1: // yellow point r = q; g = v; b = p; // RED falling, GRN max, BLU min break; case 2: // green point r = p; g = v; b = t; // RED min, GRN max, BLU rising break; case 3: // cyan point r = p; g = q; b = v; // RED min, GRN falling, BLU max break; case 4: // blue point r = t; g = p; b = v; // RED rising, GRN min, BLU max break; case 5: // magenta point default: r = v; g = p; b = q; // RED max, GRN min, BLU falling break; } } return vec3(r, g, b); } void main(void) { float n = texture2D(tex, gl_TexCoord[0].st).x; float h = n; float s = 1.0; float v = clamp(0.0, 1.0, 0.25 + log(h + 1.0)); gl_FragColor = vec4(hsv2rgb(frac(h), s, v), 1.0); }