Home Reference Source Repository

src/appComponent/sceneContainer/scene/renderController.js

import * as THREE from 'three';
import * as threeOrbitControlsLib from 'three-orbit-controls'
const threeOrbitControls= threeOrbitControlsLib.default(THREE);
import MakeSpline from "./splineMaker";

/**
 * Render Controller
 */
class RenderControllerClass {

	/**
	 * initialize using three js
	 * @param {object} cameraControlAreaElement its the element which camera could control in it
	 * @param {number} width canvas width
	 * @param {number} height canvas height
	 */
	setup(cameraControlAreaElement,width,height){
		this.renderer = new THREE.WebGLRenderer();
		this.renderer.setSize(width,height);

		this.scene = new THREE.Scene();

		this.addCamera(cameraControlAreaElement);
		this.addLights();
		this.buildAxes(1000);

		this.repeatRendering();

		return this.renderer.domElement;
	}
	/**
	 * Make lights
	 */
	addLights() {
		let light = new THREE.PointLight(0xFF0000, 1, 100);
		light.position.set( 10, 0, 10 );
		this.scene.add(light);

		light = new THREE.PointLight(0xFF0000, 1, 50);
		light.position.set( -20, 15, 10 );
		this.scene.add(light);

		this.renderer.setClearColor(0x222222, 1);
	}

	/**
	 * add 3 Axis
	 * @param length determine 3 axis length
	 */
	buildAxes(length) {
		// const axes = new THREE.AxisHelper( length );
		// this.scene.add( axes );
		const axes = new THREE.Object3D();
		this.axes=axes;
		const color=0x2c2c2c;
		axes.add( this.buildAxis( new THREE.Vector3( -length, 0, 0 ), new THREE.Vector3( length, 0, 0 ), color, true ) ); // +X
		axes.add( this.buildAxis( new THREE.Vector3( 0, -length, 0 ), new THREE.Vector3( 0, length, 0 ), color, true ) ); // +Y
		axes.add( this.buildAxis( new THREE.Vector3( 0, 0, -length ), new THREE.Vector3( 0, 0, length ), color, true ) ); // +Z

		this.scene.add(axes);
	}
	buildAxis( src, dst, colorHex, dashed ) {
		var geom = new THREE.Geometry(),
			mat;

		if(dashed) {
			mat = new THREE.LineDashedMaterial({ linewidth: 1, color: colorHex, dashSize: 1, gapSize: 1 });
		} else {
			mat = new THREE.LineBasicMaterial({ linewidth: 1, color: colorHex });
		}

		geom.vertices.push( src.clone() );
		geom.vertices.push( dst.clone() );
		geom.computeLineDistances(); // This one is SUPER important, otherwise dashed lines will appear as simple plain lines

		return new THREE.Line( geom, mat, THREE.LinePieces );
	}

	/**
	 * add camera
	 * @param {object} cameraControlAreaElement its the element which camera could control in it
     */
	addCamera(cameraControlAreaElement) {
		this.camera =new THREE.PerspectiveCamera(
			35,         // FOV
			800 / 640,  // Aspect
			0.1,        // Near
			10000       // Far
		);
		this.camera.position.set(0, 0, 0);
		this.camera.position.z = 20;
		this.camera.lookAt(this.scene.position);
		const controls = new threeOrbitControls(this.camera,cameraControlAreaElement);
		const originUpdate=controls.update;
		const thisComponent=this;
		controls.update=function(){//when camera state changes
			originUpdate();
			thisComponent.onCameraChange();
		};
	}

	/**
	 * it just renders what is in the scene and won't create anything
	 */
	rerender() {
		this.renderer.render(this.scene, this.camera);
	}

	/**
	 * it will call back on camera changes
	 */
	onCameraChange() {
		if (this.curState) this.curState.cameraChanged = true;
		return true;
	}
	/**
	 * it will call back on control changes
	 */
	onStateChange(newState) {
		this.curState = newState;
	}

	/**
	 * rebuild spline
	 */
	rebuildSpline(data) {
		if (data) {
			this.axes.visible=data.optionsReducer.showAxes;
			if (this.spline) this.scene.remove(this.spline);
			this.spline = MakeSpline(data);
			this.scene.add(this.spline);
		}
	}

	/**
	 * control the rendering
	 */
	repeatRendering() {
		if (this.curState) {
			if (!this.curState.hasRendered) {
				this.rebuildSpline(this.curState);
				this.rerender();
				this.curState.hasRendered = true;
			}
			if (this.curState.cameraChanged) {
				this.rerender();
				this.curState.cameraChanged = false;
			}
		}
		const thisObj=this;
		requestAnimationFrame(function(){
			thisObj.repeatRendering();
		});
	}
}

export const RenderController = new RenderControllerClass();