【问题标题】:How to use three.js with React如何在 React 中使用 three.js
【发布时间】:2021-04-15 13:07:59
【问题描述】:

我正在尝试在 React 应用程序中使用three.js,但是即使是three.js 文档中的基本示例也无法在画布上加载。

我首先使用运行良好的示例制作了 vanilla.js sandbox 实现。然后我把它移植过来,创建了一个 react+three.js 最小的 sandbox 实现,但它无法工作。

任何人都可以看看它并指出正确的方向吗?

class Viewer extends Component {
    state = {};

    scene = null;

    camera = null;

    renderer = new WebGLRenderer();

    inst = 0;

    viewerRef = React.createRef();

    componentDidMount() {
        const { domElement } = this.renderer;
        this.scene = new Scene();
        this.scene.background = new Color("#ccc");
        this.camera = new Camera(
        75,
        domElement.innerWidth / domElement.innerHeight,
        0.1,
        1000
        );
        this.renderer.setSize(domElement.innerWidth, domElement.innerHeight);
        this.viewerRef.current.appendChild(this.renderer.domElement);
        const geometry = new BoxGeometry(1, 1, 1);
        const material = new MeshBasicMaterial({ color: 0x05ff00 });
        const cube = new Mesh(geometry, material);

        this.scene.add(cube);

        this.camera.position.z = 5;
        this.display();
    }

    display = () => {
        this.renderer.render(this.scene, this.camera);
        requestAnimationFrame(this.display);
    };

    render = () => <div className="viewer" ref={this.viewerRef} />;
}

【问题讨论】:

  • HERE 是我前一阵子做的一个three.js / react 的东西,也许看看它,特别是Scene component 会帮助你。
  • 感谢大家花时间回答。我已经放弃了我的努力,如果这解决了我的问题,我必须重新审视。很快就会回复。

标签: javascript reactjs three.js


【解决方案1】:

这里是 CodeSandBox,它与 Three.js 的基本 React 包装器代码一起使用。它还具有 THREE.OrbitControls 集成和缩放代码:

https://codesandbox.io/s/github/supromikali/react-three-demo

现场演示:https://31yp61zxq6.codesandbox.io/

如果上面列出的链接不适合您,这里是完整的代码 sn-p:

index.js 代码

import React, { Component } from "react";
import ReactDOM from "react-dom";
import THREE from "./three";


class App extends Component {
    componentDidMount() {


        // BASIC THREE.JS THINGS: SCENE, CAMERA, RENDERER
        // Three.js Creating a scene tutorial
        // https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        camera.position.z = 5;

        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);



        // MOUNT INSIDE OF REACT
        this.mount.appendChild(renderer.domElement); // mount a scene inside of React using a ref



        // CAMERA CONTROLS
        // https://threejs.org/docs/index.html#examples/controls/OrbitControls
        this.controls = new THREE.OrbitControls(camera);



        // ADD CUBE AND LIGHTS
        // https://threejs.org/docs/index.html#api/en/geometries/BoxGeometry
        // https://threejs.org/docs/scenes/geometry-browser.html#BoxGeometry
        var geometry = new THREE.BoxGeometry(2, 2, 2);
        var material = new THREE.MeshPhongMaterial( {
            color: 0x156289,
            emissive: 0x072534,
            side: THREE.DoubleSide,
            flatShading: true
        } );
        var cube = new THREE.Mesh(geometry, material);
        scene.add(cube);

        var lights = [];
        lights[ 0 ] = new THREE.PointLight( 0xffffff, 1, 0 );
        lights[ 1 ] = new THREE.PointLight( 0xffffff, 1, 0 );
        lights[ 2 ] = new THREE.PointLight( 0xffffff, 1, 0 );

        lights[ 0 ].position.set( 0, 200, 0 );
        lights[ 1 ].position.set( 100, 200, 100 );
        lights[ 2 ].position.set( - 100, - 200, - 100 );

        scene.add( lights[ 0 ] );
        scene.add( lights[ 1 ] );
        scene.add( lights[ 2 ] );



        // SCALE ON RESIZE

        // Check "How can scene scale be preserved on resize?" section of Three.js FAQ
        // https://threejs.org/docs/index.html#manual/en/introduction/FAQ

        // code below is taken from Three.js fiddle
        // http://jsfiddle.net/Q4Jpu/

        // remember these initial values
        var tanFOV = Math.tan( ( ( Math.PI / 180 ) * camera.fov / 2 ) );
        var windowHeight = window.innerHeight;

        window.addEventListener( 'resize', onWindowResize, false );

        function onWindowResize( event ) {

            camera.aspect = window.innerWidth / window.innerHeight;

            // adjust the FOV
            camera.fov = ( 360 / Math.PI ) * Math.atan( tanFOV * ( window.innerHeight / windowHeight ) );

            camera.updateProjectionMatrix();
            camera.lookAt( scene.position );

            renderer.setSize( window.innerWidth, window.innerHeight );
            renderer.render( scene, camera );

        }



        // ANIMATE THE SCENE
        var animate = function() {
            requestAnimationFrame(animate);

            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            renderer.render(scene, camera);
        };

        animate();
    }
    render() {
        return <div ref={ref => (this.mount = ref)} />;
    }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

three.js 代码(THREE.OrbitControls 导入)

import * as THREE from 'three';


window.THREE = THREE; // THREE.OrbitControls expects THREE to be a global object
require('three/examples/js/controls/OrbitControls');


export default {...THREE, OrbitControls: window.THREE.OrbitControls};

结果应该是这样的:

【讨论】:

  • 很棒的演示!我必须将this.controls = new THREE.OrbitControls(camera); 行转换为this.controls = new THREE.OrbitControls(camera, renderer.domElement); 才能使其正常工作。我使用的是 0.127.0 版本。
【解决方案2】:

我不确定为什么没有人提到react-three-fiber。这是 ThreeJS 的 React 渲染器。

最好的部分是,使用 rollupjs,我们甚至可以摇树很多不必要的代码,我们不会在我们的 React ThreeJS 应用程序中使用这些代码。此外,以期望的方式使用react-three-fiber,我们可以为我们的 ThreeJS 动画实现 60FPS ?

要了解基础知识,只需查看react-three-fiber Examples

【讨论】:

    【解决方案3】:

    目前您的沙盒存在一些问题,不一定与 React 相关。

    1. innerWidthinnerHeight 未定义。 clientWidthclientHeight 可能是您要获取 dom 元素尺寸的字段。

    2. 在将画布添加到文档之前,正在读取画布的尺寸,这意味着元素的尺寸将始终为0 0。在计算相机纵横比和设置渲染大小之前先插入元素。

    3. Camera 不打算直接使用。 The docs specify it as an abstract base class for cameras -- 改用PerspectiveCamera

    这是一个带有上述修复的代码示例

    const { domElement } = this.renderer;
    
    // Fix 1
    this.viewerRef.current.appendChild(domElement);
    
    // Fix 2
    const width = domElement.clientWidth;
    const height = domElement.clientHeight;
    
    this.scene = new Scene();
    this.scene.background = new Color("#ccc");
    
    // Fix 3
    this.camera = new PerspectiveCamera(
        75,
        width  / height,
        0.1,
        1000
    );
    this.renderer.setSize(width, height);
    const geometry = new BoxGeometry(1, 1, 1);
    const material = new MeshBasicMaterial({ color: 0x05ff00 });
    const cube = new Mesh(geometry, material);
    
    this.scene.add(cube);
    this.camera.position.z = 5;
    this.display();
    

    希望有帮助!

    【讨论】:

      猜你喜欢
      • 2018-06-28
      • 2018-01-23
      • 2021-10-09
      • 2015-07-02
      • 2020-02-25
      • 2018-09-02
      • 1970-01-01
      • 2017-01-17
      • 2012-12-16
      相关资源
      最近更新 更多