如何将 Threejs 连接到 React?

Posted

技术标签:

【中文标题】如何将 Threejs 连接到 React?【英文标题】:How to connect Threejs to React? 【发布时间】:2017-05-06 00:31:12 【问题描述】:

我使用 React 并使用画布。我想将画布更改为 WebGL(Threejs 库)。如何将此库连接到 React?

我有一些元素,例如

<div ref="threejs"></div>

如何使它成为 Threejs 库调用的字段? PS:。我不想使用 react-threejs 之类的扩展

【问题讨论】:

componentDidMount 中,您可以访问DOM 引用this.refs.threejs 并使用.appendChild(threeRenderer.domElement) 之类的东西 进一步阅读生命周期方法,如componentDidMount: facebook.github.io/react/docs/… 查看我的回答如何在 React 中映射第 3 方库:***.com/a/40350880/1333836 在您的情况下应该看起来类似。 【参考方案1】:

以下是如何设置的示例 (see demo):

import React,  Component  from 'react'
import * as THREE from 'three'

class Scene extends Component 
  constructor(props) 
    super(props)

    this.start = this.start.bind(this)
    this.stop = this.stop.bind(this)
    this.animate = this.animate.bind(this)
  

  componentDidMount() 
    const width = this.mount.clientWidth
    const height = this.mount.clientHeight

    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(
      75,
      width / height,
      0.1,
      1000
    )
    const renderer = new THREE.WebGLRenderer( antialias: true )
    const geometry = new THREE.BoxGeometry(1, 1, 1)
    const material = new THREE.MeshBasicMaterial( color: '#433F81' )
    const cube = new THREE.Mesh(geometry, material)

    camera.position.z = 4
    scene.add(cube)
    renderer.setClearColor('#000000')
    renderer.setSize(width, height)

    this.scene = scene
    this.camera = camera
    this.renderer = renderer
    this.material = material
    this.cube = cube

    this.mount.appendChild(this.renderer.domElement)
    this.start()
  

  componentWillUnmount() 
    this.stop()
    this.mount.removeChild(this.renderer.domElement)
  

  start() 
    if (!this.frameId) 
      this.frameId = requestAnimationFrame(this.animate)
    
  

  stop() 
    cancelAnimationFrame(this.frameId)
  

  animate() 
    this.cube.rotation.x += 0.01
    this.cube.rotation.y += 0.01

    this.renderScene()
    this.frameId = window.requestAnimationFrame(this.animate)
  

  renderScene() 
    this.renderer.render(this.scene, this.camera)
  

  render() 
    return (
      <div
        style= width: '400px', height: '400px' 
        ref=(mount) =>  this.mount = mount 
      />
    )
  


export default Scene

您可能还对full screen example 感兴趣(请参阅GitHub)。

Here's an example using React Hooks 而不是一个类。

【讨论】:

想通了才发现这个,应该多点赞! 您能解释一下让示例在远程计算机上运行的所有过程吗?我只是了解纯 javascript。谢谢你:) 未将 self (this) 对象绑定到动画函数确实会在看到此示例之前引起问题。【参考方案2】:

您可以使用react-three-fiber

npm install three @react-three/fiber

用法

import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';
import ReactDOM from 'react-dom';

class Simple extends React.Component 
  constructor(props, context) 
    super(props, context);

    // construct the position vector here, because if we use 'new' within render,
    // React will think that things have changed when they have not.
    this.cameraPosition = new THREE.Vector3(0, 0, 5);

    this.state = 
      cubeRotation: new THREE.Euler(),
    ;

    this._onAnimate = () => 
      // we will get this callback every frame

      // pretend cubeRotation is immutable.
      // this helps with updates and pure rendering.
      // React will be sure that the rotation has now updated.
      this.setState(
        cubeRotation: new THREE.Euler(
          this.state.cubeRotation.x + 0.1,
          this.state.cubeRotation.y + 0.1,
          0
        ),
      );
    ;
  

  render() 
    const width = window.innerWidth; // canvas width
    const height = window.innerHeight; // canvas height
    return (<React3
      mainCamera="camera" // this points to the perspectiveCamera which has the name set to "camera" below
      width=width
      height=height

      onAnimate=this._onAnimate
    >
      <scene>
        <perspectiveCamera
          name="camera"
          fov=75
          aspect=width / height
          near=0.1
          far=1000
          position=this.cameraPosition
        />
        <mesh
          rotation=this.state.cubeRotation
        >
          <boxGeometry
            width=1
            height=1
            depth=1
          />
          <meshBasicMaterial
            color=0x00ff00
          />
        </mesh>
      </scene>
    </React3>);
  

ReactDOM.render(<Simple/>, document.body);

【讨论】:

I don't want to use extensions like react-threejs 是否有示例会改变 Euler 对象,而不是每次发生更改时都创建一个新实例? @pailhead 通知 react 状态已经改变,你必须调用 setState 方法。 React 将旧值与新值进行比较,如果检测到更改,则会发生新的渲染。新旧比较是“浅”的(不是“深”,即通过引用比较数组和对象)。欧拉的突变不会被 React 检测到。 请注意,React setState 方法是异步的。根据当前状态更新状态不是一个好主意。请参阅 ***.com/a/48224805/731548 了解正确的做法。 @cquezel 可以存储一个更原始的值,例如 - 最后一次更改的时间戳。我相信这会导致检测到更改。想知道有没有这样的例子。【参考方案3】:

我已经将 three.js 的第一个示例转换为 React 的东西。 希望这会有所帮助 从“反应”导入反应; 导入'./App.css'; 从“三”导入 * 作为三;

class App extends React.Component
  constructor(props)
    super(props)
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
      );
    this.renderer = new THREE.WebGL1Renderer();
        this.renderer.setSize( window.innerWidth, window.innerHeight );
    this.geometry = new THREE.BoxGeometry();
    this.material = new THREE.MeshBasicMaterial(  color: 0x32a852);
        this.cube = new THREE.Mesh( this.geometry, this.material)
  
  animate = () => 
    requestAnimationFrame(this.animate)
    this.cube.rotation.x += 0.01;
    this.cube.rotation.y += 0.01;
    this.renderer.render(this.scene, this.camera);
    
  
  componentDidMount() 
        document.body.appendChild( this.renderer.domElement );
        this.scene.add( this.cube );
        this.camera.position.z = 5;
        this.animate()
    
  render()
    return(
      <body id='document-body-01'>
      </body>
    );
  


export default App;

所以想法是这三个组件可以分解为构造函数、动画函数和componentdidmount。 我相信 this.varname 可以放在任何地方。 我觉得constructor是个好地方。 这样也可以设置其他示例。

【讨论】:

【参考方案4】:

我推荐你使用三纤&三drei库。

然后尝试使用&lt;Canvas&gt;&lt;/Canvas&gt;,您可以使用 React 的 useRef 钩子与画布对话。

https://docs.pmnd.rs/react-three-fiber/getting-started/introduction

这些文档非常适合入门,请务必查看它们!

【讨论】:

除了发布的链接之外,如果您提供基本示例会很好。

以上是关于如何将 Threejs 连接到 React?的主要内容,如果未能解决你的问题,请参考以下文章

如何将按钮事件连接到另一个 React 组件?

如何将 React Native Promise 连接到 Swift

如何使用 Spring Boot jwt 将身份验证系统连接到 React.js

无法将 React 连接到 Graphcool 后端

无法将 Redux 商店连接到 React Typescript App

将 React Redux 连接到 Typescript 中的组件