编码为一个,但渲染器在 Three.js 中渲染两个 3D 模型

问题描述 投票:0回答:1

我正在尝试将 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)

javascript three.js 3d react-three-fiber
1个回答
0
投票

编辑:我看到你使用三光纤。所以只有第一部分对你有用。但如果你想交换到普通的 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);
    }
  }
© www.soinside.com 2019 - 2024. All rights reserved.