firtoz / react-three-renderer

Render into a three.js canvas using React.
https://toxicfork.github.com/react-three-renderer-example/
MIT License
1.49k stars 155 forks source link

Question - How to implement the fpx-loader example of three.js by using react-three-renderer #179

Open hmtri1011 opened 7 years ago

hmtri1011 commented 7 years ago

I can preview a fbx model using threeJS but I want to implement a Component in React that can do it.

This is the code I use to preview a fbx file:

`

three.js - FBXLoader test
<script src="../build/three.js"></script>

<script src="js/controls/OrbitControls.js"></script>

<script src="js/curves/NURBSCurve.js"></script>
<script src="js/curves/NURBSUtils.js"></script>
<script src="js/loaders/FBXLoader2.js"></script>

<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/libs/zlib_and_gzip.min.js"></script>
<script>
    if (!Detector.webgl) Detector.addGetWebGLMessage();

    var container, stats, controls;
    var camera, scene, renderer, light;

    var clock = new THREE.Clock();

    var mixers = [];

    init();

    function init() {
        container = document.createElement('div');
        document.body.appendChild(container);
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
        scene = new THREE.Scene();

        // grid
        var gridHelper = new THREE.GridHelper(28, 28, 0x303030, 0x303030);
        gridHelper.position.set(0, - 0.04, 0);
        scene.add(gridHelper);

        // stats
        stats = new Stats();
        container.appendChild(stats.dom);

        console.log(stats);
        // model
        var manager = new THREE.LoadingManager();
        manager.onProgress = function (item, loaded, total) {
            console.log(item, loaded, total);
        };

        var onProgress = function (xhr) {
            if (xhr.lengthComputable) {
                var percentComplete = xhr.loaded / xhr.total * 100;
                console.log(Math.round(percentComplete, 2) + '% downloaded');
            }
        };

        var onError = function (xhr) {
            console.error(xhr);
        };

        var loader = new THREE.FBXLoader(manager);
        loader.load('models/fbx/accient_2_full.fbx', function (object) {
            scene.add(object);
        }, onProgress, onError);

        renderer = new THREE.WebGLRenderer();
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x000000);
        container.appendChild(renderer.domElement);

        // controls, camera
        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.target.set(0, 12, 0);
        camera.position.set(2, 18, 28);
        controls.update();

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

        light = new THREE.HemisphereLight(0xffffff, 0x444444, 1.0);
        light.position.set(0, 1, 0);
        scene.add(light);

        light = new THREE.DirectionalLight(0xffffff, 1.0);
        light.position.set(0, 1, 0);
        scene.add(light);
        animate();
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
        requestAnimationFrame(animate);
        if (mixers.length > 0) {
            for (var i = 0; i < mixers.length; i++) {
                mixers[i].update(clock.getDelta());
            }
        }
        stats.update();
        render();
    }

    function render() {
        renderer.render(scene, camera);
    }
</script>

`

How can I change it into React Component? I'm stuck in the code appendChild to dom Any help would be appreciated!

hmtri1011 commented 7 years ago

This is the code what I want to create a React Component that can render a FBX Model, but It shows a THREE.FBXLoader is not a constructor.

Am I doing wrong, really need some help

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import React3 from 'react-three-renderer'
import * as THREE from 'three'
import Stats from 'stats.js'

/*eslint-disable react/no-string-refs */
/*eslint-disable react/no-find-dom-node */
export default class Preview3D extends Component {
  constructor(props) {
    super(props)

    this.state = {
      cameraPosition: new THREE.Vector3(0, 50, 1500),
      lookAt: new THREE.Vector3(0, 200, 0)
    }

    this.lightPosition = new THREE.Vector3(1, 1, 1)
    this.clock = new THREE.Clock()

    this.mixers = []
    this._onAnimate = () => {}
  }

  componentDidMount() {
    const { scene } = this.refs

    // stats
    this.stats = new Stats()
    this.refs.container.appendChild(this.stats.domElement)

    const onProgress = function(xhr) {
      if (xhr.lengthComputable) {
        var percentComplete = xhr.loaded / xhr.total * 100
        console.log(Math.round(percentComplete, 2) + '% downloaded')
      }
    }

    const onError = function(xhr) {
      console.error(xhr)
    }

    const manager = new THREE.LoadingManager()
    manager.onProgress = function(item, loaded, total) {
      console.log(item, loaded, total)
    }

    const loader = new THREE.FBXLoader(manager)
    loader.load(
      '../accient_2_full.fbx',
      function(object) {
        scene.children.push(object)
      },
      onProgress,
      onError
    )

    // controls, camera
    const controls = new THREE.OrbitControls(
      this.refs.mainCamera,
      ReactDOM.findDOMNode(this.refs.react3)
    )

    controls.target.set(0, 12, 0)
    controls.addEventListener('change', () => {
      this.setState({
        cameraPosition: this.refs.mainCamera.position
      })
    })

    let light = new THREE.HemisphereLight(0xffffff, 0x444444, 1.0)
    light.position.set(0, 1, 0)
    scene.children.push(light)

    light = new THREE.DirectionalLight(0xffffff, 1.0)
    light.position.set(0, 1, 0)
    scene.children.push(light)
  }

  componentWillUnmount() {
    delete this.stats
  }

  render() {
    const width = window.innerWidth // canvas width
    const height = window.innerHeight // canvas height

    return (
      <div ref="container">
        <React3
          mainCamera="camera" // this points to the perspectiveCamera below
          width={width}
          height={height}
          onAnimate={this._onAnimate}
          ref="react3"
        >
          <scene ref="scene">
            <perspectiveCamera
              name="camera"
              fov={70}
              aspect={width / height}
              near={1}
              far={3000}
              position={this.state.cameraPosition}
              lookAt={this.state.lookAt}
            />
            <gridHelper size={1000} divisions={10} />
            <directionalLight
              color={0xffffff}
              intensity={2}
              position={this.lightPosition}
            />
            <mesh>
              <boxGeometry width={1} height={1} depth={1} />
              <meshBasicMaterial color={0x00ff00} />
            </mesh>
          </scene>
        </React3>
      </div>
    )
  }
}
toxicFork commented 7 years ago

The THREE.FBXLoader is not a constructor problem should be able to be resolved by including the the code of these relevant files (e.g. by placing their code on top of your file, or by using require):

<script src="js/curves/NURBSCurve.js"></script>
<script src="js/curves/NURBSUtils.js"></script>
<script src="js/loaders/FBXLoader2.js"></script>