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

THREE.js相机旋转完成后物体闪烁问题排查求助

问题分析与修复方案

你的纹理闪烁、物体短暂消失问题,核心来自重复渲染冲突、场景重复初始化、纹理异步加载未处理这几个关键点,以下是具体修复步骤:


1. 移除重复渲染调用,修复主动画循环

原animate函数里重复调用requestAnimationFrame和renderer.render,导致帧渲染冲突,且deltaTime未做单位转换(毫秒转秒),旋转速度异常。修改为:

let lastTime = 0;
const animate = (time: number) => {
  const deltaTime = (time - lastTime) * 0.001; // 毫秒转秒,控制旋转速度
  lastTime = time;

  shapesRef.current.forEach((shape) => {
    shape.rotation.y += 0.002 * deltaTime;
    shape.rotation.z += 0.003 * deltaTime;
  });
  
  renderer.render(sceneRef.current!, cameraRef.current!);
  requestAnimationFrame(animate);
};

同时要把核心对象存入useRef,确保跨useEffect访问:

const sceneRef = useRef<THREE.Scene | null>(null);
const cameraRef = useRef<THREE.PerspectiveCamera | null>(null);
const shapesRef = useRef<THREE.Mesh[]>([]);

// 初始化时赋值
sceneRef.current = new THREE.Scene();
cameraRef.current = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建完物体后赋值
shapesRef.current = shapes;

2. 避免切换索引时重建整个场景

原useEffect依赖currentIndex,导致每次切换都会销毁旧场景、创建新场景,这是闪烁的核心原因。调整依赖项,只初始化一次场景:

// 主初始化useEffect,仅执行一次
useEffect(() => {
  // URL清理、WebGL检查、场景/相机/渲染器初始化代码保留
  // 纹理加载、物体创建逻辑移到异步加载部分(见步骤4)

  // 事件监听、resize处理、清理函数不变
}, [router]); // 仅保留router作为依赖,因为URL处理需要它

// 单独监听currentIndex变化,更新相机和音频
useEffect(() => {
  updateAudio(currentIndex);
  updateCameraRotation();
}, [currentIndex]);

同步修改updateCameraRotation,让它能访问cameraRef:

const updateCameraRotation = () => {
  const camera = cameraRef.current;
  if (!camera) return;
  
  const numShapes = shapesRef.current.length;
  const anglePerShape = (Math.PI * 2) / numShapes;
  let angle = (currentIndex / numShapes) * Math.PI * 2;

  if (numShapes % 2 !== 0) {
    angle -= anglePerShape / 2;
  }

  camera.rotation.y = -angle;
};

3. 修复相机旋转动画,避免与主循环冲突

原animateCameraRotation手动调用render,和主动画循环的渲染冲突,导致帧错乱。改成仅更新相机状态,让主循环负责渲染:

const animateCameraRotation = (
  startAngle: number,
  endAngle: number,
  callback: () => void
) => {
  const duration = 500;
  const startTime = performance.now();

  const animateStep = (time: number) => {
    const elapsed = time - startTime;
    const progress = Math.min(elapsed / duration, 1);
    const camera = cameraRef.current;
    if (camera) {
      camera.rotation.y = THREE.MathUtils.lerp(startAngle, endAngle, progress);
    }

    if (progress < 1) {
      requestAnimationFrame(animateStep);
    } else {
      callback();
      updateCameraRotation(); // 确保最终位置精准
    }
  };

  requestAnimationFrame(animateStep);
};

移除renderer.clearDepth()和renderer.render调用,主循环会自动处理渲染流程。


4. 处理纹理异步加载,确保就绪后再渲染

TextureLoader.load是异步操作,原代码直接创建网格,可能纹理未加载完成就渲染,导致纹理闪烁或缺失。改成等待所有纹理加载完成后再创建物体:

// 封装纹理加载为异步函数
const loadTextures = async () => {
  const textureLoader = new THREE.TextureLoader();
  const textureUrls = [
    "/images/window.jpg",
    "/images/plant.JPG",
    "/images/doodle.jpg",
    "/images/cyclops.png",
    "/images/dualwield.png",
  ];

  return Promise.all(
    textureUrls.map(url => 
      new Promise<THREE.Texture>((resolve) => {
        textureLoader.load(url, resolve);
      })
    )
  );
};

// 在主useEffect中调用
loadTextures().then(textures => {
  const numShapes = textures.length;
  // 创建所有物体
  for (let i = 0; i < numShapes; i++) {
    const geometry = new THREE.BoxGeometry(0.3, 4, 4);
    const material = new THREE.MeshStandardMaterial({ map: textures[i] });
    const shape = new THREE.Mesh(geometry, material);
    shape.renderOrder = i;
    
    const angle = (i / numShapes) * Math.PI * 2;
    shape.position.x = Math.sin(angle) * 10;
    shape.position.z = Math.cos(angle) * 10;
    shape.lookAt(new THREE.Vector3(0, 0, 0));
    
    sceneRef.current!.add(shape);
    shapesRef.current.push(shape);
  }

  // 初始化相机位置和旋转
  updateCameraRotation();
  // 纹理加载完成后启动动画循环
  animate(0);
});

5. 清理冗余渲染器设置

移除renderer.clear(),因为autoClear默认值为true,渲染器会在每次render前自动清除缓冲,手动调用会导致额外的清除操作。


以上修改后,能彻底解决纹理闪烁、物体消失的问题——屏幕越大,渲染冲突的影响越明显,修复重复渲染和场景重复初始化是解决问题的核心。

内容的提问来源于stack exchange,提问作者dagnym

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:35:54