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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:35:26