为什么自定义的纹理没有显示出来?这是因为 WebGL 对纹理有一种严格的限制,在两个维度上都不是 2 的幂。2 的幂是1,2,4,8,16,32,64,128,256,512,1024,2048,等等。假如 3D 物体的面长宽是 256 x 256。256 是 2 的幂,而自定义的纹理图的长宽为 320 x 240。这两个都不是2的幂,因此尝试显示纹理时会显示失败。在着色器中,当调用 texture2D 并且引用的纹理设置不正确时,WebGL 将使用黑色的颜色(0,0,0,1)代替纹理。
解决方案:
要解决这个问题,我们需要设置 wrap mode
为 CLAMP_TO_EDGE
,并且设置 filtering
为 LINEAR
或者 NEAREST
,这样就关闭了 mip mapping
。代码如下:
import fTextureImg from '../../assets/f-texture.jpg' // ... 中间其他代码 ... // Create a texture. const texture = gl.createTexture() gl.bindTexture(gl.TEXTURE_2D, texture) // Fill the texture with a 1x1 blue pixel. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255])) AsynLoadImage(fTextureImg, (image) => { // Now that the image has loaded make copy it to the texture. gl.bindTexture(gl.TEXTURE_2D, texture) gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image) /*** 下面是解决纹理渲染失败的关键代码 ***/ // Check if the image is a power of 2 in both dimensions. if (isPowerOf2(image.width) && isPowerOf2(image.height)) { // Yes, it's a power of 2. Generate mips. gl.generateMipmap(gl.TEXTURE_2D) } else { // No, it's not a power of 2. Turn off mips and set wrapping to clamp to edge 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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) } drawScene() }) // 下面是用到的自定义的函数 function isPowerOf2 (value) { return (value & (value - 1)) === 0 } function AsynLoadImage (url, cb) { const img = new Image() img.src = url if (img.complete) { cb(img) return } img.onload = function () { img.onload = null cb(img) return }; img.onerror = function () { img.onerror = null cb(img) } }
附录:
WebGL API 的 WebGLRenderingContext.texParameter[fi]()
方法用于设置纹理参数.
void gl.texParameterf(GLenum target, GLenum pname, GLfloat param);
void gl.texParameteri(GLenum target, GLenum pname, GLint param);
target 是 GLenum 指定绑定点(目标)。可能的值:
gl.TEXTURE_2D
: 二维纹理.
gl.TEXTURE_CUBE_MAP
: 立方体纹理.
当使用 WebGL 2 context 时,还可以使用以下值
gl.TEXTURE_3D
: 三维贴图.
gl.TEXTURE_2D_ARRAY
: 二维数组贴图.
pname
参数是 Glenum 指定要设置的纹理参数. param
参数是 GLfloat 或 GLint 已指定的 pname
参数的值。
pname |
描述 | 参数 |
---|---|---|
Available in WebGL 1 | ||
gl.TEXTURE_MAG_FILTER |
纹理放大滤波器 | gl.LINEAR (默认值), gl.NEAREST . |
gl.TEXTURE_MIN_FILTER |
纹理缩小滤波器 | gl.LINEAR , gl.NEAREST , gl.NEAREST_MIPMAP_NEAREST , gl.LINEAR_MIPMAP_NEAREST , gl.NEAREST_MIPMAP_LINEAR (默认值), gl.LINEAR_MIPMAP_LINEAR . |
gl.TEXTURE_WRAP_S |
纹理坐标水平填充 s |
gl.REPEAT (默认值),gl.CLAMP_TO_EDGE , gl.MIRRORED_REPEAT . |
gl.TEXTURE_WRAP_T |
纹理坐标垂直填充 t |
gl.REPEAT (默认值),gl.CLAMP_TO_EDGE , gl.MIRRORED_REPEAT . |
Additionally available when using the EXT_texture_filter_anisotropic extension |
||
ext.TEXTURE_MAX_ANISOTROPY_EXT |
纹理最大向异性 | GLfloat 值. |
Additionally available when using a WebGL 2 context | ||
gl.TEXTURE_BASE_LEVEL |
纹理映射等级 | 任何整型值. |
gl.TEXTURE_COMPARE_FUNC |
纹理对比函数 | gl.LEQUAL (默认值), gl.GEQUAL , gl.LESS , gl.GREATER , gl.EQUAL , gl.NOTEQUAL , gl.ALWAYS , gl.NEVER . |
gl.TEXTURE_COMPARE_MODE |
纹理对比模式 | gl.NONE (默认值), gl.COMPARE_REF_TO_TEXTURE . |
gl.TEXTURE_MAX_LEVEL |
最大纹理映射数组等级 | 任何整型值. |
gl.TEXTURE_MAX_LOD |
纹理最大细节层次值 | 任何整型值. |
gl.TEXTURE_MIN_LOD |
纹理最小细节层次值 | 任何浮点型值. |
gl.TEXTURE_WRAP_R |
纹理坐标r 包装功能 |
gl.REPEAT (默认值), gl.CLAMP_TO_EDGE , gl.MIRRORED_REPEAT . |
参考引用:
https://webglfundamentals.org/webgl/lessons/webgl-3d-textures.html
https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/texParameter