概念
纹理映射能为图像添加上皮肤,将一张图片或者图像映射到几何图形上,其作用是根据纹理图像,为之前光栅化的每个片元涂上颜色 (组成纹理图像的像素又被称为纹素)
纹理坐标系(左) 与 图片坐标系(右)
在纹理坐标系中,向上为y轴的正方向,图片坐标系则相反
纹理坐标系是理想状态,实际渲染纹理时 webgl 使用的图片坐标系。因此在向缓冲区对象中传递几何图形的点位和纹理图像的点位时,应该使用图片坐标系作为参考。
取样器类型
取样器只能是 uniform 变量,唯一能给取样器变量赋值的是纹理单元编号,必须使用 gl.uniform1i()赋值
sampler2D - 2维平面取样器
samplerCube - 3维取样器
/* fragmentShader */
precision mediump float;
uniform sampler2D u_sampler;
varying vec2 v_textureCoord;
void main() {
gl_FragColor = texture2D(u_sampler, v_textureCoord);
}
纹理单元
webgl通过一种叫纹理单元的机制来同时使用多个纹理,每个纹理单元有一个单元编号来管理一张纹理图像。即使当前程序只需要一个纹理,也需要为其指定一个纹理单元。
系统支持的纹理单元数取决于硬件和浏览器的webgl实现,默认情况下webgl支持8个纹理单元,一些其他系统支持的更多。内置变量 gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2…, gl.TEXTURE7各表示一个纹理单元。
webgl API
实现纹理映射的大致过程
1.准备纹理图像 - new Image()
2.配置纹理映射方式 - 将纹理图像如何放置在图形上
3.加载纹理图像,并对其配置,以在webgl中使用
4.在片元着色器中将相应的纹素从纹理中取出,并将纹素的颜色赋给片元
webgl立方体纹理
加载立方体纹理素材
async function delay(texture, target, index) {
return new Promise((resolve, reject) => {
texture.image.onload = function () {
gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
resolve(texture);
}
})
}
/**
*
* @param {*} 立体纹理图片地址
* @returns
*/
async function initCubeTexture(gl, dataArr) {
var texture;
texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
for (let index = 0; index < dataArr.length; index++) {
let data = dataArr[index];
let target = data.target;
texture.image = new Image();
texture.image.src = data.imgurl;
texture = await delay(texture, target, index);
}
handleLoadedCubeTexture(gl, texture, dataArr, texture.image);
return texture;
}
/**
*
* @param {*} 立体纹理
*/
function handleLoadedCubeTexture(gl, texture, dataArr, image) {
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
}
纹理赋值
uniformTexture = gl.getUniformLocation(gl.program, "qpicture");
gl.uniform1i(uniformTexture, 0);
shader纹理赋值
uniform samplerCube qpicture;
vec4 texturecolor = textureCube(qpicture, normalize(v_normal));