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
相关产品推荐
相关产品推荐

