如何在MUI组件中使用three.js显示OBJ格式3D模型?
在MUI组件中用Three.js展示OBJ模型
问题分析
你的代码已成功加载OBJ模型,但缺少Three.js渲染的核心环节:未创建相机、渲染器,也未将渲染结果挂载到MUI组件的DOM节点上,同时存在状态管理和对象生命周期的不合理处理。
修正后的完整代码
import React, { useState, useEffect, useRef } from 'react'; import { Container, Typography, Box } from '@mui/material'; import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; import * as THREE from 'three'; const useStyles = () => ({ container: { marginTop: 2, marginBottom: 2, }, canvas: { width: '100%', height: '600px', backgroundColor: '#f0f0f0', }, }); const View3DWound = (props) => { const [isModelLoaded, setIsModelLoaded] = useState(false); const { id } = useParams(); const classes = useStyles(); const canvasContainerRef = useRef(null); // 用ref存储Three.js核心对象,避免组件重复渲染时重复创建 const threeObjectsRef = useRef({ scene: null, camera: null, renderer: null, animationId: null, }); useEffect(() => { const container = canvasContainerRef.current; if (!container) return; // 初始化Three.js核心对象 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, container.clientWidth / container.clientHeight, 0.1, 1000 ); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(container.clientWidth, container.clientHeight); renderer.setClearColor(0xf0f0f0); container.appendChild(renderer.domElement); // 添加光源,否则模型会显示为黑色 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(5, 5, 5); scene.add(directionalLight); // 加载OBJ模型 const loader = new OBJLoader(); loader.load( './assets/TechnicLEGO_CAR_1.obj', (object) => { scene.add(object); // 调整模型位置和缩放,适配相机视角 object.position.set(0, 0, 0); object.scale.set(0.5, 0.5, 0.5); // 相机定位到能完整看到模型的位置 camera.position.z = 5; setIsModelLoaded(true); }, (xhr) => { console.log(`${(xhr.loaded / xhr.total) * 100}% 已加载`); }, (error) => { console.error('模型加载出错:', error); } ); // 动画循环,持续渲染场景 const animate = () => { const animationId = requestAnimationFrame(animate); // 可选:添加模型旋转效果 scene.children.forEach((child) => { if (child.type === 'Group') { child.rotation.y += 0.01; } }); renderer.render(scene, camera); threeObjectsRef.current.animationId = animationId; }; animate(); // 保存核心对象到ref threeObjectsRef.current = { scene, camera, renderer, animationId: null }; // 组件卸载时清理资源,避免内存泄漏 return () => { cancelAnimationFrame(threeObjectsRef.current.animationId); renderer.dispose(); container.removeChild(renderer.domElement); }; }, []); return ( <Container className={classes.container}> <Typography variant="h4">查看患者 {id} 的3D模型</Typography> <Box className={classes.canvas} ref={canvasContainerRef}> {!isModelLoaded && <Typography>模型加载中...</Typography>} </Box> </Container> ); }; export default View3DWound;
关键修正点
- 使用
useRef获取MUI的Box容器,用来挂载Three.js生成的canvas元素 - 将Three.js的场景、相机、渲染器存储在ref中,避免组件重复渲染时重复创建实例
- 添加环境光和方向光,解决模型加载后显示为黑色的问题
- 调整相机位置与模型缩放比例,确保模型在视野内完整展示
- 增加动画循环,实现场景持续渲染,可选添加模型旋转效果
- 组件卸载时清理渲染器和动画帧,避免内存泄漏
- 用
isModelLoaded状态替代存储模型对象,更合理地管理加载状态
内容的提问来源于stack exchange,提问作者Thakur Saad
相关产品推荐
相关产品推荐

