Я пытаюсь использовать 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} />;
}
спасибо всем, что нашли время ответить. Я отказался от своих усилий и должен вернуться, если это решило мои проблемы. скоро отвечу.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


На данный момент есть несколько проблем с вашей песочницей, которые не обязательно связаны с React.
innerWidth и innerHeight не определены. clientWidth и clientHeight - это, вероятно, поля, которые вы ищете, чтобы получить размеры элемента dom.
Размеры холста считываются перед добавлением в документ, то есть размеры элемента всегда будут 0 0. Вставьте элемент сначала перед вычислением соотношения сторон камеры и установкой размера рендеринга.
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.
Я не уверен, почему никто не упомянул реагировать-три-волокна. Это средство визуализации React для ThreeJS.
Самое приятное, что с помощью rollupjs мы можем даже встряхнуть много ненужного кода, который мы не будем использовать в нашем приложении React ThreeJS. Кроме того, используя react-three-fiber желаемым образом, мы можем достичь 60 кадров в секунду для нашей анимации ThreeJS ?
Чтобы изучить основы, просто загляните в react-three-fiberПримеры