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

React+Three.js中GLTF/GLB模型显示异常求助

React + Three.js 模型加载问题:模型极小且放大后变形

我在React环境中使用Three.js开发,通过gltfjsx将GLTF/GLB格式的3D模型转换为JSX组件展示。加载流程看似正常,但页面上看不到模型。排查后发现模型尺寸极小,调整相机放大后完全变形。尝试用Visual Studio插件将GLTF转为JSON格式的GLTF文件,问题依旧。


相关代码

App.js

import { Canvas } from "@react-three/fiber";
import { Model } from "./Model";
import { Suspense } from "react";

function App() {
  return (
    <>
      <Canvas>
        <Suspense fallback={<LoadingFallback />}>
          <Model position={[0, 0, 0]} />
        </Suspense>
      </Canvas>
    </>
  );
}

function LoadingFallback() {
  return (
    <mesh visible position={[0, 0, 0]}>
      <sphereGeometry args={[1, 16, 16]} />
      <meshStandardMaterial color="red" />
    </mesh>
  );
}

export default App;

Model.jsx

import React, { useRef } from "react";
import { useGLTF } from "@react-three/drei";

export function Model(props) {
  const { nodes, materials } = useGLTF("model.gltf");
  return (
    <group {...props} dispose={null}>
      <mesh
        geometry={nodes.mesh_0.geometry}
        material={nodes.mesh_0.material}
        position={[-0.059, 0, 0.056]}
        rotation={[-Math.PI / 2, 0, 0]}
      />
      <mesh
        geometry={nodes.mesh_1.geometry}
        material={nodes.mesh_1.material}
        position={[-0.059, 0, 0.056]}
        rotation={[-Math.PI / 2, 0, 0]}
      />
    </group>
  );
}

useGLTF.preload("/model.gltf");

model.gltf

{
  "asset": {
    "generator": "3D Builder",
    "version": "2.0"
  },
  "scene": 0,
  "scenes": [
    {
      "nodes": [
        0,
        1
      ]
    }
  ],
  "nodes": [
    {
      "mesh": 0,
      "matrix": [
        1,
        0,
        0,
        0,
        0,
        -1.1920928955078125e-7,
        -0.9999998807907104,
        0,
        0,
        0.9999998807907104,
        -1.1920928955078125e-7,
        0,
        -0.0589279979467392,
        6.676553532258822e-9,
        0.056006982922554016,
        1
      ]
    },
    {
      "mesh": 1,
      "matrix": [
        1,
        0,
        0,
        0,
        0,
        -1.1920928955078125e-7,
        -0.9999998807907104,
        0,
        0,
        0.9999998807907104,
        -1.1920928955078125e-7,
        0,
        -0.0589279979467392,
        6.676553532258822e-9,
        0.056006982922554016,
        1
      ]
    }
  ],
  "meshes": [
    {
      "primitives": [
        {
          "attributes": {
            "POSITION": 0,
            "COLOR_0": 1
          },
          "mode": 4,
          "indices": 2
        }
      ]
    },
    {
      "primitives": [
        {
          "attributes": {
            "POSITION": 3,
            "COLOR_0": 4
          },
          "mode": 4,
          "indices": 5
        }
      ]
    }
  ],
  "accessors": [
    {
      "bufferView": 0,
      "byteOffset": 0,
      "count": 86,
      "componentType": 5126,
      "type": "VEC3",
      "min": [
        0.049275994300842285,
        -1.3066596265629834e-16,
        0
      ],
      "max": [
        0.1178559958934784,
        0.08991597592830658,
        0.018389593809843063
      ]
    },
    {
      "bufferView": 1,
      "byteOffset": 0,
      "count": 86,
      "componentType": 5121,
      "type": "VEC4",
      "normalized": true
    },
    {
      "bufferView": 2,
      "byteOffset": 0,
      "count": 504,
      "componentType": 5125,
      "type": "SCALAR"
    },
    {
      "bufferView": 3,
      "byteOffset": 0,
      "count": 120,
      "componentType": 5126,
      "type": "VEC3",
      "min": [
        0,
        -1.3066596265629834e-16,
        0
      ],
      "max": [
        0.09220199286937714,
        0.11201398074626923,
        0.018389593809843063
      ]
    },
    {
      "bufferView": 4,
      "byteOffset": 0,
      "count": 120,
      "componentType": 5121,
      "type": "VEC4",
      "normalized": true
    },
    {
      "bufferView": 5,
      "byteOffset": 0,
      "count": 708,
      "componentType": 5125,
      "type": "SCALAR"
    }
  ],
  "bufferViews": [
    {
      "buffer": 0,
      "byteOffset": 0,
      "byteLength": 1032,
      "byteStride": 12,
      "target": 34962
    },
    {
      "buffer": 0,
      "byteOffset": 1032,
      "byteLength": 344,
      "byteStride": 4,
      "target": 34962
    },
    {
      "buffer": 0,
      "byteOffset": 1376,
      "byteLength": 2016,
      "target": 34963
    },
    {
      "buffer": 0,
      "byteOffset": 3392,
      "byteLength": 1440,
      "byteStride": 12,
      "target": 34962
    },
    {
      "buffer": 0,
      "byteOffset": 4832,
      "byteLength": 480,
      "byteStride": 4,
      "target": 34962
    },
    {
      "buffer": 0,
      "byteOffset": 5312,
      "byteLength": 2832,
      "target": 34963
    }
  ],
  "buffers": [
    {
      "uri": "model_data.bin",
      "byteLength": 8144
    }
  ]
}

问题分析与解决办法

1. 修复模型尺寸问题

从GLTF的accessor数据可以看到,模型顶点坐标的最大范围仅0.1左右,说明模型本身单位尺寸极小。直接放大相机视角会导致透视变形,正确做法是缩放模型本身:
修改Model.jsx的外层group,添加scale属性:

<group {...props} dispose={null} scale={[10, 10, 10]}>

可根据实际效果调整缩放倍数。

2. 添加交互控件调整视角

默认Canvas的相机位置可能未对准模型,建议添加OrbitControls方便手动调整视角:
先确保安装了@react-three/drei,然后在App.js中修改:

import { Canvas } from "@react-three/fiber";
import { Model } from "./Model";
import { Suspense, OrbitControls } from "@react-three/drei";
import { Suspense as ReactSuspense } from "react";

function App() {
  return (
    <>
      <Canvas>
        <ReactSuspense fallback={<LoadingFallback />}>
          <Model position={[0, 0, 0]} />
        </ReactSuspense>
        <OrbitControls enableZoom={true} />
      </Canvas>
    </>
  );
}

3. 修复代码遗漏问题

原App.js中使用了Suspense但未从react导入,需补上:

import { Suspense } from "react";

4. 优化模型导出流程

3D Builder导出的GLTF可能存在坐标或变换异常,建议用Blender重新导出:

  • 将模型导入Blender
  • 选中模型按Ctrl+A,依次应用缩放、旋转、位置变换
  • 导出为GLTF时,勾选"应用变换"选项

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 07:49:55