本文由雲+社群發表webgl繪製影象時,往著色器中傳入顏色資訊就可以給圖形繪製出相應的顏色,現在已經知道頂點著色器和片段著色器一起決定著向顏色緩衝區寫入顏色資訊並最終呈現出來,那麼這個過程是什麼樣,如果圖形的顏色需要用現有來渲染那麼又該如何操作?
在繪製開始前,經常見到呼叫函式清空畫布的**gl.clear(gl.color_buffer_bit),清空畫布的繪圖區實際上就是用之前定義好的背景顏色將顏色緩衝的的顏色清除。顏色緩衝區中存放著需要顯示到畫布上的畫素的顏色資料,它屬於幀快取的一部分,與深度快取、模板快取等一起決定著最終畫布上影象的顯示資訊。
可以將顏色快取區看成影象顏色儲存器,在快取區中以rgb或rgba的格式儲存著畫布上每乙個畫素的顏色資訊,各個畫素點組合起來就構成了顏色快取的矩形陣列。這個定義看起來與儲存器是很相似的,顏色快取為rgb或是rgba每乙個通道分配存放位數,其中rgb就是顏色資料,a表示alpha也就是該畫素的透明度資訊,顏色占用的位數值就是顏色深度,比如顏色深度為24位,表示每乙個畫素24位,一般24位的分配方案就是紅色、藍色、綠色各佔8位,如果需要透明效果的話,可以採用32位顏色深度為alpha通道分配8位。
這裡可以總結得出,畫布上各個畫素點呈現的顏色就是存放在顏色緩衝區的顏色資訊所決定的,而繪製圖形的顏色緩衝區的資訊又是由頂點著色器決定。要知道顏色如何渲染就要深入分析著色器的工作過程。
要繪製乙個三角形,我們是這樣定義著色器的:
// 頂點著色器
const vshader_source =
`attribute vec4 a_position;
void main() `;
// 片段著色器
const fshader_source =
`void main() `;
之後通過gl.program將頂點position座標傳入頂點著色器,這就相當於在畫布上確定了幾個點的座標資訊,這些點需要用線條連線起來才能構成圖形,這個由頂點座標裝配成幾何圖形的過程就叫做圖形裝配。
被裝配的基本圖形被稱作圖元,它包含點、線、麵等基本幾何圖形。在呼叫webgl的drawarrays或drawelements方法時作為引數傳入,從而指定圖元型別。
乙個三角形的繪製過程拆分來看就是執行三次頂點著色器,將三個點座標都傳入裝配區,根據繪製函式的圖元引數gl.********s將三個點裝配成三角形,然後進入下乙個過程——光柵化。
簡單來說,光柵化就是將圖形轉化成片元,可以理解成乙個個畫素。只有將圖形轉化成畫素後才能交由片段著色器處理。
光柵化結束後,webgl執行片段著色器。每執行一次片段著色器就處理乙個片元,將該片元的顏色寫入顏色緩衝區中,等到圖形中所有的片元處理完畢畫布上就得到了最後的影象。
如上面的例子,每乙個片元都會被執行成紅色,由這乙個個紅色畫素組成的三角形也就是紅色的。
如果要繪製乙個多顏色三角圖形又是乙個什麼過程呢?首先需要修改著色器的定義,也許可以這樣:
// 頂點著色器
const vshader_source =
`attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;
void main() `;
// 片段著色器
const fshader_source =
`varying vec4 v_color;
void main() `;
向頂點著色器傳入頂點座標和顏色兩個資料,執行三次後得到三角形三個頂點的座標和顏色,接下來通過圖元裝配得到乙個三角形的圖元,到了關鍵的光柵化這一步,該如何定義片元的顏色呢?webgl採用乙個叫做內插的過程來計算顏色的值。
以一條線為例來解釋內插,兩個端點分別為(1.0,0.0,0.0)和(0.0,1.0,0.0),從一端到另一端,r的值從1.0降到0.0,g的值由0.0公升到1.0,線上的所有點顏色值都這樣計算出來,實現了平滑的顏色漸變,這就是內插。
經過內插,圖形的每乙個片元都指定了自己的顏色,寫入顏色緩衝區後呈現出來。
如果要為webgl建立更加複雜更加自然的現實效果,就需要採用貼圖來將現成的貼到圖形上。
容器中存放的也是乙個個rgb或rgba的畫素,將的資訊讀取後存放在紋理物件或者說紋理影象中,紋理影象有自己的座標系,座標中每乙個單元格就存放的紋理影象的畫素資訊,也被稱作紋素。
將紋理影象的座標轉換到畫布上圖形的座標的對映過程就是紋理對映,這個過程中,為圖形頂點指定了紋理座標,剩下的顏色由內插計算得出,寫入顏色緩衝區後,圖形的表面就被貼上了影象的顏色。
用乙個案例來實現紋理貼圖,現在要做的是:
在這個例子中我選擇提前載入。在這裡要注意有的瀏覽器不允許訪問本地檔案,可以考慮自己搭建server或是開啟瀏覽器訪問本地檔案。
function main() ;
// 初始化之前先載入
loadimage([
`src/images/0.jpeg`,
], webgl).then((gl) =>
gl.clearcolor(0, 0, 0, 1);
gl.clear(gl.color_buffer_bit | gl.depth_buffer_bit);
const n = initvertexbuffers(gl);
inittextures(gl, n, 0);
});}
loadimage的實現很簡單,用乙個promise來處理非同步載入,傳入陣列為了之後支援多張。在initvertexbuffers中建立資料buffer,將圖形頂點和紋理影象座標一起傳入著色器。
function initvertexbuffers(gl)
然後看看最主要的inittextures,在這裡配置紋理:
function inittextures(gl, n, index) `]);
// 繫結紋理物件
gl.bindtexture(gl.texture_2d, texture);
// 配置紋理物件的引數
gl.texparameteri(gl.texture_2d, gl.texture_wrap_s, gl.clamp_to_edge);
gl.texparameteri(gl.texture_2d, gl.texture_wrap_t, gl.clamp_to_edge);
gl.texparameteri(gl.texture_2d, gl.texture_min_filter, gl.linear);
// 將紋理影象分配給紋理物件
gl.teximage2d(gl.texture_2d, 0, gl.rgba, gl.rgba, gl.unsigned_byte, image);
// 將紋理單元編號傳給著色器
gl.uniform1i(u_sampler, index);
// 繪製
gl.drawarrays(gl.********_strip, 0, n);
}
這裡又遇到兩個概念:
紋理物件配置引數 texparameteri方法用來配置紋理物件引數,函式第二個引數傳入配置引數名,第三個引數傳入配置引數值,可以配置的引數有:
詳細參考texparameteri
紋理單元 如果需要使用多張就要管理多個紋理,webgl為了使用多個紋理,用紋理單元來處理紋理影象。webgl的實現至少支援8個紋理單元,分別用gl.texrtrue0,gl.texrtrue1,...,gl.texrtrue7來表示。
最後是著色器**,在呼叫gl.drawarrays傳入圖元型別********_strip後執行:
const vshader_source =
`attribute vec4 a_position;
attribute vec2 a_texcoord;
varying vec2 v_texcoord;
void main() `;
const fshader_source =
`precision mediump float;
uniform sampler2d u_sampler;
varying vec2 v_texcoord;
void main() `;
頂點著色器中傳入紋理影象的頂點座標,將它傳遞給片段著色器,在片段著色器中宣告了乙個專用於紋理物件的資料型別sampler2d,指向乙個紋理單元編號(接下來解釋),著色器獲取紋素由函式texture2d完成,傳入引數紋理單元編號和紋理影象座標。
WebGL 紋理顏色原理
本文由雲 社群發表 webgl繪製影象時,往著色器中傳入顏色資訊就可以給圖形繪製出相應的顏色,現在已經知道頂點著色器和片段著色器一起決定著向顏色緩衝區寫入顏色資訊並最終呈現出來,那麼這個過程是什麼樣,如果圖形的顏色需要用現有來渲染那麼又該如何操作?在繪製開始前,經常見到呼叫函式清空畫布的 gl.cl...
WebGL 紋理顏色原理
本文由雲 社群發表 webgl繪製影象時,往著色器中傳入顏色資訊就可以給圖形繪製出相應的顏色,現在已經知道頂點著色器和片段著色器一起決定著向顏色緩衝區寫入顏色資訊並最終呈現出來,那麼這個過程是什麼樣,如果圖形的顏色需要用現有來渲染那麼又該如何操作?在繪製開始前,經常見到呼叫函式清空畫布的 gl.cl...
WebGL 顏色與紋理
1.紋理座標 紋理座標是紋理影象上的座標,通過紋理座標可以在紋理影象上獲取紋理顏色。webgl系統中的紋理座標系統是二維的,如圖所示。為了將紋理座標和廣泛使用的x y座標區分開來,webgl使用s和t命名紋理座標 st座標系統 紋理影象的四個角座標為左下角 0.0,0.0 右下角 1.0,0.0 右...