webgl 纹理进阶(一) MipMap与RipMap(各向异性过滤)

一.简介

在我们使用纹理的过程中,经常会遇到纹理过大或者过小的情况,纹理过大会使得一个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)

}

使用了各向异性之后:

不使用:

由此看出,各向异性使用之后只有在压缩很严重的情况下才会使用较小纹理采样

相关推荐
熊的猫11 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn18 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
四喜花露水1 小时前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust2 小时前
css:基础
前端·css
帅帅哥的兜兜2 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
yi碗汤园2 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称2 小时前
购物车-多元素组合动画css
前端·css
编程一生2 小时前
回调数据丢了?
运维·服务器·前端