我正在尝试将 3D 模型合并到我的项目中,但由于某种原因,画布渲染了两个而不是一个 3D 模型。如果有人能给我指出正确的方向,我是 Three.js 的初学者,我尝试过删除场景、改变画布、相机细节。但似乎不起作用。
正如您在图像中看到的那样,有两个 3D 模型,它是否由于某种原因平铺?我检查了3D软件场景,里面没有两个模型。
useEffect(() => {
const scene = new THREE.Scene();
// Add lights to the 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);
const renderer = new THREE.WebGLRenderer({ alpha: true }); // Set alpha to true for transparent background
// Adjust renderer size to fit within the container
const containerWidth = window.innerWidth;
const containerHeight = window.innerHeight;
renderer.setSize(containerWidth, containerHeight);
renderer.setClearColor(0x000000, 0); // Set clear color to transparent
containerRef.current.appendChild(renderer.domElement);
// Load the phone model
const gltfLoader = new GLTFLoader();
gltfLoader.load("/phone_port.gltf", (gltfScene) => {
const phoneModel = gltfScene.scene;
phoneModel.scale.set(0.5, 0.5, 0.5);
scene.add(phoneModel);
});
// Set camera position and orientation
camera.lookAt(0.5, 0, 0);
// Update camera aspect ratio based on container size
camera.aspect = containerWidth / containerHeight;
camera.updateProjectionMatrix();
// Clean up Three.js resources on unmount
return () => {
renderer.dispose();
};
}, []);
return (
<div ref={containerRef}>
<Canvas
camera ={{
fov: cameraProps.fov,
aspect: cameraProps.aspect,
near: cameraProps.near,
far: cameraProps.far,
position: cameraProps.position,
}}
gl={{ alpha: true }}
onCreated={({ camera }) => {
controls.current.enabled = true;
}}
onPointerEnter={() => {
// Enable OrbitControls when the mouse enters the canvas
controls.current.enabled = true;
}}
onPointerLeave={() => {
// Disable OrbitControls when the mouse leaves the canvas
controls.current.enabled = false;
}}
/>
</div>
);
}
export default Mobile;```
![Screenshot of the page](https://ibb.co/TkL3D1s)
编辑:我看到你使用三光纤。所以只有第一部分对你有用。但如果你想交换到普通的 Three.js。您可以使用我答案的第二部分。
第一部分: 在 React 18 中,useEffect 在挂载时被调用两次。因此,您需要一些技巧来仅调用函数一次,但更推荐的方法是在卸载 useEffect 时正确清理所有创建的东西。
renderer.dispose() 并不是 100% 完美清除 3D 场景中所有内容的方法。在某些线程中,您可以发现人们将所有值设置为 null,以将内容从内存中移走。
第二部分: 我通常在单独的函数中编写三个 js 代码,并且有 init 和 unmount 方法。
有一个简短的示例,但并不理想,如果已经安装,最好也有一些状态来处理异步操作,例如加载模型和纹理。
function ThreeCanvasWrapper(): JSX.Element {
const canvasRef = React.useRef<HTMLDivElement>(null);
const projectTextRef = React.useRef<HTMLDivElement>();
const threeCanvas = useMemo(() => new ThreeCanvas(), []);
useEffect(() => {
if (canvasRef.current && projectTextRef.current) {
threeCanvas.init(canvasRef.current, projectTextRef.current);
}
return () => {
threeCanvas.unmount();
};
}, [threeCanvas]);
return (
<>
<Stack
id={canvas3dWrapperId}
sx={{
width: "100%",
minHeight: "100vh",
maxHeight: "100vh",
willChange: "transform",
}}
ref={canvasRef}
></Stack>
</>
);
}
export default ThreeCanvasWrapper;
您可以将代码移至 init 函数。卸载时,我清除了我创建的所有内容,以确保所有内容都被销毁。
unmount() {
this.planes.forEach((plane) => {
plane.destroy();
});
if (this.scene) {
this.scene.traverse((child) => {
if (child instanceof Mesh) {
child.geometry.dispose();
child.geometry = null;
child.material.dispose();
child.material = null;
}
});
this.renderer.domElement.remove();
this.css3dRenderer.domElement.remove();
this.renderer.dispose();
this.scene.remove(...this.scene.children);
}
}