• 21
    Like
  • 0
    Comment

react-three-rendererを使うことで、Three.jsのオブジェクトをJSXの中でコンポーネントとして記述することができます。

Example (w/redux)

scene, camera, meshなどThree.jsのオブジェクトがcomponentとして提供されていて、通常のReactComponent同様にsetStateで描画が更新されます。アニメーション処理はonAnimate内に記述します。

example.jsx
import React from 'react';
import React3 from 'react-three-renderer';
import { connect } from 'react-redux'
import * as THREE from 'three';
import { fetchTexture } from '../actions/texture';

const pi = Math.PI;
const rad = pi / 180;
const width = window.innerWidth;
const height = window.innerHeight;

class Example extends React.Component {
  state = {
    dirZ: -1,
    dirRad: rad,
    planePosition: new THREE.Vector3(0, 0, 500),
    planeRotation: new THREE.Euler(0, 0, 0)
  };

  cameraPosition = new THREE.Vector3(0, 100, 500);
  lightPosition = new THREE.Vector3(0, 100, 30);

  componentDidMount() {
    this.props.fetchPhotosWithTexture();
  }

  onAnimate() {
    this.setState({
      planePosition: new THREE.Vector3(
        this.state.planePosition.x,
        this.state.planePosition.y,
        this.state.planePosition.z + this.state.dirZ
      ),
      planeRotation: new THREE.Euler(
        this.state.planeRotation.x + this.state.dirRad,
        this.state.planeRotation.y,
        this.state.planeRotation.z + this.state.dirRad
      )
    });
  }

  render() {
    return (
      <React3
        mainCamera="camera"
        width={width}
        height={height}
        clearColor={0x000000}
        pixelRatio={window.devicePixelRatio}
        onAnimate={this.onAnimate.bind(this)}
      >
        <scene>
          <directionalLight position={this.lightPosition} />
          <ambientLight color={0xaaaaaa} />
          <perspectiveCamera
            name="camera"
            fov={45}
            aspect={width / height}
            near={1}
            far={2000}
            position={this.cameraPosition}
          />
          <gridHelper size={200} step={50} />
          <axisHelper size={1000} />

          {this.props.texture ?
            <mesh
              position={this.state.planePosition}
              rotation={this.state.planeRotation}
            >
              <planeGeometry
                width={this.props.texture.image.width / 2}
                height={this.props.texture.image.height / 2}
              />
              <meshLambertMaterial
                map={this.props.texture}
                side={THREE.DoubleSide}
              />
            </mesh>
          : null}
        </scene>
      </React3>
    );
  }
}

export default connect(
  state => ({ texture: state.texture }),
  { fetchTexture }
)(Example)

雑なsample

Debug

便利なことにReact Developer Toolsも通常のReact.jsと同じように使うことができます。
(さすがにprops, stateはReadOnlyになっていてこちらから動的に変えることはできないようですが)

スクリーンショット 2016-12-25 22.48.43.png

所感

私はReact.js製のアプリケーション内にThree.jsのコンテンツを表示するために使いましたが、Three.jsのオブジェクトの構造をより明示的に記述できるのは良いですね。React.js, Three.jsどちらも触ったことがあればAPI Documentationを見ればすぐに書けるかと思います。