<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          了不起的 Creator Shader修仙之路—探照燈效果詳解

          共 2959字,需瀏覽 6分鐘

           ·

          2020-08-04 02:33

          介紹

          探照燈效果就是指整個(gè)場(chǎng)景或者圖片都是黑的,只有燈光照射的地方才是亮的。實(shí)現(xiàn)方式有很多種,我們這里用shader來(lái)實(shí)現(xiàn),主要原因就是用shader來(lái)實(shí)現(xiàn),效率更高,效果更好,并且拓展性更強(qiáng)一些。下面是一個(gè)探照燈效果:

          探照燈實(shí)現(xiàn)

          光照原理

          我們知道在程序中顏色由RGB三個(gè)數(shù)值來(lái)決定,比如紅光的RGB值是255、0、0,但在GLSL語(yǔ)言中表示顏色的最大值是1.0,而且通常用一個(gè)vec4來(lái)表示,所以紅光就是:vec4(1.0, 0.0, 0.0, 1.0); 第四個(gè)參數(shù)是alpha值,這里我們都設(shè)置為1。

          這里我們?cè)僬f(shuō)一下現(xiàn)實(shí)中我們看到物體有各式各樣的顏色,并不是它們本身是這個(gè)顏色,而是它所能反射光的顏色。太陽(yáng)光中是包含所有顏色光的,而一個(gè)物體能反射什么顏色的光與物體本身粒子特性有關(guān),決定了它能反射光的波長(zhǎng)范圍,而其他范圍的光則被吸收,所以我們就看到了各種顏色的物體。如下圖所示:

          利用這個(gè)原理,我們就可以通過(guò)shader來(lái)控制目標(biāo)的顏色顯示來(lái)模擬光照了,比如我們?cè)O(shè)定一個(gè)白色光照:vec4(1.0, 1.0, 1.0, 1.0)。該向量與片段著色器中的顏色相乘,因?yàn)槊總€(gè)值都是1,所以物體顏色并不會(huì)改變。當(dāng)我們?cè)O(shè)置為紅光vec4(1.0, 0.0, 0.0, 1.0)時(shí),物體就會(huì)發(fā)紅。

          我們?cè)倏刂乒庹盏姆秶且粋€(gè)圓形,那么就是一個(gè)探照燈效果了。

          著色器實(shí)現(xiàn)

          • 下面是著色器的實(shí)現(xiàn)過(guò)程,不是完整代碼,只有代碼片段,熟悉GLSL語(yǔ)言的同學(xué)應(yīng)該可以看懂,不了解的同學(xué)可以直接到文末獲取完整代碼再回頭過(guò)來(lái)學(xué)習(xí)亦可。

          • 首先是光照范圍邏輯,根據(jù)兩點(diǎn)距離和光照中心點(diǎn)來(lái)判斷是否在光照范圍內(nèi),光照范圍內(nèi)的點(diǎn)為目標(biāo)顏色,范圍外的點(diǎn)則設(shè)置成黑色:

          // 計(jì)算當(dāng)前點(diǎn)是否在光照范圍內(nèi)float dist = sqrt(pow(fragPos.x - light_center.x, 2.0) + pow(fragPos.y - light_center.y, 2.0));// 光照半徑float light_radius = 0.2;// 根據(jù)點(diǎn)到光源圓心的距離判斷光照范圍if (dist > light_radius) {    // 超出光照范圍則為黑色    gl_FragColor = vec4(0, 0, 0, 1.0);} else {    gl_FragColor = o;}

          運(yùn)行效果:

          • 此時(shí)一個(gè)大體的光照范圍效果就有了,但是不太自然,光照的邊緣沒(méi)有過(guò)渡,并且有鋸齒存在,下面我們通過(guò)插值來(lái)把光照的邊緣增加過(guò)渡效果:

          // 通過(guò)插值讓光照過(guò)度平滑float r = (1.0 - smoothstep(light_radius, light_radius + 0.1, dist));gl_FragColor = vec4(o.r * r, o.g * r, o.b * r, 1.0);
          • smoothstep函數(shù)接收三個(gè)參數(shù),第一個(gè)是范圍的最小值,第二個(gè)是范圍的最大值,第三個(gè)參數(shù)是需要計(jì)算的目標(biāo)值x,x小于最小值則返回0,大于最大值返回1,其余返回0到1的插值。上面代碼里的范圍是光照半徑及半徑加0.1的范圍內(nèi)進(jìn)行插值來(lái)實(shí)現(xiàn)光線邊緣的過(guò)渡效果。修改完再看,效果已經(jīng)不錯(cuò)了:

          • 最后我們通過(guò)代碼來(lái)設(shè)置light_center參數(shù)就能實(shí)現(xiàn)光源的移動(dòng)了:

          // Touch move事件函數(shù)public touchMove(event: cc.Event) {    let touch: cc.Touch = event.touch;    // 根據(jù)屏幕坐標(biāo)獲得-1 ~ 1 的范圍坐標(biāo),傳遞給著色器使用    let x = touch.getLocation().x / (cc.winSize.width / 2) - 1;    let y = touch.getLocation().y / (cc.winSize.height / 2) - 1;    let center = cc.v2(x, y);    this._materi.effect.setProperty("light_center", center);}
          • 細(xì)心的朋友可能發(fā)現(xiàn),如果你的場(chǎng)景或者目標(biāo)圖片不是正方形,那么光照的范圍可能就不是個(gè)正圓了,而是一個(gè)橢圓。這是因?yàn)镺penGL中的坐標(biāo)范圍是從-1到1,但寬高長(zhǎng)度并不一定是等比的。所以我們?cè)谟?jì)算圓的范圍時(shí),可以把場(chǎng)景或者圖片的寬高比傳入進(jìn)來(lái),然后計(jì)算圓范圍時(shí)進(jìn)行修正就可以了:

          // 計(jì)算當(dāng)前點(diǎn)是否在光照范圍內(nèi), 增加寬高比的修正,wh_ratio是傳入的目標(biāo)寬高比。float?dist?=?sqrt(pow(fragPos.x?*?wh_ratio?-?light_center.x?*?wh_ratio,?2.0)?+?pow(fragPos.y?-?light_center.y,?2.0));

          進(jìn)一步優(yōu)化

          漫反射環(huán)境光

          • 大家知道,無(wú)論我們?cè)诙嗝雌岷诘奈葑永铮覀兛偸悄茈[約看見物體輪廓的,這就是因?yàn)橛新瓷涞沫h(huán)境光造成的。物體表面都不是光滑的,都是凹凸不平的,總會(huì)把光源的光線,反射到各個(gè)方向,其它物體接收到反射光后會(huì)再次反射,反復(fù)循環(huán),這就是漫反射,我們也叫環(huán)境光。這就是為什么我們?cè)跊](méi)有光源的屋子里也能看見東西的原因,漫反射原理如下圖:

          • 在我們的例子中光線沒(méi)有照到的地方漆黑一片,有時(shí)我們也需要一些漫反射造成的環(huán)境光。真實(shí)的漫反射算法非常復(fù)雜,要通過(guò)法向量來(lái)運(yùn)算,我們這里只是一個(gè)2D的紋理貼圖,所以我們就把環(huán)境光設(shè)置成一個(gè)平均的常數(shù)就可以了,在光線沒(méi)有照到的邏輯中加入環(huán)境光邏輯:

          // 設(shè)置環(huán)境光強(qiáng)度為0.1float ambient_strength = 0.1;// 通過(guò)插值讓光照過(guò)度平滑float r = (1.0 - smoothstep(light_radius, light_radius + 0.1, dist));// 該判斷用于保證漫反射的環(huán)境光有效if (r <= ambient_strength) {    r = ambient_strength;}gl_FragColor = vec4(o.r * r, o.g * r, o.b * r, 1.0);
          • 這時(shí)運(yùn)行效果就和教程開頭的效果基本一樣了。

          光照強(qiáng)度和光源顏色

          • 前面的實(shí)現(xiàn)過(guò)程中我們對(duì)在光照范圍內(nèi)的目標(biāo)顏色沒(méi)有干預(yù),保證了目標(biāo)的固有色。但有時(shí)我們也需要改變一些,比如上面講到了環(huán)境光,沒(méi)有光照的地方并不是漆黑一片了,那么反過(guò)來(lái),有光照的地方就一定是亮的嗎?有時(shí)我們也需要調(diào)整一下光照的亮度和光照的顏色。

          • 我們先看光照的亮度,這個(gè)比較簡(jiǎn)單,邏輯和環(huán)境光強(qiáng)度一樣,我們?cè)俣x一個(gè)光源強(qiáng)度的參數(shù)就可以了:

          // 光照強(qiáng)度,我們修改為0.8float result = 0.8;// 根據(jù)點(diǎn)到光源圓心的距離判斷光照范圍if (dist > light_radius) {    // 設(shè)置環(huán)境光強(qiáng)度為0.1    float ambient_strength = 0.1;    // 通過(guò)插值讓光照過(guò)度平滑    float r = (1.0 - smoothstep(light_radius, light_radius + 0.1, dist)) * result;    // 該判斷用于保證漫反射的環(huán)境光有效    if (r <= ambient_strength) {        r = ambient_strength;    }    gl_FragColor = vec4(o.r * r, o.g * r, o.b * r, 1.0);} else {    gl_FragColor = vec4(o.r * result, o.g * result, o.b * result, 1.0);}
          • 我們將光照部分和參與插值運(yùn)算的光照邊緣過(guò)渡部分都乘上光照強(qiáng)度就可以實(shí)現(xiàn)我們的目標(biāo)效果了。(不過(guò)這里需要注意的一個(gè)問(wèn)題是,光照強(qiáng)度result如果小于環(huán)境光強(qiáng)度ambient_strength會(huì)是什么效果呢?大家可以試一下,并嘗試修改。)

          • 接下來(lái)我們?cè)黾庸庠搭伾闹С郑鶕?jù)教程開頭講的光照原理,我們可以直接把之前我們例子中的目標(biāo)顏色乘以一個(gè)光源顏色就可以了,光源顏色我們就用上面說(shuō)過(guò)的紅光:

          // 光源顏色,紅光vec4 light_color = vec4(1, 0, 0, 1);// 光照強(qiáng)度,我們修改為0.8float result = 0.8;// 根據(jù)點(diǎn)到光源圓心的距離判斷光照范圍if (dist > light_radius) {    // 設(shè)置環(huán)境光強(qiáng)度為0.1    float ambient_strength = 0.1;    // 通過(guò)插值讓光照過(guò)度平滑    float r = (1.0 - smoothstep(light_radius, light_radius + 0.1, dist)) * result;    // 該判斷用于保證漫反射的環(huán)境光有效    if (r <= ambient_strength) {        r = ambient_strength;    }    gl_FragColor = vec4(o.r * r, o.g * r, o.b * r, 1.0) * light_color;} else {    gl_FragColor = vec4(o.r * result, o.g * result, o.b * result, 1.0) * light_color;}
          • 運(yùn)行效果如下:

          最后

          完整代碼地址如下:
          https://github.com/yue19870813/cocos_demo/tree/master/CocosDemo_2_3_3/assets/case/searchlight

          也可以點(diǎn)擊閱讀原文獲取代碼地址。

          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲欧美视频免费观看 | 色色网站在线观看观看 | 激情开心五月天 | 日本a不卡 | 人人爱人人做人人草 |