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

如何让React+Next.js中GLB模型显示效果与Babylon Sandbox一致?

问题描述

我用React+Next.js开发网站,要展示GLB格式的3D模型。这个模型在Babylon Sandbox里显示效果正常,但用@react-three/fiber、@react-three/drei和three.js嵌入网站后,效果差很多。调过directionalLight等灯光参数还是不行,附上模型组件和展示组件的代码,求解决。

模型组件代码

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

export default function Model(props) {
  const { nodes, materials } = useGLTF('/apple-iphone-13-pro-max.glb')
  return (
    <group {...props} dispose={null}>
      <group rotation={[-Math.PI / 2, 0, 0]}>
        <group rotation={[Math.PI / 2, 0, 0]} scale={0.01}>
          <group scale={100}>
            <mesh geometry={nodes.Body_Mic_0.geometry} material={materials.material} />
            <mesh geometry={nodes.Body_Bezel_0.geometry} material={materials.Bezel} />
            <mesh geometry={nodes.Body_Body_0.geometry} material={materials.Body} />
            <mesh geometry={nodes.Body_Wallpaper_0.geometry} material={materials.Wallpaper} />
            <mesh geometry={nodes.Body_Camera_Glass_0.geometry} material={materials.Camera_Glass} />
            <mesh geometry={nodes.Body_Lens_0.geometry} material={materials.Lens} />
            <mesh geometry={nodes.Body_Material_0.geometry} material={materials.Material} />
            <mesh geometry={nodes.Camera_Body_0.geometry} material={materials.Body} />
            <mesh geometry={nodes.Camera_Glass_0.geometry} material={materials.Glass} />
            <mesh geometry={nodes.Camera_Camera_Frame001_0.geometry} material={materials['Camera_Frame.001']} />
            <mesh geometry={nodes.Camera_Mic_0.geometry} material={materials.material} />
            <mesh geometry={nodes.Body001_Screen_Glass_0.geometry} material={materials.Screen_Glass} />
            <mesh geometry={nodes.Button_Frame_0.geometry} material={materials.Frame} />
            <mesh geometry={nodes.Circle003_Frame_0.geometry} material={materials.Frame} />
            <mesh geometry={nodes.Apple_Logo_Logo_0.geometry} material={materials.Logo} />
            <mesh geometry={nodes.Camera001_Body_0.geometry} material={materials.Body} />
            <mesh geometry={nodes.Camera001_Gray_Glass_0.geometry} material={materials.Gray_Glass} />
            <mesh geometry={nodes.Camera001_Flash_0.geometry} material={materials.Flash} />
            <mesh geometry={nodes.Camera001_Port_0.geometry} material={materials.Port} />
            <mesh geometry={nodes.Camera001_Camera_Frame_0.geometry} material={materials.Camera_Frame} />
            <mesh geometry={nodes.Camera001_Camera_Glass_0.geometry} material={materials.Camera_Glass} />
            <mesh geometry={nodes.Camera001_Lens_0.geometry} material={materials.Lens} />
            <mesh geometry={nodes.Camera001_Black_Glass_0.geometry} material={materials.Black_Glass} />
            <mesh geometry={nodes.Camera003_Material002_0.geometry} material={materials['Material.002']} />
            <mesh geometry={nodes.Frame_Frame_0.geometry} material={materials.Frame} />
            <mesh geometry={nodes.Frame_Frame2_0.geometry} material={materials.Frame2} />
            <mesh geometry={nodes.Frame_Port_0.geometry} material={materials.Port} />
            <mesh geometry={nodes.Frame_Antenna_0.geometry} material={materials.Antenna} />
            <mesh geometry={nodes.Frame_Mic_0.geometry} material={materials.material} />
          </group>
        </group>
      </group>
    </group>
  )
}

useGLTF.preload('/apple-iphone-13-pro-max.glb')

展示组件代码

import React, { Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import Model from "./apple-iphone-13-pro-max";

const ModelDisplayer = () => {
  return (
    <Canvas
      camera={{ position: [5, 5, 5], fov: 10 }}
      className="w-full h-full bg-orange-500"
    >
      <Suspense fallback={null}>
        <Model position={[0, 0, 0]} />
      </Suspense>
      <ambientLight intensity={7} />
      <directionalLight intensity={3} />
      <OrbitControls />
    </Canvas>
  );
};

export default ModelDisplayer;
解决方案

1. 直接加载完整GLB场景(最快捷对齐效果)

Babylon Sandbox会自动读取模型自带的灯光、环境和材质配置,你当前手动拆分nodes的方式丢失了这些信息。修改模型组件,直接渲染完整场景:

import React from 'react'
import { useGLTF } from '@react-three/drei'

export default function Model(props) {
  const { scene } = useGLTF('/apple-iphone-13-pro-max.glb')
  return <primitive object={scene} {...props} dispose={null} />
}

useGLTF.preload('/apple-iphone-13-pro-max.glb')

这样能1:1还原模型在导出时的所有设置,和Babylon Sandbox的基础效果对齐。

2. 优化手动灯光配置(如果需要自定义)

如果你一定要手动布光,参考Babylon的默认柔和布光逻辑,调整参数:

<Canvas camera={{ position: [5, 5, 5], fov: 10 }} className="w-full h-full bg-gray-100">
  <Suspense fallback={null}>
    <Model position={[0, 0, 0]} />
  </Suspense>
  {/* 弱环境光保留基础亮度 */}
  <ambientLight intensity={0.3} />
  {/* 主光源提供主要照明,带阴影增强立体感 */}
  <directionalLight position={[10, 10, 5]} intensity={1.2} castShadow />
  {/* 补光削弱阴影过暗问题 */}
  <directionalLight position={[-10, 10, -5]} intensity={0.8} />
  {/* 底部补光避免底部过黑 */}
  <pointLight position={[0, -5, 0]} intensity={0.5} />
  <OrbitControls />
</Canvas>

注意:你之前设置的ambientLight intensity={7}强度过高,会完全压过其他光源,导致模型失去层次感。

3. 增强PBR材质表现

GLB模型的PBR材质依赖环境贴图来体现金属/粗糙质感,用drei的Environment组件添加环境:

import { Environment } from '@react-three/drei'

// 在Canvas内部添加
<Environment preset="studio" />

如果有自己的HDR贴图,也可以指定路径:

<Environment files="/path/to/your.hdr" />

4. 清理冗余的模型变换

你的模型组件里有多层重复的旋转和缩放(先转-90度再转回来,先缩0.01再缩100),会导致坐标计算混乱,用上面的primitive方式加载完整场景会自动处理原始模型的姿态,无需手动调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:09:26