After making a stand alone three js app I wanted to make this three js app a component in my React application.
I needed multiple scenes overlayed so I made a threeApp function that instantiates a scene, camera, renderer and adds it to the DOM. So I tried to make a lot of stuff reusable.
After following this answer I managed to get some a three js scene with a spinning cube in my react app. Success! Since I already made a functioning OOP (?) implementation without react so I dove right in.
Right now I have a rendered canvas in my app but the objects in it are not getting rendered. However I can see the scene in three js inspector extension. If I console log at the animate/update functions they all fire.
This is the react component copied from this SO answer which originally worked.
import React, { Component } from 'react'
import * as THREE from 'three'
import testCube from "./viz/testCube"
import VizHandler from './VizHandler'
class Visualizer 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 vizHandler = this.vizHandler = new VizHandler();
vizHandler.init(this.mount);
this.start()
}
componentWillUnmount() {
this.stop()
// this.mount.removeChild(threeApps['vizholder'].getRenderer().domElement)
// vizHandler.unmount(this.mount);
}
start() {
if (!this.frameId) {
this.frameId = requestAnimationFrame(this.animate)
}
}
stop() {
cancelAnimationFrame(this.frameId)
}
animate() {
this.vizHandler.update(); // update / animate stuff in here
this.vizHandler.render()
this.frameId = window.requestAnimationFrame(this.animate)
}
render() {
return (
<div
// style={{ width: '400px', height: '400px' }}
ref={(mount) => { this.mount = mount }}
/>
)
}
}
export default Visualizer
I handle multiple threejs scenes/canvases here in the VizHandler function/class
import * as THREE from "three";
import threeApp from "./threeApp";
import WhiteRing from "./viz/WhiteRing";
import testCube from "./viz/testCube";
import Bars from "./viz/Bars";
const VizHandler = function () {
var threeApps = [];
var rings = new WhiteRing();
var bars = new Bars();
var cube = new testCube();
function init(mount) {
threeApps['vizholder'] = new threeApp();
// threeApps['overlay'] = new threeApp();
threeApps['vizholder'].init(mount, 'VizHolder') ;
// threeApps['overlay'].init(mount, 'Overlay');
window.scene = threeApps['vizholder'].getScene();
window.THREE = THREE;
const vizHolder = threeApps['vizholder'].getVizHolder();
rings.init( vizHolder );
bars.init( vizHolder );
cube.init( vizHolder );
}
function update() {
rings.update();
bars.update();
cube.update();
}
function render() {
threeApps["vizholder"].render();
}
return {
init: init,
update: update,
render: render,
getVizHolder: function( name ) {
if ( name ) return threeApps[name].getVizHolder();
else return threeApps['vizholder'].getVizHolder();
},
getRenderer: function( name ) {
if ( name ) return threeApps[name].getRenderer();
else return threeApps['vizholder'].getRenderer();
},
getThreeApps: function() {
return threeApps
},
};
};
And this is the most basic cube to that I'm trying to render.
import * as THREE from 'three';
const testCube = function () {
let cube;
function init (vizHolder) {
const groupHolder = new THREE.Object3D();
groupHolder.name = "TemplateViz";
vizHolder.add(groupHolder);
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color: '#ffffff' })
cube = new THREE.Mesh(geometry, material)
cube.name = "TESTCUBE";
groupHolder.add(cube);
vizHolder.add(groupHolder);
}
function update() {
cube.rotation.x += 0.01
cube.rotation.y += 0.01
}
return {
init: init,
update: update,
}
};
export default testCube;
And the result of all this is a renderer element in the dom that does not render my elements to the scene. I can change the renderer color and update the objects in the scene but I cannot make them appear.
EDIT: After solving the problem in my more simplified answer here, I forgot to post 1 important file where the error eventually occurred. The threeApp class where I make scenes, renderers and camera's. The code below was the non working code.
import * as THREE from "three";
function threeApp() {
let camera, scene, renderer;
let groundLight, skyLight, hemiLight;
let vizHolder;
let objName;
let renderColor = '#909009';
function init(mount, name) {
objName = name;
this.holderName = name;
renderer = new THREE.WebGLRenderer({
// antialias: true,
// alpha: true
});
renderer.setSize(800, 600);
renderer.domElement.className = "renderer";
mount.appendChild(renderer.domElement);
//3D SCENE
camera = new THREE.PerspectiveCamera(70, 800 / 600, 1, 3000);
camera.position.z = 1000;
camera.name = "camera";
scene = new THREE.Scene();
// window.THREE = THREE;
scene.name = name + " scene";
console.log( 'name', name );
if ( name == "VizHolder") {
window.scene = scene;
}
camera.lookAt(scene);
scene.fog = new THREE.Fog(0xffd8e5, 1000, 3000);
scene.add(camera);
//INIT VIZ
vizHolder = new THREE.Object3D();
vizHolder.name = name;
scene.add(vizHolder);
}
function update () {
render();
}
function render() {
renderer.render(scene, camera);
}
function onResize () {
var renderW = window.innerWidth;
var renderH = window.innerHeight;
camera.aspect = renderW / renderH;
camera.updateProjectionMatrix();
renderer.setSize(renderW, renderH);
}
return {
init: init,
render: render,
onResize: onResize,
getVizHolder: function() {
return vizHolder;
},
getCamera: function() {
return camera;
},
getScene: function() {
return scene;
},
getRenderer: function() {
return renderer;
},
setRenderColor: setRenderColor
}
};
export default threeApp