Градиент с HSV, а не RGB в OpenGL

OpenGL може да оцвети правоъгълник с градиент от цветове от едната към другата страна. Използвам следния код за това в C++

glBegin(GL_QUADS);
{
    glColor3d(simulationSettings->hotColour.redF(), simulationSettings->hotColour.greenF(), simulationSettings->hotColour.blueF());
    glVertex2d(keyPosX - keyWidth/2, keyPosY + keyHight/2);
    glColor3d(simulationSettings->coldColour.redF(), simulationSettings->coldColour.greenF(), simulationSettings->coldColour.blueF());
    glVertex2d(keyPosX - keyWidth/2, keyPosY - keyHight/2);
    glColor3d(simulationSettings->coldColour.redF(), simulationSettings->coldColour.greenF(), simulationSettings->coldColour.blueF());
    glVertex2d(keyPosX + keyWidth/2, keyPosY - keyHight/2);
    glColor3d(simulationSettings->hotColour.redF(), simulationSettings->hotColour.greenF(), simulationSettings->hotColour.blueF());
    glVertex2d(keyPosX + keyWidth/2, keyPosY + keyHight/2);
}

Използвам някои библиотеки на Qt, за да направя преобразуванията между HSV и RGB. Както можете да видите от кода, рисувам правоъгълник с цветен градиент от това, което наричам hotColour към coldColour.

защо го правя Програмата, която направих, рисува 3D вектори в пространството и посочва дължината им с цвета им. На потребителя се предлага да избере горещите (висока стойност) и студените (ниска стойност) цветове и програмата автоматично ще направи градиента, използвайки HSV мащабиране.

Защо HSV мащабиране? тъй като HSV е с една стойност в цветната карта, която използвам, и създаването на градиенти с него линейно е много лесна задача. За да може потребителят да избере цветовете, аз му предлагам цветна карта на QColourDialog

http://qt-project.org/doc/qt-4.8/qcolordialog.html

На тази цветна карта можете да видите, че червеното е налично от дясната и лявата страна, което прави невъзможно да има линейна скала за тази цветна карта с RGB. Но с HSV линейната скала е много лесно постижима, където просто трябва да използвам линейна скала между 0 и 360 за стойностите на Hue.

С тази парадигма можем да видим, че горещите и студените цветове определят посоката на градиента, така че например, ако избера нюанс да бъде 0 за студено и 359 за горещо, HSV ще ми даде градиент между 0 и 359 и ще включете целия спектър от цветове в градиента; докато в OpenGL основно ще премине от червено към червено, което не е градиент!!!!!!

Как мога да принудя OpenGL да използва HSV градиент вместо RGB? Единствената идея, която ми хрумва, е да нарежа правоъгълника, който искам да оцветя, и да направя много градиенти върху по-малки правоъгълници, но мисля, че това не е най-ефективният начин да го направя.

Някакви идеи?


person Sam    schedule 05.03.2012    source източник


Отговори (2)


Как мога да принудя OpenGL да използва HSV градиент вместо RGB?

Не бих го нарекъл "принуждаване", а "учене". Начинът по подразбиране на OpenGL за интерполиране на вектори с атрибути на върхове е чрез барицентрична интерполация на единичните векторни елементи въз основа на NDC координатите на фрагмента.

Трябва да кажете на OpenGL как да превърне тези барицентрични интерполирани HSV стойности в RGB.

За това въвеждаме фрагментен шейдър, който приема, че атрибутът на цветовия връх не е RGB, а HSV.

#version 120
varying vec3 vertex_hsv; /* set this in appropriate vertex shader to the vertex attribute data*/

vec3 hsv2rgb(vec3 hsv)
{
    float h = hsv.x * 6.; /* H in 0°=0 ... 1=360° */
    float s = hsv.y;
    float v = hsv.z;
    float c = v * s;

    vec2 cx = vec2(v*s, c * ( 1 - abs(mod(h, 2.)-1.) ));

    vec3 rgb = vec3(0., 0., 0.);
    if( h < 1. ) {
        rgb.rg = cx;
    } else if( h < 2. ) {
        rgb.gr = cx;
    } else if( h < 3. ) {
        rgb.gb = cx;
    } else if( h < 4. ) {
        rgb.bg = cx;
    } else if( h < 5. ) {
        rgb.br = cx;
    } else {
        rgb.rb = cx;
    }
    return rgb + vec3(v-cx.y);
}

void main()
{
    gl_FragColor = hsv2rgb(vertex_hsv);
}
person datenwolf    schedule 05.03.2012
comment
Откъде идва 6 в първото ви изчисление float h = hsv.x * 6.; и какво означава? - person tobsen; 30.05.2012
comment
Също така къде е дефинирано c в ред vec2 cx = vec2(v*s, c * ( 1 - abs(mod(h, 2.)-1.) ));? - person tobsen; 30.05.2012
comment
@tobsen: „c“ забравих да заменя правилно в редакция. Относно фактора 6: Нюансът в HSL е даден като ъгъл, а кодът по-горе предполага да направи пълен завой на цветовия цикъл за диапазона от стойности h в 0…1, съответстващ на H в 0°…360° или 0 до 2pi. Така че имаме 6 сектора в цветовия цикъл, които извличаме, като увеличаваме диапазона на стойността h с 6 и го вземаме по модул 2 (в изчислението на cx), тогава серията от изрази if прави интерполацията между първичните в кръга H заобикаляне. - person datenwolf; 30.05.2012

Можете да направите това с фрагментен шейдър. Рисувате четворка и прилагате своя фрагментен шейдър, който оцветява желаното от вас четворка. Начинът, по който бих направил това, е да задам цветовете на ъглите на HSV стойностите, които искате, след което във фрагментния шейдър да конвертирате интерполираните цветови стойности от HSV обратно в RGB. За повече информация относно фрагментните шейдъри вижте документи.

person user1118321    schedule 05.03.2012