一.简介
在我们使用纹理的过程中,经常会遇到纹理过大或者过小的情况,纹理过大会使得一个pixel内对应多个tixel,会生成摩尔纹,如下图所示,而纹理过小则会产生马赛克,本节先记录纹理过大时的解决情况
二.在webgl中如何设置
2.1.创建一个纹理
js
function initTexture(gl,image){
var texture=gl.createTexture()
//获取纹理存储位置
var u_Sampler=gl.getUniformLocation(gl.program, 'u_Sampler')
//y轴翻转
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
// //设置一次读取一字节
// const alignment =1;
// gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);
//开启0号纹理单元
gl.activeTexture(gl.TEXTURE0)
//想target绑定纹理单元
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_MIN_FILTER,gl.LINEAR)
//当纹理过小时采样方法设置
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR)
//将纹理传递给着色器
gl.uniform1i(u_Sampler,0)
}
在webgl1中要求纹理图片宽高为2的n次幂,在webgl2中无此要求
这儿使用了一个2048*2048分辨率的图片,效果如下:
可以看到,已经产生了摩尔纹
2.2. MipMAP(多级渐远纹理)
采样会引起走样,那么我们不采样,只得到一定范围的平均值。
这是点查询与范围查询的问题
- 点查询,给出一个点,得到一个点的值
- 范围查询,不采样,给出一个区域,得到区域的(平均)值
Mipmap 多级渐远纹理 可以进行快速的范围查询,但是是近似的,并且只有方形
2.3 在webgl中产生MipMap
js
gl.generateMipmap(gl.TEXTURE_2D)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR_MIPMAP_LINEAR)
在webgl1中,
gl.TEXTURE_MIN_FILTER
默认值为gl.NEAREST_MIPMAP_LINEAR
,即要求默认打开MipMap
,因此在上面2.1代码中,如果不设置为gl.LINEAR
,会出不来效果
pname |
Description | param |
---|---|---|
Available in WebGL 1 | ||
gl.TEXTURE_MAG_FILTER |
Texture magnification filter | gl.LINEAR (default value), gl.NEAREST . |
gl.TEXTURE_MIN_FILTER |
Texture minification filter | gl.LINEAR , gl.NEAREST , gl.NEAREST_MIPMAP_NEAREST , gl.LINEAR_MIPMAP_NEAREST , gl.NEAREST_MIPMAP_LINEAR (default value), gl.LINEAR_MIPMAP_LINEAR . |
效果如下:
2.4 各向异性过滤
Mipmap会把远处的细节都模糊掉 因为它只能查询方块的区域内,以及插值毕竟只是近似
-
解决三线性插值的方法就是各向异性过滤
-
方块的近似有时候太过勉强,如下图纹理映射后奇形怪状的
- Mipmap做的是方块的 也就是下图左上角的图,但是不方正的压缩做不了
-
各向异性过滤允许我们对长条的区域进行范围查询,但是对于斜着的区域,不行 生成各向异性过滤的图(Ripmaps)的开销是原本的三倍 各向异性的意思是,在不同的方向上它的表现各不相同 各向异性的几X是压缩几倍,也就是从左上角往右下角多几层
-
EWA过滤,把任意不规则的形状拆成很多不同的圆形,去覆盖这个形状 多次查询自然可以覆盖,但是耗时大
2.5 webgl启用各向异性过滤
- 获取扩展
js
// 获取扩展对象
var ext = gl.getExtension('EXT_texture_filter_anisotropic');
if (!ext) {
console.log("Anisotropic filtering extension is not available.");
}
......
// 设置纹理参数,启用各向异性过滤
gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 16); // 设置各向异性级别,可以是任意正数
效果如下:
3.MipMap可视化
下面使用自定义设置层级,将MipMap可视化,从1级到11级从蓝色到红色,可以查看mipMap层级,代码如下:
js
function initTexture(gl,image){
var texture=gl.createTexture()
//获取纹理存储位置
var u_Sampler=gl.getUniformLocation(gl.program, 'u_Sampler')
//y轴翻转
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
// //设置一次读取一字节
// const alignment =1;
// gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);
//开启0号纹理单元
gl.activeTexture(gl.TEXTURE0)
//想target绑定纹理单元
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image)
gl.generateMipmap(gl.TEXTURE_2D)
//配置纹理图像
gl.texImage2D(gl.TEXTURE_2D, 1, gl.RGBA,1024,1024,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(1024,lerpColor(1)))
gl.texImage2D(gl.TEXTURE_2D, 2, gl.RGBA,512,512,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(512,lerpColor(2)))
gl.texImage2D(gl.TEXTURE_2D, 3, gl.RGBA,1256,1256,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(256,lerpColor(3)))
gl.texImage2D(gl.TEXTURE_2D, 4, gl.RGBA,128,128,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(128,lerpColor(4)))
gl.texImage2D(gl.TEXTURE_2D, 5, gl.RGBA,64,64,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(64,lerpColor(5)))
gl.texImage2D(gl.TEXTURE_2D, 6, gl.RGBA,32,32,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(32,lerpColor(6)))
gl.texImage2D(gl.TEXTURE_2D, 7, gl.RGBA,16,16,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(16,lerpColor(7)))
gl.texImage2D(gl.TEXTURE_2D, 8, gl.RGBA,8,8,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(8,lerpColor(8)))
gl.texImage2D(gl.TEXTURE_2D, 9, gl.RGBA,4,4,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(4,lerpColor(9)))
gl.texImage2D(gl.TEXTURE_2D, 10, gl.RGBA,2,2,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(2,lerpColor(10)))
gl.texImage2D(gl.TEXTURE_2D, 11, gl.RGBA,1,1,0, gl.RGBA,gl.UNSIGNED_BYTE,createColorArray(1,lerpColor(11)))
//配置纹理参数
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR_MIPMAP_LINEAR)
// gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_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);
//设置纹理参数,启用各向异性过滤
gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 16); // 设置各向异性级别,可以是任意正数
//将纹理传递给着色器
gl.uniform1i(u_Sampler,0)
}
使用了各向异性之后:
不使用:
由此看出,各向异性使用之后只有在压缩很严重的情况下才会使用较小纹理采样