React Three Fiber报错:THREE.BufferGeometry计算半径为NaN
问题描述
使用React.js和React Three Fiber开发网站3D组件,共3个组件,其中2个运行正常,突然有一个组件失效,排查6小时仍未解决:
- 报错信息:
THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values. - 组件仅首次加载显示,刷新页面后出现白屏(截图:白屏状态)
- 注释该组件时网站正常,取消注释后触发上述问题
组件代码如下:
import React, { Suspense, useEffect, useState } from "react"; import { Canvas } from "@react-three/fiber"; import { OrbitControls, Preload, useGLTF } from "@react-three/drei"; import CanvasLoader from "../Loader"; const Computers = ({ isMobile }) => { const computer = useGLTF("./desktop_pc/scene.gltf"); return ( <mesh> <hemisphereLight intensity={0.15} groundColor='black' /> <spotLight position={[-20, 50, 10]} angle={0.12} penumbra={1} intensity={1.5} castShadow shadow-mapSize={1024} /> <pointLight intensity={1} /> <primitive object={computer.scene} scale={isMobile ? 0.7 : 0.75} position={isMobile ? [0, -3, -2.2] : [0, -3.25, -1.5]} rotation={[-0.01, -0.2, -0.1]} /> </mesh> ); }; const ComputersCanvas = () => { const [isMobile, setIsMobile] = useState(false); useEffect(() => { // 监听屏幕尺寸变化 const mediaQuery = window.matchMedia("(max-width: 500px)"); // 初始化isMobile状态 setIsMobile(mediaQuery.matches); // 屏幕尺寸变化回调 const handleMediaQueryChange = (event) => { setIsMobile(event.matches); }; // 添加监听 mediaQuery.addEventListener("change", handleMediaQueryChange); // 组件卸载时移除监听 return () => { mediaQuery.removeEventListener("change", handleMediaQueryChange); }; }, []); return ( <Canvas frameloop='demand' shadows dpr={[1, 2]} camera={{ position: [20, 3, 5], fov: 25 }} gl={{ preserveDrawingBuffer: true }} > <Suspense fallback={<CanvasLoader />}> <OrbitControls enableZoom={false} maxPolarAngle={Math.PI / 2} minPolarAngle={Math.PI / 2} /> <Computers isMobile={isMobile} /> </Suspense> <Preload all /> </Canvas> ); }; export default ComputersCanvas;
解决方案
1. 检查GLTF模型完整性
- 用Blender或GLTF在线预览工具打开
./desktop_pc/scene.gltf,验证模型是否存在顶点位置为NaN的几何体,或模型文件是否损坏。 - 若模型异常,从建模软件重新导出标准GLTF格式,确保导出过程无报错。
2. 优化模型加载逻辑
给useGLTF添加错误捕获,避免加载失败导致全局崩溃:
const computer = useGLTF("./desktop_pc/scene.gltf", () => { return new Promise((resolve, reject) => { fetch("./desktop_pc/scene.gltf") .then(res => res.json()) .then(data => resolve(data)) .catch(err => { console.error("模型加载失败:", err); reject(err); }); }); });
3. 修改动态属性挂载对象
不要直接在primitive上修改scale/position,改用group包裹,修改group的属性避免破坏模型几何体:
<group scale={isMobile ? 0.7 : 0.75} position={isMobile ? [0, -3, -2.2] : [0, -3.25, -1.5]} rotation={[-0.01, -0.2, -0.1]} > <primitive object={computer.scene} /> </group>
4. 手动修复BoundingSphere计算
如果模型本身正常但仍报错,手动覆盖几何体的BoundingSphere:
import * as THREE from 'three'; // 在Computers组件中添加useEffect useEffect(() => { if (computer.scene) { computer.scene.traverse((obj) => { if (obj.isMesh && obj.geometry) { obj.geometry.computeBoundingSphere(); // 若计算出NaN,手动设置默认球体 if (isNaN(obj.geometry.boundingSphere.radius)) { obj.geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(0,0,0), 10); } } }); } }, [computer.scene]);
5. 调整Preload逻辑
尝试移除<Preload all />,或仅预加载目标模型,避免全局预加载导致的冲突:
<Preload models={["./desktop_pc/scene.gltf"]} />
内容的提问来源于stack exchange,提问作者Priyansh Sharma
相关产品推荐
相关产品推荐

