2009-05-15 4 views
5

При рендеринге сцены текстурированных полигонов я хотел бы иметь возможность переключаться между рендерингом в исходных цветах и ​​режиме «в оттенках серого». Я пытался добиться этого, используя операции смешивания и цветной матрицы; ни одна из них не работала (при смешивании я не мог найти glBlendFunc(), который достиг чего-то, отдаленно напоминающего то, что я хотел, и операций с цветной матрицей ...are discussed here).Как реализовать рендеринг оттенков серого в OpenGL?

Решение, которое приходит на ум (но также довольно дорого), заключается в том, чтобы захватить экран каждого кадра и преобразовать полученную текстуру в оттенки серого и отобразить это вместо ... (Где я сказал оттенки серого, я на самом деле имел в виду что угодно с низкое насыщение, но я предполагаю, что для большинства возможных решений он не будет сильно отличаться от оттенков серого).

Какие еще варианты у меня есть?

ответ

9

Бадбуффер OpenGL по умолчанию использует цветовое пространство RGB, которое не сохраняет явное насыщенность. Вам нужен подход для извлечения насыщения, его изменения и изменения.

Мое предыдущее предложение, которое просто использовало длину вектора 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 или ВПГ цветового пространства. Как показано ниже, с использованием шейдера фрагмента 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); 
} 
+0

"v" не определен. Рассматривая другие алгоритмы для hsv2rgb, кажется, что это действительно должно быть «значение» Кроме того, окончательный регистр case (case 5) также должен быть стандартным случаем. –

2

Если вы работаете против современного OpenGL, я бы сказал, что pixel shaders - очень подходящее решение здесь. Либо подключаясь к каждому затенению многоугольника по мере их рендеринга, либо выполняя одиночный полноэкранный квадрат во втором проходе, который просто считывает каждый пиксель, преобразует его в оттенки серого и записывает его обратно. Если ваше разрешение, графическое оборудование и целевая частота кадров не являются «экстремальными», в большинстве случаев это должно выполняться в большинстве случаев.

2

Для большинства рабочих столов Render-To-Texture уже не так дорого, все из них, как и цветные, а также эффекты, такие как цветение или глубина резкости, видимые в последних названиях, зависят от него.

На самом деле вы не преобразуете текстуру экрана как таковую в оттенки серого, вы бы хотели нарисовать квадратный квадрат с текстурой и фрагментарный шейдер, преобразующий валионы в оттенки серого.

Другой вариант состоит в том, чтобы иметь два набора фрагментарных шейдеров для ваших треугольников, один из которых просто копирует атрибут gl_FrontColor в качестве фиксированной функции pieline, а другой, который записывает значения оттенков серого в буфер экрана.

Третий вариант может быть проиндексирован цветовыми режимами, если вы установили uüp в палитру оттенков серого, но этот режим может быть устаревшим и слабо поддержан; плюс вы теряете много функциональности, например, смешивание, если я правильно помню.

+0

yup, no blending with colorindex mode. что вы имеете в виду «все compiz, aero и т. д.»? – zyndor

+0

Он означает, что визуализаторы окон рабочего стола часто используют рендеринг для текстуры в наши дни (он, скорее всего, программист оконного менеджера). – Triang3l

Смежные вопросы