Sto cercando di cambiare la tonalità di un'immagine usando uno shader di frammenti GLSL. Voglio ottenere qualcosa di simile al livello di regolazione Tonalità / Saturazione di Photoshop.
Nell'immagine seguente puoi vedere quello che ho finora. Voglio cambiare la tonalità del quadrato verde in modo che assomigli al quadrato rosso sulla destra, ma con questo shader ottengo un quadrato mezzo rosa per metà rosso (il quadrato nel mezzo).
Quello che sto facendo nello shader di frammento è convertire il colore della trama in HSV, quindi aggiungo il colore HSV che ottengo dallo shader di vertice e riconvertisco il colore in RGB.
Che cosa sto facendo di sbagliato?
Shader di frammenti:
precision mediump float;
varying vec2 vTextureCoord;
varying vec3 vHSV;
uniform sampler2D sTexture;
vec3 convertRGBtoHSV(vec3 rgbColor) {
float r = rgbColor[0];
float g = rgbColor[1];
float b = rgbColor[2];
float colorMax = max(max(r,g), b);
float colorMin = min(min(r,g), b);
float delta = colorMax - colorMin;
float h = 0.0;
float s = 0.0;
float v = colorMax;
vec3 hsv = vec3(0.0);
if (colorMax != 0.0) {
s = (colorMax - colorMin ) / colorMax;
}
if (delta != 0.0) {
if (r == colorMax) {
h = (g - b) / delta;
} else if (g == colorMax) {
h = 2.0 + (b - r) / delta;
} else {
h = 4.0 + (r - g) / delta;
}
h *= 60.0;
if (h < 0.0) {
h += 360.0;
}
}
hsv[0] = h;
hsv[1] = s;
hsv[2] = v;
return hsv;
}
vec3 convertHSVtoRGB(vec3 hsvColor) {
float h = hsvColor.x;
float s = hsvColor.y;
float v = hsvColor.z;
if (s == 0.0) {
return vec3(v, v, v);
}
if (h == 360.0) {
h = 0.0;
}
int hi = int(h);
float f = h - float(hi);
float p = v * (1.0 - s);
float q = v * (1.0 - (s * f));
float t = v * (1.0 - (s * (1.0 - f)));
vec3 rgb;
if (hi == 0) {
rgb = vec3(v, t, p);
} else if (hi == 1) {
rgb = vec3(q, v, p);
} else if (hi == 2) {
rgb = vec3(p, v, t);
} if(hi == 3) {
rgb = vec3(p, q, v);
} else if (hi == 4) {
rgb = vec3(t, p, v);
} else {
rgb = vec3(v, p, q);
}
return rgb;
}
void main() {
vec4 textureColor = texture2D(sTexture, vTextureCoord);
vec3 fragRGB = textureColor.rgb;
vec3 fragHSV = convertRGBtoHSV(fragRGB);
fragHSV += vHSV;
fragHSV.x = mod(fragHSV.x, 360.0);
fragHSV.y = mod(fragHSV.y, 1.0);
fragHSV.z = mod(fragHSV.z, 1.0);
fragRGB = convertHSVtoRGB(fragHSV);
gl_FragColor = vec4(convertHSVtoRGB(fragHSV), textureColor.w);
}
EDIT: Usando le funzioni fornite da Sam Hocevar nella sua risposta, il problema con le bande rosa è risolto, ma riesco a raggiungere solo metà dello spettro dei colori. Posso cambiare la tonalità dal rosso al verde, ma non posso cambiarla in blu o rosa.
Nello shader di frammenti, lo sto facendo ora:
void main() {
vec4 textureColor = texture2D(sTexture, vTextureCoord);
vec3 fragRGB = textureColor.rgb;
vec3 fragHSV = rgb2hsv(fragRGB);
float h = vHSV.x / 360.0;
fragHSV.x *= h;
fragHSV.yz *= vHSV.yz;
fragHSV.x = mod(fragHSV.x, 1.0);
fragHSV.y = mod(fragHSV.y, 1.0);
fragHSV.z = mod(fragHSV.z, 1.0);
fragRGB = hsv2rgb(fragHSV);
gl_FragColor = vec4(hsv2rgb(fragHSV), textureColor.w);
}
int hi = int(h/60.0); float f = h/60.0 - float(hi);
inveceint hi = int(h); float f = h - float(hi);
? Non so se questo lo stia causando.