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

Three Fiber Canvas移动端部分白屏问题求助(GitHub Pages部署)

问题描述

我在GitHub Pages上部署了一个作品集网站,使用Three.js/React Three Fiber创建了15个Canvas展示技术技能。但移动端访问时,有7个Canvas显示白屏,8个正常;桌面端访问所有Canvas均能正常工作。移动端显示截图:移动端白屏截图

相关代码如下:

import { Canvas } from '@react-three/fiber';
import {
    Decal,
    Float,
    OrbitControls,
    PerformanceMonitor,
    Preload,
    useTexture,
  } from '@react-three/drei';

 import Loader from '../Loader';
 

import { Suspense, lazy, useState } from 'react';

const Ball = (props:any) => {

    const [decal] = useTexture([props.imgUrl]);

  return (<Float speed={2.5} rotationIntensity={1} floatIntensity={2}>
        <ambientLight intensity={0.25} />
        <directionalLight position={[0, 0, 0.05]} />
        <mesh castShadow receiveShadow scale={2.75}>
        <icosahedronGeometry args={[1, 2]} />
        <meshStandardMaterial
          color="#3d3d3d"
          polygonOffset
          polygonOffsetFactor={-5}
          flatShading
        />
        <Decal
          position={[0, 0, 1]}
          rotation={[2 * Math.PI, 0, 6.25]}
          flatShading
          map={decal}
        />
      </mesh>
    </Float>
  )
}

const BallCanvas = ({ icon }:any) => {

  const [dpr, setDpr] = useState(1.5)
  
    return (
      <Canvas frameloop="always"
      // shadows
      // camera={{position: [20, 3, 5]}}
      // resize={{scroll:false}}
      dpr={dpr}
      gl={{preserveDrawingBuffer: true, alpha: true}}>
         <PerformanceMonitor onIncline={() => setDpr(2)} onDecline={() => setDpr(1)} >
        <Suspense fallback={<Loader />}>
          <OrbitControls enableZoom={false} enableRotate={true} position={0} />
          <Ball imgUrl={icon} />
        </Suspense>
  
        <Preload all />
        </PerformanceMonitor>
      </Canvas>
    );
  };

export default BallCanvas
解决方案

1. 限制WebGL实例数量

移动端浏览器对同时运行的WebGL上下文数量有严格限制(通常8-16个),15个Canvas同时加载极易触顶,导致部分实例初始化失败。

  • 实现懒加载:仅当Canvas进入视口时才初始化Three.js场景,离开时销毁上下文释放资源;
  • 合并场景:将多个小型3D元素合并到同一个Canvas中,减少WebGL实例数量。

2. 优化DPR与渲染性能

移动端GPU性能有限,初始dpr={1.5}+frameloop="always"的组合易导致负载过高崩溃:

  • 把初始DPR设为1,调整性能监控逻辑,避免频繁切换:
    const [dpr, setDpr] = useState(1)
    <PerformanceMonitor 
      onIncline={() => setDpr(1.5)} 
      onDecline={() => setDpr(1)}
      threshold={0.8} // 增加阈值,避免小幅性能波动触发切换
    >
    
  • 替换frameloop="always"为frameloop="demand",仅在交互时渲染,降低资源消耗。

3. 修复纹理加载问题

移动端对纹理兼容性要求更高,加载失败会直接导致白屏:

  • 给useTexture添加错误处理,加载失败时显示占位元素:
    const Ball = (props:any) => {
      const [decal, error] = useTexture([props.imgUrl], undefined, (err) => console.error('纹理加载失败:', props.imgUrl, err));
      if (error) return <mesh><boxGeometry /><meshBasicMaterial color="#ccc" /></mesh>;
      // 原有渲染逻辑
    }
    
  • 确保所有纹理尺寸为2的幂次方(如256x256、512x512),避免移动端GPU兼容性问题。

4. 移除不必要的WebGL配置

preserveDrawingBuffer: true会强制保留帧缓冲区数据,大幅增加内存占用,移动端内存不足时会崩溃:

<Canvas 
  frameloop="always"
  dpr={dpr}
  gl={{ alpha: true }} // 移除preserveDrawingBuffer配置
>

5. 修正OrbitControls配置

移动端触摸交互易出现控件冲突,position={0}配置存在异常,改为明确相机位置:

<Canvas 
  // ...其他配置
  camera={{ position: [0, 0, 5] }} // 确保相机能看到场景
>
  <OrbitControls 
    enableZoom={false} 
    enableRotate={true}
    minPolarAngle={0}
    maxPolarAngle={Math.PI}
  />
</Canvas>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:13:26