日積月累Shader - 06 色彩

提示

教程例子都可以到下面網(wǎng)址進(jìn)行運(yùn)行瓢捉,不需要另外安裝軟件環(huán)境:
官方提供在線編寫(xiě)shader工具:https://thebookofshaders.com/edit.php
glslsandbox網(wǎng)站:http://glslsandbox.com/
shadertoy網(wǎng)站:https://www.shadertoy.com/

本文提到的關(guān)鍵字

關(guān)鍵字 描述 圖像
mix(a,b,float x) 混合ab顏色,根據(jù)x的值富拗,x~0偏向a睡雇,x~1偏向b

色彩變量

以x,y,z定義顏色是不是有些奇怪?正因如此,我們有其他方法訪問(wèn)這些變量——以不同的名字燕耿。.x, .y, .z也可以被寫(xiě)作.r, .g, .b 和 .s, .t, .p。(.s, .t, .p通常被用做后面章節(jié)提到的貼圖空間坐標(biāo))你也可以通過(guò)使用索引位置[0], [1] 和 [2]來(lái)訪問(wèn)向量

vec3 red = vec3(1.0,0.0,0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;

下面的代碼展示了所有訪問(wèn)相同數(shù)據(jù)的方式:

vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;

雞尾酒

GLSL中向量類型的另一大特點(diǎn)是可以用你需要的任意順序簡(jiǎn)單地投射和混合(變量)值姜胖。這種能力被(形象地)稱為:雞尾酒誉帅。

vec3 yellow, magenta, green;

// Making Yellow
yellow.rg = vec2(1.0);  // 同時(shí)設(shè)置紅綠空間
yellow[2] = 0.0;        // 設(shè)置藍(lán)色值為0

// Making Magenta
magenta = yellow.rbg;   // 調(diào)換了藍(lán)綠空間

// Making Green
green.rgb = yellow.bgb; // 將藍(lán)色空間覆蓋到紅色空間

混合顏色

在黃藍(lán)之間漸變過(guò)渡

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

vec3 colorA = vec3(0.149,0.141,0.912);
vec3 colorB = vec3(1.000,0.833,0.224);

void main() {
    vec3 color = vec3(0.0);

    float pct = abs(sin(u_time));

    // Mix uses pct (a value from 0-1) to
    // mix the two colors
    color = mix(colorA, colorB, pct);

    gl_FragColor = vec4(color,1.0);
}

繪制漸變

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

vec3 colorA = vec3(0.149,0.141,0.912);
vec3 colorB = vec3(1.000,0.833,0.224);

float plot (vec2 st, float pct){
  return  smoothstep( pct-0.01, pct, st.y) -
          smoothstep( pct, pct+0.01, st.y);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    vec3 pct = vec3(st.x);

    // pct.r = smoothstep(0.0,1.0, st.x);
    // pct.g = sin(st.x*PI);
    // pct.b = pow(st.x,0.5);

    color = mix(colorA, colorB, pct);

    // Plot transition lines for each channel
    // color = mix(color,vec3(1.0,0.0,0.0),plot(st,pct.r));
    // color = mix(color,vec3(0.0,1.0,0.0),plot(st,pct.g));
    color = mix(color,vec3(0.0,0.0,1.0),plot(st,pct.b));

    gl_FragColor = vec4(color,1.0);
}

在05講中的代碼,稍微改一下右莱,之前混合顏色是通過(guò)公式(1-ps)a+psb蚜锨,也就是用mix去簡(jiǎn)化了它的寫(xiě)法mix(a,b慢蜓,ps)

色相

不是出賣色相的色相亚再,是HSB(色相,飽和度和亮度)

將x坐標(biāo)(位置)映射到Hue值并將y坐標(biāo)映射到明度晨抡,我們就得到了五彩的可見(jiàn)光光譜针余。這樣的色彩空間分布實(shí)現(xiàn)起來(lái)非常方便饲鄙,比起RGB,用HSB來(lái)拾取顏色更直觀圆雁。

我們不能脫離色彩空間來(lái)談?wù)擃伾碳丁U缒闼藃gb值伪朽,有其他不同的方法去描述定義顏色轴咱。HSB代表色相,飽和度和亮度(或稱為值)烈涮。這更符合直覺(jué)也更有利于組織顏色朴肺。稍微花些時(shí)間閱讀下面的 rgb2hsv()hsv2rgb() 函數(shù)。

vec3 rgb2hsb( in 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 hsb2rgb( in vec3 c ){
    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
                             6.0)-3.0)-1.0,
                     0.0,
                     1.0 );
    rgb = rgb*rgb*(3.0-2.0*rgb);
    return c.z * mix(vec3(1.0), rgb, c.y);
}
#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);

    // We map x (0.0 - 1.0) to the hue (0.0 - 1.0)
    // And the y (0.0 - 1.0) to the brightness
    color = hsb2rgb(vec3(st.x,1.0,st.y));

    gl_FragColor = vec4(color,1.0);
}

極坐標(biāo)下的HSB

HSB原本是在極坐標(biāo)下產(chǎn)生的(以半徑和角度定義)而并非在笛卡爾坐標(biāo)系(基于xy定義)下坚洽。將HSB映射到極坐標(biāo)我們需要取得角度和到像素屏中點(diǎn)的距離戈稿。由此我們運(yùn)用 length() 函數(shù)和 atan(y,x) 函數(shù)(在GLSL中通常用atan(y,x))。

當(dāng)用到矢量和三角學(xué)函數(shù)時(shí)讶舰,vec2, vec3 和 vec4被當(dāng)做向量對(duì)待鞍盗,即使有時(shí)候他們代表顏色。我們開(kāi)始把顏色和向量同等的對(duì)待跳昼,事實(shí)上你會(huì)慢慢發(fā)現(xiàn)這種理念的靈活性有著相當(dāng)強(qiáng)大的用途般甲。

一旦我們得到角度和長(zhǎng)度,我們需要單位化這些值:0.0到1.0鹅颊。在27行敷存, atan(y,x) 會(huì)返回一個(gè)介于-PI到PI的弧度值(-3.14 to 3.14),所以我們要將這個(gè)返回值除以 TWO_PI(在code頂部定義了)來(lái)得到一個(gè)-0.5到0.5的值堪伍。這樣一來(lái)锚烦,用簡(jiǎn)單的加法就可以把這個(gè)返回值最終映射到0.0到1.0。半徑會(huì)返回一個(gè)最大值0.5(因?yàn)槲覀冇?jì)算的是到視口中心的距離帝雇,而視口中心的范圍已經(jīng)被映射到0.0到1.0)涮俄,所以我們需要把這個(gè)值乘以二來(lái)得到一個(gè)0到1.0的映射。

#ifdef GL_ES
precision mediump float;
#endif

#define TWO_PI 6.28318530718

uniform vec2 u_resolution;
uniform float u_time;

//  Function from I?igo Quiles
//  https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
                             6.0)-3.0)-1.0,
                     0.0,
                     1.0 );
    rgb = rgb*rgb*(3.0-2.0*rgb);
    return c.z * mix( vec3(1.0), rgb, c.y);
}

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);

    // Use polar coordinates instead of cartesian
    vec2 toCenter = vec2(0.5)-st;
    float angle = atan(toCenter.y,toCenter.x);
    float radius = length(toCenter)*2.0;

    // Map the angle (-PI to PI) to the Hue (from 0 to 1)
    // and the Saturation to the radius
    color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0));

    gl_FragColor = vec4(color,1.0);
}

如果你仔細(xì)觀察用來(lái)拾色的色輪(見(jiàn)下圖)摊求,你會(huì)發(fā)現(xiàn)它用一種根據(jù)RYB色彩空間的色譜。例如刘离,紅色的對(duì)面應(yīng)該是綠色室叉,但在我們的例子里是青色。你能找到一種修復(fù)的方式來(lái)讓它看起來(lái)和下圖一樣么硫惕?[提示:這是用塑形函數(shù)的好機(jī)會(huì)茧痕!]

函數(shù)和變量

int newFunction(in vec4 aVec4,   // read-only
                out vec3 aVec3,    // write-only
                inout int aInt);   // read-write

在進(jìn)入下一章之前讓我們停下腳步回顧下。復(fù)習(xí)下之前例子的函數(shù)恼除。你會(huì)注意到變量類型之前有個(gè)限定符 in踪旷,在這個(gè) qualifier (限定符)例子中它特指這個(gè)變量是只讀的曼氛。在之后的例子中我們會(huì)看到可以定義一個(gè) out 或者 inout變量。最后這個(gè) inout令野,再概念上類似于參照輸入一個(gè)變量舀患,這意味著我們有可能修改一個(gè)傳入的變量。

或許你還不相信我們可以用所有這些元素來(lái)畫(huà)一些炫酷的東西气破。下一章我們會(huì)學(xué)習(xí)如何結(jié)合所有這些技巧通過(guò)融合 (blending) 空間來(lái)創(chuàng)造幾何形狀聊浅。沒(méi)錯(cuò)。现使。低匙。融合(blending) 空間。

https://thebookofshaders.com/06/?lan=ch

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碳锈,一起剝皮案震驚了整個(gè)濱河市顽冶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌售碳,老刑警劉巖强重,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異团滥,居然都是意外死亡竿屹,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)灸姊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拱燃,“玉大人,你說(shuō)我怎么就攤上這事力惯⊥胗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵父晶,是天一觀的道長(zhǎng)哮缺。 經(jīng)常有香客問(wèn)我,道長(zhǎng)甲喝,這世上最難降的妖魔是什么尝苇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮埠胖,結(jié)果婚禮上糠溜,老公的妹妹穿的比我還像新娘。我一直安慰自己直撤,他們只是感情好非竿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著谋竖,像睡著了一般红柱。 火紅的嫁衣襯著肌膚如雪承匣。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天锤悄,我揣著相機(jī)與錄音韧骗,去河邊找鬼。 笑死铁蹈,一個(gè)胖子當(dāng)著我的面吹牛宽闲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播握牧,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼容诬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了沿腰?” 一聲冷哼從身側(cè)響起览徒,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颂龙,沒(méi)想到半個(gè)月后习蓬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡措嵌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年躲叼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片企巢。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枫慷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浪规,到底是詐尸還是另有隱情或听,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布笋婿,位于F島的核電站誉裆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缸濒。R本人自食惡果不足惜足丢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庇配。 院中可真熱鬧斩跌,春花似錦、人聲如沸垦沉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)萤捆。三九已至,卻和暖如春赚导,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工著角, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人旋恼。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓吏口,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親冰更。 傳聞我的和親對(duì)象是個(gè)殘疾皇子产徊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容