जीएलएसएल शेडर - चेंज ह्यू / संतृप्ति / चमक


14

मैं एक GLSL टुकड़ा shader का उपयोग कर एक छवि का रंग बदलने की कोशिश कर रहा हूँ। मैं फ़ोटोशॉप के ह्यू / संतृप्ति समायोजन परत के समान कुछ हासिल करना चाहता हूं।

निम्नलिखित छवि में आप देख सकते हैं कि मुझे अब तक क्या मिला है। मैं हरे रंग के वर्ग के रंग को बदलना चाहता हूं, इसलिए यह दाईं ओर लाल वर्ग जैसा दिखता है, लेकिन इस शेडर के साथ मुझे आधा लाल आधा गुलाबी वर्ग (बीच में वर्ग) मिलता है।
यहाँ छवि विवरण दर्ज करें

मैं जो टुकड़े टुकड़े कर रहा हूं, वह बनावट के रंग को एचएसवी में परिवर्तित कर रहा है, फिर मैं एचएसवी रंग जोड़ता हूं, जो मुझे वर्टेकर के शेडर से मिलता है और मैं रंग को वापस आरजीबी में बदल देता हूं।
मैं क्या गलत कर रहा हूं?

टुकड़े टुकड़े करना:

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: सैम होसेवर ने अपने उत्तर में दिए गए कार्यों का उपयोग करते हुए, गुलाबी बैंड के साथ समस्या को हल किया है, लेकिन मैं केवल रंगीन स्पेक्ट्रम के आधे तक पहुंच सकता हूं। मैं रंग को लाल से हरे रंग में बदल सकता हूं, लेकिन मैं इसे नीले या गुलाबी में नहीं बदल सकता। यहाँ छवि विवरण दर्ज करें

टुकड़े टुकड़े में, मैं अब यह कर रहा हूँ:

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);बजाय इसका मतलब नहीं था int hi = int(h); float f = h - float(hi);? पता नहीं है कि अगर यह पैदा कर रहा है, यद्यपि।
कोलेबी

@kolrabi मैंने कोशिश की है, लेकिन मुझे अभी भी गुलाबी बैंड मिल रहे थे। मैंने आखिरकार उस समस्या को हल कर दिया है जो सैम होसेवर ने अपने उत्तर में प्रदान किए गए रूपांतरण कार्यों के साथ की है।
मिविक्लिन

@ नागरिक: हम सवालों के जवाब नहीं देते। यदि आपको स्वयं ही उत्तर मिल गया है, तो अपने प्रश्न का उत्तर पोस्ट करें।
निकोल बोलस

जवाबों:


22

ये कार्य बहुत खराब प्रदर्शन करेंगे। मैं उन कार्यों का उपयोग करने का सुझाव देता हूं जो जीपीयू को ध्यान में रखकर लिखे गए हैं। यहाँ मेरा हैं:

vec3 rgb2hsv(vec3 c)
{
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

ध्यान दें कि इन फ़ंक्शंस के लिए H[0… 360] के बजाय [0… 1] की सीमा है, इसलिए आपको अपने इनपुट को अनुकूलित करना होगा।

स्रोत: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl


इन कार्यों के उपयोग से समस्या हल हो गई। कोई और अधिक गुलाबी बैंड। लेकिन मुझे लगता है कि मैं अभी भी कुछ गलत कर रहा हूं। मैंने अपनी मूल पोस्ट अधिक जानकारी के साथ संपादित की है। धन्यवाद।
मिविक्लिन

1
बहुत दिलचस्प! क्या आप बता सकते हैं कि ये कार्य बेहतर प्रदर्शन क्यों करते हैं? "मन में GPU है" की तरह क्या है?
मार्को

4
@ मार्को जीपीयू बड़े if()निर्माण को संभालने में बहुत अच्छे नहीं हैं , लेकिन वेक्टर ऑपरेशन (कई स्केलर मूल्यों पर समानांतर संचालन) में अच्छे हैं। उपरोक्त फ़ंक्शन कभी भी उपयोग नहीं करते हैं if(), ऑपरेशन को समानांतर करने की कोशिश करते हैं, और सामान्य तौर पर वे कम निर्देशों का उपयोग करते हैं। ये आमतौर पर अच्छे संकेतक होते हैं कि वे तेज होने वाले हैं।
सम होसेवर

क्या ये कार्य मानक एचएसवी फ़ार्मुलों (गोलाई की त्रुटियों को नज़रअंदाज़ करते हुए) के समतुल्य हैं, या वे एक सन्निकटन हैं?
स्टीफन मोनोव

3

जैसा कि निकोल बोलस ने मूल पोस्ट की टिप्पणियों में सुझाव दिया है, मैं अपनी समस्या का समाधान एक अलग उत्तर में पोस्ट कर रहा हूं।

पहला मुद्दा छवि को गुलाबी बैंड के साथ प्रदान किया जा रहा था, जैसा कि मूल पोस्ट शो में छवि है। मैंने इसे अपने जवाब में दिए गए फ़ंक्शंस सैम होसेवर ( /gamedev//a/59808/22302 ) का उपयोग करके तय किया ।

दूसरा मुद्दा यह था कि मैं बनावट के पिक्सेल के ह्यू को उस मूल्य से गुणा कर रहा था जिसे मैं शेडर को भेज रहा था, जिसका मतलब है कि बनावट के पिक्सेल ह्यू से ऑफसेट होना है, इसलिए मुझे गुणा के बजाय एक अतिरिक्त प्रदर्शन करना था।
मैं अभी भी संतृप्ति और चमक के लिए एक गुणन करता हूं क्योंकि मुझे अन्यथा एक अजीब व्यवहार मिलता है, और मुझे वास्तव में मूल बनावट की संतृप्ति या चमक की तुलना में उन्हें आगे बढ़ाने की आवश्यकता नहीं है।

यह उस shader का मुख्य () तरीका है जिसका मैं अभी उपयोग कर रहा हूँ। इसके साथ मैं ह्यू को 0º से 360 des तक स्थानांतरित कर सकता हूं, छवि को असंतृप्त कर सकता हूं और चमक को कम कर सकता हूं।

void main() {
    vec4 textureColor = texture2D(sTexture, vTextureCoord);
    vec3 fragRGB = textureColor.rgb;
    vec3 fragHSV = rgb2hsv(fragRGB).xyz;
    fragHSV.x += vHSV.x / 360.0;
    fragHSV.yz *= vHSV.yz;
    fragHSV.xyz = mod(fragHSV.xyz, 1.0);
    fragRGB = hsv2rgb(fragHSV);
    gl_FragColor = vec4(fragRGB, textureColor.w);
} 

2
टिप: आप शायद mod()ह्यू चाहते हैं , लेकिन संतृप्ति और चमक आप clamp()इसके बजाय चाहते हो सकते हैं ।
गुस्तावो मैकिएल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.