在 WebGL 中使用纹理贴图 (texture)

加载纹理

首先加入加载纹理的代码。现在我们只使用一张单一的纹理贴到立方体的 6 个面上,但是同样的方法可以用来加载任意数量的纹理贴图。

加载纹理的代码如下:

function initTextures() {
  cubeTexture = gl.createTexture();
  cubeImage = new Image();
  cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }
  cubeImage.src = "cubetexture.png";
}

function handleTextureLoaded(image, texture) {
  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);
  gl.generateMipmap(gl.TEXTURE_2D);
  gl.bindTexture(gl.TEXTURE_2D, null);
}

函数 initTextures() 首先调用 GL createTexture() 函数来创建一个 GL 纹理对象 cubeTexture。为了把图片文件加载到纹理,代码首先创建了一个 Image 对象然后把需要当作纹理使用的图形文件加载了进来。当图片加载完成后回调函数 handleTextureLoaded() 就会执行。

接下来为了真正地形成纹理,我们通过把新创建的纹理对象绑定到 gl.TEXTURE_2D 来让它成为当前操作纹理。然后通过调用 texImage2D() 把已经加载的图片图形数据写到纹理。

代码的接下来两行设置了纹理过滤器,过滤器用来控制当图片缩放时像素如何生成如何插值。在这个例子里,我们对图片放大使用的是线性过滤,而对图片缩小使用的是多级渐进纹理过滤。接下来我们通过调用 generateMipMap() (en-US) 来生成多级渐进纹理,接着通过给 gl.TEXTURE_2D 绑定值 null 来告诉 WebGL 我们对当前纹理的操作已经结束了。

非 2 的幂纹理

一般来说,宽和高都是 2 的幂的纹理使用是最理想的。2 的幂纹理在渲染内存里的存储更高效,而且对它们的使用限制也更少。由美术工作人员生成的纹理最终在用来渲染前都应该使用放大或缩小的方式把它生成为 2 的幂纹理,其实事实上来说,在创作纹理之初就应该直接使用大小是 2 的幂的宽和高。纹理的每一边都应该是像 1,2,4,8,16,32,64,128,256,512,1024 或 2048 这样的值。当然也要注意尺寸的大小,因为虽说现在的大部分设置都已经可以支持 4096 像素的图片,但也不是全部;而有一些设备甚至可以支持 8192 或更高像素呢。

有的时候从你的特定情况出发,使用 2 的幂纹理会比较困难。当使用到第三方的资源时,一般来说最好的方式就是先使用 HTML5 的画布把图片修正成 2 的幂然后再放到 WebGL 中进行渲染使用,这样一来,如果图片拉伸比较明显的话纹理坐标的值可需要适当地进行修正。

但是,如果你一定要使用非 2 的幂纹理的话,WebGL 也有原生支持,不过这些支持是受限的。当然在某些情况下使用非 2 的幂纹理也是很有用的,比如这张纹理刚好与你的显示器的分辨率相匹配,或者使用画布重新生成纹理的方式并不值得时。但是要特别注意的是:这种非 2 的幂纹理不能用来生成多级渐进纹理,而且不能使用纹理重复(重复纹理寻址等)。

使用重复纹理寻址的一个例子就是使用一张砖块的纹理来平铺满一面墙壁。

多级渐进纹理和纹理坐标重复可以通过调用 texParameteri() 来禁用,当然首先你已经通过调用 bindTexture() 绑定过纹理了。这样虽然已经可以使用非 2 的幂纹理了,但是你将无法使用多级渐进纹理,纹理坐标包装,纹理坐标重复,而且无法控制设备如何处理你的纹理。

// gl.NEAREST is also allowed, instead of gl.LINEAR, as neither mipmap.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// Prevents s-coordinate wrapping (repeating).
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// Prevents t-coordinate wrapping (repeating).
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

现在,当使用以上参数时,兼容 WebGL 的设备就会自动变得可以使用任何分辨率的纹理(当然还要考虑像素上限)。如果不使用上面这些参数的话,任何非 2 的幂纹理使用都会失败然后返回一张纯黑图片。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值