如何访问纹理的自定义LOD?WebGL指定LOD参数未生效问题
问题原因与解决办法
核心问题
你遇到的情况是因为WebGL 1.0中,当纹理的TEXTURE_MIN_FILTER设置为NEAREST或LINEAR(默认值为LINEAR)时,片元着色器中texture2D的第三个LOD参数会被忽略,渲染时会直接使用最精细的LOD层级(即LOD 0),不管你指定的LOD值是多少。
解决步骤
要让手动指定的LOD参数生效,需要做两个关键设置:
修改纹理的最小过滤模式为支持Mipmap的类型
必须将TEXTURE_MIN_FILTER设置为以下值之一:gl.NEAREST_MIPMAP_NEARESTgl.NEAREST_MIPMAP_LINEARgl.LINEAR_MIPMAP_NEARESTgl.LINEAR_MIPMAP_LINEAR
(可选但推荐)明确纹理的最大LOD层级
因为你只上传了LOD 0和LOD 1,显式设置TEXTURE_MAX_LEVEL为1,可以避免WebGL尝试访问不存在的更高层级,提升性能。
修改后的关键代码片段
在上传完两个LOD纹理的代码之后,添加以下参数设置:
// 设置支持Mipmap的最小过滤模式 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); // 明确最大LOD层级 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 1); // 设置纹理包裹模式(避免UV越界问题) 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);
完整修改后的代码
<html> <head> </head> <body> <canvas id="canvas" height="400" width="400" style="border: 1px solid black;"></canvas> </body> <script> const vs = ` attribute vec4 a_position; void main() { gl_Position = a_position; } `; const fs = ` precision mediump float; uniform sampler2D tex; float width = 400.0; void main() { gl_FragColor = texture2D(tex, vec2(0.5, 0.5), 1.0); } `; const canvas = document.getElementById('canvas'); const gl = canvas.getContext('webgl'); const vShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vShader, vs); gl.compileShader(vShader); const fShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fShader, fs); gl.compileShader(fShader); const program = gl.createProgram(); gl.attachShader(program, vShader); gl.attachShader(program, fShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (!success) { console.log(gl.getProgramInfoLog(program)); } const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const pixels = [ 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, ]; const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); // LOD 0 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8ClampedArray(pixels)); // LOD 1 gl.texImage2D(gl.TEXTURE_2D, 1, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8ClampedArray([0, 255, 0, 255])); // 新增纹理参数设置 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 1); 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); const positions = [ -0.7, -0.5, 0.7, -0.5, 0, .5, ] gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.lineWidth(50.0); gl.useProgram(program); gl.enableVertexAttribArray(positionAttributeLocation); gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLE_FAN, 0, 3); </script> </html>
原理说明
WebGL的纹理过滤逻辑中,只有当最小过滤模式启用Mipmap时,才会考虑LOD参数。默认的LINEAR或NEAREST过滤模式是为无Mipmap的纹理设计的,此时会强制使用最高分辨率的LOD层级,忽略所有手动指定的LOD值。
内容的提问来源于stack exchange,提问作者teddybeard
相关产品推荐
相关产品推荐

