# 一、纹理

​ 通过片元着色器一个一个像素给模型添加颜色费时费力,一般都是使用纹理贴图将图片贴在模型表面。

  1. 着色器上的代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const vertexCode = `
attribute vec4 a_Position;
//a_TexCoord接收纹理坐标,因为纹理是2维的所以使用vec2。
attribute vec2 a_TexCoord;
//向片元着色器传递纹理坐标。
varying vec2 v_TexCoord;
void main(){
gl_Position = a_Position;
v_TexCoord = a_TexCoord;
}
`
const fragmentCode = `
//涉及到片元颜色要开精度,这里找了半天。
precision mediump float;
//接收由顶点着色器传来的纹理坐标
varying vec2 v_TexCoord;
//sampler2D为二维纹理类型,用于采集纹素即纹理的颜色。
uniform sampler2D u_Sampler;
void main(){
//将顶点传递过来的v_TexCoord纹理坐标提取相应的纹素赋值给片元着色器上的颜色。
gl_FragColor = texture2D(u_Sampler,v_TexCoord);
}
`
  1. 获取图片
1
2
3
4
5
6
//注意webgl的图片存在跨域
const img = new Image()
img.src = './image/墙壁纹理.png'
img.onload=()=>{

}
  1. 与纹理对象的相关操作

这里的步骤有些类似于之前的创建缓冲区对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
img.onload=()=>{
/*
1.创建纹理对象
*/
const texture = gl.createTexture()
/*
2.开始y轴翻转
*/
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1)
/*
3.激活纹理对象
*/
//gl.TEXTURE[0-7],一个模型最后可以有8张贴图。
gl.activeTexture(gl.TEXTURE0)
/*
4.绑定纹理对象
*/
//与缓冲区对象一样,无法直接操作纹理对象,需要绑定,类似于es6的proxy。
gl.bindTexture(gl.TEXTURE_2D,texture)

/*
5.配置纹理对象,该过程决定了以一种什么样的方式对纹理进行映射。
gl.texParameteri(target, pname, param)
第一个参数为纹理类型,比如gl.TEXTURE_2D。
第二个参数主要有两类,一类是决定当纹理要放大或者缩小时,使用什么样的方式,另一类是设置环绕模式。
第一类分为以下两种情况
1.gl_TEXTURE_MAG_FILTER 当纹理像素小于模型像素也即纹理要放大时。
1.gl_LINEAR:默认值,取最近(指的是曼哈顿距离)四个像素的纹素的加权平均。这个模式效果好,但是耗费性能
2.gl_NEAREST:取最近一个像素的纹素。这个模式会出现锯齿,但是性能好。
2.gl_TEXTURE_MIN_FILTER 当纹理像素大于模型像素也即纹理要缩小的时候,有以下六种模式。
MIPMAP表示的是多级纹理映射。比如有一张512*512像素的图片,会生成256*256,128*128一直到1*1的图片,然后如果模型在512到256像素范围,
就会使用512以及256的图片以linear或者nearest的方式进行采集纹素。使用这个模式的话,最好保证图片的像素是2的幂次,同时在调用gl.texImage2D后,
调用gl.generateMipmap(gl.TEXTURE_2D)以生成不同像素大小的图片。
1.gl.LINEAR
2.gl.NEAREST
3.gl.NEAREST_MIPMAP_NEAREST
4.gl.LINEAR_MIPMAP_NEAREST
5.gl.NEAREST_MIPMAP_LINEAR (默认值)
6.gl.LINEAR_MIPMAP_LINEAR.
第二类指的是设置环绕模式。图片坐标,左下角为0.0,右上角为1.0,整个图片在0.0到1.0之间。如果取纹素的坐标超出这个范围就要用到这个模式
gl.TEXTURE_WRAP_[S,T]:s代表x轴,t代表y轴。
1.gl.REPEAT:重复纹理
2.gl.MIRRORED_REPEAT:镜像重复纹理,与REPEAT不同的是重复的纹理是镜像的
3.gl.CLAMP_TO_EDGE:超出的部分使用边缘的纹素。
*/
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.CLAMP_TO_EDGE)
/*
6.分配纹理图像
*/
/*
以下是webgl2.0的新的api
gl.texImage2D(target, level, internalformat, format, type, pixels)
1.target:纹理类型,gl.TEXTURE_2D。
2.level:纹理级别,越大越模糊,0为基本级别。
3.internalFormat:纹理数据的储存方式,比如gl.RGBA
4.format:数据格式比如gl.RGBA
5.type:数据的类型,比如gl.FLOAT
6.pixels:image dom对象。
*/
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img)
/*
7.将纹理传递给片元着色器
*/
const u_Sampler = gl.getUniformLocation(program,'u_Sample')
//第二个参数0表示的是用的是第一个贴图,一个模型最多可以有8个贴图。
gl.uniform1i(u_Sampler,0)

gl.clearColor(0.0,0.0,0.0,1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
//绘制矩形
gl.drawArrays(gl.TRIANGLE_STRIP,0,4)
}