WebGL?多重紋理的使用介紹
引言
基于上篇的內(nèi)容,紋理中最小的單位是紋素,若干紋素組成一個紋理單元,每個紋理單元用一個number值來管理,那么我們來看看它是如何工作的。
激活
在使用紋理單元之前,得需要激活紋理單元
activeTexture()
參數(shù):
- 指定準備激活的紋理單元:webgl.TEXTURE0、webgl.TEXTURE1...最后的數(shù)字表示紋理單元的編號
綁定
這一步,需要告訴WebGL系統(tǒng)紋理對象使用的是何種類型的紋理,在對該對象的操作之前,需要先綁定該對象,這和之前的緩沖區(qū)對象的數(shù)據(jù)寫操作類似。
bindTexture(webgl.TEXTURE_2D, texture0)
參數(shù):
- webgl.TEXTURE_2D: 二維紋理;webgl.TEXTURE_CUBE_MAP: 立方體紋理
- texture0:需要綁定指定的紋理對象
該方法開啟紋理對象,以及將紋理對象texture0綁定到紋理單元webgl.TEXTURE0上,之后通過操作紋理單元去操作紋理對象。
配置
這兒主要是對紋理對象具體的信息操作了,例如紋理單元類型、尺寸、是否裁剪、紋理的展示方式(放大或縮小)等,下面我們再一一分析。
texParameteri(target, pname, param)
參數(shù):
- target: webgl.TEXTURE_2D或webgl.TEXTURE_CUBE_MAP
- pname: webgl.TEXTURE_MAG_FILTER紋理放大,例如16x16的紋理圖像映射到32x32的像素空間中;webgl.TEXTURE_MIN_FILTER紋理縮小, 應用場景相反;webgl.TEXTURE_WRAP_S紋理水平軸(ST坐標系統(tǒng))方向填充;webgl.TEXTURE_WRAP_T紋理T軸方向填充。
- param: webgl.LINEAR線性變換,使用距離像素中心最近的四個點,進行線性平均加權,然后作為新的顏色值; webgl.NEAREST最近的距離優(yōu)先,新的像素值取中心像素的值;CLAMP_TO_EDGE: 設置紋理 S/T 軸方向上的邊緣環(huán)繞方式為CLAMP_TO_EDGE,即在超出邊緣的部分使用紋理邊緣的像素顏色填充. webgl.REPEAT紋理重復補充;webgl.MIRRORED_REPEAT:紋理鏡像對稱式重復
會發(fā)現(xiàn)參數(shù)pname、param中的參數(shù)常量分類比較多,對應的分類是
- pname : TEXTURE_MAG_FILTER、TEXTURE_MIN_FILTER
- param: NEAREST、LINEAR
和
- pname : TEXTURE_WRAP_S、TEXTURE_WRAP_T
- param: REPEAT、MIRRORED_REPEAT、CLAMP_TO_EDGE
分配
紋理對象信息配置好后,接著可以將紋理圖像分配給紋理對象
webgl.texImage2D(target, level, internalformat, format type, image)
參數(shù):
- target: webgl.TEXTURE_2D或webgl.TEXTURE_CUBE_MAP
- level: 指定紋理緩沖區(qū)中要加載的紋理級別,一般為 0
- internalformat: 紋理對象內(nèi)部數(shù)據(jù)格式,通常使用webgl.RGBA
- format: 紋理數(shù)據(jù)格式,必須與internalformat相同的值
- type: 紋理數(shù)據(jù)類型
- image: 紋理對象中image對象
其中的紋理數(shù)據(jù)類型有:
webgl.UNSIGNED_BYTE: 無符號整型,每個顏色分量占據(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)過上面一系列準備后,我們就可以把最終的紋理單元傳遞給片元著色器了,這兒就用到了方法 webgl.uniform1i(),上篇這個方法已經(jīng)說過了,就不再說明了。
主要看看片元著色器中是怎么做的
uniform sampler2D texture; varying vec2 inUV; vec4 color1=texture2D(texture, vec2(inUV.x, 1.0 - inUV.y)); gl_FragColor=color1;
- 定義了一個可以在外部訪問的一種特殊的、專用于紋理對象的數(shù)據(jù)類型sampler2D,就是對應的紋理單元類型webgl.TEXTURE_2D;如果是webgl.TEXTURE_CUBE_MAP呢,則是samplerCube.
- 通過uniform1i方法,將紋理對象傳遞到了片元著色器中的texture變量
- inUV接收頂點著色器中的頂點的紋理坐標,當然這里的紋理坐標是在外部設置的
- texture2D()在片元著色器中根據(jù)紋理坐標獲取紋理圖像上的紋素的顏色
- 把獲取到的顏色賦值給片元著色器
經(jīng)過對紋理的加載、設置、映射,剩下的就是繪畫了。
webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4)
好了,晦澀難懂的概念介紹完了,就把具體的代碼貼出來吧!
效果

代碼
著色器設置
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ū)的設置
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ù)據(jù)
紋理對象的初始化
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
})
}
這兒需要使用異步方法,因為需要在image.onload方法中返回設置信息數(shù)據(jù)后的紋理對象。 在 webgl 的紋理加載中,由于圖片是異步加載的,因此我們需要使用 Promise 來處理加載完畢后的回調(diào)函數(shù)。
繪制和動態(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)
//紋理變動
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)
}
具體的代碼就是這些了。
小結一下
到目前為止,我們已經(jīng)了解了頂點著色器、片元著色器、頂點緩沖區(qū)、矩陣繪制和變換、紋理圖像、紋理疊加等,這樣我們已經(jīng)基本上對二維繪圖掌握了,一個面我們了解了,之后我們可能就去看看多個面的物體和場景。
那么就讓我們一起看看三維世界吧!
以上就是WebGL 多重紋理的詳細內(nèi)容,更多關于WebGL 多重紋理的資料請關注腳本之家其它相關文章!
相關文章
純html+css+javascript實現(xiàn)樓層跳躍式的頁面布局(實例代碼)
這篇文章主要介紹了純html+css+javascript實現(xiàn)樓層跳躍式的頁面布局,需要的朋友可以參考下2017-10-10

