سؤال

عند تقديم مشهد من المضلعات المحكم ، أود أن أكون قادرًا على التبديل بين التقديم بالألوان الأصلية ووضع "رمادي". لقد كنت أحاول تحقيق ذلك باستخدام عمليات المزج والألوان ؛ لم يعمل أي منها (مع المزج لم أتمكن ... تناقش هنا).

يتمثل الحل الذي يتبادر إلى الذهن (ولكنه أيضًا باهظ الثمن إلى حد ما) في التقاط الشاشة كل إطار وتحويل الملمس الناتج إلى واحد رمادي وعرضه بدلاً من ذلك ... (حيث قلت رماديًا ، لقد كنت أقصد بالفعل أي شيء بتشبع منخفض ، لكنني أظن معظم الحلول الممكنة ، لن يختلف كل ذلك عن رمادي).

ما هي الخيارات الأخرى التي لدي؟

هل كانت مفيدة؟

المحلول

يستخدم OpenGL FrameBuffer الافتراضي مساحة RGB Colour-Space ، والتي لا تخزن تشبعًا صريحًا. تحتاج إلى نهج لاستخراج التشبع ، وتعديله ، وتغييره مرة أخرى.

اقتراحي السابق الذي استخدم ببساطة طول متجه RGB لتمثيل 0 في اللمعان كان غير صحيح ، لأنه لم يأخذ التحجيم في الاعتبار ، أعتذر.

ينتقل رصيد المقتطف القصير الجديد إلى المستخدم العادي "RTFM_FTW" من ## OpenGL و ## OpenGL3 على Freenode/IRC ، ويتيح لك تعديل التشبع مباشرة دون حساب RGB-> HSV-> RGB ، وهو أمر بالضبط ما تريد. على الرغم من أن رمز HSV أدنى فيما يتعلق بسؤالك ، إلا أنني أتركه يبقى.

void main( void ) 
{ 
    vec3 R0 = texture2DRect( S, gl_TexCoord[0].st ).rgb;
    gl_FragColor = vec4( mix( vec3( dot( R0, vec3( 0.2125, 0.7154, 0.0721 ) ) ),
        R0, T ), gl_Color.a ); 
}

إذا كنت تريد تحكمًا أكبر من مجرد التشبع ، فأنت بحاجة إلى التحويل إلى مساحة HSL أو HSV Colour-Space. كما هو موضح أدناه باستخدام تظليل شظية GLSL.

اقرأ مواصفات OpenGL 3.0 و GLSL 1.30 http://www.opengl.org/registry لمعرفة كيفية استخدام وظيفة GLSL V1.30.

#version 130
#define RED 0
#define GREEN 1
#define BLUE 2

in vec4 vertexIn;
in vec4 colorIn;
in vec2 tcoordIn;
out vec4 pixel;
Sampler2D tex;
vec4 texel;
const float epsilon = 1e-6;

vec3 RGBtoHSV(vec3 color)
{
    /* hue, saturation and value are all in the range [0,1> here, as opposed to their
       normal ranges of: hue: [0,360>, sat: [0, 100] and value: [0, 256> */
    int sortindex[3] = {RED,GREEN,BLUE};
    float rgbArr[3] = float[3](color.r, color.g, color.b);

    float hue, saturation, value, diff;
    float minCol, maxCol;
    int minIndex, maxIndex;

    if(color.g < color.r)
        swap(sortindex[0], sortindex[1]);
    if(color.b < color.g)
        swap(sortindex[1], sortindex[2]);
    if(color.r < color.b)
        swap(sortindex[2], sortindex[0]);

    minIndex = sortindex[0];
    maxIndex = sortindex[2];
    minCol = rgbArr[minIndex];
    maxCol = rgbArr[maxIndex];

    diff = maxCol - minCol;

    /* Hue */
    if( diff < epsilon){
        hue = 0.0;
    }
    else if(maxIndex == RED){
        hue = ((1.0/6.0) * ( (color.g - color.b) / diff )) + 1.0;
        hue = fract(hue);
    }
    else if(maxIndex == GREEN){
        hue = ((1.0/6.0) * ( (color.b - color.r) / diff )) + (1.0/3.0);
    }
    else if(maxIndex == BLUE){
        hue = ((1.0/6.0) * ( (color.r - color.g) / diff )) + (2.0/3.0);        
    }

    /* Saturation */
    if(maxCol < epsilon)
        saturation = 0;
    else
        saturation = (maxCol - minCol) / maxCol;

    /* Value */
    value = maxCol;

    return vec3(hue, saturation, value);
}
vec3 HSVtoRGB(vec3 color)
{
    float f,p,q,t, hueRound;
    int hueIndex;
    float hue, saturation, value;
    vec3 result;

    /* just for clarity */
    hue = color.r;
    saturation = color.g;
    value = color.b;

    hueRound = floor(hue * 6.0);
    hueIndex = int(hueRound) % 6;
    f = (hue * 6.0) - hueRound;
    p = value * (1.0 - saturation);
    q = value * (1.0 - f*saturation);
    t = value * (1.0 - (1.0 - f)*saturation);

    switch(hueIndex)
    {
        case 0:
            result = vec3(value,t,p);
        break;
        case 1:
            result = vec3(q,value,p);
        break;
        case 2:
            result = vec3(p,value,t);
        break;
        case 3:
            result = vec3(p,q,value);
        break;
        case 4:
            result = vec3(t,p,value);
        break;
        default:
            result = vec3(value,p,q);
        break;
    }
    return result;
}
void main(void)
{
    vec4 srcColor;
    vec3 hsvColor;
    vec3 rgbColor;
    texel = Texture2D(tex, tcoordIn);
    srcColor = texel*colorIn;
    hsvColor = RGBtoHSV(srcColor.rgb);
    /* You can do further changes here, if you want. */
    hsvColor.g = 0; /* Set saturation to zero */
    rgbColor = HSVtoRGB(hsvColor);
    pixel = vec4(rgbColor.r, rgbColor.g, rgbColor.b, srcColor.a);
}

نصائح أخرى

إذا كنت تعمل ضد OpenGL الحديثة ، فأنا أقول تظليل البكسل هو حل مناسب جدا هنا. إما عن طريق التثبيت في تظليل كل مضلع أثناء عرضه ، أو عن طريق القيام بربعة شاشة واحدة على شاشة واحدة في تمريرة ثانية تقرأ كل بكسل ، وتحول إلى رمادي ، ويكتبه مرة أخرى. ما لم تكن حلك ، وأجهزة الرسومات ، والأطراف المستهدفة "متطرفة" بطريقة أو بأخرى ، يجب أن تكون قابلة للتنفيذ هذه الأيام في معظم الحالات.

بالنسبة لمعظم أجهزة سطح المكتب ، لم يعد ذلك باهظ الثمن بعد الآن ، كل من Compiz ، Aero ، وما إلى ذلك ، وتأثيرات مثل الإزهار أو عمق المجال الذي شوهد في العناوين الحديثة.

في الواقع ، لا تقوم بتحويل نسيج الشاشة في حد ذاته إلى رمادي ، فأنت ترغب في رسم رباعي الحجم مع الملمس وشظية تظليل يحول البدايات إلى رمادي.

خيار آخر هو أن يكون لديك مجموعتان من تظليل الأجزاء لمثلثاتك ، واحدة فقط نسخ سمة GL_FRONTCOLOR كما تفعل الوظيفة الثابتة ، والآخر يكتب قيمًا رماديًا إلى المخزن المؤقت للشاشة.

قد يكون الخيار الثالث هو أوضاع ألوان فهرسة ، إذا قمت بتعيين Uüp لوحة رمادية ، ولكن قد يتم إهمال هذا الوضع ودعمه بشكل سيئ الآن ؛ بالإضافة إلى أنك تفقد الكثير من الوظائف مثل المزج ، إذا كنت أتذكر بشكل صحيح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top