Как использовать three.js с React

Я пытаюсь использовать three.js в приложении React, однако даже базовый образец из документации three.js не загружается на холст.

Сначала я сделал реализацию vanilla.js песочница с образцом, который отлично работает. Затем я перенес его, чтобы создать минимальную реализацию React + three.js песочница, которая не работает.

Может ли кто-нибудь взглянуть на это и указать мне правильное направление?

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} />;
}
ЗДЕСЬ - это вещь three.js / react, которую я сделал некоторое время назад, возможно, взглянув на нее, в частности, Компонент сцены поможет вам.
2pha 31.12.2018 02:22

спасибо всем, что нашли время ответить. Я отказался от своих усилий и должен вернуться, если это решило мои проблемы. скоро отвечу.

jagzviruz 23.04.2019 11:21
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
3 219
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

На данный момент есть несколько проблем с вашей песочницей, которые не обязательно связаны с React.

  1. innerWidth и innerHeight не определены. clientWidth и clientHeight - это, вероятно, поля, которые вы ищете, чтобы получить размеры элемента dom.

  2. Размеры холста считываются перед добавлением в документ, то есть размеры элемента всегда будут 0 0. Вставьте элемент сначала перед вычислением соотношения сторон камеры и установкой размера рендеринга.

  3. Camera не предназначен для прямого использования. В документации он указан как абстрактный базовый класс для камер. - используйте вместо него 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();

Надеюсь, это поможет!

Вот CodeSandBox, который работает с базовым кодом оболочки React для Three.js. Он также имеет интеграцию THREE.OrbitControls и масштабирование при изменении размера кода:

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

Живая демонстрация: https://31yp61zxq6.codesandbox.io/

Вот полный фрагмент кода в случае, если перечисленные выше ссылки вам не подходят:

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.

Mostafa Farzán 15.04.2021 01:31

Я не уверен, почему никто не упомянул реагировать-три-волокна. Это средство визуализации React для ThreeJS.

Самое приятное, что с помощью rollupjs мы можем даже встряхнуть много ненужного кода, который мы не будем использовать в нашем приложении React ThreeJS. Кроме того, используя react-three-fiber желаемым образом, мы можем достичь 60 кадров в секунду для нашей анимации ThreeJS ?

Чтобы изучить основы, просто загляните в react-three-fiberПримеры

Другие вопросы по теме