You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:24:58