紋理單元和物件
紋理單元,也稱紋理對映單元或紋理處理單元,是GPU進行取樣的元件。紋理物件是包含圖片顏色資料的資料結構和紋理相關數學資訊。一個紋理單元必須訪問一個紋理物件來完成工作。紋理單元是處理器,而紋理物件儲存被處理的資料。
GLSL中的sampler型別包括sampler2D和samplerCube。 sampler2D用在標準紋理影像上,而samplerCube用在立方體紋理上。sampler型別的值索引到一個紋理單元上。值用來告訴取樣過程中哪個紋理單元被用到。取樣值必須是宣告在全域性的uniform型別中,不能在著色器程式中去分配值。紋理單元的值可以是0,1,2... 在GLSL中的應用
uniform sampler2D u_texture;複製程式碼
在JS中:
u_texture_location = gl.getUniformLocation(prog, "u_texture");
gl.uniform1i(u_texture_location, 2);複製程式碼
紋理的使用:
影像紋理的使用基本過程就是建立,啟用,並與對應的著色器程式關聯;
- 建立紋理物件,關聯到對應的記憶體中
textureObj = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, textureObj);
// 用來載入圖片到紋理物件中
gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);複製程式碼
- 匹配紋理單元 在告知紋理單元處理紋理物件時需要先啟用紋理單位“gl.activeTexture”。引數包括gl.TEXTURE0, gl.TEXTURE1... 初始情況下 TEXTURE0是啟用的。
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, textureObj);複製程式碼
texture 來源 http://math.hws.edu/graphicsbook/c6/s4.html#webgl.4.4
立方體紋理
Webgl支援立方體紋理。紋理物件可以儲存立方體紋理。兩個紋理物件可以同時繫結到同一個紋理單元,一個是普通紋理,另一個是立方體紋理。兩個紋理物件繫結到不同的目標上gl.TEXTURE2D和gl.TEXTURE_CUBE_MAP。紋理物件texObj繫結的方式:
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texObj);複製程式碼
紋理物件一旦繫結到一個物件上,就不能再次被繫結到其他地方。立方體紋理包含6個圖片,每張圖片對應立方體的一個面。繫結到立方體紋理上的紋理物件有6個常數進行指定:
gl.TEXTURE_CUBE_MAP_NEGATIVE_X
gl.TEXTURE_CUBE_MAP_POSITIVE_X
gl.TEXTURE_CUBE_MAP_NEGATIVE_Y
gl.TEXTURE_CUBE_MAP_POSITIVE_Y
gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
gl.TEXTURE_CUBE_MAP_POSITIVE_Z複製程式碼
這些常數被用在gl.texImage2D和gl.copyTexImage2D的目標上。圖片載入到cubemap紋理物件有6個目標,但用來將紋理物件繫結到紋理單元的只有gl.TEXTURE_CUBE_MAP。立方體紋理儲存了一組6張圖片,必須單獨的載入到紋理物件上。例子魚眼??
function loadCubemapTexture(){
var tex = gl.createTexture();
var imageCt = 0;
load("negx.jpg", gl.TEXTURE_CUBE_MAP_NEGATIVE_X);
load("posx.jpg", gl.TEXTURE_CUBE_MAP_POSITIVE_X);
load("negy.jpg", gl.TEXTURE_CUBE_MAP_NEGATIVE_Y);
load("posy.jpg", gl.TEXTURE_CUBE_MAP_POSITIVE_Y);
load("negz.jpg", gl.TEXTURE_CUBE_MAP_NEGATIVE_Z);
load("posz.jpg", gl.TEXTURE_CUBE_MAP_POSITIVE_Z);
function load(url, target){
var img = new Image();
img.onload = function(){
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
imageCt++;
if(imageCt === 6){
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
textureObject = tex;
draw();
}
}
img.src = url;
}
}複製程式碼
立方體紋理中的影像必須相同大小,並且是正方體的,大小也應該是2的冪次。另外對於紋理引數必須應用在所有的6個面上。如:
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);複製程式碼
對於立方體紋理為了面與面之間沒有明顯的裂縫,建議將紋理wrap的模式改為CLAMP_TO_EDGE來避免。
在片段著色器上,uniform sapmlerCube
vec4 color = textureCube(u_texture, vector);複製程式碼
紋理座標
紋理座標通常是根據將要渲染的物體座標進行計算的。紋理座標也是跟著物體座標的變換而變化的。最簡單生成方式是使用物體座標的x,y座標。如果一個點座標是acoords,那麼意味著會採用a_coords_xy作為紋理座標。這種簡單的對映對應朝向正z軸方向的多邊形來說是可行的,但對於在xy面的多邊形來說並沒有好的結果。結果可能如下圖:
來源:http://math.hws.edu/graphicsbook/c7/s3.html
可以看到的是正面的結果是正常的,而其他幾個面的結果就比較奇怪。這個問題的原因在於我們沒有對其他面紋理座標進行投影變換。
對於平的材質,多邊形上所有的法向量都是同一方向的,這個計算就可以在頂點著色器上完成;對於平滑的材質而言,每個點上的法向量都不太一樣,如果在不同的頂點上投影不同方向的紋理座標並進行插值,那麼結果很可能是一團糟的。因此這種情況就適合在片段著色器中計算。
程式式的紋理
程式式紋理是通過指定一個函式來計算值而不是選取已知的。在Webgl中程式式紋理定義在片段著色器中。採用vec2代表紋理座標而不是sampler2D。這也可以擴充套件到3D紋理,使用vec3。相比於二維紋理投影在平面點上,三維紋理是投影在空間中。
vec4 color;
float a = floor(v_texCoords.x * scale);
float b = floor(v_texCoords.y * scale);
if(mod(a+b, 2.0) > 0.5){
color = vec4(1.0, 0.5, .5, 1.0);
} else {
color = vec4(0.6, 0.6, 1.0, 1.0);
}複製程式碼
參考: