WebGL?多重紋理的使用介紹
引言
基于上篇的內(nèi)容,紋理中最小的單位是紋素,若干紋素組成一個(gè)紋理單元,每個(gè)紋理單元用一個(gè)number值來管理,那么我們來看看它是如何工作的。
激活
在使用紋理單元之前,得需要激活紋理單元
activeTexture()
參數(shù):
- 指定準(zhǔn)備激活的紋理單元:webgl.TEXTURE0、webgl.TEXTURE1...最后的數(shù)字表示紋理單元的編號(hào)
綁定
這一步,需要告訴WebGL系統(tǒng)紋理對(duì)象使用的是何種類型的紋理,在對(duì)該對(duì)象的操作之前,需要先綁定該對(duì)象,這和之前的緩沖區(qū)對(duì)象的數(shù)據(jù)寫操作類似。
bindTexture(webgl.TEXTURE_2D, texture0)
參數(shù):
- webgl.TEXTURE_2D: 二維紋理;webgl.TEXTURE_CUBE_MAP: 立方體紋理
- texture0:需要綁定指定的紋理對(duì)象
該方法開啟紋理對(duì)象,以及將紋理對(duì)象texture0綁定到紋理單元webgl.TEXTURE0上,之后通過操作紋理單元去操作紋理對(duì)象。
配置
這兒主要是對(duì)紋理對(duì)象具體的信息操作了,例如紋理單元類型、尺寸、是否裁剪、紋理的展示方式(放大或縮小)等,下面我們?cè)僖灰环治觥?/p>
texParameteri(target, pname, param)
參數(shù):
- target: webgl.TEXTURE_2D或webgl.TEXTURE_CUBE_MAP
- pname: webgl.TEXTURE_MAG_FILTER紋理放大,例如16x16的紋理圖像映射到32x32的像素空間中;webgl.TEXTURE_MIN_FILTER紋理縮小, 應(yīng)用場(chǎng)景相反;webgl.TEXTURE_WRAP_S紋理水平軸(ST坐標(biāo)系統(tǒng))方向填充;webgl.TEXTURE_WRAP_T紋理T軸方向填充。
- param: webgl.LINEAR線性變換,使用距離像素中心最近的四個(gè)點(diǎn),進(jìn)行線性平均加權(quán),然后作為新的顏色值; webgl.NEAREST最近的距離優(yōu)先,新的像素值取中心像素的值;CLAMP_TO_EDGE: 設(shè)置紋理 S/T 軸方向上的邊緣環(huán)繞方式為CLAMP_TO_EDGE,即在超出邊緣的部分使用紋理邊緣的像素顏色填充. webgl.REPEAT紋理重復(fù)補(bǔ)充;webgl.MIRRORED_REPEAT:紋理鏡像對(duì)稱式重復(fù)
會(huì)發(fā)現(xiàn)參數(shù)pname、param中的參數(shù)常量分類比較多,對(duì)應(yīng)的分類是
- pname : TEXTURE_MAG_FILTER、TEXTURE_MIN_FILTER
- param: NEAREST、LINEAR
和
- pname : TEXTURE_WRAP_S、TEXTURE_WRAP_T
- param: REPEAT、MIRRORED_REPEAT、CLAMP_TO_EDGE
分配
紋理對(duì)象信息配置好后,接著可以將紋理圖像分配給紋理對(duì)象
webgl.texImage2D(target, level, internalformat, format type, image)
參數(shù):
- target: webgl.TEXTURE_2D或webgl.TEXTURE_CUBE_MAP
- level: 指定紋理緩沖區(qū)中要加載的紋理級(jí)別,一般為 0
- internalformat: 紋理對(duì)象內(nèi)部數(shù)據(jù)格式,通常使用webgl.RGBA
- format: 紋理數(shù)據(jù)格式,必須與internalformat相同的值
- type: 紋理數(shù)據(jù)類型
- image: 紋理對(duì)象中image對(duì)象
其中的紋理數(shù)據(jù)類型有:
webgl.UNSIGNED_BYTE: 無符號(hào)整型,每個(gè)顏色分量占據(jù)1字節(jié) webgl.UNSIGNED_SHORT_5_6_5:RGB webgl.UNSIGNED_SHORT_4_4_4:RGBA webgl.UNSIGNED_SHORT_5_5_5_1:RGBA
傳遞
經(jīng)過上面一系列準(zhǔn)備后,我們就可以把最終的紋理單元傳遞給片元著色器了,這兒就用到了方法 webgl.uniform1i(),上篇這個(gè)方法已經(jīng)說過了,就不再說明了。
主要看看片元著色器中是怎么做的
uniform sampler2D texture; varying vec2 inUV; vec4 color1=texture2D(texture, vec2(inUV.x, 1.0 - inUV.y)); gl_FragColor=color1;
- 定義了一個(gè)可以在外部訪問的一種特殊的、專用于紋理對(duì)象的數(shù)據(jù)類型sampler2D,就是對(duì)應(yīng)的紋理單元類型webgl.TEXTURE_2D;如果是webgl.TEXTURE_CUBE_MAP呢,則是samplerCube.
- 通過uniform1i方法,將紋理對(duì)象傳遞到了片元著色器中的texture變量
- inUV接收頂點(diǎn)著色器中的頂點(diǎn)的紋理坐標(biāo),當(dāng)然這里的紋理坐標(biāo)是在外部設(shè)置的
- texture2D()在片元著色器中根據(jù)紋理坐標(biāo)獲取紋理圖像上的紋素的顏色
- 把獲取到的顏色賦值給片元著色器
經(jīng)過對(duì)紋理的加載、設(shè)置、映射,剩下的就是繪畫了。
webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4)
好了,晦澀難懂的概念介紹完了,就把具體的代碼貼出來吧!
效果
代碼
著色器設(shè)置
const VSHADER_SOURCE = ` attribute vec2 a_position; attribute vec2 outUV; varying vec2 inUV; void main(void){ gl_Position=vec4(a_position, 0.0, 1.0); inUV=outUV; } ` const FSHADER_SOURCE = ` precision mediump float; uniform sampler2D texture; uniform sampler2D texture1; varying vec2 inUV; uniform float anim; void main(void){ vec4 color1=texture2D(texture, vec2(inUV.x, 1.0 - inUV.y)); vec4 color2=texture2D(texture1, vec2(inUV.x + anim, 1.0 - inUV.y)); gl_FragColor=color1+color2; } `
數(shù)據(jù)緩存區(qū)的設(shè)置
const initBuffer = async () => { let positions = [ 0.8, -0.8, -0.8, -0.8, 0.8, 0.8, -0.8, 0.8, ] let pointPosition = new Float32Array(positions) let aPsotion = webgl.getAttribLocation(webgl.program, "a_position") let triangleBuffer = webgl.createBuffer() webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer) webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW) webgl.enableVertexAttribArray(aPsotion) webgl.vertexAttribPointer(aPsotion, 2, webgl.FLOAT, false, 0, 0) var texCoords = [ 1, 0, 0, 0, 1, 1, 0, 1, ] const attribOutUV = webgl.getAttribLocation(webgl.program, "outUV") let texCoordBuffer = webgl.createBuffer() webgl.bindBuffer(webgl.ARRAY_BUFFER, texCoordBuffer) webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(texCoords), webgl.STATIC_DRAW) webgl.enableVertexAttribArray(attribOutUV) webgl.vertexAttribPointer(attribOutUV, 2, webgl.FLOAT, false, 0, 0) uniformTexture = webgl.getUniformLocation(webgl.program, "texture") uniformTexture1 = webgl.getUniformLocation(webgl.program, "texture1") texture0 = await initTexture('/web-gl/landscape.png') texture1 = await initTexture("/web-gl/fog.png") }
主要是設(shè)置頂點(diǎn)坐標(biāo)和紋理坐標(biāo)的數(shù)據(jù)
紋理對(duì)象的初始化
const initTexture = (imageSrc: string): Promise<WebGLTexture> => { return new Promise((resolve, reject) => { let textureHandle = webgl.createTexture() const image = new Image() image.onload = function () { webgl.bindTexture(webgl.TEXTURE_2D, textureHandle) webgl.texParameteri( webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_S, webgl.CLAMP_TO_EDGE ) webgl.texParameteri( webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_T, webgl.CLAMP_TO_EDGE ) webgl.texParameteri( webgl.TEXTURE_2D, webgl.TEXTURE_MIN_FILTER, webgl.LINEAR ) webgl.texImage2D( webgl.TEXTURE_2D, 0, webgl.RGBA, webgl.RGBA, webgl.UNSIGNED_BYTE, image ) resolve(textureHandle) } image.onerror = reject image.src = imageSrc }) }
這兒需要使用異步方法,因?yàn)樾枰趇mage.onload方法中返回設(shè)置信息數(shù)據(jù)后的紋理對(duì)象。 在 webgl 的紋理加載中,由于圖片是異步加載的,因此我們需要使用 Promise 來處理加載完畢后的回調(diào)函數(shù)。
繪制和動(dòng)態(tài)變化
const updateCount = () => { count = count + 0.001 if (count >= 1.14) { count = -1.0 } } const draw = () => { webgl.clearColor(0.0, 1.0, 1.0, 1.0) webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT) webgl.enable(webgl.DEPTH_TEST) //紋理變動(dòng) uniformAnim = webgl.getUniformLocation(webgl.program, "anim"); updateCount() webgl.uniform1f(uniformAnim, count); webgl.activeTexture(webgl.TEXTURE0) webgl.bindTexture(webgl.TEXTURE_2D, texture0) webgl.uniform1i(uniformTexture, 0) webgl.activeTexture(webgl.TEXTURE1) webgl.bindTexture(webgl.TEXTURE_2D, texture1) webgl.uniform1i(uniformTexture1, 1) webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4) requestAnimationFrame(draw) }
具體的代碼就是這些了。
小結(jié)一下
到目前為止,我們已經(jīng)了解了頂點(diǎn)著色器、片元著色器、頂點(diǎn)緩沖區(qū)、矩陣?yán)L制和變換、紋理圖像、紋理疊加等,這樣我們已經(jīng)基本上對(duì)二維繪圖掌握了,一個(gè)面我們了解了,之后我們可能就去看看多個(gè)面的物體和場(chǎng)景。
那么就讓我們一起看看三維世界吧!
以上就是WebGL 多重紋理的詳細(xì)內(nèi)容,更多關(guān)于WebGL 多重紋理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于JS實(shí)現(xiàn)點(diǎn)擊圖片在彈出層顯示大圖效果
Javascript是個(gè)好東西。Jquery是基于這個(gè)好東西的一個(gè)強(qiáng)大的庫(kù)。本文將利用JavaScript實(shí)現(xiàn)點(diǎn)擊圖片在彈出層顯示大圖功能,感興趣的可以了解一下2022-08-08JavaScript定時(shí)器實(shí)現(xiàn)的原理分析
JavaScript中的定時(shí)器大家基本在平時(shí)的開發(fā)中都遇見過吧,但是又有多少人去深入的理解其中的原理呢?本文我們就來分析一下定時(shí)器的實(shí)現(xiàn)原理、定時(shí)器的妙用、定時(shí)器使用注意事項(xiàng),有興趣的朋友可以看下2016-12-12JS正則截取兩個(gè)字符串之間及字符串前后內(nèi)容的方法
這篇文章主要介紹了JS正則截取兩個(gè)字符串之間及字符串前后內(nèi)容的方法,結(jié)合實(shí)例形式簡(jiǎn)單分析了JS正則截取字符串操作的常用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2017-01-01JavaScript 報(bào)表展示實(shí)現(xiàn)代碼
以下是從網(wǎng)上找到的一段JavaScript實(shí)現(xiàn)圖形報(bào)表的代碼,對(duì)于想客戶端顯示報(bào)表的朋友可以參考下。2009-12-12JavaScipt驗(yàn)證URL新方法詳解(2023 年版)
這篇文章主要為大家介紹了JavaScipt驗(yàn)證URL新方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12純html+css+javascript實(shí)現(xiàn)樓層跳躍式的頁(yè)面布局(實(shí)例代碼)
這篇文章主要介紹了純html+css+javascript實(shí)現(xiàn)樓層跳躍式的頁(yè)面布局,需要的朋友可以參考下2017-10-10