Three.js中代码仅加载单个3D模型却渲染出两个的问题求助
Three.js中代码仅加载单个3D模型却渲染出两个的问题求助
嘿,刚看完你的代码,立马就找到问题根源啦!你现在相当于同时开了两套完全独立的Three.js渲染系统,自然会出现两个模型的视觉效果(准确说是两个叠加的渲染画布,其中一个加载了模型,看起来像是重复渲染了)。
具体来说:
- 你在
useEffect里手动写了一套完整的Three.js流程:新建场景、相机、渲染器,加载模型并添加到场景,最后把渲染器的画布塞进容器里。 - 同时你又在组件的return里渲染了
<Canvas>组件——这是react-three-fiber提供的封装组件,它内部会自动创建属于自己的场景、相机、渲染器,相当于又开了一个新的画布。
这两套系统完全独立,叠加在页面上,就导致你看到了“两个模型”的效果。
给你两个解决方案,选其中一个就行:
方案一:改用react-three-fiber的组件式写法(更符合React生态)
删掉useEffect里的所有手动Three.js代码,用react-three-fiber的钩子和组件来实现,代码会更简洁:
import { Canvas, useGLTF } from '@react-three/fiber'; import { OrbitControls } from '@react-three/drei'; import { useRef } from 'react'; // 封装模型组件 function PhoneModel() { const gltf = useGLTF('/phone_port.gltf'); return <primitive object={gltf.scene} scale={[0.5, 0.5, 0.5]} />; } function Mobile() { const controls = useRef(); const cameraProps = { /* 填入你的相机参数 */ }; return ( <div> <Canvas camera={{ fov: cameraProps.fov, aspect: cameraProps.aspect, near: cameraProps.near, far: cameraProps.far, position: cameraProps.position, }} gl={{ alpha: true }} onCreated={({ camera }) => { camera.lookAt(0.5, 0, 0); }} onPointerEnter={() => { controls.current.enabled = true; }} onPointerLeave={() => { controls.current.enabled = false; }} > {/* 添加灯光 */} <ambientLight intensity={0.5} /> <directionalLight position={[5, 5, 5]} intensity={0.5} /> {/* 加载模型 */} <PhoneModel /> {/* 轨道控制器 */} <OrbitControls ref={controls} enabled={false} /> </Canvas> </div> ); } export default Mobile;
方案二:完全用手动Three.js写法(适合纯Three.js场景)
保留useEffect里的代码,但要补上渲染循环(你之前的代码没写,模型其实不会实时渲染),同时删掉return里的<Canvas>组件,只留容器:
import { useEffect, useRef } from 'react'; import * as THREE from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 如果需要控制器 function Mobile() { const containerRef = useRef(); const cameraProps = { /* 填入你的相机参数 */ }; const controls = useRef(); useEffect(() => { const scene = new THREE.Scene(); // 添加灯光 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(5, 5, 5); scene.add(directionalLight); const camera = new THREE.PerspectiveCamera(cameraProps.fov, cameraProps.aspect, cameraProps.near, cameraProps.far); camera.position.copy(cameraProps.position); camera.lookAt(0.5, 0, 0); const renderer = new THREE.WebGLRenderer({ alpha: true }); const containerWidth = window.innerWidth; const containerHeight = window.innerHeight; renderer.setSize(containerWidth, containerHeight); renderer.setClearColor(0x000000, 0); containerRef.current.appendChild(renderer.domElement); // 添加轨道控制器(如果需要) controls.current = new OrbitControls(camera, renderer.domElement); controls.current.enabled = false; // 加载模型 let phoneModel = null; const gltfLoader = new GLTFLoader(); gltfLoader.load("/phone_port.gltf", (gltfScene) => { phoneModel = gltfScene.scene; phoneModel.scale.set(0.5, 0.5, 0.5); scene.add(phoneModel); }); // 渲染循环 const animate = () => { requestAnimationFrame(animate); controls.current?.update(); // 更新控制器 renderer.render(scene, camera); }; animate(); // 窗口大小适配 const handleResize = () => { const newWidth = window.innerWidth; const newHeight = window.innerHeight; camera.aspect = newWidth / newHeight; camera.updateProjectionMatrix(); renderer.setSize(newWidth, newHeight); }; window.addEventListener('resize', handleResize); // 清理资源 return () => { window.removeEventListener('resize', handleResize); renderer.dispose(); phoneModel && scene.remove(phoneModel); controls.current?.dispose(); }; }, []); return <div ref={containerRef}></div>; } export default Mobile;
只要选其中一种方式,把另一套渲染逻辑删掉,就能解决“两个模型”的问题啦!
备注:内容来源于stack exchange,提问作者Sunny Dowari
相关产品推荐
相关产品推荐

