ThreeJS像素扭曲效果开发:解决纹理更新无图像数据警告
解决ThreeJS DataTexture更新警告问题
问题根源
触发THREE.WebGLRenderer : Texture marked for update but no image data found警告的核心原因是:DataTexture的数据未完全初始化,加上纹理数据访问索引错误,导致WebGL无法识别有效的纹理图像数据。
修复步骤
1. 完整初始化DataTexture数据
当前regenerateGrid函数只填充了前size*4个元素,但RGBA格式的DataTexture需要size*size*4个数据点。修改循环逻辑,遍历所有像素完成初始化:
function regenerateGrid(){ size = settingsItem.grid; width = size; height = size; const newSize = width * height; const data = new Float32Array(4 * newSize); const a = 255; // 遍历所有纹理像素,完整初始化RGBA数据 for (let j = 0; j < size; j++) { for (let i = 0; i < size; i++) { let r = Math.random() * 255 - 125; let r1 = Math.random() * 255 - 125; // 计算RGBA格式的正确索引:4*(列 + 行*宽度) const stride = 4 * (i + size * j); data[stride] = r; data[stride + 1] = r1; data[stride + 2] = r; data[stride + 3] = a; } } textureData = new THREE.DataTexture(data, width, height, THREE.RGBAFormat, THREE.FloatType); textureData.magFilter = textureData.minFilter = THREE.NearestFilter; textureData.needsUpdate = true; // 初始化时触发更新 if(material) { material.uniforms.uDataTexture.value = textureData; } }
2. 修复纹理数据索引计算
updateDataTexture中错误使用3倍索引(对应RGB格式),但我们用的是RGBA格式,需改为4倍索引,避免数据越界:
function updateDataTexture() { let data = textureData.image.data; // 步长改为4,对应RGBA四个通道 for (let i = 0; i < data.length; i += 4) { data[i] *= settingsItem.relaxation; data[i+1] *= settingsItem.relaxation; } let gridMouseX = size * mouse.x; let gridMouseY = size * (1 - mouse.y); let maxDist = size * settingsItem.mouse; let aspect = height / width; for (let i = 0; i < size; i++) { for (let j = 0; j < size; j++) { let distance = ((gridMouseX - i) ** 2) / aspect + (gridMouseY - j) ** 2; let maxDistq = maxDist ** 2; if (distance < maxDistq) { // 修复为RGBA格式的索引计算 let index = 4 * (i + size * j); let power = maxDist / Math.sqrt(distance); power = clamp(power, 0, 10); data[index] += settingsItem.strength * 100 * mouse.vX * power; data[index + 1] -= settingsItem.strength * 100 * mouse.vY * power; } } } mouse.vX *= 0.9; mouse.vY *= 0.9; textureData.needsUpdate = true; }
3. 移除冗余的纹理更新操作
TextureLoader.load会自动处理纹理加载与更新,无需手动设置texture.needsUpdate = true,删除这行冗余代码:
function addObjects() { regenerateGrid(); let textureLoader = new THREE.TextureLoader(); texture = textureLoader.load(img.src); // 移除下面这行代码 // texture.needsUpdate = true; // ... 其余代码保持不变 }
4. 传递正确的分辨率给着色器
在渲染循环中更新uniforms.resolution,确保UV计算匹配画布尺寸:
function render(){ if (!isPlaying) return; time += 0.05; updateDataTexture(); material.uniforms.time.value = time; // 传递画布尺寸及逆尺寸给着色器 material.uniforms.resolution.value.set(width, height, 1/width, 1/height); requestAnimationFrame(render.bind(this)); renderer.render(scene, camera); }
额外优化
避免在regenerateGrid中覆盖全局width/height变量(该变量存储画布尺寸),改用局部变量存储纹理尺寸,防止混淆:
function regenerateGrid(){ const gridSize = settingsItem.grid; const texWidth = gridSize; const texHeight = gridSize; const newSize = texWidth * texHeight; const data = new Float32Array(4 * newSize); // ... 后续代码将width/height替换为texWidth/texHeight }
内容的提问来源于stack exchange,提问作者Maël Ar
相关产品推荐
相关产品推荐

