
如图所示,这个demo加载了外部纹理图片,并映射到中间矩形上
纹理又称为纹理图像,就是用于贴在矩形表面的图片

纹理 又称为纹理图像,就是用于贴在矩形表面的图片。
纹理映射 就是将一张图像/贴纸映射到一个几何图形的表面上。
纹素 指的是组成纹理图像的像素。
纹理坐标 上图左变图像中的st(也称uv坐标系)坐标就是纹理坐标,纹理坐标是二维坐标,通过纹理坐标可以在纹理图像上获取纹素的颜色,从上图可知,纹理坐标实际上使用的是二维坐标系统的第一象限
坐标映射关系 纹理图像是如何贴到几何图形,是通过纹理图像的纹理坐标与几何图形的顶点坐标的映射关系确定的,如上图中纹理坐标(0.0,1.0)映射到几何图形的顶点P1,纹理坐标(0.0,0.0)映射到几何图形的顶点P2,纹理坐标(1.0,1.0)映射到几何图形的顶点P3,纹理坐标(1.0,0.0)映射到几何图形的顶点P4
函数功能:创建纹理对象
--------------------------------------------------------------------------
调用示例:gl.createTexture()
--------------------------------------------------------------------------
参数 无
--------------------------------------------------------------------------
返回值 non-null 创建的纹理对象
null 创建纹理对象失败
--------------------------------------------------------------------------
错 误 无
与之对应的有一个删除纹理对象的方法gl.deleteTexture(texture),用来删除纹理对象texture
函数功能:使用pname和param指定的方式处理和加载的纹理图像
--------------------------------------------------------------------------
调用示例:gl.pixelStorei(pname, param)
--------------------------------------------------------------------------
参数
pname 可以是以下二者之一
gl.UNPACK_FLIP_Y_WEBGL 对图像进行Y轴反转。默认值为false
gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL
将图像RGB颜色值的每一个分量乘以A默认值为false
param 指定非0(true)或0(false),必须为整数
--------------------------------------------------------------------------
返回值 无
--------------------------------------------------------------------------
错 误 INVALID_ENUM pname不是合法的值
————————————————
当需要使用多个纹理时,WebGL为我们提供了一种称作 纹理单元 的机制,每一个纹理单元有自己的编号,通过这个编号可以管理对应的纹理图像,即使只需要使用一张纹理图像,也需要指定一个纹理单元,使用纹理单元前需要借助 gl.activeTexture() 方法来激活纹理单元
函数功能:激活texUnit指定的纹理单元
--------------------------------------------------------------------------
调用示例:gl.activeTexture(texUnit)
--------------------------------------------------------------------------
参数
texUnit 指定纹理单元编号,gl.TEXTURE0,gl.TEXTURE1 ...
gl.TEXTURE7。最后的数字表示纹理单元的编号
--------------------------------------------------------------------------
返回值 无
--------------------------------------------------------------------------
错 误 INVALID_ENUM texUnit的值不合法
————————————————
我们已经知道在对缓冲区对象进行写入数据前,需要绑定缓冲区对象,同样在对纹理对象进行操作前,也需要绑定纹理对象。我们不能直接操作纹理对象,必须向将纹理对象绑定到纹理单元上,然后通过操作纹理单元来操作纹理对象。 gl.bindTexture() 函数就是WebGL提供的用来绑定纹理对象的方法
函数功能:开启texture指定的纹理对象,并将其绑定到target(目标)上,如果已经通过
gl.activeTexture()激活了某个纹理单元,则纹理对象会绑定到这个纹理单元上
--------------------------------------------------------------------------
调用示例:gl.bindTexture(target, texture)
--------------------------------------------------------------------------
参数
target gl.TEXTURE_2D或gl.TEXTURE_BUVE_MAP
分别代表二维纹理和立方体纹理
texture 要绑定的纹理对象
--------------------------------------------------------------------------
返回值 无
--------------------------------------------------------------------------
错 误 INVALID_ENUM target的值不合法
————————————————
绑定纹理对象后,我们还需要设置纹理图像映射到图形上的具体方式,如怎么获取纹素颜色,如何填充,这时我们需要用到 gl.texParameteri() 方法了
函数功能:将param的值赋给pname指定的参数上,并绑定到目标上
---------------------------------------------------------------------------------------
调用示例:gl.texParameteri(target, pname, param)
---------------------------------------------------------------------------------------
参数
target gl.TEXTURE_2D或gl.TEXTURE_BUVE_MAP
分别代表二维纹理和立方体纹理
pname 纹理参数,可选值:
gl.TEXTURE_MAG_FILTER 纹理放大方法,默认值gl.LINEAR
gl.TEXTURE_MIN_FILTER 纹理缩小方法,默认值gl.NEAREST_MIPMAP_LINEAR
gl.TEXTURE_WRAP_S 纹理水平填充,默认值gl.REPEAT
gl.TEXTURE_WRAP_T 纹理垂直填充,默认值gl.REPEAT
param 纹理参数的值,
当pname为gl.TEXTURE_MAG_FILTER或gl.TEXTURE_MIN_FILTER
可选值:
gl.NEAREST 使用原纹理上距离映射后像素(新像素)中心最近的那个
像素的颜色值,作为新像素的值
gl.LINEAR 使用距离新像素中心最近的四个像素的颜色的加权平均值,
作为新像素的值,图像效果更好,但开销较大
当pname为gl.TEXTURE_WRAP_S或gl.TEXTURE_WRAP_T
可选值:
gl.REPEAT 平铺式的重复纹理
gl.MIRRORED_REPEAT 镜像对称式的重复纹理
gl.CLAMP_TO_EDGE 使用纹理图像边缘值
---------------------------------------------------------------------------------------
返回值 无
---------------------------------------------------------------------------------------
错 误 INVALID_ENUM target的值不合法
INVALID_OPERATION 当前目标没有绑定纹理对象
————————————————
通过上面的介绍,你会发现纹理参数pname的每个可选值都有一个默认值,如果你不调用gl.texParameteri() 方法,也会使用默认值,需要注意的是 gl.TEXTURE_MIN_FILTER 纹理缩小方法的默认值是 gl.NEAREST_MIPMAP_LINEAR 这个默认值是一个被称为MIPMAP(金字塔)的纹理类型。实际上MIPMAP是一系列的纹理,它们包括:gl.NEAREST_MIPMAP_NEAREST、gl.LINEAR_MIPMAP_NEAREST、gl.NEAREST_MIPMAP_LINEAR、gl.LINEAR_MIPMAP_LINEAR
进入最后一步也是关键的一步,将纹理图像分配给纹理对象
函数功能:将image指定的图像分配给绑定到目标上的纹理对象
---------------------------------------------------------------------------------------
调用示例:gl.texImage2D(target, level, internalformat, format, type, image)
---------------------------------------------------------------------------------------
参数
target gl.TEXTURE_2D或gl.TEXTURE_BUVE_MAP
分别代表二维纹理和立方体纹理
level 传入0 (该参数用于金字塔纹理)
internalformat 图像的内部格式,可选值:
gl.RGB 红、绿、蓝
gl.RGBA 红、绿、蓝、透明度
gl.ALPHA (0.0,0.0,0.0,透明度)
gl.LUMINANCE L、L、L、1L:流明
gl.LUMINANCE_ALPHA L、L、L,透明度
format 纹理数据的格式,必须使用与internalformat相同的值
type 纹理数据的数据格式,可选值:
gl.UNSIGNED_TYPE 无符号整型,每个颜色分量占据1字节
gl.UNSIGNED_SHORT_5_6_5 RGB:每个分量分别占据5、6、5比特
gl.UNSIGNED_SHORT_4_4_4_4 RGBA:每个分量都占据4比特
gl.UNSIGNED_SHORT_5_5_5_1 RGBA:每个分量分别占据5、5、5、1比特
image 包含纹理图像的Image对象
---------------------------------------------------------------------------------------
返回值 无
---------------------------------------------------------------------------------------
错 误 INVALID_ENUM target的值不合法
INVALID_OPERATION 当前目标没有绑定纹理对象
————————————————
const VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
void main() {
gl_Position = a_Position;
v_TexCoord = a_TexCoord;
}
`;
const FSHADER_SOURCE = `
precision mediump float;
uniform sampler2D u_Sampler;
varying vec2 v_TexCoord;
void main() {
//texture2D抽取文素颜色
gl_FragColor = texture2D(u_Sampler,v_TexCoord);
}
`;
// 图片加载
function loadImage(url) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.onload = () => {
resolve(img);
};
img.onerror = (e) => {
console.error("Failed to load image!");
reject(e);
};
img.src = url;
});
}
const initTextures = (gl, n, img) => {
// 创建纹理对象
const texture = gl.createTexture();
// 获取纹理变量的存储位置
const u_Sampler = gl.getUniformLocation(gl.program, "u_Sampler");
//对纹理进行Y轴反转
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
//开启0号纹理单元
gl.activeTexture(gl.TEXTURE0);
//向target绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D, texture);
//配置纹理参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
//配置纹理图像
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_SHORT_5_6_5, img);
//将0号纹理传递给着色器
gl.uniform1i(u_Sampler, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
};
const main = () => {
//获取绘制dom
const canvas = document.getElementById("webgl");
//获取canvas上下文
const gl = canvas.getContext("webgl");
//初始化着色器
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
return console.log("Failed to initialize shaders.");
}
const initVertexBuffers = (gl) => {
//类型化数组设置顶点坐标
const vertices = new Float32Array([
-0.5, 0.5, 0.3, 0.7, -0.5, -0.5, 0.3, 0.2, 0.5, 0.5, 0.7, 0.7, 0.5, -0.5,
0.7, 0.2,
]);
const n = 4; //点的个数
//创建缓冲区对象
const vertexTexCoordBuffer = gl.createBuffer();
if (!vertexTexCoordBuffer) {
console.log("Failed to create the buffer object");
return -1;
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
//向缓冲区对象中写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
const a_TexCoord = gl.getAttribLocation(gl.program, "a_TexCoord");
if (a_Position === -1 || !a_TexCoord === -1) {
console.error("Failed to get the attribute location!");
return;
}
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 4 * 4, 0);
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, 4 * 4, 4 * 2);
//链接a_Position变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);
gl.enableVertexAttribArray(a_TexCoord);
return n;
};
const n = initVertexBuffers(gl);
if (n < 0) {
console.error("n<0");
return;
}
//图片加载成功后 => 进行纹理加载
loadImage("../static/sky.jpg").then(function (img) {
initTextures(gl, n, img);
});
};
main();
为了更好的理解纹理坐标系与顶点坐标系映射关系,调整一下纹理坐标,更方便我们理解纹理是如何映射到几何体上的