🎯 目标:贴纹理
在平面上贴纹理。
1. 读取纹理
参考资料:MDN 的 加载纹理
因为只画一次,所以绘图函数写在了加载图像的回调后,保证设置完后再绘制纹理。
function loadTexture(gl, shaderProgram, imageSrc) {
let texture = gl.createTexture();
let image = new Image();
image.src = imageSrc;
//加载完图像后执行的函数
image.onload = function () {
//绑定纹理
gl.bindTexture(gl.TEXTURE_2D, texture);
//指定二维纹理贴图,详细级别。颜色组件,数据格式,数据类型,数据源
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
//设置纹理在放大和缩小时候采用的采样方案。
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(
gl.TEXTURE_2D,
gl.TEXTURE_MIN_FILTER,
gl.LINEAR_MIPMAP_NEAREST
);
//生成 mipmap
gl.generateMipmap(gl.TEXTURE_2D);
//绑定纹理
gl.activeTexture(gl.TEXTURE0); //TEXTURE0 默认激活,注释掉也行
//传入纹理数据到着色器
gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
//绘制
gl.useProgram(shaderProgram);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
};
return texture;
}
2. 修改着色器
因为是逐像素传数据,所以先用attribute
型接受数据,然后传到varying
中以传入片段着色器中。
在片段着色器中使用sampler2D
类型承载GL_TEXTURE
对象。texture2D
获取纹理对应坐标上的颜色值。
const vertexSource = `
attribute vec2 aPosition;
attribute vec2 aTexCoord;
varying lowp vec2 vTexCoord;
void main(){
vTexCoord = aTexCoord;
gl_Position=vec4(aPosition,0.0,1.0);
}
`;
const fragmentSource = `
varying lowp vec2 vTexCoord;
uniform sampler2D uSampler;
void main(){
gl_FragColor = texture2D(uSampler,vTexCoord);
}
`;
3. 纹理映射
指定图形上显示的纹理的坐标,按照点的顺序来。
2020.09.13:这里正方形的点只写
x
和y
是因为上面的着色器里已经把z
设定了。半年过去自己都忘记了 😅。
//正方形的点
const vertices = [-0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5];
//纹理对应坐标
const tex = [0, 0, 0, 1, 1, 0, 1, 1];
上次写的一次性输入,这次分别绑定缓冲:
function simpleBindBuffer(gl, shaderProgram, name, data, size) {
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
const index = gl.getAttribLocation(shaderProgram, name);
gl.vertexAttribPointer(index, size, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(index);
return buffer;
}
//设置缓冲
simpleBindBuffer(gl, shaderProgram, "aPosition", vertices, 2);
simpleBindBuffer(gl, shaderProgram, "aTexCoord", tex, 2);
这样就能在平面上贴上纹理了。
4. 错误
generateMipmap: The base level of the texture does not have power-of-two dimensions.
webgl 1.0
只能给图片边长为 2 的幂的图片生成 mipmap, webgl 2.0
就没有这个问题。
使用 webgl 2.0
需要 const gl = canvas.getContext("webgl2")
。